哈喽,我是小白~
今天你们数据处理好了嘛?
当你看到这篇文章的时候,今天一定会搞懂一件事:缺失值处理!
因为不当的缺失值处理可能导致模型偏差或性能下降。通过恰当的处理方式,如均值填充、插值法等,能够保留数据的完整性并最大化模型的训练效果。有效的缺失值处理还能帮助减少噪音数据对模型预测的负面影响,提升实验的可靠性与准确性。
所以,咱们通过以下10种方式,搞定你的数据集:
检测缺失值 删除缺失值 用均值填充 用中位数填充 用众数填充 前向填充 插值法 条件填充 通过模型预测填充 标记缺失值
咱们一起从主要功能和使用方式,详细的来学习一下~
1. 检测缺失值
在处理缺失值之前,首先需要确定数据集中存在哪些缺失值。Pandas 提供了几个函数用于检测缺失值:isnull()
和 isna()
是最常用的检测缺失值的方法。
主要功能
isnull()
/isna()
: 检测 DataFrame 中的缺失值,返回布尔值的 DataFrame,缺失值显示为True
。sum()
: 统计每列/每行的缺失值数量。
Python实现
import pandas as pd
import numpy as np
# 创建一个带有缺失值的小数据集
data = {'A': [1, 2, np.nan, 4],
'B': [5, np.nan, np.nan, 8],
'C': ['x', 'y', 'z', np.nan]}
df = pd.DataFrame(data)
# 检测缺失值
print("是否存在缺失值:")
print(df.isnull()) # 逐个元素显示是否为缺失值
# 统计每列缺失值的数量
print("\n每列缺失值数量:")
print(df.isnull().sum())
输出:
是否存在缺失值:
A B C
0 False False False
1 False True False
2 True True False
3 False False True
每列缺失值数量:
A 1
B 2
C 1
dtype: int64
2. 删除缺失值(dropna()
)
在一些情况下,数据中有太多缺失值或某列对分析不重要,可以选择直接删除含有缺失值的行或列。
主要功能
dropna()
: 删除包含缺失值的行或列,支持自定义删除的方式:axis=0
:删除行。axis=1
:删除列。how='all'
:仅删除全为缺失值的行/列。
Python实现
# 删除含有缺失值的行
df_drop_rows = df.dropna(axis=0)
print("删除缺失值行后的DataFrame:")
print(df_drop_rows)
# 删除含有缺失值的列
df_drop_columns = df.dropna(axis=1)
print("\n删除缺失值列后的DataFrame:")
print(df_drop_columns)
# 只删除全为缺失的行
df_drop_all = df.dropna(how='all')
print("\n删除全为缺失值行后的DataFrame:")
print(df_drop_all)
输出:
删除缺失值行后的DataFrame:
A B C
0 1.0 5.0 x
删除缺失值列后的DataFrame:
A C
0 1.0 x
1 2.0 y
2 NaN z
3 4.0 NaN
删除全为缺失值行后的DataFrame:
A B C
0 1.0 5.0 x
1 2.0 NaN y
2 NaN NaN z
3 4.0 8.0 NaN
3. 用均值填充(fillna()
)
对于数值型数据,缺失值可以用该列的均值进行填充,以保留数据信息。
主要功能
fillna(value)
:用指定值填充缺失值。inplace=True
:直接修改原数据集,不返回副本。
Python实现
# 用均值填充A列的缺失值
df_mean_fill = df.copy()
df_mean_fill['A'].fillna(df['A'].mean(), inplace=True)
print("用均值填充A列后的DataFrame:")
print(df_mean_fill)
输出:
用均值填充A列后的DataFrame:
A B C
0 1.0 5.0 x
1 2.0 NaN y
2 2.333333 NaN z
3 4.0 8.0 NaN
4. 用中位数填充
如果数据中有较多的异常值(离群点),使用中位数代替均值来填充缺失值更加稳健。
主要功能
fillna(df['column'].median())
:用该列的中位数填充缺失值。
Python实现
# 用中位数填充B列的缺失值
df_median_fill = df.copy()
df_median_fill['B'].fillna(df['B'].median(), inplace=True)
print("用中位数填充B列后的DataFrame:")
print(df_median_fill)
输出:
用中位数填充B列后的DataFrame:
A B C
0 1.0 5.0 x
1 2.0 6.5 y
2 NaN 6.5 z
3 4.0 8.0 NaN
5. 用众数填充
对于分类变量或文本数据,缺失值可以用该列的众数(最常见的值)填充。
主要功能
mode()
:返回 DataFrame 中出现频率最高的值。
Python实现
# 用众数填充C列的缺失值
df_mode_fill = df.copy()
df_mode_fill['C'].fillna(df['C'].mode()[0], inplace=True)
print("用众数填充C列后的DataFrame:")
print(df_mode_fill)
输出:
用众数填充C列后的DataFrame:
A B C
0 1.0 5.0 x
1 2.0 NaN y
2 NaN NaN z
3 4.0 8.0 x
6. 前向填充(ffill()
)和后向填充(bfill()
)
在时间序列或顺序数据中,前向填充和后向填充是一种常用的方法,用来使用相邻的值填充缺失数据。
主要功能
ffill()
:用前一个有效值填充缺失值。bfill()
:用后一个有效值填充缺失值。
Python实现
# 前向填充
df_ffill = df.copy()
df_ffill.fillna(method='ffill', inplace=True)
print("前向填充后的DataFrame:")
print(df_ffill)
# 后向填充
df_bfill = df.copy()
df_bfill.fillna(method='bfill', inplace=True)
print("\n后向填充后的DataFrame:")
print(df_bfill)
输出:
前向填充后的DataFrame:
A B C
0 1.0 5.0 x
1 2.0 5.0 y
2 2.0 5.0 z
3 4.0 8.0 z
后向填充后的DataFrame:
A B C
0 1.0 5.0 x
1 2.0 8.0 y
2 4.0 8.0 z
3 4.0 8.0 NaN
7. 插值法(interpolate()
)
插值法通过估计缺失值之间的趋势进行填充,常用于时间序列或连续型数据。常见的插值方法包括线性插值和时间插值。
主要功能
interpolate(method='linear')
:线性插值法。
Python实现
# 线性插值法填充A列
df_interpolate = df.copy()
df_interpolate['A'].interpolate(method='linear', inplace=True)
print("插值法填充A列后的DataFrame:")
print(df_interpolate)
输出:
插值法填充A列后的DataFrame:
A B C
0 1.0 5.0 x
1 2.0 NaN y
2 3.0 NaN z
3 4.0 8.0 NaN
8. 条件填充
通过条件逻辑来选择填充的值,可以根据数据集的其他特征来填充缺失值。
主要功能
loc[]
:基于条件进行定位和填充。
Python实现
# 根据条件填充A列的缺失值,例如根据C列的值填充
df_conditional_fill = df.copy()
df_conditional_fill.loc[df['C'] == 'z', 'A'] = 100
print("根据条件填充A列后的DataFrame:")
print(df_conditional_fill)
输出:
根据条件填充A列后的DataFrame:
A B C
0 1.0 5.0 x
1 2.0 NaN y
2 100.0 NaN z
3 4.0 8.0 NaN
9. 通过模型预测填充
对于复杂数据,可以通过训练机器学习模型预测缺失值。常见的方法包括使用回归模型来预测数值缺失值,或分类模型预测类别缺失值。
主要功能
LinearRegression
:用于数值预测。KNN
:用于分类缺失值的预测。
Python实现
from sklearn.linear_model import LinearRegression
# 用其他列作为特征,训练模型填充缺失值
df_model_fill = df.copy()
# 删除含有NaN的行,获取训练数据
df_train = df_model_fill.dropna()
# 特征与目标
X_train = df_train[['A', 'C']].dropna() # 假设A列与C列有关系
y_train = df_train['B']
# 构建线性回归模型
model = LinearRegression()
model.fit(X_train, y_train)
# 预测缺失值
missing_data = df_model_fill[df_model_fill['B'].isnull()]
predicted_values = model.predict(missing_data[['A', 'C']])
# 填充缺失值
df_model_fill.loc[df_model_fill['B'].isnull(), 'B'] = predicted_values
print("用模型预测填充B列后的DataFrame:")
print(df_model_fill)
10. 标记缺失值
有时缺失值本身携带信息,可以创建一个新的二进制列,标记数据是否为缺失。
主要功能
isnull()
:检测缺失值,返回布尔值。astype(int)
:将布尔值转换为整数(1 表示缺失,0 表示不缺失)。
Python实现
# 创建一个新列来标记A列中缺失值
df_mark_missing = df.copy()
df_mark_missing['A_missing'] = df['A'].isnull().astype(int)
print("标记A列缺失值后的DataFrame:")
print(df_mark_missing)
输出:
标记A列缺失值后的DataFrame:
A B C A_missing
0 1.0 5.0 x 0
1 2.0 NaN y 0
2 NaN NaN z 1
3 4.0 8.0 NaN 0
有了以上的10种方式,基本可以在适当的时候选择其中一种,避免数据丢失或偏差,并确保模型能获得更高的预测准确率。
代表案例
我这里使用一个包含虚拟数据的案例。这个数据集包含数值型和分类型数据,数据会被生成并包含多个缺失值。我们将使用 Pandas 进行处理,并可视化这些处理方法的效果。
在此案例中,我们会:
生成一个包含缺失值的虚拟数据集。 使用不同的缺失值处理方法:删除缺失值、均值填充、中位数填充、前向填充、插值等。 绘制4个不同的图表来展示每个处理方法的效果,这些图表将组合成一个图形。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 设置随机种子,保证可重复性
np.random.seed(42)
# 生成虚拟数据集
data = {
'A': np.random.randint(1, 100, size=50).astype(float), # 数值型
'B': np.random.normal(50, 10, size=50), # 数值型(带有正态分布)
'C': np.random.choice(['X', 'Y', 'Z'], size=50), # 类别型
'D': np.random.choice([np.nan, 1, 0], size=50, p=[0.2, 0.4, 0.4]) # 二进制分类,带有缺失值
}
# 将部分数据设为NaN(人为加入缺失值)
df = pd.DataFrame(data)
df.loc[np.random.choice(df.index, size=10, replace=False), 'A'] = np.nan
df.loc[np.random.choice(df.index, size=15, replace=False), 'B'] = np.nan
# 创建子图布局
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 1. 原始数据(带缺失值)
sns.scatterplot(x=df.index, y=df['A'], ax=axes[0, 0], color='red', marker='o', s=100, label="Column A (Original)")
sns.scatterplot(x=df.index, y=df['B'], ax=axes[0, 0], color='blue', marker='x', s=100, label="Column B (Original)")
axes[0, 0].set_title('Original Data with Missing Values')
axes[0, 0].legend()
# 2. 均值填充
df_mean_filled = df.copy()
df_mean_filled['A'].fillna(df['A'].mean(), inplace=True)
df_mean_filled['B'].fillna(df['B'].mean(), inplace=True)
sns.scatterplot(x=df_mean_filled.index, y=df_mean_filled['A'], ax=axes[0, 1], color='green', marker='o', s=100, label="Column A (Mean Filled)")
sns.scatterplot(x=df_mean_filled.index, y=df_mean_filled['B'], ax=axes[0, 1], color='purple', marker='x', s=100, label="Column B (Mean Filled)")
axes[0, 1].set_title('Mean Filling')
axes[0, 1].legend()
# 3. 中位数填充
df_median_filled = df.copy()
df_median_filled['A'].fillna(df['A'].median(), inplace=True)
df_median_filled['B'].fillna(df['B'].median(), inplace=True)
sns.scatterplot(x=df_median_filled.index, y=df_median_filled['A'], ax=axes[1, 0], color='orange', marker='o', s=100, label="Column A (Median Filled)")
sns.scatterplot(x=df_median_filled.index, y=df_median_filled['B'], ax=axes[1, 0], color='cyan', marker='x', s=100, label="Column B (Median Filled)")
axes[1, 0].set_title('Median Filling')
axes[1, 0].legend()
# 4. 插值填充
df_interpolated = df.copy()
df_interpolated['A'].interpolate(method='linear', inplace=True)
df_interpolated['B'].interpolate(method='linear', inplace=True)
sns.scatterplot(x=df_interpolated.index, y=df_interpolated['A'], ax=axes[1, 1], color='pink', marker='o', s=100, label="Column A (Interpolated)")
sns.scatterplot(x=df_interpolated.index, y=df_interpolated['B'], ax=axes[1, 1], color='yellow', marker='x', s=100, label="Column B (Interpolated)")
axes[1, 1].set_title('Interpolation Filling')
axes[1, 1].legend()
# 调整子图间距
plt.tight_layout()
# 显示图形
plt.show()
1. 数据生成:使用 numpy
生成虚拟数据集,包括数值型、分类型和带有缺失值的二进制数据。我们人为加入了缺失值来模拟实际数据中的不完整情况。
2. 不同的缺失值处理方法:
原始数据:展示数据中存在的缺失值。 均值填充:使用每列的均值填充缺失值。 中位数填充:使用每列的中位数填充缺失值。 插值法填充:使用线性插值方法填充数值数据的缺失值。
左上角:展示原始数据集,带有明显的缺失值点。 右上角:展示均值填充后的数据,缺失值被每列的均值替代。 左下角:展示中位数填充后的数据,缺失值被中位数替代,处理异常值更稳健。 右下角:展示插值法填充后的数据,数据的缺失值通过线性插值进行填充,生成平滑的过渡值。
这个案例,我们展示了 Pandas 中多种缺失值处理方法,并通过不同颜色和形状的图形展示了每种方法对数据集的影响。大家可以研究一番~
最后