大家好,歡迎來到數據新手村的第十八天!昨天我們成功將 Olist 訂單資料載入到 DataFrame 中,並對它進行了初步的「健康檢查」。
我們手上現在有近 10 萬筆訂單,但通常我們只對「符合特定條件」的子集感興趣。例如,身為一個數據分析師,老闆可能會問你:
今天,我們就要來學習如何使用 Pandas 強大的布林索引 (Boolean Indexing),像一個精準的外科醫生一樣,從龐大的數據中,切出我們想要的任何部分。
這個概念在 Day 11 的 NumPy 中已經學過了,在 Pandas 中完全一樣,但威力更強大,因為我們可以針對帶有欄位名稱的資料進行篩選。
它的運作分為兩步驟:
True
/False
組成的 Series
。Series
篩網放回 df[]
中,就能篩選出所有條件為 True
的列 (row)。讓我們來找出所有「已送達 (delivered)」的訂單。
# --- 正確讀取資料 ---
# (請根據實際檔案路徑修改)
orders_df = pd.read_csv("D:/Datasets/Olist/olist_orders_dataset.csv")
customers_df = pd.read_csv("D:/Datasets/Olist/olist_customers_dataset.csv")
# --- 正確合併 ---
# 用正確的訂單表和客戶表進行合併
orders_with_customer_df = pd.merge(orders_df, customers_df, on='customer_id')
# --- 範例 1:單一條件篩選 ---
print("### 範例 1:單一條件篩選 ###")
condition = orders_with_customer_df['order_status'] == 'delivered'
delivered_orders_df = orders_with_customer_df[condition]
print(f"已送達的訂單總數: {len(delivered_orders_df)}")
print("已送達訂單的前五筆:")
print(delivered_orders_df.head())
print("\n" + "="*30 + "\n")
輸出結果:
已送達的訂單總數: 96478
已送達訂單的前五筆:
order_id customer_id
0 e481f51cbdc54678b7cc49136f2d6af7 9ef432eb6251297304e76186b10a928d
1 53cdb2fc8bc7dce0b6741e2150273451 b0830fb4747a6c6d20dea0b8c802d7ef
2 47770eb9100c2d0c44946d9cf07ec65d 41ce2a54c0b03bf3443c3d931a367089
3 949d5b44dbf5de918fe9c16f97b45f8a f88197465ea7920adcdbec7375364d82
4 ad21c59c0840e6cb83a9ceb5573f8159 8ab97904e6daea8866dbdbc4fb7aad2c
order_status order_purchase_timestamp order_approved_at
0 delivered 2017-10-02 10:56:33 2017-10-02 11:07:15
1 delivered 2018-07-24 20:41:37 2018-07-26 03:24:27
2 delivered 2018-08-08 08:38:49 2018-08-08 08:55:23
3 delivered 2017-11-18 19:28:06 2017-11-18 19:45:59
4 delivered 2018-02-13 21:18:39 2018-02-13 22:20:29
order_delivered_carrier_date order_delivered_customer_date
0 2017-10-04 19:55:00 2017-10-10 21:25:13
1 2018-07-26 14:31:00 2018-08-07 15:27:45
2 2018-08-08 13:50:00 2018-08-17 18:06:29
3 2017-11-22 13:39:59 2017-12-02 00:28:42
4 2018-02-14 19:46:34 2018-02-16 18:17:02
order_estimated_delivery_date customer_unique_id
0 2017-10-18 00:00:00 7c396fd4830fd04220f754e42b4e5bff
1 2018-08-13 00:00:00 af07308b275d755c9edb36a90c618231
2 2018-09-04 00:00:00 3a653a41f6f9fc3d2a113cf8398680e8
3 2017-12-15 00:00:00 7c142cf63193a1473d2e66489a9ae977
4 2018-02-26 00:00:00 72632f0f9dd73dfee390c9b22eb56dd6
customer_zip_code_prefix customer_city customer_state
0 3149 sao paulo SP
1 47813 barreiras BA
2 75265 vianopolis GO
3 59296 sao goncalo do amarante RN
4 9195 santo andre SP
==============================
⚠️ 新手最常見的錯誤:
在 Pandas 中,必須使用 & 和 |,不能使用 and 和 or。
每一個獨立的條件,都必須用小括號 () 包起來!
讓我們來找出所有「已送達」且「來自聖保羅州 (SP)」的訂單。
# --- 範例 2:多重條件篩選 ---
print("### 範例 2:多重條件篩選 ###")
# 建立兩個獨立的條件
condition1 = orders_with_customer_df['order_status'] == 'delivered'
condition2 = orders_with_customer_df['customer_state'] == 'SP'
# 使用 & 將兩個條件組合起來
sp_delivered_df = orders_with_customer_df[condition1 & condition2]
print(f"原始合併後的訂單總數: {len(orders_with_customer_df)}")
print(f"來自聖保羅州(SP)且已送達的訂單數: {len(sp_delivered_df)}")
print("來自聖保羅州(SP)且已送達訂單的前五筆:")
print(sp_delivered_df.head())
print("\n" + "="*30 + "\n")
輸出結果:
原始合併後的訂單總數: 99441
來自聖保羅州(SP)且已送達的訂單數: 40501
來自聖保羅州(SP)且已送達訂單的前五筆:
order_id customer_id
0 e481f51cbdc54678b7cc49136f2d6af7 9ef432eb6251297304e76186b10a928d
4 ad21c59c0840e6cb83a9ceb5573f8159 8ab97904e6daea8866dbdbc4fb7aad2c
9 e69bfb5eb88e0ed6a785585b27e16dbf 31ad1d1b63eb9962463f764d4e6e0c9d
11 34513ce0c4fab462a55830c0989c7edb 7711cf624183d843aafe81855097bc37
13 5ff96c15d0b717ac6ad1f3d77225a350 19402a48fe860416adf93348aba37740
order_status order_purchase_timestamp order_approved_at
0 delivered 2017-10-02 10:56:33 2017-10-02 11:07:15
4 delivered 2018-02-13 21:18:39 2018-02-13 22:20:29
9 delivered 2017-07-29 11:55:02 2017-07-29 12:05:32
11 delivered 2017-07-13 19:58:11 2017-07-13 20:10:08
13 delivered 2018-07-25 17:44:10 2018-07-25 17:55:14
order_delivered_carrier_date order_delivered_customer_date
0 2017-10-04 19:55:00 2017-10-10 21:25:13
4 2018-02-14 19:46:34 2018-02-16 18:17:02
9 2017-08-10 19:45:24 2017-08-16 17:14:30
11 2017-07-14 18:43:29 2017-07-19 14:04:48
13 2018-07-26 13:16:00 2018-07-30 15:52:25
order_estimated_delivery_date customer_unique_id
0 2017-10-18 00:00:00 7c396fd4830fd04220f754e42b4e5bff
4 2018-02-26 00:00:00 72632f0f9dd73dfee390c9b22eb56dd6
9 2017-08-23 00:00:00 299905e3934e9e181bfb2e164dd4b4f8
11 2017-08-08 00:00:00 782987b81c92239d922aa49d6bd4200b
13 2018-08-08 00:00:00 e2dfa3127fedbbca9707b36304996dab
customer_zip_code_prefix customer_city customer_state
0 3149 sao paulo SP
4 9195 santo andre SP
9 18075 sorocaba SP
11 4278 sao paulo SP
13 4812 sao paulo SP
# --- 範例 3:.isin() 方法 ---
print("### 範例 3:.isin() 方法 ###")
# 定義一個我們想尋找的州列表
states_to_find = ['SP', 'RJ', 'MG']
# 使用 .isin() 進行篩選
southeast_orders_df = orders_with_customer_df[orders_with_customer_df['customer_state'].isin(states_to_find)]
print(f"東南部三州(SP, RJ, MG)的訂單總數: {len(southeast_orders_df)}")
print("東南部三州訂單的前五筆:")
print(southeast_orders_df.head())
輸出結果:
東南部三州(SP, RJ, MG)的訂單總數: 66233
東南部三州訂單的前五筆:
order_id customer_id
0 e481f51cbdc54678b7cc49136f2d6af7 9ef432eb6251297304e76186b10a928d
4 ad21c59c0840e6cb83a9ceb5573f8159 8ab97904e6daea8866dbdbc4fb7aad2c
7 6514b8ad8028c9f2cc2374ded245783f 9bdf08b4b3b52b5526ff42d37d47f222
9 e69bfb5eb88e0ed6a785585b27e16dbf 31ad1d1b63eb9962463f764d4e6e0c9d
10 e6ce16cb79ec1d90b1da9085a6118aeb 494dded5b201313c64ed7f100595b95c
order_status order_purchase_timestamp order_approved_at
0 delivered 2017-10-02 10:56:33 2017-10-02 11:07:15
4 delivered 2018-02-13 21:18:39 2018-02-13 22:20:29
7 delivered 2017-05-16 13:10:30 2017-05-16 13:22:11
9 delivered 2017-07-29 11:55:02 2017-07-29 12:05:32
10 delivered 2017-05-16 19:41:10 2017-05-16 19:50:18
order_delivered_carrier_date order_delivered_customer_date
0 2017-10-04 19:55:00 2017-10-10 21:25:13
4 2018-02-14 19:46:34 2018-02-16 18:17:02
7 2017-05-22 10:07:46 2017-05-26 12:55:51
9 2017-08-10 19:45:24 2017-08-16 17:14:30
10 2017-05-18 11:40:40 2017-05-29 11:18:31
order_estimated_delivery_date customer_unique_id
0 2017-10-18 00:00:00 7c396fd4830fd04220f754e42b4e5bff
4 2018-02-26 00:00:00 72632f0f9dd73dfee390c9b22eb56dd6
7 2017-06-07 00:00:00 932afa1e708222e5821dac9cd5db4cae
9 2017-08-23 00:00:00 299905e3934e9e181bfb2e164dd4b4f8
10 2017-06-07 00:00:00 f2a85dec752b8517b5e58a06ff3cd937
customer_zip_code_prefix customer_city customer_state
0 3149 sao paulo SP
4 9195 santo andre SP
7 26525 nilopolis RJ
9 18075 sorocaba SP
10 20780 rio de janeiro RJ
結語
今天我們掌握了 Pandas 中數據篩選的利器——布林索引。透過組合 &, | 和 .isin(),我們幾乎可以從 DataFrame 中取出任何我們感興趣的資料子集。
但真實世界的數據並不總是那麼完美。如果資料中有些欄位是空白的呢?我們該如何處理?明天,Day 19,我們將正式進入數據分析師最重要的工作:資料清洗,並從如何處理缺失值 (Missing Values) 開始。