iT邦幫忙

2025 iThome 鐵人賽

DAY 19
0
自我挑戰組

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

Day 19 - 資料清洗(一):如何優雅地處理缺失值 (Missing Values)

  • 分享至 

  • xImage
  •  

大家好,歡迎來到數據新手村的第十九天!在數據分析界有句名言:「一個數據分析師 80% 的時間,都花在清理數據上。

從今天開始,我們將正式動手處理「髒數據」,而所有髒數據中最常見的,就是缺失值 (Missing Values)。缺失值在 Pandas 中通常以 NaN (Not a Number) 的形式出現,它們會讓我們的統計計算(例如 mean())出錯,是分析前必須處理的頭號敵人。


1. 偵測缺失值

在處理之前,我們得先找到它們。df.info() 是我們的第一道防線,它可以告訴我們每欄的非缺失值數量。如果想更精確地統計每欄到底有多少個缺失值,可以使用 .isna() 搭配 .sum()

import pandas as pd
# 假設 orders_df 已經讀取好了
# orders_df = pd.read_csv('../../data/olist_datasets/olist_orders_dataset.csv')

# .isna() 會回傳一個 True/False 的 DataFrame,True 代表該位置是缺失值
# .sum() 會將 True (視為1) 加總,從而計算出每欄的缺失值總數
missing_counts = orders_df.isna().sum()

print("各欄位的缺失值數量:")
print(missing_counts[missing_counts > 0]) # 只顯示有缺失值的欄位

輸出結果:
各欄位的缺失值數量:
order_approved_at 160
order_delivered_carrier_date 1783
order_delivered_customer_date 2965
dtype: int64

從 Olist 訂單表中,我們會發現 order_approved_at, order_delivered_carrier_date, order_delivered_customer_date 這幾個時間欄位有大量的缺失值。這是合理的,因為「已取消」或「處理中」的訂單,自然不會有後續的「送達時間」。

  1. 處理策略一:刪除 (.dropna())
    這是最簡單粗暴,但有時也最有效的方法:直接刪除包含缺失值的列或欄。

# 為了演示,先複製一份 DataFrame
df_copy = orders_df.copy()

print(f"刪除前,資料筆數: {len(df_copy)}")

# .dropna() 預設會刪除任何包含至少一個缺失值的「列 (row)」
df_dropped = df_copy.dropna()

print(f"刪除後,資料筆數: {len(df_dropped)}")

輸出結果:
刪除前,資料筆數: 99441
刪除後,資料筆數: 96461

何時該用刪除法?
只有當包含缺失值的資料筆數,佔總體比例非常非常小(例如 < 1%),且您確定刪除它們不會對整體數據分佈造成偏差時,才考慮使用。在我們的 Olist 案例中,直接刪除會損失太多寶貴的訂單資訊,顯然不合適。

  1. 處理策略二:填補 (.fillna())
    相較於刪除,填補是一個更常見、更細膩的作法。我們可以根據欄位的特性,用一個合理的值來填補 NaN。

填補固定值
例如,對於類別型或文字型資料,我們可以用一個特定的字串(如 "Unknown")來填補。

填補統計量 (最常用!)
對於數值型資料,最常見的作法是用該欄位的平均數 (mean) 或中位數 (median) 來填補。


# 假設我們有一個包含缺失值的數值 Series
numeric_data = pd.Series([1.0, 2.0, np.nan, 4.0, 5.0, np.nan])
print(f"原始資料:\n{numeric_data}\n")

# 計算平均值 (忽略 NaN)
mean_value = numeric_data.mean()
print(f"平均值為: {mean_value}\n")

# 使用平均值填補缺失值
filled_data = numeric_data.fillna(mean_value)
print(f"用平均值填補後的資料:\n{filled_data}")

輸出結果:
原始資料:
0 1.0
1 2.0
2 NaN
3 4.0
4 5.0
5 NaN
dtype: float64

平均值為: 3.0

用平均值填補後的資料:
0 1.0
1 2.0
2 3.0
3 4.0
4 5.0
5 3.0
dtype: float64

進階填補 (ffill, bfill)
對於時間序列數據,有時用前一個時間點 (ffill) 或後一個時間點 (bfill) 的值來填補會更合理。


結語
今天我們學會如何偵測並處理數據中最惱人的缺失值。請記住,沒有一種方法是萬能的,我們必須根據數據的特性和分析的目的,來選擇最合適的處理策略。刪除雖然簡單,但填補通常能更好地保留數據的完整性。

我們處理了「空格子」,但如果格子裡有東西,卻是錯誤的「類型」(例如,日期被存成文字)呢?明天,Day 20,我們將繼續資料清洗的旅程,學習如何轉換 Pandas 的資料類型!


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

尚未有邦友留言

立即登入留言