iT邦幫忙

2024 iThome 鐵人賽

DAY 22
1
AI/ ML & Data

征服機器學習的終極秘技系列 第 22

Day 22 - 應用實作練習:數據清理

  • 分享至 

  • xImage
  •  

前言

經過初步的資料探勘後,我們需要進一步處理數據中的缺失值、異常值、重複值等問題,以確保模型能夠在乾淨的數據上進行訓練。以下是數據清理的主要步驟和實作方法:

1) 與目標預測無關參數處理

在初步資料探勘時,我們有提到病患名字、醫生名字、醫院名稱與病患的檢測結果並無顯著相關性。因此,在數據清理過程中,我們將這些無關的欄位移除。

移除無關特徵

import pandas as pd 
 
health_data = pd.read_csv('healthcare_dataset.csv') 
cleaning_data = health_data.drop(columns=['Name', 'Doctor', 'Hospital'], axis=1)  # 移除無關特徵 

2) 目標預測 Label 清理

由於我們只想預測兩類別,分別是 Normal 和 Abnormal,因此我們將 Inconclusive 的個案刪掉。做法如下:

cleaning_data = cleaning_data[cleaning_data['Test Results']!='Inconclusive']

3) 缺失值處理

# 檢查缺失值
missing_values = cleaning_data.isnull().sum()
missing_values

我們得到的結果如下:
https://ithelp.ithome.com.tw/upload/images/20240923/20168116S2Kpv0g9Fp.jpg
可以看到全部都是 0,代表我們的收案數據集中,並無缺失值。
但假如讀者在實作時,有發現缺失值可以依照不同的需求和缺失值比例進行處理。
處理方法包含:

  • 類別型數據:通常使用眾數填補。例如:
# 使用眾數填補缺失值 
cleaning_data['Admission Type'].fillna(cleaning_data['Admission Type'].mode()[0], inplace=True) 
# 顯示填補後的資料 
print("\n使用眾數填補缺失值後的資料:") 
cleaning_data
  • 數值型數據:通常使用平均值填補。例如:
# 使用平均值填補缺失值 
cleaning_data['Age'].fillna(cleaning_data['Age'].mean(), inplace=True)
# 顯示填補後的資料
print("\n使用平均值填補缺失值後的資料:")
cleaning_data

舉例來說,原始資料與填補後的資料對比:
原始資料:

Name Age Admission Type
Alice 25.0 Urgent
Bob 30.0 Emergency
Charlie NaN Elective
David 35.0 NaN
Edward 30.0 Emergency

使用眾數填補 Admission Type,平均數填補 Age 後的資料:

Name Age Admission Type
Alice 25.0 Urgent
Bob 30.0 Emergency
Charlie 30.0 Elective
David 35.0 Emergency
Edward 30.0 Emergency

Note:若某欄位缺失值過多,則通常會考慮刪除該欄位:

cleaning_data.drop(columns=['...'], inplace=True)

由於 Kaggle 數據集無缺失值,因此無需做任何處理。以上只是範例僅供參考。

4) 異常值檢測

  • Z-Score 檢測:
# 對所有數值型欄位計算 Z 分數
numeric_columns = cleaning_data.select_dtypes(include=['float64', 'int64']).columns

# 計算每個數值欄位的 Z 分數
for column in numeric_columns:
    mean = cleaning_data[column].mean()
    std = cleaning_data[column].std()
    cleaning_data[column + '_z_score'] = (cleaning_data[column] - mean) / std

# 篩選出 Z 分數絕對值大於 3 的異常值(針對每個數值欄位)
outliers_z = cleaning_data[(cleaning_data[numeric_columns + '_z_score'].abs() > 3).any(axis=1)]

print("異常值資料:")
outliers_z
  • IQR 規則檢測:
# 對所有數值型欄位計算 IQR
numeric_columns = cleaning_data.select_dtypes(include=['float64', 'int64']).columns

# 建立一個空的 DataFrame 來存儲所有的異常值
outliers_iqr = pd.DataFrame()

for column in numeric_columns:
    # 計算 Q1 和 Q3
    Q1 = cleaning_data[column].quantile(0.25)
    Q3 = cleaning_data[column].quantile(0.75)
    
    # 計算 IQR
    IQR = Q3 - Q1
    
    # 計算異常值範圍
    lower_bound = Q1 - 1.5 * IQR
    upper_bound = Q3 + 1.5 * IQR
    
    # 篩選出異常值
    outliers = cleaning_data[(cleaning_data[column] < lower_bound) | (cleaning_data[column] > upper_bound)]
    
    # 將該欄位的異常值合併到最終的異常值 DataFrame
    outliers_iqr = pd.concat([outliers_iqr, outliers])

# 刪除重複的異常值行
outliers_iqr = outliers_iqr.drop_duplicates()

# 顯示異常值
print("IQR 規則篩選出的異常值資料:")
outliers_iqr

兩種方法得到結果皆如下:
https://ithelp.ithome.com.tw/upload/images/20240923/20168116Fsqsfnn84G.jpg
異常值資料為空,代表這兩種方法我們都並無找到異常值數據。

筆者喜好:更傾向使用 IQR 規則來檢測異常值。若發現異常值,會考慮刪除該數據點,除非數據量過少,則可能會保留並與相關專業人士討論處理方式。
例如,在 Kaggle 資料集中,我們發現 Billing Amount 中有少數負數或異常小的值,這些數據對整體分析影響不大,因此決定將這些數據刪除並再重新確認一次異常值:

# 刪除 Billing Amount 小於 100 的行  
cleaning_data_filtered = cleaning_data[cleaning_data['Billing Amount'] >= 100]

# Calculate lower and upper bounds for each numeric column
numeric_columns = ['Age', 'Room Number', 'Billing Amount']
lower_bound = {}
upper_bound = {}

for column in numeric_columns:
    Q1 = cleaning_data_filtered[column].quantile(0.25)
    Q3 = cleaning_data_filtered[column].quantile(0.75)
    IQR = Q3 - Q1
    lower_bound[column] = Q1 - 1.5 * IQR
    upper_bound[column] = Q3 + 1.5 * IQR
# Filter outliers based on the calculated bounds
outliers_iqr = cleaning_data_filtered[((cleaning_data_filtered['Age'] < lower_bound['Age']) | (cleaning_data_filtered['Age'] > upper_bound['Age'])) | ((cleaning_data_filtered['Room Number'] < lower_bound['Room Number']) | (cleaning_data_filtered['Room Number'] > upper_bound['Room Number'])) |((cleaning_data_filtered['Billing Amount'] < lower_bound['Billing Amount']) | (cleaning_data_filtered['Billing Amount'] > upper_bound['Billing Amount']))
]
outliers_iqr

5) 重複值處理

在資料探勘過程中,發現數據中有 534 筆完全重複的數據。這些重複數據對模型來說是多餘的,因此我們需要將其刪除:

cleaning_data_filtered = cleaning_data_filtered.drop_duplicates()

若有不完全重複值,也會檢查是否有同個病患重複檢測,若有也會刪除。

6) 數據一致性

確保所有數據格式一致、單位統一、標籤正確。若發現錯誤,可以手動修正或使用 Python 進行數據清理。Kaggle 資料集未發現此問題。

7) 數據不平衡檢查

# 檢查標註分佈 
label_distribution = cleaning_data_filtered['Test Results'].value_counts() 
print(label_distribution) 

結果顯示:
Test Results
Abnormal 18390
Normal 18293
Name: count, dtype: int64

數據分佈較為均衡,不存在某一類別過多或過少的情況。如果數據不平衡,可以考慮在模型訓練階段使用 SMOTE 技術來平衡類別分佈。

8) 多重共線性檢查

import seaborn as sns 
import matplotlib.pyplot as plt 

X = cleaning_data_filtered[['Age', 'Billing Amount', 'Room Number']] 

# 計算 Pearson 相關係數
pearson_corr = X.corr(method='pearson') 
print(pearson_corr) 
 
# 計算 Spearman 相關係數 
spearman_corr = X.corr(method='spearman') 
print(spearman_corr) 

# 可視化相關矩陣
plt.figure(figsize=(10, 8)) 
sns.heatmap(pearson_corr, annot=True, cmap='coolwarm', vmin=-1, vmax=1) 
plt.title('Pearson Correlation Matrix') 
plt.show()
plt.figure(figsize=(10, 8))
sns.heatmap(spearman_corr, annot=True, cmap='coolwarm', vmin=-1, vmax=1) 
plt.title('Spearman Correlation Matrix')
plt.show()

結果顯示:各特徵之間的相關性非常低,接近於 0,這表明這些特徵之間幾乎沒有線性關聯性,因此不太可能存在嚴重的多重共線性問題。
https://ithelp.ithome.com.tw/upload/images/20240924/20168116gNgSpvJLhY.jpg
https://ithelp.ithome.com.tw/upload/images/20240924/20168116r2mONPVINb.jpg

結論

本章介紹了數據清理的關鍵步驟,包括處理缺失值、異常值、重複數據,確保數據的一致性等。我們還移除了與預測無關的參數,為模型的訓練提供了乾淨且有用的數據。在下一章,我們將探討特徵工程中的特徵轉換與縮放。這些步驟有助於提升模型性能,確保數據特徵在相同尺度上進行比較。


上一篇
Day 21 - 應用實作練習:資料探勘
下一篇
Day 23 - 應用實作練習:特徵工程
系列文
征服機器學習的終極秘技30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言