# 311159023徐若曦_程式設計期末報告
## Python
### outline.py
#### 程式設計
```
import csv
"""
模組與基本邏輯:
- 此程式用於篩選 CSV 資料,根據使用者輸入的條件進行處理。
- 程式讀取名為 data.csv 的檔案,輸出結果為 newdata.csv。
- 使用者需要指定相關的欄位與篩選條件。
"""
# 提示用戶準備好資料檔案
print("請將檔案命名為data.csv並與此程式放置於同一資料夾中,newdata.csv即為修改後的檔案。")
# 等待用戶確認資料已準備好
ready = input("我已經準備好資料了(Y): ")
"""
功能細節:
- 使用 while 迴圈確保用戶輸入有效的確認指令。
- 只有在輸入 "Y" 或 "y" 時,程式才會繼續執行。
"""
# 確保用戶輸入有效的確認指令
while not (ready == "Y" or ready == "y"):
print("請將資料準備好再輸入 Y 。")
ready = input("我已經準備好資料了(Y): ")
else:
# 開啟並讀取 data.csv 檔案
with open("data.csv", mode="r", newline="") as file:
reader = list(csv.reader(file)) # 讀取 CSV 並轉換為列表
"""
功能細節:
- 建立一個字典對應欄位的編號與欄位名稱 (tital)。
- 另一個字典儲存每個欄位的數據 (data)。
- 所有數據轉換為整數以便後續處理。
"""
# 建立一個字典來對應欄位的編號與欄位名稱
tital = {}
for i in range(1, len(reader[0])):
tital[str(i)] = reader[0][i]
# 建立一個字典來儲存每個欄位的數據
data = {}
for i in range(len(reader[0])):
data[reader[0][i]] = []
for j in range(1, len(reader)):
data[reader[0][i]].append(float(reader[j][i])) # 將數據轉換為浮點數存入字典
# 將欄位名稱的字典轉為字串形式,用於提示用戶輸入
titaltoString = str(tital)[1:-2].replace("'", "").replace(": ", ":")
valueA = "valueA(" + titaltoString + "): " # 提示用戶輸入 valueA 對應的欄位
valueB = "valueB(" + titaltoString + "): " # 提示用戶輸入 valueB 對應的欄位
"""
使用者互動:
- 讓用戶選擇兩個欄位 (valueA 和 valueB)。
- 驗證輸入是否有效,並避免兩者相同。
"""
# 讓用戶選擇 valueA
a = input(valueA)
while a not in tital: # 確保輸入有效
print(a, "不在提示字串內,請重新輸入。")
a = input(valueA)
else:
dataA = data[tital[a]] # 提取對應欄位的數據
# 讓用戶選擇 valueB
b = input(valueB)
while b not in tital or b == a: # 確保輸入有效且不同於 valueA
if b not in tital:
print(b, "不在提示字串內,請重新輸入。")
elif b == a:
print("valueA 與 valueB 相同,請重新輸入。")
b = input(valueB)
else:
dataB = data[tital[b]] # 提取對應欄位的數據
# 讓用戶選擇正相關 (p) 或負相關 (n)
corr = input("correlation(p/n): ")
while corr != "p" and corr != "n":
print("請輸入 p 或 n 。")
corr = input("correlation(p/n): ")
# 讓用戶輸入檢測標準(差異值界限)
outline = input("outline: ")
while not outline.isnumeric() or int(outline) <= 0: # 確保輸入有效數值
print("請輸入大於 0 的數字。")
outline = input("outline: ")
else:
outline = int(outline)
"""
資料處理流程:
- 定義函數 dic,用於建立字典以儲存數據出現次數。
- 進行數據排序 (sortA 和 sortB),若為負相關則反轉 sortB。
- 利用 rank 函數為數據分配排名。
"""
# 定義函數:建立字典儲存數據出現的次數
def dic(e):
dic = {}
for i in range(len(e)):
dic[e[i]] = 0
return dic
# 建立兩個字典,分別存放 dataA 和 dataB 的排序次數
dictA = dic(dataA)
dictB = dic(dataB)
# 將數據排序
sortA = sorted(dataA)
sortB = sorted(dataB)
# 如果用戶選擇負相關,將排序後的 sortB 反轉
if corr == "p":
pass
elif corr == "n":
sortB = list(reversed(sortB))
# 定義函數:根據排序結果為數據分配排名
def rank(d, s):
for i in d:
d[i] = s.index(i) + 1
return
# 計算 dictA 和 dictB 的排名
rank(dictA, sortA)
rank(dictB, sortB)
"""
資料篩選:
- 根據 outline 的條件,篩選出符合的資料。
- 不符合條件的索引存入 out 列表。
"""
# 初始化存放篩選結果的列表
finalA = []
finalB = []
out = [] # 儲存不符合條件的資料索引
# 根據 outline 條件篩選數據
for k in range(len(dataA)):
if abs(dictA[dataA[k]] - dictB[dataB[k]]) < outline:
finalA.append(dataA[k])
finalB.append(dataB[k])
else:
out.append(k + 1)
"""
結果輸出:
- 將篩選後的結果寫入 newdata.csv。
- 只保留符合條件的行。
"""
# 將篩選後的結果寫入 newdata.csv
with open("newdata.csv", mode="w", newline="") as file:
writer = csv.writer(file)
for i in range(len(reader)):
if i not in out:
writer.writerow(reader[i]) # 寫入符合條件的行
```
### outline_chatgpt.py
#### 程式設計
```
import csv
"""
函數部分:
1. `get_input`:
- 用於處理用戶輸入,提供有效選項檢查。
- 支援允許空值的情況。
2. `read_csv_file`:
- 用於讀取 CSV 檔案內容,將其轉為列表格式。
- 如果檔案不存在,提示錯誤並退出程式。
3. `write_csv_file`:
- 將數據寫入 CSV 檔案,過濾掉指定的行。
4. `rank_data`:
- 計算數據的排名。
- 將每個數據值對應到其排名(從 1 開始)。
5. `filter_data_by_outline`:
- 根據排名差異篩選數據。
- 返回符合條件與不符合條件的索引列表。
主程式部分:
1. 提示用戶準備好檔案並讀取 `data.csv`。
2. 使用 `tital` 字典對應欄位名稱與編號,供用戶選擇。
3. 讓用戶選擇兩個欄位(`valueA` 和 `valueB`),並檢查選擇的有效性。
4. 根據用戶選擇的相關性類型(正相關或負相關)處理數據。
5. 使用排名計算和篩選條件,篩選數據並排除不符合條件的行。
6. 將篩選後的數據寫入 `newdata.csv`。
7. 最後提示用戶處理完成。
用戶互動部分:
1. 確保用戶輸入有效選項或符合條件的數值。
2. 避免錯誤操作,如選擇相同的欄位或輸入無效值。
資料處理部分:
1. 排名邏輯:
- 根據數據排序後計算排名。
2. 篩選邏輯:
- 比較兩欄數據的排名差異,若小於 `outline`,則保留該行。
- 否則將該行排除,並記錄其索引。
"""
# 定義函數:用於獲取使用者輸入,並提供有效選項檢查與空值處理
def get_input(prompt, valid_options=None, allow_empty=False):
while True:
value = input(prompt)
if allow_empty and not value: # 如果允許空值且輸入為空,直接返回
return value
if valid_options is None or value in valid_options: # 檢查是否為有效選項
return value
print(f"無效輸入,請重新輸入有效選項:{valid_options}")
# 定義函數:讀取 CSV 檔案
def read_csv_file(filename):
try:
with open(filename, mode="r", newline="") as file:
return list(csv.reader(file)) # 將 CSV 內容讀取為列表格式
except FileNotFoundError:
print(f"找不到檔案 {filename},請確認檔案名稱與路徑。")
exit(1) # 找不到檔案則退出程式
# 定義函數:寫入 CSV 檔案,過濾掉指定的行
def write_csv_file(filename, data, excluded_indices):
with open(filename, mode="w", newline="") as file:
writer = csv.writer(file)
for i, row in enumerate(data):
if i not in excluded_indices: # 排除不符合條件的行
writer.writerow(row)
# 定義函數:根據數據內容進行排名
def rank_data(data):
sorted_data = sorted(data) # 將數據排序
# 將數據中的每個值對應到其排名
ranks = {value: rank + 1 for rank, value in enumerate(sorted_data)}
return ranks
# 定義函數:根據 outline 條件篩選數據
def filter_data_by_outline(dataA, dataB, ranksA, ranksB, outline):
finalA, finalB, out = [], [], [] # 初始化列表,用於存放篩選結果與不合條件的索引
for i in range(len(dataA)):
# 比較兩數據排名的差異是否小於 outline
if abs(ranksA[dataA[i]] - ranksB[dataB[i]]) < outline:
finalA.append(dataA[i]) # 符合條件的數據
finalB.append(dataB[i])
else:
out.append(i + 1) # 不符合條件的索引
return finalA, finalB, out
# 主程式開始
print("請將檔案命名為 data.csv 並與此程式放置於同一資料夾中,newdata.csv 即為修改後的檔案。")
# 提示使用者確認資料已準備好
ready = get_input("我已經準備好資料了(Y): ", valid_options=["Y", "y"])
# 讀取 CSV 檔案內容
data = read_csv_file("data.csv")
# 取得 CSV 檔案的標題列(第一行)
headers = data[0]
# 建立一個字典,對應欄位的編號與名稱
tital = {str(i): headers[i] for i in range(1, len(headers))}
# 將 CSV 內容轉換為字典格式,key 是欄位名稱,value 是數據列表
dataset = {headers[i]: [int(row[i]) for row in data[1:]] for i in range(len(headers))}
# 將欄位名稱與對應編號的字典轉換為提示字串
titaltoString = ", ".join([f"{k}:{v}" for k, v in tital.items()])
# 讓使用者選擇 valueA 對應的欄位
valueA = get_input(f"valueA({titaltoString}): ", valid_options=tital.keys())
# 讓使用者選擇 valueB,並檢查其不同於 valueA
valueB = get_input(f"valueB({titaltoString}): ", valid_options=tital.keys())
while valueB == valueA:
print("valueA 與 valueB 相同,請重新輸入。")
valueB = get_input(f"valueB({titaltoString}): ", valid_options=tital.keys())
# 從資料集中提取選定欄位的數據
dataA = dataset[tital[valueA]]
dataB = dataset[tital[valueB]]
# 讓使用者選擇相關性類型(正相關或負相關)
correlation = get_input("correlation(p/n): ", valid_options=["p", "n"])
# 讓使用者輸入 outline(篩選條件,數值差異的界限)
outline = int(get_input("outline: ", allow_empty=False))
# 計算兩個欄位數據的排名
ranksA = rank_data(dataA)
ranksB = rank_data(dataB)
# 如果選擇負相關,將 dataB 反轉排序
if correlation == "n":
dataB = list(reversed(dataB))
# 根據 outline 條件篩選數據
_, _, out = filter_data_by_outline(dataA, dataB, ranksA, ranksB, outline)
# 將篩選後的數據寫入新的 CSV 檔案
write_csv_file("newdata.csv", data, out)
# 提示使用者處理完成
print("資料處理完畢,請檢查 newdata.csv。")
```
#### 執行結果
```
請將檔案命名為 data.csv 並與此程式放置於同一資料夾中,newdata.csv 即為修改後的檔案。
我已經準備好資料了(Y): Y
valueA(1:營業額, 2:消費滿1萬贈, 3:消費滿3萬贈, 4:消費滿5萬贈, 5:消費滿10萬贈, 6:消費滿20萬贈, 7:滿萬送千(抵用券)): 1
valueB(1:營業額, 2:消費滿1萬贈, 3:消費滿3萬贈, 4:消費滿5萬贈, 5:消費滿10萬贈, 6:消費滿20萬贈, 7:滿萬送千(抵用券)): 2
correlation(p/n): p
outline: 5
資料處理完畢,請檢查 newdata.csv。
```
### Example
#### data.csv
```
編號,營業額,消費滿1萬贈,消費滿3萬贈,消費滿5萬贈,消費滿10萬贈,消費滿20萬贈,滿萬送千(抵用券)
1,81340000,419550,248760,140000,115200,78000,1010500
2,49000000,19600,29800,45000,42180,48256,210018
3,83440000,324750,173250,162750,270900,85000,1256000
4,58000000,28000,35010,56000,69800,56312,385000
5,87000000,138000,69500,101300,31000,86780,1550000
6,50010000,27010,30000,46000,43200,49500,225000
7,97680000,244863,177510,128100,292572,96000,904750
8,45386000,18000,26000,41000,38000,36125,195000
9,85165000,250624,190846,148625,129480,73900,1190000
10,55433000,21457,133661,225000,170000,46101,340750
11,101448000,331920,187640,103920,29850,95980,1049400
12,73383000,149085,103609,81900,73550,84000,935550
13,114056000,284106,67070,121580,264000,79361,1314500
14,71690000,112500,93000,78000,68000,69250,1015000
15,99844000,512602,62400,182784,71823,79800,1278475
16,69037000,126720,93456,47040,69850,71000,1473065
17,98290000,163858,94128,71775,82569,91580,1514425
18,69128000,99225,102570,40128,70104,65000,1397550
19,96490000,186010,135720,82795,78289,89715,1706925
20,74745000,81480,110226,52026,81900,81000,1935615
21,89658000,156305,81405,88120,26000,77890,1813350
22,71790000,93000,65575,78537,109000,58296,1779800
23,86677000,138458,60750,94102,148920,74500,2291850
24,66472000,74906,30400,60500,83129,46278,1938695
25,78966000,139203,37556,74756,236374,68000,2077350
26,60136000,82085,25506,39776,81000,59708,1477850
27,79646000,104835,38190,82772,231942,71000,2235695
28,65380000,72580,30100,54600,59800,51800,1580800
29,76358000,60825,24564,66814,151831,116768,2175250
30,68560000,118000,88120,49800,51200,78000,186500
31,60819000,49275,37521,63133,165456,57144,1835075
32,57000000,25600,16800,59850,71500,48600,450800
33,39010000,54800,42000,21000,130010,45600,867000
34,36000000,22000,18650,41500,38600,36500,388000
35,37495000,48829,20580,13160,113600,36800,1069200
36,45000000,28600,23900,48050,43800,41500,486000
37,79800000,95000,45900,69700,173500,139800,1568000
38,51000000,33900,27600,68500,54300,46990,778000
```
#### newdata.csv
```
編號,營業額,消費滿1萬贈,消費滿3萬贈,消費滿5萬贈,消費滿10萬贈,消費滿20萬贈,滿萬送千(抵用券)
2,49000000,19600,29800,45000,42180,48256,210018
4,58000000,28000,35010,56000,69800,56312,385000
6,50010000,27010,30000,46000,43200,49500,225000
7,97680000,244863,177510,128100,292572,96000,904750
8,45386000,18000,26000,41000,38000,36125,195000
9,85165000,250624,190846,148625,129480,73900,1190000
11,101448000,331920,187640,103920,29850,95980,1049400
13,114056000,284106,67070,121580,264000,79361,1314500
14,71690000,112500,93000,78000,68000,69250,1015000
15,99844000,512602,62400,182784,71823,79800,1278475
18,69128000,99225,102570,40128,70104,65000,1397550
19,96490000,186010,135720,82795,78289,89715,1706925
21,89658000,156305,81405,88120,26000,77890,1813350
22,71790000,93000,65575,78537,109000,58296,1779800
23,86677000,138458,60750,94102,148920,74500,2291850
24,66472000,74906,30400,60500,83129,46278,1938695
25,78966000,139203,37556,74756,236374,68000,2077350
27,79646000,104835,38190,82772,231942,71000,2235695
28,65380000,72580,30100,54600,59800,51800,1580800
31,60819000,49275,37521,63133,165456,57144,1835075
34,36000000,22000,18650,41500,38600,36500,388000
36,45000000,28600,23900,48050,43800,41500,486000
38,51000000,33900,27600,68500,54300,46990,778000
```