# 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() ``` ![截圖 2023-11-20 下午9.46.50](https://hackmd.io/_uploads/rJCIQyFET.png) --- 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() ``` ![截圖 2023-11-21 上午3.02.40](https://hackmd.io/_uploads/Sk4D6QK4T.png) **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() ``` ![截圖 2023-11-21 上午3.07.22](https://hackmd.io/_uploads/rkStC7FEa.png) ![截圖 2023-11-21 上午3.08.16](https://hackmd.io/_uploads/r1d207tEp.png) ![截圖 2023-11-21 上午3.08.43](https://hackmd.io/_uploads/SJTa07FNp.png) **計算準確率** ```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) ``` ![截圖 2023-11-21 上午3.10.24](https://hackmd.io/_uploads/ryi4k4YN6.png) **實際情況** ```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)) ``` ![截圖 2023-11-21 上午3.12.32](https://hackmd.io/_uploads/ry-2yEKV6.png)