Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions homework/m1_numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@

def green_mean():
"""建立 [10, 20, 30, 40, 50],回傳所有元素的平均值 (float)"""
# TODO: 你的程式碼
pass
arr = np.array([10, 20, 30, 40, 50])
return arr.mean()


def green_double():
"""建立 [10, 20, 30, 40, 50],回傳所有元素乘以 2 的 ndarray"""
# TODO: 你的程式碼
pass
arr = np.array([10, 20, 30, 40, 50])
return arr * 2


def green_filter():
"""建立 [10, 20, 30, 40, 50],回傳大於 25 的元素 (ndarray)"""
# TODO: 你的程式碼
pass
arr = np.array([10, 20, 30, 40, 50])
return arr[arr > 25]


# ============================================================
Expand All @@ -41,26 +41,25 @@ def green_filter():

def yellow_expensive_count(prices):
"""回傳單價 > 1000 的商品數量 (int)"""
# TODO: 你的程式碼
pass
return np.sum(prices > 1000)


def yellow_top3_stock_indices(stocks):
"""
回傳庫存最多的前 3 個商品的索引位置 (ndarray, 由大到小排)
提示:np.argsort
"""
# TODO: 你的程式碼
pass
# argsort 是從小到大,[::-1] 翻轉成大到小,再取前三個
return np.argsort(stocks)[::-1][:3]


def yellow_restock_cost(prices, stocks):
"""
單價 < 500 的商品,每種各進貨 50 個,回傳總花費 (float/int)
提示:布林遮罩 + .sum()
"""
# TODO: 你的程式碼
pass
# 選出符合條件的價格加總後再乘以進貨量
return np.sum(prices[prices < 500]) * 50


# ============================================================
Expand All @@ -76,5 +75,8 @@ def red_double11_prices(prices, stocks):
回傳每個商品的雙 11 售價 (ndarray)
提示:np.where 可以巢狀使用
"""
# TODO: 你的程式碼
pass
return np.where(
stocks >= 100,
prices * 0.7,
np.where(stocks >= 20, prices * 0.9, prices)
)
93 changes: 39 additions & 54 deletions homework/m2_pandas_cleaning.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,88 +9,73 @@
"""
import pandas as pd


# ============================================================
# 🟢 送分題(每題 10 分,共 30 分)
# ============================================================

def green_read_csv():
"""
讀取 orders_raw.csv,回傳原始 DataFrame(不做任何清理)
提示:pd.read_csv()
"""
# TODO: 你的程式碼
pass
"""讀取 orders_raw.csv,回傳原始 DataFrame"""
df = pd.read_csv('datasets/ecommerce/orders_raw.csv')
return df


def green_shape(df):
"""
回傳 DataFrame 的 (列數, 欄數) tuple
提示:df.shape
"""
# TODO: 你的程式碼
pass
"""回傳 DataFrame 的 (列數, 欄數) tuple"""
return df.shape


def green_dtypes(df):
"""
回傳 DataFrame 的欄位型別 (Series)
提示:df.dtypes
"""
# TODO: 你的程式碼
pass
"""回傳 DataFrame 的欄位型別 (Series)"""
return df.dtypes


# ============================================================
# 🟡 核心題(每題 15 分,共 45 分)
# ============================================================

def yellow_clean_columns(df):
"""
清理欄位名稱:去除前後空白、全部轉小寫
回傳清理後的 DataFrame(不要修改原始 df)
提示:df.columns.str.strip().str.lower()
"""
# TODO: 你的程式碼
pass
"""清理欄位名稱:去除前後空白、全部轉小寫"""
new_df = df.copy()
new_df.columns = new_df.columns.str.strip().str.lower()
return new_df


def yellow_clean_amount(df):
"""
清理 amount 欄位:移除 '$' 和 ',' 符號,轉為 float
假設欄位名稱已經是小寫的 'amount'
回傳清理後的 DataFrame(不要修改原始 df)
提示:.str.replace() + .astype(float)
"""
# TODO: 你的程式碼
pass
"""清理 amount 欄位:移除 '$' 和 ',' 符號,轉為 float"""
new_df = df.copy()
# 先將符號取代為空字串,再轉換型別
new_df['amount'] = new_df['amount'].str.replace('$', '', regex=False).str.replace(',', '', regex=False).astype(float)
return new_df


def yellow_drop_duplicates(df):
"""
移除完全重複的列,回傳去重後的 DataFrame
提示:df.drop_duplicates()
"""
# TODO: 你的程式碼
pass
"""移除完全重複的列"""
return df.drop_duplicates()


# ============================================================
# 🔴 挑戰題(25 分)
# ============================================================

def red_clean_orders(path):
"""
完整清理 pipeline:一個函式搞定所有清理步驟
1. 讀取 CSV
2. 欄位名稱:去空白、轉小寫
3. amount:移除 '$' ',',轉 float
4. order_date:轉為 datetime(無法轉換的設為 NaT)
5. 刪除 amount 或 order_date 為空的列
6. 移除重複列

回傳:清理後的 DataFrame
提示:pd.to_datetime(errors='coerce')
"""
# TODO: 你的程式碼
pass
"""完整清理 pipeline"""
# 1. 讀取 CSV
df = pd.read_csv(path)

# 2. 欄位名稱:去空白、轉小寫
df.columns = df.columns.str.strip().str.lower()

# 3. amount:移除 '$' ',',轉 float
# 使用 regex=True 的一次性取代或連續 replace
df['amount'] = df['amount'].str.replace(r'[\$,]', '', regex=True).astype(float)

# 4. order_date:轉為 datetime(無法轉換的設為 NaT)
df['order_date'] = pd.to_datetime(df['order_date'], errors='coerce')

# 5. 刪除 amount 或 order_date 為空的列
df = df.dropna(subset=['amount', 'order_date'])

# 6. 移除重複列
df = df.drop_duplicates()

return df
67 changes: 31 additions & 36 deletions homework/m3_pandas_advanced.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,32 @@
"""
import pandas as pd


# ============================================================
# 🟢 送分題(每題 10 分,共 30 分)
# ============================================================

def green_load_and_merge():
"""
讀取三張表,合併成一張完整的 DataFrame 並回傳
- orders_clean.csv LEFT JOIN customers.csv ON customer_id
- 再 LEFT JOIN products.csv ON product_id
提示:pd.merge(how='left')
"""
# TODO: 你的程式碼
pass
df_orders = pd.read_csv('datasets/ecommerce/orders_clean.csv')
df_customers = pd.read_csv('datasets/ecommerce/customers.csv')
df_products = pd.read_csv('datasets/ecommerce/products.csv')

# 執行連續合併
df = pd.merge(df_orders, df_customers, on='customer_id', how='left')
df = pd.merge(df, df_products, on='product_id', how='left')
return df


def green_row_count(df):
"""回傳 DataFrame 的列數 (int)"""
# TODO: 你的程式碼
pass
return len(df)


def green_column_list(df):
"""回傳 DataFrame 的所有欄位名稱 (list)"""
# TODO: 你的程式碼
pass
return df.columns.tolist()


# ============================================================
Expand All @@ -46,31 +46,26 @@ def green_column_list(df):
def yellow_top_category(df):
"""
哪個商品類別 (category) 的總營收最高?
回傳該類別名稱 (str)
提示:groupby('category')['amount'].sum()
"""
# TODO: 你的程式碼
pass
# 根據 category 分組,加總 amount 後取最大值的索引
return df.groupby('category')['amount'].sum().idxmax()


def yellow_gold_vip_stats(df):
"""
Gold VIP 客戶總共下了幾張訂單?總金額多少?
回傳 tuple: (訂單數 int, 總金額 float)
提示:df[df['vip_level'] == 'Gold']
"""
# TODO: 你的程式碼
pass
gold_df = df[df['vip_level'] == 'Gold']
order_count = len(gold_df)
total_amount = gold_df['amount'].sum()
return (int(order_count), float(total_amount))


def yellow_region_avg_amount(df):
"""
計算每個地區 (region) 的平均訂單金額
回傳 Series(index=region, values=平均金額)
提示:groupby('region')['amount'].mean()
"""
# TODO: 你的程式碼
pass
return df.groupby('region')['amount'].mean()


# ============================================================
Expand All @@ -80,18 +75,18 @@ def yellow_region_avg_amount(df):
def red_rfm_top5(df):
"""
RFM 分析:找出最有價值的前 5 位客戶

計算每位客戶的:
- R (Recency):最近一次下單日期
- F (Frequency):訂單總數
- M (Monetary):消費總金額

回傳 DataFrame:
- 欄位:customer_id, customer_name, R, F, M
- 按 M 由大到小排序
- 只取前 5 筆

提示:groupby('customer_id').agg(...)
"""
# TODO: 你的程式碼
pass
# 確保日期格式正確,才能計算最近下單日期
df['order_date'] = pd.to_datetime(df['order_date'])

rfm = df.groupby(['customer_id', 'customer_name']).agg({
'order_date': 'max', # Recency: 最近一次日期
'order_id': 'count', # Frequency: 訂單總數
'amount': 'sum' # Monetary: 消費總額
}).reset_index()

# 重命名欄位
rfm.columns = ['customer_id', 'customer_name', 'R', 'F', 'M']

# 按 M 排序並取前 5
return rfm.sort_values(by='M', ascending=False).head(5)
Loading
Loading