# 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 ```