iT邦幫忙

2025 iThome 鐵人賽

DAY 21
0
自我挑戰組

數據新手村:統計系畢業生 30 天打怪升級之旅系列 第 21

Day 21 - 在 Pandas 中新增與刪除欄位

  • 分享至 

  • xImage
  •  

大家好,歡迎來到數據新手村的第二十一天!在過去幾天,我們學會了載入資料、篩選資料、處理缺失值和轉換資料類型。我們的數據集已經變得越來越乾淨。

但數據分析的魅力,不僅在於「清理」現有的資料,更在於從中「創造」出新的、更有價值的資訊。這個過程,我們稱之為**「特徵工程 (Feature Engineering)」**。

今天,我們就要來學習特徵工程最基礎、也最重要的一步:如何在 Pandas DataFrame 中新增刪除欄位 (Column)


1. 新增欄位:直接賦值法

這是最簡單、最直觀的新增欄位方式。我們可以直接對一個新的欄位名稱賦值,Pandas 就會自動幫我們創建它。

範例一:基於現有欄位的簡單計算

讓我們讀取 order_items 資料表,它包含了商品價格 (price) 和運費 (freight_value)。我們可以很輕易地計算出每個品項的「總價」。

import pandas as pd

# 讀取訂單商品資料表
order_items_df = pd.read_csv('../../data/olist_datasets/olist_order_items_dataset.csv')

# 新增 'total_value' 欄位,其值等於 price + freight_value
order_items_df['total_value'] = order_items_df['price'] + order_items_df['freight_value']

# 檢視結果,注意看最右邊多出來的新欄位
print(order_items_df.head())

輸出結果:
order_id order_item_id
0 00010242fe8c5a6d1ba2dd792cb16214 1
1 00018f77f2f0320c557190d7a144bdd3 1
2 000229ec398224ef6ca0657da4fc703e 1
3 00024acbcdf0a6daa1e931b038114c75 1
4 00042b26cf59d7ce69dfabb4e55b4fd9 1

                     product_id                         seller_id  \

0 4244733e06e7ecb4970a6e2683c13e61 48436dade18ac8b2bce089ec2a041202
1 e5f2d52b802189ee658865ca93d83a8f dd7ddc04e1b6c2c614352b383efe2d36
2 c777355d18b72b67abbeef9df44fd0fd 5b51032eddd242adc84c38acab88f23d
3 7634da152a4610f1595efa32f14722fc 9d7a1d34a5052409006425275ba1c2b4
4 ac6c3623068f30de03045865e4e10089 df560393f3a51e74553ab94004ba5c87

shipping_limit_date price freight_value total_value
0 2017-09-19 09:45:35 58.90 13.29 72.19
1 2017-05-03 11:05:13 239.90 19.93 259.83
2 2018-01-18 14:48:30 199.00 17.87 216.87
3 2018-08-15 10:10:18 12.99 12.79 25.78
4 2017-02-13 13:57:51 199.90 18.14 218.04

範例二:發揮 datetime 型態的威力 (本篇重點)
還記得我們昨天學的 pd.to_datetime() 嗎?現在就是它發揮價值的時刻!一旦欄位是 datetime 型態,我們就可以輕易地進行日期運算。

讓我們來計算 Olist 訂單從「客戶下單」到「商品送達」總共花了幾天。


# 讀取訂單主表
orders_df = pd.read_csv('../../data/olist_datasets/olist_orders_dataset.csv')

# 將兩個時間欄位都轉換成 datetime 型態
orders_df['order_purchase_timestamp'] = pd.to_datetime(orders_df['order_purchase_timestamp'])
orders_df['order_delivered_customer_date'] = pd.to_datetime(orders_df['order_delivered_customer_date'])

# 兩個 datetime 欄位相減,會得到一個 Timedelta 物件
# 我們再用 .dt.days 將其轉換為「天數」
orders_df['delivery_days'] = (orders_df['order_delivered_customer_date'] - orders_df['order_purchase_timestamp']).dt.days

# 檢視我們新建立的 'delivery_days' 欄位
# 為了方便觀察,我們只選取相關的欄位來看
orders_df[['order_purchase_timestamp', 'order_delivered_customer_date', 'delivery_days']].head()

輸出結果:

order_purchase_timestamp order_delivered_customer_date delivery_days
0 2017-10-02 10:56:33 2017-10-10 21:25:13 8.0
1 2018-07-24 20:41:37 2018-08-07 15:27:45 13.0
2 2018-08-08 08:38:49 2018-08-17 18:06:29 9.0
3 2017-11-18 19:28:06 2017-12-02 00:28:42 13.0
4 2018-02-13 21:18:39 2018-02-16 18:17:02 2.0

看到 delivery_days 欄位了嗎?這就是一個全新的、由我們自己創造出來的有價值的「特徵」!

2. 新增欄位:.apply() 與自訂函式

如果新增欄位的邏輯比較複雜,無法用簡單的加減乘除完成呢?例如,我們想根據價格,將商品分為「高價」、「中價」、「低價」三類。這時,.apply() 方法就派上用場了。

.apply() 可以讓我們將一個自訂的函式,應用到欄位的每一個元素上。


# 為了演示,我們只取 order_items_df 的前五筆
sample_df = order_items_df.head().copy() # .copy() 避免 SettingWithCopyWarning

# 步驟 1: 定義一個分類邏輯的函式
def categorize_price(price):
    if price > 500:
        return '高價'
    elif price > 100:
        return '中價'
    else:
        return '低價'

# 步驟 2: 將這個函式 apply 到 'price' 欄位上,並將結果存入新欄位
sample_df['price_category'] = sample_df['price'].apply(categorize_price)

print(sample_df[['price', 'price_category']])

輸出結果:
price price_category
0 58.90 低價
1 239.90 中價
2 199.00 中價
3 12.99 低價
4 199.90 中價

3. 刪除欄位:.drop() 方法

有增就有刪。當我們發現某些欄位不再需要時,可以使用 .drop() 方法來移除它們。


# 假設我們想刪除 'total_value' 和 'price_category' 這兩個我們剛建立的欄位
# 使用 columns 參數來指定要刪除的欄位列表
df_after_drop = sample_df.drop(columns=['total_value', 'price_category'])

# .drop() 預設會回傳一個新的 DataFrame,原始的 sample_df 維持不變
print("刪除後的 DataFrame:")
df_after_drop.head()
Pro Tip: .drop() 方法有一個 inplace=True 的參數。如果設定了它,drop 會直接在原始的 DataFrame 上進行修改,而不會回傳新的。但一般更推薦 df = df.drop(...) 這種重新賦值的方式,程式碼的流向會更清晰。

輸出結果:
刪除後的 DataFrame:

order_id order_item_id product_id seller_id shipping_limit_date price freight_value
0 00010242fe8c5a6d1ba2dd792cb16214 1 4244733e06e7ecb4970a6e2683c13e61 48436dade18ac8b2bce089ec2a041202 2017-09-19 09:45:35 58.90 13.29
1 00018f77f2f0320c557190d7a144bdd3 1 e5f2d52b802189ee658865ca93d83a8f dd7ddc04e1b6c2c614352b383efe2d36 2017-05-03 11:05:13 239.90 19.93
2 000229ec398224ef6ca0657da4fc703e 1 c777355d18b72b67abbeef9df44fd0fd 5b51032eddd242adc84c38acab88f23d 2018-01-18 14:48:30 199.00 17.87
3 00024acbcdf0a6daa1e931b038114c75 1 7634da152a4610f1595efa32f14722fc 9d7a1d34a5052409006425275ba1c2b4 2018-08-15 10:10:18 12.99 12.79
4 00042b26cf59d7ce69dfabb4e55b4fd9 1 ac6c3623068f30de03045865e4e10089 df560393f3a51e74553ab94004ba5c87 2017-02-13 13:57:51 199.90 18.14

結語

今天我們學會了如何「改造」我們的 DataFrame。新增欄位是數據分析中極具創造性的一環,我們不再只是被動地清理數據,而是開始主動地從數據中創造新的知識與洞見。

我們已經學會了如何準備單一的表格。但數據分析的威力,體現在從「多個表格」的關聯中找出答案。明天,Day 22,我們將迎來 Pandas 中威力最強大、也是數據分析師每天必用的功能——Group By 分組聚合。我們將學會如何從數萬筆訂單中,計算出「每個城市的平均銷售額」這類高價值的商業洞見!


上一篇
Day 20 - 資料清洗(二):型態決定一切,Pandas 資料類型轉換大法
系列文
數據新手村:統計系畢業生 30 天打怪升級之旅21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言