資料的預處理是資料分析,或者機器學習訓練前的重要步驟。
透過資料預處理,可以
- 提高資料質量,處理資料的缺失值、異常值和重複值等問題,增加資料的準確性和可靠性
- 整合不同資料,資料的來源和結構可能多種多樣,分析和訓練前要整合成一個資料集
- 提高資料效能,對資料的值進行變換,規約等(比如無量綱化),讓演算法更加高效
本篇介紹的缺失值處理,是資料預處理中非常重要的一步,因為很多機器學習演算法都假設資料是完整的,演算法的執行過程中沒有考慮缺失值的影響。
所以,為了提高資料質量、改進資料分析結果、提高資料探勘和機器學習的效果,缺失值處理必不可少。
1. 原理
處理缺失值的手段大致有4類:
- 刪除存在缺失值資料行
- 填充缺失值
- 不處理缺失值
- 用深度學習方法處理
1.1. 刪除缺失值資料
刪除缺失值是最簡單的一種處理方式,不過,在某些情況下,這可能會導致資料的大量丟失。
如果資料丟失過多,可能會改變資料的分佈,影響模型的準確性。
所以,只有在缺失值佔比很小的情況下,才會考慮使用這種處理方式。
刪除缺失值用pandas
庫的方法即可,比如:
import pandas as pd
df = pd.util.testing.makeMissingDataframe()
print("刪除前: {} 行".format(len(df)))
df = df.dropna()
print("刪除後: {} 行".format(len(df)))
# 執行結果
刪除前: 30 行
刪除後: 19 行
1.2. 填充缺失值
直接刪除存在缺失值的資料行雖然簡單,但是在實際應用中,使用的並不多。
實際情況下,使用最多的還是填充缺失值。
scikit-learn
庫中,填充缺失值的方式主要有:
1.2.1. 均值填充
均值填充就是用缺失值所在列的平均值來填充缺失值。
from sklearn.impute import SimpleImputer
data = np.array([[1, 2, 3], [4, np.nan, 6], [7, 8, np.nan]])
print("均值填充前:\n{}".format(data))
imp = SimpleImputer(missing_values=np.nan, strategy="mean")
data = imp.fit_transform(data)
print("均值填充後:\n{}".format(data))
# 執行結果
均值填充前:
[[ 1. 2. 3.]
[ 4. nan 6.]
[ 7. 8. nan]]
均值填充後:
[[1. 2. 3. ]
[4. 5. 6. ]
[7. 8. 4.5]]
填充的5
和4.5
分別是第二列和第三列的平均值。
1.2.2. 中位數填充
中位數填充就是用缺失值所在列的中位數來填充缺失值。
from sklearn.impute import SimpleImputer
data = np.array([[1, 2, 3], [4, np.nan, 6], [7, 8, np.nan], [10, 11, 12]])
print("中位數填充前:\n{}".format(data))
imp = SimpleImputer(missing_values=np.nan, strategy="median")
data = imp.fit_transform(data)
print("中位數填充後:\n{}".format(data))
# 執行結果
中位數填充前:
[[ 1. 2. 3.]
[ 4. nan 6.]
[ 7. 8. nan]
[10. 11. 12.]]
中位數填充後:
[[ 1. 2. 3.]
[ 4. 8. 6.]
[ 7. 8. 6.]
[10. 11. 12.]]
填充的8
和6
分別是第二列和第三列的中位數。
1.2.3. 眾數填充
眾數填充就是用缺失值所在列的眾數數來填充缺失值。
from sklearn.impute import SimpleImputer
data = np.array([[1, 2, 3], [4, np.nan, 6], [7, 8, np.nan], [10, 8, 3]])
print("眾數填充前:\n{}".format(data))
imp = SimpleImputer(missing_values=np.nan, strategy="most_frequent")
data = imp.fit_transform(data)
print("眾數填充後:\n{}".format(data))
# 執行結果
眾數填充前:
[[ 1. 2. 3.]
[ 4. nan 6.]
[ 7. 8. nan]
[10. 8. 3.]]
眾數填充後:
[[ 1. 2. 3.]
[ 4. 8. 6.]
[ 7. 8. 3.]
[10. 8. 3.]]
填充的8
和3
分別是第二列和第三列的眾數。
1.2.4. 常量填充
常量填充就是用指定的常量來填充缺失值。
from sklearn.impute import SimpleImputer
data = np.array([[1, 2, 3], [4, np.nan, 6], [7, 8, np.nan]])
print("常量填充前:\n{}".format(data))
imp = SimpleImputer(missing_values=np.nan, fill_value=100, strategy="constant")
data = imp.fit_transform(data)
print("常量填充後:\n{}".format(data))
# 執行結果
常量填充前:
[[ 1. 2. 3.]
[ 4. nan 6.]
[ 7. 8. nan]]
常量填充後:
[[ 1. 2. 3.]
[ 4. 100. 6.]
[ 7. 8. 100.]]
缺失值用常量100
填充了。
1.2.5. 插值填充
插值填充就是使用線性插值或多項式插值等方法,基於已知的資料點估計缺失值。
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
data = np.array([[1, 2, 3], [4, np.nan, 6], [7, 8, np.nan]])
print("插值填充前:\n{}".format(data))
imp = IterativeImputer(max_iter=10, random_state=0)
data = imp.fit_transform(data)
print("插值填充後:\n{}".format(data))
# 執行結果
插值填充前:
[[ 1. 2. 3.]
[ 4. nan 6.]
[ 7. 8. nan]]
插值填充後:
[[1. 2. 3. ]
[4. 5.00203075 6. ]
[7. 8. 8.99796726]]
1.2.6. K近鄰填充
K近鄰填充就是利用K近鄰演算法,找到與缺失值最近的K個資料點,用它們的值的平均數或中位數來填充缺失值。
from sklearn.impute import KNNImputer
data = np.array([[1, 2, 3], [4, np.nan, 6], [7, 8, np.nan], [10, 11, 12]])
print("K近鄰填充前:\n{}".format(data))
imp = KNNImputer(n_neighbors=2)
data = imp.fit_transform(data)
print("K近鄰填充後:\n{}".format(data))
# 執行結果
K近鄰填充前:
[[ 1. 2. 3.]
[ 4. nan 6.]
[ 7. 8. nan]
[10. 11. 12.]]
K近鄰填充後:
[[ 1. 2. 3.]
[ 4. 5. 6.]
[ 7. 8. 9.]
[10. 11. 12.]]
2. 作用
缺失值處理的主要作用包括:
- 提高資料完整性和準確性:如果資料中存在缺失值,可能會影響分析的準確性,甚至導致錯誤的結論。因此,透過填補缺失值,我們可以確保資料的完整性和準確性。
- 提升資料質量:缺失值可能會降低資料的質量,使得資料分析變得更為困難。透過處理缺失值,我們可以提升資料的質量,使得分析結果更加可靠。
- 提高演算法效能:許多機器學習和資料探勘演算法在處理不完整資料時效能會下降。處理缺失值可以使得這些演算法更好地執行,提高其效能。
- 減少資訊丟失:在某些情況下,缺失值可能代表著某些資訊的丟失。透過對這些缺失值進行處理,我們可以儘量減少資訊丟失的數量。
- 消除或減少噪聲:缺失值的存在可能會引入資料中的噪聲,這種噪聲可能會對資料分析產生干擾,甚至影響模型的訓練效果。透過填補這些缺失值,我們可以消除或減少這種噪聲。
3. 總結
在選擇處理缺失值的方法時,需要考慮資料的性質、缺失值的比例、資料的分佈以及具體的分析任務等因素。
同時,不同的方法可能適用於不同的場景,需要結合具體情況進行選擇。