iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0
自我挑戰組

拯救混亂數據:30 天 Python 輕量級 ETL 與電商關聯資料分析系列 第 11

承諾與背叛:計算物流延遲天數,揭露 1 星負評的致命元兇

  • 分享至 

  • xImage
  •  

比運費更致命的體驗殺手

在 Day 10 中,我們用「運費比率」量化了偏遠地區買家的物流負擔。但商業常識告訴我們:買家願意付款結帳,代表運費再貴他都已經「知情且默許」。

真正會讓買家留下極端差評(1 星負評)的,通常不是預期內的成本,而是「預期的落差」也就是平台答應了預計送達日,包裹卻遲遲沒出現。

今天我們將引入全新的顧客評價表 (order_reviews),
透過時間特徵工程計算「實際配送天數」與「延遲天數」,用數據量化物流跳票對顧客滿意度的毀滅性打擊。

步驟一:呼叫評價表,拆解「重複評論」陷阱

我們先從資料字典中取出 olist_order_reviews_dataset:

# 從字典中取出評價表
reviews = olist_db['olist_order_reviews_dataset']

# 檢視欄位資訊
reviews[['review_id', 'order_id', 'review_score', 'review_creation_date']].head(3)

如圖:

https://ithelp.ithome.com.tw/upload/images/20260918/20136155koOyNXhJxb.png

在進行跨表合併前,老手的防呆雷達必須立刻啟動:一張訂單只會有一則評價嗎?

# 檢查是否有同一張 order_id 對應多筆 review 的情況
duplicate_reviews = reviews['order_id'].duplicated().sum()
print(f"重複評論的訂單數: {duplicate_reviews} 筆")

如圖 :

https://ithelp.ithome.com.tw/upload/images/20260918/20136155VSR9Y9LsIK.png

執行後會發現有數百筆訂單存在多次評價(可能買家更新了評論)。
如果直接 Merge,資料粒度又會被悄悄拉膨脹!

我們在合併前先按評論時間保留最新的一筆:

# 依據 review_creation_date 排序,只保留每筆訂單最新的評價
clean_reviews = reviews.sort_values('review_creation_date').drop_duplicates(
    subset='order_id', 
    keep='last'
)

# 合併回我們的有效訂單主表
orders_with_reviews = pd.merge(
    valid_orders, 
    clean_reviews[['order_id', 'review_score']], 
    on='order_id', 
    how='inner'
)

print(f"成功合併評價的訂單數: {len(orders_with_reviews):,} 筆")

如圖:

https://ithelp.ithome.com.tw/upload/images/20260918/20136155qCzlsL4e1s.png

步驟二:特徵工程——計算實際天數與延遲天數

我們需要從時間戳記中衍生出兩個關鍵的行為指標:

# 1. 實際配送耗時(換算為天數)
orders_with_reviews['actual_delivery_days'] = (
    orders_with_reviews['order_delivered_customer_date'] - orders_with_reviews['order_purchase_timestamp']
).dt.total_seconds() / (24 * 3600)

# 2. 延遲落差(大於 0 代表遲到,小於等於 0 代表提早或準時送達)
orders_with_reviews['delay_days'] = (
    orders_with_reviews['order_delivered_customer_date'] - orders_with_reviews['order_estimated_delivery_date']
).dt.total_seconds() / (24 * 3600)

# 3. 建立二元標記:是否延遲交付?
orders_with_reviews['is_delayed'] = orders_with_reviews['delay_days'] > 0

orders_with_reviews[['order_id', 'actual_delivery_days', 'delay_days', 'is_delayed', 'review_score']].head(3)

實作 :

https://ithelp.ithome.com.tw/upload/images/20260918/201361553EjmiVqnZ4.png

  • 實際配送天數 (actual_delivery_days): 送達顧客時間 - 下單購買時間

  • 延遲天數 (delay_days): 送達顧客時間 - 官方預估送達時間

步驟三:數據聚合——延遲的代價有多大?

有了標籤後,我們馬上比較「準時履約」與「延遲履約」的顧客評分差異:

# 依是否延遲分組,計算平均評分與單量佔比
delay_impact = orders_with_reviews.groupby('is_delayed').agg(
    order_count=('order_id', 'count'),
    avg_score=('review_score', 'mean')
).reset_index()

delay_impact['share_pct'] = (delay_impact['order_count'] / delay_impact['order_count'].sum() * 100).round(2)
delay_impact['avg_score'] = delay_impact['avg_score'].round(2)
delay_impact

實作 : 

https://ithelp.ithome.com.tw/upload/images/20260918/20136155ra03NTqIXU.png

數據對比:

  • 準時履約 (is_delayed == False): 平均評分高達 4.2 分左右,維持極佳的滿意度水準。
  • 配送延遲 (is_delayed == True): 平均評分雪崩至 1.6~2.2 分!

延遲訂單雖然只佔整體約 7%~10%,但它幾乎直接宣判了這批顧客的流失。
買家對「平台食言」的容忍度幾乎為零。

步驟四:視覺化——評分分佈的極端斷崖

我們透過堆疊長條圖(Barplot)直接觀察評分結構的變化:

import matplotlib.pyplot as plt
import seaborn as sns

plt.figure(figsize=(10, 5))
sns.countplot(
    data=orders_with_reviews, 
    x='review_score', 
    hue='is_delayed', 
    palette=['#3498db', '#e74c3c']
)

plt.title('Review Score Distribution: On-Time vs Delayed Delivery', fontsize=12, fontweight='bold')
plt.xlabel('Review Score (1-5 Stars)')
plt.ylabel('Order Count')
plt.legend(title='Is Delayed?', labels=['On-Time', 'Delayed'])
plt.tight_layout()
plt.show()

實作 : 

https://ithelp.ithome.com.tw/upload/images/20260918/201361550pTfRS1pLn.png


今天打通了物流與客戶體驗的數據孤島:

  • 識破多對一評論: 在 Join 前先進行 order_id 去重,捍衛資料粒度。

  • 提煉體驗指標: 用時間差衍生出 delay_days 與 is_delayed,量化履約承諾。

  • 定位體驗斷崖: 證實了延遲是直接造成 1 星負評的核心原因,為營運團隊提供了改善滿意度的明確抓手。

我們現在清楚知道了「時效跳票」對評分的殺傷力。
那麼,到底哪一種類型的商品最常延遲?
或者是哪種商品即使準時到了,依然常常拿差評?
明天 Day 12,我們將跨入「品類維度 (Product Category)」,找出產品本身的潛在地雷!


上一篇
[Day 10] 驗證偏遠州的代價:計算運費比率 (Freight Ratio) 揪出物流痛點
下一篇
[Day 12] 揪出隱形炸彈:品類跨表翻譯與「高負評率」門檻過濾實戰
系列文
拯救混亂數據:30 天 Python 輕量級 ETL 與電商關聯資料分析15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言