---
# System prepended metadata

title: 311159023徐若曦_程式設計期末報告

---

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