最强总结!十大Pandas缺失值处理技巧 !!

文摘   2024-09-20 11:27   北京  

哈喽,我是小白~

今天你们数据处理好了嘛?

当你看到这篇文章的时候,今天一定会搞懂一件事:缺失值处理

因为不当的缺失值处理可能导致模型偏差或性能下降。通过恰当的处理方式,如均值填充、插值法等,能够保留数据的完整性并最大化模型的训练效果。有效的缺失值处理还能帮助减少噪音数据对模型预测的负面影响,提升实验的可靠性与准确性。

所以,咱们通过以下10种方式,搞定你的数据集:

  • 检测缺失值
  • 删除缺失值
  • 用均值填充
  • 用中位数填充
  • 用众数填充
  • 前向填充
  • 插值法
  • 条件填充
  • 通过模型预测填充
  • 标记缺失值

咱们一起从主要功能和使用方式,详细的来学习一下~

1. 检测缺失值

在处理缺失值之前,首先需要确定数据集中存在哪些缺失值。Pandas 提供了几个函数用于检测缺失值:isnull() 和 isna() 是最常用的检测缺失值的方法。

主要功能

  • isnull()/isna(): 检测 DataFrame 中的缺失值,返回布尔值的 DataFrame,缺失值显示为 True
  • sum(): 统计每列/每行的缺失值数量。

Python实现

import pandas as pd
import numpy as np

# 创建一个带有缺失值的小数据集
data = {'A': [12, 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 进行处理,并可视化这些处理方法的效果。

在此案例中,我们会:

  1. 生成一个包含缺失值的虚拟数据集。
  2. 使用不同的缺失值处理方法:删除缺失值、均值填充、中位数填充、前向填充、插值等。
  3. 绘制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(1100, size=50).astype(float),  # 数值型
    'B': np.random.normal(5010, size=50),  # 数值型(带有正态分布)
    'C': np.random.choice(['X''Y''Z'], size=50),  # 类别型
    'D': np.random.choice([np.nan, 10], size=50, p=[0.20.40.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(22, figsize=(1410))

# 1. 原始数据(带缺失值)
sns.scatterplot(x=df.index, y=df['A'], ax=axes[00], color='red', marker='o', s=100, label="Column A (Original)")
sns.scatterplot(x=df.index, y=df['B'], ax=axes[00], color='blue', marker='x', s=100, label="Column B (Original)")
axes[00].set_title('Original Data with Missing Values')
axes[00].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[01], 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[01], color='purple', marker='x', s=100, label="Column B (Mean Filled)")
axes[01].set_title('Mean Filling')
axes[01].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[10], 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[10], color='cyan', marker='x', s=100, label="Column B (Median Filled)")
axes[10].set_title('Median Filling')
axes[10].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[11], color='pink', marker='o', s=100, label="Column A (Interpolated)")
sns.scatterplot(x=df_interpolated.index, y=df_interpolated['B'], ax=axes[11], color='yellow', marker='x', s=100, label="Column B (Interpolated)")
axes[11].set_title('Interpolation Filling')
axes[11].legend()

# 调整子图间距
plt.tight_layout()

# 显示图形
plt.show()

1. 数据生成:使用 numpy 生成虚拟数据集,包括数值型、分类型和带有缺失值的二进制数据。我们人为加入了缺失值来模拟实际数据中的不完整情况。

2. 不同的缺失值处理方法:

  • 原始数据:展示数据中存在的缺失值。
  • 均值填充:使用每列的均值填充缺失值。
  • 中位数填充:使用每列的中位数填充缺失值。
  • 插值法填充:使用线性插值方法填充数值数据的缺失值。

  • 左上角:展示原始数据集,带有明显的缺失值点。
  • 右上角:展示均值填充后的数据,缺失值被每列的均值替代。
  • 左下角:展示中位数填充后的数据,缺失值被中位数替代,处理异常值更稳健。
  • 右下角:展示插值法填充后的数据,数据的缺失值通过线性插值进行填充,生成平滑的过渡值。

这个案例,我们展示了 Pandas 中多种缺失值处理方法,并通过不同颜色和形状的图形展示了每种方法对数据集的影响。大家可以研究一番~

最后

以上就是今天所有的内容了。
如果对你来说比较有用,记得点赞、收藏,慢慢学习~
下期会有更多干货等着你!~


Python和机器学习初学者
Python和机器学习分享,只写干货,一起学习~
 最新文章