# Python程式設計入門-課堂筆記
10/17-11/14上課內容和問chatGPT得到的內容整理
10/17 科學計算
---
處理各種數學和科學任務,從數據分析到模擬和視覺化
1.數據分析:
使用Pandas庫處理和分析數據:
```python=
import pandas as pd
# 讀取數據文件
data = pd.read_csv('data.csv')
# 簡單統計摘要
print(data.describe())
# 選擇特定列
print(data['column_name'])
# 繪製直方圖
data['column_name'].hist()
```
2.線性代數:
使用NumPy執行矩陣運算
```python=
import numpy as np
# 創建矩陣
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 矩陣相加
C = A + B
# 矩陣乘法
D = np.dot(A, B)
print(C)
print(D)
```
3.科學計算:
使用SciPy解決科學計算問題,例如求解微分方程
```python=
from scipy.integrate import odeint
# 定義微分方程
def model(y, t):
return -2 * y
# 初始條件
y0 = 1
# 求解微分方程
t = np.linspace(0, 5, 100)
y = odeint(model, y0, t)
print(y)
```
4.視覺化:
使用Matplotlib繪製圖表
```python=
import matplotlib.pyplot as plt
x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(x)
plt.plot(x, y)
plt.xlabel('X軸')
plt.ylabel('Y軸')
plt.title('正弦波')
plt.show()
```
例子:計算複利
```python=
# 輸入資訊
P = 1000 # 假設本金為1000元
r = 0.03 # 年利率為3%
n = 365 # 每天複利一次
t = 1 # 1年
# 計算每日利息
daily_interest = P * (r/n)
# 計算本利和
A = P
for _ in range(n*t):
A += daily_interest
A = round(A) # 每天結束後四捨五入到整數位
# 輸出結果
print("一年後的本利和為:", A)
```
有無四捨五入對複利的影響
```python=
# 輸入資訊
P = 1000 # 假設本金為1000元
r = 0.03 # 年利率為3%
n = 365 # 每天複利一次
t = 1 # 1年
# 計算每日利息和本利和(有四捨五入)
A_with_rounding = P
for _ in range(n*t):
daily_interest = A_with_rounding * (r/n)
A_with_rounding += daily_interest
A_with_rounding = round(A_with_rounding)
# 計算每日利息和本利和(無四捨五入)
A_without_rounding = P
for _ in range(n*t):
daily_interest = A_without_rounding * (r/n)
A_without_rounding += daily_interest
# 輸出結果
print("有四捨五入的本利和為:", A_with_rounding)
print("無四捨五入的本利和為:", A_without_rounding)
# 比較兩者差異
difference = A_with_rounding - A_without_rounding
print("有四捨五入與無四捨五入的差異為:", difference)
```
計算本金對複利的影響
```python=
import matplotlib.pyplot as plt
# 計算每個本金 P 對應的差異
P_values = list(range(1000, 100001, 1000))
differences = []
for P in P_values:
A_with_rounding = P
A_without_rounding = P
for _ in range(n*t):
daily_interest = A_with_rounding * (r/n)
A_with_rounding += daily_interest
A_with_rounding = round(A_with_rounding)
daily_interest_without_rounding = A_without_rounding * (r/n)
A_without_rounding += daily_interest_without_rounding
difference = A_with_rounding - A_without_rounding
differences.append(difference)
# 繪製圖表
plt.figure(figsize=(10, 6))
plt.plot(P_values, differences)
plt.xlabel("本金 P")
plt.ylabel("四捨五入和無四捨五入的差異")
plt.title("本金 P 對差異的影響")
plt.grid(True)
plt.show()
```

---
10/24 網路爬蟲
---
先了解網頁HTML結構
```python=
<!DOCTYPE html>
<html>
<head>
<title>網頁標題</title>
</head>
<body>
<h1>歡迎來到我的網站</h1>
<p>這是一個示例網頁。</p>
<a href="https://www.example.com">訪問示例網站</a>
</body>
</html>
```
網路爬蟲第一步:向網頁請求HTML內容
```python=
import requests
# 目標網頁的URL
url = "https://www.example.com"
# 發送GET請求
response = requests.get(url)
# 檢查是否成功取得響應
if response.status_code == 200:
# 獲取網頁的HTML內容
html_content = response.text
# 在這裡你可以開始解析HTML,提取所需的資訊
else:
print("無法取得網頁,狀態碼:", response.status_code)
```
例如:提取新聞資訊
```python=
import requests
from bs4 import BeautifulSoup
URL = 'https://www.bbc.com/news/world'
# 向網頁請求HTML
response = requests.get(URL) # 注意變數名稱的大小寫
# 檢查是否成功取得響應
if response.status_code == 200:
# 獲取網頁的HTML內容
html_content = response.text
# 在這裡你可以開始解析HTML,提取所需的資訊
soup = BeautifulSoup(html_content, "html.parser")
# 使用正確的CSS選擇器來找到新聞標題
news_titles = soup.find_all("h3", {"class": "gs-c-promo-heading__title"})
for news_title in news_titles:
# 印出新聞標題文本
print(news_title.text)
else:
print("無法取得網頁,狀態碼:", response.status_code)
```
提取成大網頁特定內容
```python=
import requests
from bs4 import BeautifulSoup
# 目標網址
URL = 'https://www.ncku.edu.tw/'
# 向網頁請求HTML
response = requests.get(URL)
# 檢查是否成功取得響應
# 一個網頁伺服器成功處理一個請求時,它會返回一個狀態碼,通常是一個三位數的數字,用來表示請求的結果。200 是 HTTP 狀態碼中代表成功的代碼。
if response.status_code == 200:
# 獲取網頁的HTML內容
html_content = response.text
# 在這裡你可以開始解析HTML,提取所需的資訊
# html_content 是包含網頁 HTML 內容的字串,html.parser" 是解析器的選項,它告訴 BeautifulSoup 使用 HTML 解析器來解析 html_content。
soup = BeautifulSoup(html_content, "html.parser")
# 先大範圍搜索,這個部分包含整個網頁中的成大快訊全部訊息
informations = soup.find_all('div', class_='mouter')
# 針對成大快訊裡面的訊息去找每篇內容的標題
for information in informations:
title = information.find_all('h2', class_='mt-title')
# 如果這個標題是成大快訊,代表這部分的內容是我們要找的
# title[0]代表我們要得到第一個匹配元素的文本
if title and title[0].text == '成大快訊':
# 所以我們可以更進一步找我們要的內容
contents = information.find_all('div', class_='d-item v-it col-sm-3')
# 講每篇內容輸出,用strip使不會空格
for content in contents:
print(content.text.strip())
```
---
10/31 圖像處理
---
各種圖像處理
1.將兩張圖合併
```python=
def concatenate_images(image1, image2): # 要把兩張圖, 左右合併在一起的函式
total_width = image1.width + image2.width # 因為要左右合併在一起, 所以圖片的寬度
max_height = max(image1.height, image2.height) # 兩張圖可能不一樣高, 取比較高的圖片高度
new_image = Image.new('RGB', (total_width, max_height))
new_image.paste(image1, (0, 0)) # 貼第一張圖
new_image.paste(image2, (image1.width, 0)) # 貼第二張圖
return new_image
```
2.旋轉縮放
```python=
# 旋轉圖片 (角度)
rotated_image = image.rotate(45) # 逆時針旋轉45度
display(rotated_image)
# 縮放圖片
resized_image = image.resize((200, 200))
display(resized_image)
```
3.調整亮度
```python=
from PIL import ImageEnhance
# 調整亮度
enhancer = ImageEnhance.Brightness(image)
brightened_image = enhancer.enhance(1.5) # 1.0表示原始亮度
display(brightened_image)
# 調整對比度
enhancer = ImageEnhance.Contrast(image)
high_contrast_image = enhancer.enhance(2.0) # 1.0表示原始對比度
display(high_contrast_image)
```
4.變灰色
```python=
gray_image = image.convert("L")
combined_image = concatenate_images(image, gray_image)
plt.imshow(combined_image)
plt.axis('off') # 不顯示座標軸
plt.show()
#
```
5.使用濾鏡
```python=
# 使用模糊滤镜进行模糊处理
from PIL import ImageFilter # 一開始不能跑, 會有imagefilter的name error, 所以我才加上去的
blurred_image = image.filter(ImageFilter.GaussianBlur(radius=100))
combined_image = concatenate_images(image, blurred_image)
plt.imshow(combined_image)
plt.axis('off') # 不顯示座標軸
plt.show()
```
6.特殊處理
```python=
# 获取图片的宽度和高度
width, height = image.size
# 创建一个新的空白图片,与原始图片大小相同
negative_image = Image.new("RGB", (width, height))
# 遍历每个像素并取反RGB值
for x in range(width):
for y in range(height):
pixel = image.getpixel((x, y)) # 得到像素的值 tuple (R,G,B)
inverted_pixel = tuple(255 - value for value in pixel)
# 用for-loop 產生tuple中的每一個值
negative_image.putpixel((x, y), inverted_pixel) #把像素的(RGB)放回圖片中
combined_image = concatenate_images(image, negative_image)
plt.imshow(combined_image)
plt.axis('off') # 不顯示座標軸
plt.show()
```
---
11/7 遊戲設計
---
我自己在預習時利用chatGPT寫的圈圈叉叉小遊戲
```python=
# 用list來幫九宮格儲存遊戲資料,list裡面的資料是有順序的,所以用for迴圈代表第0到8個數據
board = [' ' for _ in range(9)]
# 定義一個函數來顯示九宮格圈圈叉叉遊戲情況,board[數字]代表這個list裡面第幾個數據
def display_board(board):
# 按照九宮格形式print出來
print(board[0],board[1],board[2])
print(board[3],board[4],board[5])
print(board[6],board[7],board[8])
# 定義另一個函數來檢查遊戲勝利條件
def check_game(board):
# 用一個list存放勝利組合,勝利組合是一個元組(),裡面的三個數字分別代表的是可以連成一條線的三個位置
win_combinations = [(0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), (0, 4, 8), (2, 4, 6)]
# 用for迴圈將borad去做每個勝利組合位置的判斷,意思就是第一個迴圈用(0,1,2)這三個位置去判斷有沒有成一條線,再來用(3,4,5)這三個位置去判斷,以此回圈
for combination in win_combinations:
# 0,1,2分別代表勝利組合()裡的第0,1,2個數字,如果這三個位置都相同,且不等於空格' ',代表連成一線
if board[combination[0]] == board[combination[1]] == board[combination[2]] != ' ':
# now 是一個變數,代表現在的玩家是誰,所以如果連成一線勝利,就return勝利玩家
return now
# 如果board上沒有空格,但還沒有判斷出誰勝利,代表平手
if ' ' not in board:
return 'tie'
else:
return False
# 第一個玩家是User1
now = 'User1'
# 主遊戲回圈
while True:
# 如果變數now等於User1時,換User1玩
if now == 'User1':
# 輸入position,減一是因為資料是從第0個開始,但位置是從1開始,所以輸入的數字要-1才能匹配到對的資料位置
print('User one turn to input now')
position = eval(input('Select input position 1~9 =' )) -1
# 防呆,如果輸入的值不在對應九宮格內,還有把輸入的position放到對應九宮格內發現這個位置不是空格,代表已經被輸入過了
if position<0 or position>8 or board[position] != ' ':
print('User one turn to input now')
print('該位置已經被輸入,請重新輸入')
position = eval(input('Select input position 1~9 =' ))-1
# 輸入position到九宮格內,就是把對應的資料從空個' '改成'o'
board[position] = 'o'
# 然後把遊戲情況顯示出來
display_board(board)
# 檢查勝利條件
result = check_game(board)
# result = now 代表有人贏了
if result == now:
print(now,'win')
# game over要記得把回圈break
break
# result = tie 代表平手
elif result == 'tie':
print('Tie')
break
# 最後要切換玩家,把now變數改為User2
now = 'User2'
# 換User2玩
else:
# 以下和User2的code一樣
print('User two turn to input now')
position = eval(input('Select input position 1~9 =' )) -1
if position<0 or position>8 or board[position] != ' ':
print('該位置已經被輸入,請重新輸入')
print('User two turn to input now')
position = eval(input('Select input position 1~9 =' ))-1
board[position] = 'x'
display_board(board)
if result == now:
print(now,'win')
break
elif result == 'tie':
print('Tie')
break
now = 'User1'
```
可改進的地方:
可以新增棋盤和把初始值設為該位置的數字,再遊戲進行時再把該位置的變數改為o或x,來讓遊戲更完整
---
11/14 機器學習
---
利用data去建構model,來讓機器能利用這個model來辨識特徵
例子:Tensor_Flow_PlayGround
這個範例是要做一個類似tensor flow playground的類神經網路分類器。
其中我們產生兩個分類
與原點距離R0到R1,Positive (藍色點)
與原點距離是R2到R3的,Negative (橘色點)
每一類各產生 𝑁 個點供訓練用, 也各產生 𝑁𝑝 個點以標記出確定Positive的範圍
**生成數據點**
```python=
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.model_selection import train_test_split
N = 200 # 原始點的數量
Np = 1200 # 額外點的數量
#
def generate_circle_points(r_min, r_max, num_points):
angles = np.random.uniform(0, 2 * np.pi, num_points)
radii = np.sqrt(np.random.uniform(r_min**2, r_max**2, num_points)) # 為什麼要這樣才會均勻, 請問數學老師
x = radii * np.cos(angles)
y = radii * np.sin(angles)
return x, y
# 生成數據點
R0 = 0
R1 = 2
R2 = 1
R3 = 3
x_o, y_o = generate_circle_points(R0, R1, N)
x_x, y_x = generate_circle_points(R2, R3, N)
# 繪製散點圖
plt.figure(figsize=(8, 8))
plt.scatter(x_o, y_o, c='blue', marker='o', label='Positive O')
plt.scatter(x_x, y_x, c='orange', marker='o', label='Negative O')
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Scatter Plot with Different Classes')
plt.legend()
plt.grid(True)
plt.axis('equal')
plt.show()
```

**Training function**
```python=
import matplotlib.pyplot as plt
import numpy as np
def plot_predictions(X_train, y_train, X_test, y_test, model):
# 使用模型對訓練集進行預測
y_pred_train_continuous = model.predict(X_train)
y_pred_train = np.where(y_pred_train_continuous.flatten() >= 0, 1, -1)
# 使用模型對測試集進行預測
y_pred_test_continuous = model.predict(X_test)
y_pred_test = np.where(y_pred_test_continuous.flatten() >= 0, 1, -1)
plt.figure(figsize=(8, 8))
# 訓練集 - 預測正確
correct_train = (y_train == y_pred_train)
oc = (y_train == 1) & correct_train
xc = (y_train == -1) & correct_train
plt.scatter(X_train[oc, 0], X_train[oc, 1], c='blue', marker='o', label='Train Correct (Positive)')
plt.scatter(X_train[xc, 0], X_train[xc, 1], c='orange', marker='o', label='Train Correct (Negative)')
# 訓練集 - 預測錯誤
incorrect_train = (y_train != y_pred_train)
oi = (y_train == 1) & incorrect_train
xi = (y_train == -1) & incorrect_train
plt.scatter(X_train[oi, 0], X_train[oi, 1], c='blue', marker='x', label='Train Incorrect (Positive)')
plt.scatter(X_train[xi, 0], X_train[xi, 1], c='orange', marker='x', label='Train Incorrect (Negative)')
# 測試集 - 預測正確
correct_test = (y_test == y_pred_test)
oc = (y_test == 1) & correct_test
xc = (y_test == -1) & correct_test
plt.scatter(X_test[oc, 0], X_test[oc, 1], c='cyan', marker='o', label='Test Correct (Positive)')
plt.scatter(X_test[xc, 0], X_test[xc, 1], c='pink', marker='o', label='Test Correct (Negative)')
# 測試集 - 預測錯誤
incorrect_test = (y_test != y_pred_test)
oi = (y_test == 1) & incorrect_test
xi = (y_test == -1) & incorrect_test
plt.scatter(X_test[oi, 0], X_test[oi, 1], c='cyan', marker='x', label='Test Incorrect (Positive)')
plt.scatter(X_test[xi, 0], X_test[xi, 1], c='pink', marker='x', label='Test Incorrect (Negative)')
plt.xlabel('X Coordinate')
plt.ylabel('Y Coordinate')
plt.title('Model Predictions')
plt.legend()
plt.grid(True)
plt.show()
```
**整理、分割數據,創建神經網絡model**
```python=
# 整合並標記數據點
X = np.vstack((np.column_stack((x_o, y_o)), np.column_stack((x_x, y_x))))
y = np.array([1] * N + [-1] * N) # 1代表o,-1代表x
# 分割數據集, 把 N 中的 20% 做為測試
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 創建神經網路模型
N1 = 3
model = Sequential()
model.add(Dense(N1, input_dim=2, activation='tanh')) # 第一層有N1個神經元,使用tanh激活函數
model.add(Dense(2, input_dim=2, activation='tanh')) # 第二層有2個神經元
model.add(Dense(1, activation='tanh')) # 第三層有1個神經元
# 編譯模型
model.compile(loss='mean_squared_error', optimizer='adam', metrics=['accuracy'])
```
**Training並記錄loss function**
```python=
# 訓練模型並記錄訓練過程
history = model.fit(X_train, y_train, epochs=1000, batch_size=5, verbose=0, validation_data=(X_test, y_test))
# 獲取損失函數值
loss_values = history.history['loss']
# 繪製損失函數圖
plt.figure(figsize=(8, 4))
plt.plot(loss_values, label='Training Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss Function During Training')
plt.legend()
plt.grid(True)
plt.show()
plot_predictions(X_train, y_train, X_test, y_test, model)
# 獲取第一層的權重和偏置
weights, biases = model.layers[0].get_weights()
# 生成更多隨機點進行預測
x_a, y_a = generate_circle_points(R0, R3, Np)
additional_X = np.column_stack((x_a, y_a))
y_pred_additional = model.predict(additional_X)
y_pred_additional = np.where(y_pred_additional.flatten() >= 0, 1, -1)
# 繪製測試數據和預測結果
plt.figure(figsize=(8, 8))
plt.scatter(x_o, y_o, c='blue', marker='o', label='Class Positive')
plt.scatter(x_x, y_x, c='orange', marker='o', label='Class Negative')
plt.scatter(additional_X[y_pred_additional == 1, 0], additional_X[y_pred_additional == 1, 1], c='blue', marker='o', label='Predicted Positive')
plt.scatter(additional_X[y_pred_additional == -1, 0], additional_X[y_pred_additional == -1, 1], c='orange', marker='o', label='Predicted Negative')
# 繪製第一層的N1條直線
x_values = np.linspace(-2, 2, 100)
y_values = np.linspace(-2, 2, 100)
for i in range(N1):
a, b = weights[:, i]
c = biases[i]
if abs(a) > abs(b):
x_line = (-b * y_values - c) / a
plt.plot(x_line, y_values, linestyle='--', label=f'Neuron {i+1} Boundary')
else:
y_line = (-a * x_values - c) / b
plt.plot(x_values, y_line, linestyle='--', label=f'Neuron {i+1} Boundary')
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Additional Points Classification with Neuron Boundaries')
plt.legend()
plt.grid(True)
plt.axis('equal')
plt.show()
```



**計算準確率**
```python=
#loss, accuracy = model.evaluate(X_train, y_train)
#print('train loss: ', loss)
#print('train accuracy: ', accuracy)
y_pred_train_continuous = model.predict(X_train)
y_pred_train = np.where(y_pred_train_continuous.flatten() >= 0, 1, -1)
TP = sum((y_pred_train==1) & (y_train == 1))
TN = sum((y_pred_train==-1) & (y_train == -1))
FP = sum((y_pred_train==1) & (y_train == -1))
FN = sum((y_pred_train==-1) & (y_train == 1))
print("In training set:")
TPR = TP/(TP+FN)
TNR = TN/(TN+FP)
FPR = 1-TNR
FNR = 1-TPR
PPV = TP/(TP+FP)
NPV = TN/(TN+FN)
F1 = 2*PPV*TPR/(PPV+TPR)
ACC = (TP+TN)/(TP+TN+FP+FN)
print("TP=",TP,"TN=",TN,"FP=",FP,"FN=",FN)
print("Accuracy=",ACC)
print("TPR(Sensitivity, Recall)=",TPR,"TNR(Specificity)=",TNR)
```

**實際情況**
```python=
# 模型预测为 1(类别 o)的点
o_predicted = additional_X[y_pred_additional == 1]
# 模型预测为 -1(类别 x)的点
x_predicted = additional_X[y_pred_additional == -1]
# 计算预测为类别 o 的点中,实际上也属于类别 o 的比例(x^2 + y^2 < 1)
o_correct = np.sum(np.sum(o_predicted**2, axis=1) < R1**2)
o_total = o_predicted.shape[0]
o_correct_ratio = o_correct / o_total if o_total > 0 else 0
# 计算预测为类别 o 的点中,实际上属于类别 x 的比例(x^2 + y^2 > 1)
o_incorrect = np.sum(np.sum(o_predicted**2, axis=1) > R2**2)
o_incorrect_ratio = o_incorrect / o_total if o_total > 0 else 0
# 计算预测为类别 x 的点中,实际上也属于类别 x 的比例(x^2 + y^2 > 2^2)
x_correct = np.sum(np.sum(x_predicted**2, axis=1) > R2**2)
x_total = x_predicted.shape[0]
x_correct_ratio = x_correct / x_total if x_total > 0 else 0
# 计算预测为类别 x 的点中,实际上属于类别 o 的比例(x^2 + y^2 < 2^2)
x_incorrect = np.sum(np.sum(x_predicted**2, axis=1) < R1**2)
x_incorrect_ratio = x_incorrect / x_total if x_total > 0 else 0
print("預測為 o 的點中,屬於類別 o 的比例: {:.4f}".format(o_correct_ratio))
print("預測為 o 的點中,屬於類別 x 的比例: {:.4f}".format(o_incorrect_ratio))
print("預測為 x 的點中,屬於類別 x 的比例: {:.4f}".format(x_correct_ratio))
print("預測為 x 的點中,屬於類別 o 的比例: {:.4f}".format(x_incorrect_ratio))
```
