# Python 10/17-11/14筆記整理
___
## 10/17運用Python進行科學計算
### 1.本利和
本利是指在投資或貸款中所產生的利息,它是基於原始本金和利率的產物。計算本利的公式如下:
$$
I = P \times r \times t
$$
其中:
- \( I \) 代表本利(總利息),
- \( P \) 代表原始本金,
- \( r \) 代表利率(以小數形式表示,例如5%轉換為0.05),
- \( t \) 代表時間(以年為單位)。
如果你想要計算總金額(本金加上本利),則公式如下:
$$ A = P + I $$
其中:
- \( A \) 代表總金額。
### 2.四捨五入VS沒有四捨五入的本利和
```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)
```
:::success
一年後的本利和為: 1000
:::
```python=
import matplotlib.pyplot as plt
# 設定參數
n = 365 # 複利次數(每年365次)
t = 10 # 年數
# 計算每個本金 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("Principal")
plt.ylabel("Difference between Rounded and Unrounded Compound Interests")
plt.title("Impact of Principal (P) on Differences")
plt.grid(True)
plt.show()
```

:::success
有四捨五入的本利和為: 1000
無四捨五入的本利和為: 1030.45326360051
有四捨五入與無四捨五入的差異為: -30.4532636005099
:::
### 3.人口成長模型
```python=
import numpy as np
import matplotlib.pyplot as plt
# 定義參數
r = 0.1 # 增長率
M = 500 # 環境容量
u0 = 10 # 初始人口大小
num_steps = 100 # 模擬的時間步數
# 初始化數據
u_values = [u0]
time_values = [0]
# 進行數值模擬
for t in range(1, num_steps + 1):
u_t = u_values[-1]
# 使用 Logistic 模型的差分方程進行數值模擬
u_next = u_t + r * u_t * (1 - u_t/M)
# 更新數據
u_values.append(u_next)
time_values.append(t)
# 繪製人口變化圖
plt.plot(time_values, u_values)
plt.xlabel('時間')
plt.ylabel('人口數')
plt.title('Logistic 模型')
plt.grid(True)
plt.show()
```

```python=
```
## 10/24運用Python進行網路爬蟲
爬蟲的基本步驟:
發送請求: 使用程式代碼發送 HTTP 請求到目標網站的伺服器,獲取網頁內容。
解析 HTML: 使用解析庫(例如 BeautifulSoup 或 lxml)解析獲得的 HTML 內容,找到目標數據的標籤和屬性。
提取數據: 根據解析結果,提取出需要的數據,可以是文字、圖片、連結等。
存儲數據: 將提取的數據存儲在本地文件或數據庫中,以便後續分析或使用。
### 1.抓成大故事觀點下面的內容
```python=
import requests
from bs4 import BeautifulSoup
# 指定目標網頁的URL
url = 'https://www.ncku.edu.tw/'
# 發送HTTP請求,獲取網頁內容
response = requests.get(url)
# 檢查是否成功獲取網頁內容
if response.status_code == 200:
# 使用Beautiful Soup解析網頁內容
soup = BeautifulSoup(response.text, 'html.parser')
# 查找包含 "故事 觀點" 文字的元素。這是第一層,要注意從網頁檢查時,藍色的
elements_1 = soup.find_all('div', class_='mouter')
# 打印找到的元素內容
k = 1
for element in elements_1:
print(f"=== 第 {k} 個元素 ===")
k = k + 1
# 在第一層元素中,查找包含 "d-item v-it col-sm-3" 類別的子元素
elements_2 = element.find_all('div', class_='d-item v-it col-sm-3')
# 打印第二層元素的文本內容
for e in elements_2:
print(e.text.strip())
else:
print('無法獲取網頁內容')
```
:::success
【92 校慶】2023「永續之島策略設計策略系列論壇」 以永續前瞻為起點 回饋母校共好台灣
【92 校慶】2023 成材產業論壇 關心人類生存大環境 聚焦綠能科技與新經濟
【92 校慶】第三屆成電論壇 重量級校友、系友探討生成式 AI 發展趨勢
建築學系 45 級 黃南淵 : 如果不能看清楚眼前美麗的玫瑰,又如何期待明年春天的來臨|成大 112 傑出校友
:::
### 2.抓獎學金資料
```python=
import requests
from bs4 import BeautifulSoup
def download_file(url, destination_filename):
# 發送 HTTP 請求獲取文件
response = requests.get(url)
response.raise_for_status() # 如果是 HTTP 錯誤,則拋出異常
with open(destination_filename, 'wb') as f:
f.write(response.content)
print(f"File saved to {destination_filename}")
# 輸入網址
response = requests.get('https://assistance-osa.ncku.edu.tw/p/403-1051-699.php?Lang=zh-tw')
# 解析成 HTML 語言
soup = BeautifulSoup(response.content, "html.parser")
# 找到對應的 tag,find_all 之後要用一個 for-loop 把找到的一個一個列出來
mtitle = soup.find_all("section", class_="mb")
for m in mtitle:
# 再往下找對應的 title
scholarship = m.find_all("div", class_="mtitle")
for s in scholarship:
# 找到 a 標籤,取得文字和連結
u = s.find('a')
print(f"Title: {u.text.strip()}")
# 找到 i 標籤,取得文字(日期等相關資訊)
d = s.find('i')
print(f"Date: {d.text.strip()}")
# 打印連結
print(f"URL: {u['href']}")
# 透過連結發送 HTTP 請求獲取子網頁內容
response2 = requests.get(u["href"])
soup2 = BeautifulSoup(response2.content, "html.parser")
# 找到包含附件的區塊
attach = soup2.find('ul', class_='mptattach')
# 找到附件的 a 標籤,取得文字和連結
file = attach.find('a')
print(f"Attachment: {file.text.strip()}")
print(f"Attachment URL: {file['href']}")
# 下載文件
download_file("https://assistance-osa.ncku.edu.tw/"+file["href"], u.text.strip() + ".pdf")
```
:::success
112上漢翔航空工業股份有限公司-獎助碩博士獎學金
2023-11-20
https://assistance-osa.ncku.edu.tw/p/406-1051-260862,r699.php?Lang=zh-tw
a15103-130.doc-.pdf
/app/index.php?Action=downloadfile&file=WVhSMFlXTm9Mekk1TDNCMFlWOHhORGMxTmpOZk5UUTBNRFV6TUY4ME16QXpOeTV3WkdZPQ==&fname=B154RPOKIC44TXMPA404USWT34B4OOHC14B040YSA105DCTSKPZWLOUW14OK50XXYWPOHD0520A0TX24YWSWJGICQOICNORLUTJDA52114NO1111
File saved to 112上漢翔航空工業股份有限公司-獎助碩博士獎學金.pdf
112上財團法人嘉義西區扶輪社文教基金會-獎學金
2023-11-13
https://assistance-osa.ncku.edu.tw/p/406-1051-260547,r699.php?Lang=zh-tw
a3491-407申請表格.odt
/app/index.php?Action=downloadfile&file=WVhSMFlXTm9MelV2Y0hSaFh6RTBOelF4TjE4NU56RTNOVFV3WHpVNU1URTBMbTlrZEE9PQ==&fname=B154RPOKICWWVXMPA4TWJGWTVWB4GGIC14FGHGYSVXQLPO40NKB424B4WS10B4SSYW5400HHDG04EGHC34XSTSA1KL3410GCTXVXA4CC34A401OOOOA4XXWXROPOSSOO
File saved to 112上財團法人嘉義西區扶輪社文教基金會-獎學金.pdf
國立成功大學永豐商業銀行傑出人才獎助學金
2023-11-13
https://assistance-osa.ncku.edu.tw/p/406-1051-260546,r699.php?Lang=zh-tw
:::
這個程式主要爬取了指定網頁中的相關資訊,包括獎學金標題、日期、連結和附件,然後進行文件下載。
## 10/31運用Python進行圖像處理
:::info
用於下載兩張圖片,然後將它們水平合併成一張新的圖片。
1.download_image(url): 這個函數使用 requests 庫向指定的 URL 發送 HTTP 請求,然後使用 PIL 库的 Image.open 方法打開圖片。該函數返回打開的圖片對象。
2.concatenate_images(image1, image2): 這個函數接受兩個圖片對象,計算它們的合併寬度和高度,然後創建一個新的圖片對象(new_image)。接著,它使用 paste 方法將第一張圖片粘貼到新圖片的左側,將第二張圖片粘貼到右側。最終,它返回合併後的圖片對象。
3.指定兩個圖片的 URL,然後使用上述函數將它們合併成一張新的圖片。合併的過程是將第一張圖片的左側和右側分別粘貼上第二張圖片,形成一張寬度是兩張圖片寬度總和,高度是兩張圖片高度的最大值的新圖片。
4.顯示合併後的圖片:使用 matplotlib 的 imshow 方法顯示合併後的圖片,並且設置 plt.axis('off') 以隱藏座標軸。
5.儲存合併後的圖片:使用 save 方法將合併後的圖片保存到本地文件系統中。
:::
### 1.拼接三張圖
```python=
import requests
from PIL import Image
from io import BytesIO
import matplotlib.pyplot as plt
def download_image(url):
# 發送 HTTP 請求獲取圖片
response = requests.get(url)
# 使用 PIL 库打開圖片
image = Image.open(BytesIO(response.content))
return image
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
# 替換成你的圖片網址
image_url1 = download_image("https://web.ncku.edu.tw/var/file/0/1000/img/DSC01181ok.jpg")
image_url2 = download_image("https://web.ncku.edu.tw/var/file/0/1000/img/418380686.jpg")
# 連接三張圖片
result_image = concatenate_images(image_url1, image_url2)
result_image = concatenate_images(result_image, image_url1)
# 顯示合併後的圖片
plt.imshow(result_image)
plt.axis('off') # 不顯示座標軸
plt.show()
# 儲存合併後的圖片
result_image.save("concatenated_image.jpg")
```

### 2.拼接圖片及文字
```python=
import requests
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
import matplotlib.pyplot as plt
def download_image(url):
# 發送 HTTP 請求獲取圖片
response = requests.get(url)
# 使用 PIL 库打開圖片
image = Image.open(BytesIO(response.content))
return image
def draw_multiline_text(draw, text, position, font, max_width):
lines = text.split('\n')
y = position[1]
for line in lines:
# 使用 textbbox 獲取文字的尺寸
text_bbox = draw.textbbox((0, 0), line, font=font)
text_width = text_bbox[2] - text_bbox[0]
text_height = text_bbox[3] - text_bbox[1]
# 計算文字位置
x = (max_width - text_width) / 2 + position[0]
draw.text((x, y), line, font=font, fill="white")
y += text_height
def create_image_with_text(image_url, text):
# 下載並獲取左邊的圖片
left_image = download_image(image_url)
# 創建一個相同大小的黑色背景圖片
right_image = Image.new('RGB', left_image.size, color='black')
# 在黑色背景圖片上添加文字
draw = ImageDraw.Draw(right_image)
font_size = int(min(right_image.size) / 10) # 根據圖片大小調整字體大小
font = ImageFont.truetype("ThePeakFontBeta_V0_101.ttf", font_size) # 使用下載的字體
# 計算文字位置
max_width = right_image.width * 0.8
x = (right_image.width - max_width) / 2
y = (right_image.height - draw.textbbox((0, 0), text, font=font)[3]) / 2
draw_multiline_text(draw, text, (x, y), font, max_width)
# 將左邊和右邊的圖片拼接
total_width = left_image.width + right_image.width
new_image = Image.new('RGB', (total_width, left_image.height))
new_image.paste(left_image, (0, 0))
new_image.paste(right_image, (left_image.width, 0))
return new_image
# 替換成你的圖片網址
image_url = "https://web.ncku.edu.tw/var/file/0/1000/img/DSC01181ok.jpg"
# 輸入你想在右邊圖片中顯示的多行文字
text = "成大職治系實在好棒棒!\n成大職治系實在好棒棒!\n成大職治系實在好棒棒!"
result_image = create_image_with_text(image_url, text)
# 顯示合併後的圖片
plt.imshow(result_image)
plt.axis('off') # 不顯示座標軸
plt.show()
# 儲存合併後的圖片
result_image.save("image_with_multiline_text.jpg")
```

### 3.拼接一張灰色調圖片
```python=
# 首先創建一個 ImageEnhance.Color 對象,然後使用 enhance 方法來調整圖片的顏色饱和度。增强後的圖片與原始圖片使用先前定義的 concatenate_images 函式進行左右合併,最後使用 matplotlib.pyplot 顯示合併後的圖片
# 创建一个颜色增强器对象
color_enhancer = ImageEnhance.Color(image)
# 调整颜色饱和度(1.0 表示原始饱和度,小于 1.0 减弱饱和度,大于 1.0 增强饱和度)
enhanced_image = color_enhancer.enhance(0.1) # 增强颜色饱和度
# 將原始圖片和增強後的圖片進行左右合併
combined_image = concatenate_images(image, enhanced_image)
# 顯示合併後的圖片
plt.imshow(combined_image)
plt.axis('off') # 不顯示座標軸
plt.show()
```

### 4.拼接一張模糊圖片
```python=
# 首先導入 ImageFilter 模組,然後使用 GaussianBlur 濾鏡對原始圖片進行模糊處理。接著,將原始圖片和模糊處理後的圖片使用先前定義的 concatenate_images 函式進行左右合併,最後使用 matplotlib.pyplot 顯示合併後的圖片
# 使用模糊滤镜进行模糊处理
blurred_image = image.filter(ImageFilter.GaussianBlur(radius=100))
# 將原始圖片和模糊處理後的圖片進行左右合併
combined_image = concatenate_images(image, blurred_image)
# 顯示合併後的圖片
plt.imshow(combined_image)
plt.axis('off') # 不顯示座標軸
plt.show()
```

### 5.拼接一張負片
```python=
# 創建一個與原始圖片大小相同的空白圖片,然後遍歷原始圖片的每個像素,將RGB值取反後放入新的圖片中。最後,將原始圖片和取反處理後的圖片進行左右合併
# 获取图片的宽度和高度
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 循环生成 tuple 中的每个值,取反 RGB 值
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運用Python進行遊戲設計
### 1.井字遊戲
```python=
def 印出井字盤(井字盤):
"""
印出井字遊戲的遊戲盤。
Parameters:
- 井字盤 (list): 存放井字遊戲狀態的列表
"""
print(井字盤[0] + '|' + 井字盤[1] + '|' + 井字盤[2])
print('-+-+-')
print(井字盤[3] + '|' + 井字盤[4] + '|' + 井字盤[5])
print('-+-+-')
print(井字盤[6] + '|' + 井字盤[7] + '|' + 井字盤[8])
def 檢查贏家(井字盤, 符號):
"""
檢查是否有玩家贏得遊戲。
Parameters:
- 井字盤 (list): 存放井字遊戲狀態的列表
- 符號 (str): 玩家的符號,'X' 或 'O'
Returns:
- bool: 若玩家贏得遊戲則返回 True,否則返回 False
"""
贏的組合 = [
[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 組合 in 贏的組合:
if 井字盤[組合[0]] == 井字盤[組合[1]] == 井字盤[組合[2]] == 符號:
return True
return False
def 主程式():
"""
井字遊戲的主程式。
"""
井字盤 = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
玩家 = 'X'
輸贏平局 = None
while True:
印出井字盤(井字盤)
輸入位置 = input(f'請玩家 {玩家} 輸入位置(1-9):')
if 輸入位置.isdigit() and 1 <= int(輸入位置) <= 9:
輸入位置 = int(輸入位置) - 1
if 井字盤[輸入位置] == 'X' or 井字盤[輸入位置] == 'O':
print('該位置已被佔據,請重新輸入。')
else:
井字盤[輸入位置] = 玩家
if 檢查贏家(井字盤, 玩家):
印出井字盤(井字盤)
print(f'恭喜玩家 {玩家} 獲勝!')
輸贏平局 = '贏'
break
elif all(位置 == 'X' or 位置 == 'O' for 位置 in 井字盤):
印出井字盤(井字盤)
print('平局!')
輸贏平局 = '平局'
break
玩家 = 'O' if 玩家 == 'X' else 'X'
else:
print('輸入無效,請輸入1到9之間的數字。')
if 輸贏平局 is None:
print('遊戲結束。')
if __name__ == '__main__':
主程式()
```
:::success
1|2|3
-+-+-
4|5|6
-+-+-
7|8|9
請玩家 X 輸入位置(1-9):5
1|2|3
-+-+-
4|X|6
-+-+-
7|8|9
請玩家 O 輸入位置(1-9):1
O|2|3
-+-+-
4|X|6
-+-+-
7|8|9
請玩家 X 輸入位置(1-9):4
O|2|3
-+-+-
X|X|6
-+-+-
7|8|9
請玩家 O 輸入位置(1-9):8
O|2|3
-+-+-
X|X|6
-+-+-
7|O|9
請玩家 X 輸入位置(1-9):6
O|2|3
-+-+-
X|X|X
-+-+-
7|O|9
恭喜玩家 X 獲勝!
:::
### 2.踩地雷
創建地雷地圖(行數, 列數, 地雷數): 生成一個地雷地圖,並在地雷位置標記為 'X'。
顯示遊戲地圖(遊戲地圖): 顯示遊戲地圖,玩家踩開的區域用 '□' 顯示。
檢查合法性(行, 列, 行數, 列數): 檢查座標是否合法。
計算周圍地雷數(地雷地圖, 行, 列): 計算指定位置周圍的地雷數。
檢查地雷(地雷地圖, 行, 列): 檢查指定位置是否有地雷。
顯示地雷地圖(地雷地圖): 顯示地雷地圖,用於在遊戲結束後顯示所有地雷位置。
整體主程式流程如下:
使用者輸入遊戲參數:行數、列數、地雷數。
生成地雷地圖並初始化遊戲地圖。
進入遊戲主迴圈:
使用者輸入檢查的位置。
檢查該位置是否合法。
若合法,檢查是否踩到地雷:
若踩到地雷,遊戲結束,顯示所有地雷位置。
若未踩到地雷,顯示周圍地雷數,繼續遊戲。
若不合法,提示重新輸入。
```python=
# 創造一個踩地雷遊戲呢?
# 創建地雷地圖
# 顯示遊戲地圖
# 檢查合法性
# 計算周圍地雷數
# 檢查地雷
# 顯示地雷地圖
import random
中文數字 = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
def 創建地雷地圖(行數, 列數, 地雷數):
地雷地圖 = [['O' for _ in range(列數)] for _ in range(行數)]
隨機地雷位置 = random.sample(range(行數 * 列數), 地雷數)
for 位置 in 隨機地雷位置:
行 = 位置 // 列數
列 = 位置 % 列數
地雷地圖[行][列] = 'X'
return 地雷地圖
def 顯示遊戲地圖(遊戲地圖):
for 行 in 遊戲地圖:
print(' '.join(行))
def 檢查合法性(行, 列, 行數, 列數):
return 0 <= 行 < 行數 and 0 <= 列 < 列數
def 計算周圍地雷數(地雷地圖, 行, 列):
周圍地雷數 = 0
鄰居方向 = [(1, 0), (-1, 0), (0, 1), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1)]
for dx, dy in 鄰居方向:
新行, 新列 = 行 + dx, 列 + dy
if 檢查合法性(新行, 新列, len(地雷地圖), len(地雷地圖[0])) and 地雷地圖[新行][新列] == 'X':
周圍地雷數 += 1
return 周圍地雷數
def 檢查地雷(地雷地圖, 行, 列):
if 地雷地圖[行][列] == 'X':
return True
return False
def 顯示地雷地圖(地雷地圖):
for 行 in 地雷地圖:
print(' '.join(行))
def 主程式():
print('歡迎來到踩地雷遊戲!')
行數 = int(input('請輸入行數:'))
列數 = int(input('請輸入列數:'))
地雷數 = int(input('請輸入地雷數:'))
地雷地圖 = 創建地雷地圖(行數, 列數, 地雷數)
遊戲地圖 = [['□' for _ in range(列數)] for _ in range(行數)]
顯示遊戲地圖(遊戲地圖)
while True:
#try:
# 行 = int(input('請輸入行數(1-{0}): '.format(行數))) - 1
# 列 = int(input('請輸入列數(1-{0}): '.format(列數))) - 1
#except ValueError:
# print('請輸入有效的數字。')
# continue
位置 = input('請輸入要檢查的位置 (例如: 1,3):')
try:
行, 列 = map(int, 位置.split(','))
行 -= 1
列 -= 1
except ValueError:
print('請輸入有效的位置 (例如: 1,3)。')
continue
if not 檢查合法性(行, 列, 行數, 列數) or 遊戲地圖[行][列] != '□':
print('請輸入有效的行數和列數。')
continue
if 檢查地雷(地雷地圖, 行, 列):
顯示地雷地圖(地雷地圖)
print('踩到地雷,遊戲結束!')
break
else:
周圍地雷數 = 計算周圍地雷數(地雷地圖, 行, 列)
遊戲地圖[行][列] = 中文數字[周圍地雷數]
顯示遊戲地圖(遊戲地圖)
if __name__ == "__main__":
主程式()
```
:::success
歡迎來到踩地雷遊戲!
請輸入行數:10
請輸入列數:10
請輸入地雷數:90
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
請輸入要檢查的位置 (例如: 1,3):3,1
X X X X X X X X O X
O X X X X X X X O X
X O X X X X X X X X
X X O X X X X X O X
X X X X X X X X X X
X X X X X X X O X O
X X X X X X X X X X
X X X X X X X X X X
X X X X X X O X X O
X X X X X X X X X X
踩到地雷,遊戲結束!
:::
### 3.猜數字幾A幾B
```python=
import random
def 生成祕密數字():
# 生成一個四位不重複的數字作為祕密數字
數字列表 = [str(i) for i in range(10)]
random.shuffle(數字列表)
return ''.join(數字列表[:4])
def 獲取猜測():
while True:
# 輸入玩家的猜測,確保輸入的是四位不重複的數字
猜測 = input("請猜一個四位數字(數字不重複):")
if len(猜測) == 4 and 猜測.isdigit() and len(set(猜測)) == 4:
return 猜測
print("無效的輸入!")
def 獲取提示(猜測, 祕密數字):
# 檢查猜測和祕密數字的相符情況,並返回提示字串
A的數量 = sum(1 for a, b in zip(猜測, 祕密數字) if a == b)
B的數量 = sum(1 for g in 猜測 if g in 祕密數字) - A的數量
return f"{A的數量}A{B的數量}B"
def 遊戲開始():
# 初始化遊戲,生成祕密數字
祕密數字 = 生成祕密數字()
嘗試次數 = 0
while True:
# 玩家進行猜測
猜測 = 獲取猜測()
嘗試次數 += 1
if 猜測 == 祕密數字:
# 猜對時結束遊戲,顯示結果
print(f"恭喜你猜對了!答案就是 {祕密數字}。你總共猜了 {嘗試次數} 次。")
break
提示 = 獲取提示(猜測, 祕密數字)
print(f"提示:{提示}")
if __name__ == "__main__":
# 啟動遊戲
遊戲開始()
```
:::success
提示:0A1B
提示:1A1B
提示:1A1B
提示:1A1B
:::
## 11/14運用Python進行機器學習
```pyhton=
# 生成兩個圓形的數據點,並以散點圖的形式呈現。其中,generate_circle_points 函數用於生成在指定半徑範圍內均勻分布的圓形點。程式碼使用Matplotlib進行繪圖,其中兩個圓形的數據點分別以藍色和橙色的散點表示,並且加入了相應的標籤和標題。
import matplotlib.pyplot as plt
import numpy as np
# 定義生成圓形點的函數
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
N = 200 # 原始點的數量
# 生成兩個圓形的數據點
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()
```

```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()
```
```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'])
```
```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()
# 获取训练和验证集准确度
# train_acc = history.history['accuracy']
# val_acc = history.history['val_accuracy']
# 绘制准确度图
#plt.figure(figsize=(8, 4))
#plt.plot(train_acc, label='Training Accuracy')
#plt.plot(val_acc, label='Validation Accuracy')
#plt.xlabel('Epoch')
#plt.ylabel('Accuracy')
#plt.title('Model Accuracy 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()
```


:::info
在二元分類(Binary Classification)的混淆矩陣(Confusion Matrix)中,常見的術語包括:
1. **True Positive (TP):** 正樣本被正確地分類為正類。在這裡,指的是模型正確地預測為正類的實例數。
2. **True Negative (TN):** 負樣本被正確地分類為負類。在這裡,指的是模型正確地預測為負類的實例數。
3. **False Positive (FP):** 負樣本被錯誤地分類為正類。在這裡,指的是模型錯誤地將實際為負類的樣本預測為正類的實例數。
4. **False Negative (FN):** 正樣本被錯誤地分類為負類。在這裡,指的是模型錯誤地將實際為正類的樣本預測為負類的實例數。
這些術語的組合形成了混淆矩陣:
\[
\begin{array}{cc|c}
& & \text{實際} \\
& & \text{正類} & \text{負類} \\
\hline
\text{預測} & \text{正類} & TP & FP \\
& \text{負類} & FN & TN \\
\end{array}
\]
進一步的評估指標:
當進行二元分類(Binary Classification)時,混淆矩陣(Confusion Matrix)是一個用來評估模型性能的重要工具,其中包含了以下術語:
1. **True Positive (TP):** 正樣本被正確地分類為正類。指的是模型正確地預測為正類的實例數。
2. **True Negative (TN):** 負樣本被正確地分類為負類。指的是模型正確地預測為負類的實例數。
3. **False Positive (FP):** 負樣本被錯誤地分類為正類。指的是模型錯誤地將實際為負類的樣本預測為正類的實例數。
4. **False Negative (FN):** 正樣本被錯誤地分類為負類。指的是模型錯誤地將實際為正類的樣本預測為負類的實例數。
混淆矩陣的形式如下:
\[ \begin{array}{ccc}
& \text{實際正類} & \text{實際負類} \\
\hline
\text{預測正類} & TP & FP \\
\text{預測負類} & FN & TN \\
\end{array} \]
這裡還有一些常見的評估指標:
- **Accuracy (ACC):** 分類器正確預測的比例,計算方式為 $( \frac{{TP + TN}}{{TP + TN + FP + FN}} )$.
- **True Positive Rate (TPR), Sensitivity, Recall:** 正類實例中被分類為正類的比例,計算方式為 $( \frac{{TP}}{{TP + FN}} )$.
- **True Negative Rate (TNR), Specificity:** 負類實例中被分類為負類的比例,計算方式為 $( \frac{{TN}}{{TN + FP}} \)$.
- **False Positive Rate (FPR):** 負類實例中被誤分正類的比例,計算方式為$( 1 - \text{TNR} \) 或 \( \frac{{FP}}{{TN + FP}} )$.
- **False Negative Rate (FNR):** 正類實例中被誤分為負類的比例,計算方式為 $( 1 - \text{TPR} \) 或 \( \frac{{FN}}{{TP + FN}} )$.
- **Precision (Positive Predictive Value, PPV):** 被分類為正類的實例中真正為正類的比例,計算方式為 $( \frac{{TP}}{{TP + FP}} )$.
- **Negative Predictive Value (NPV):** 被分類為負類的實例中真正為負類的比例,計算方式為 $( \frac{{TN}}{{TN + FN}} )$.
- **F1 Score:** 精確度和召回率的調和平均值,計算方式為 $( \frac{{2 \cdot \text{PPV} \cdot \text{TPR}}}{{\text{PPV} + \text{TPR}}} )$.
:::
```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)
#loss, accuracy = model.evaluate(X_test, y_test)
#print('test loss: ', loss)
#print('test accuracy: ', accuracy)
#y_pred_test_continuous = model.predict(X_test)
#y_pred_test = np.where(y_pred_test_continuous.flatten() >= 0, 1, -1)
```
:::success
10/10 [==============================] - 0s 2ms/step
In training set:
TP= 156 TN= 134 FP= 30 FN= 0
Accuracy= 0.90625
TPR(Sensitivity, Recall)= 1.0 TNR(Specificity)= 0.8170731707317073
:::