什么是缺失值?

在数据分析中,缺失值(Missing Value)指的是数据集中某些行或列没有有效值。比如一份学生成绩表中,某学生的数学成绩没填,或者某公司某季度的销售额数据丢失了。在 pandas 中,缺失值通常用 NaN(Not a Number)表示,有时也会遇到 None,但 NaN 是更标准的数值型缺失值表示。

如何检查缺失值?

在处理缺失值前,第一步是找到数据中哪里有缺失值。pandas 提供了两个简单实用的方法:

1. isnull():标记缺失值

df.isnull() 会返回一个布尔型 DataFrame,True 表示该位置是缺失值,False 表示有效数据。

import pandas as pd
import numpy as np

# 创建一个带缺失值的示例 DataFrame
data = {
    '姓名': ['小明', '小红', '小刚', '小丽', '小强'],
    '年龄': [20, np.nan, 22, 21, np.nan],
    '成绩': [85, 92, np.nan, 78, 88]
}
df = pd.DataFrame(data)

# 检查所有位置是否缺失
print(df.isnull())

输出结果:

    姓名    年龄   成绩
0  False  False  False
1  False   True  False
2  False  False   True
3  False  False  False
4  False   True  False

2. isnull().sum():统计缺失值数量

df.isnull().sum() 可以快速统计每列的缺失值总数,方便定位问题。

# 统计每列缺失值数量
print(df.isnull().sum())

输出结果:

姓名    0
年龄    2
成绩    1
dtype: int64

3. info():查看数据整体缺失情况

df.info() 可以查看每列的数据类型和非空值数量,直观判断缺失值分布。

df.info()

输出结果:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 3 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   姓名      5 non-null      object 
 1   年龄      3 non-null      float64
 2   成绩      4 non-null      float64
dtypes: float64(2), object(1)
memory usage: 240.0+ bytes

缺失值处理方法

处理缺失值的核心思路是:要么删除缺失值,要么用合理的值填充缺失值

方法一:删除缺失值(dropna)

当缺失值很少且不影响整体数据时,可以直接删除包含缺失值的行或列。

1. 删除有缺失值的行(默认)

df.dropna(axis=0, how='any')
- axis=0:删除行(默认);axis=1:删除列。
- how='any':只要行/列中有一个缺失值就删除;how='all':仅当所有值都是缺失值时才删除。

# 删除所有有缺失值的行
df_drop_rows = df.dropna(axis=0)
print(df_drop_rows)

输出结果(仅保留无缺失值的行):

    姓名   年龄   成绩
0  小明  20.0  85.0
3  小丽  21.0  78.0

2. 删除有缺失值的列

# 删除所有有缺失值的列
df_drop_cols = df.dropna(axis=1)
print(df_drop_cols)

输出结果(仅保留无缺失值的列):

    姓名
0  小明
1  小红
2  小刚
3  小丽
4  小强

方法二:填充缺失值(fillna)

当缺失值较多或删除会丢失关键信息时,填充缺失值更常用。pandas 的 fillna() 支持多种填充方式。

1. 用固定值填充

直接用某个固定值(如 0、-1)填充所有缺失值。

# 用 0 填充所有缺失值
df_fill_0 = df.fillna(0)
print(df_fill_0)

输出结果:

    姓名    年龄   成绩
0  小明  20.0  85.0
1  小红   0.0  92.0
2  小刚  22.0   0.0
3  小丽  21.0  78.0
4  小强   0.0  88.0

2. 用统计量填充(均值/中位数/众数)

数值型数据适合用统计量填充,比如:
- 均值:适合对称分布数据(如正态分布)。
- 中位数:适合偏态分布数据(抗极端值能力强)。
- 众数:适合分类数据(出现次数最多的值)。

# 用年龄列的均值填充年龄缺失值
df['年龄'] = df['年龄'].fillna(df['年龄'].mean())
print(df['年龄'])

输出结果(年龄列均值为 (20+22+21)/3=21):

0    20.0
1    21.0
2    22.0
3    21.0
4    21.0
Name: 年龄, dtype: float64

3. 向前/向后填充(ffill/bfill)

适用于时间序列数据或有顺序的数据(如按时间排列的销售额)。
- ffill():用前一个非缺失值填充后面的缺失值。
- bfill():用后一个非缺失值填充前面的缺失值。

# 模拟时间序列数据
df_time = pd.DataFrame({'value': [1, np.nan, 3, np.nan, 5]})

# 向前填充
df_forward = df_time.fillna(method='ffill')
print("向前填充结果:")
print(df_forward)

# 向后填充
df_backward = df_time.fillna(method='bfill')
print("\n向后填充结果:")
print(df_backward)

输出结果:

向前填充结果:
   value
0    1.0
1    1.0
2    3.0
3    3.0
4    5.0

向后填充结果:
   value
0    1.0
1    3.0
2    3.0
3    5.0
4    5.0

综合实践案例

假设我们有一份电商订单数据,需要处理缺失值。

数据准备

# 订单数据
orders = {
    '订单ID': [101, 102, 103, 104, 105],
    '客户姓名': ['A', 'B', 'C', 'D', 'E'],
    '金额': [150, np.nan, 200, np.nan, 80],
    '支付方式': ['微信', '支付宝', np.nan, '微信', '支付宝']
}
df_orders = pd.DataFrame(orders)

步骤1:检查缺失值

print(df_orders.isnull().sum())

输出:

订单ID      0
客户姓名     0
金额       2
支付方式     1
dtype: int64

步骤2:处理缺失值

  • 金额列:数值型,用均值填充。
  • 支付方式列:分类型,用众数(出现次数最多的值)填充。
# 填充金额列的缺失值(均值)
df_orders['金额'] = df_orders['金额'].fillna(df_orders['金额'].mean())

# 填充支付方式列的缺失值(众数)
df_orders['支付方式'] = df_orders['支付方式'].fillna(df_orders['支付方式'].mode()[0])

print(df_orders)

输出结果:

   订单ID 客户姓名     金额 支付方式
0   101    A  150.0   微信
1   102    B  143.333333   支付宝  # 均值=(150+200+80)/3≈143.33
2   103    C  200.0   支付宝  # 众数是支付宝(出现2次)
3   104    D  143.333333   微信
4   105    E   80.0   支付宝

总结

缺失值处理的核心步骤:
1. 检查缺失值:用 isnull()isnull().sum() 定位问题。
2. 选择处理策略
- 缺失值极少(<5%)且不重要 → 删除dropna())。
- 缺失值较多或关键数据 → 填充fillna()),优先用统计量(均值/中位数)或固定值。
3. 验证结果:处理后再次检查数据,确保缺失值已合理处理。

处理缺失值没有“万能方法”,需结合数据特点和业务需求灵活选择,避免因处理不当导致数据偏差。

小夜