填充缺失值
使用 fillna() 及其 method 参数,将 NaN 替换为常量、列均值,或使用向前填充、向后填充。
填充缺失值 是 CoddyKit 上的免费 Pandas & NumPy Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Pandas & NumPy Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Pandas & NumPy Academy 课程共包含 4 节课。
fillna() 简介
插补是指用合理的替代值替换缺失值,而不是删除所在的行。Pandas 的 fillna() 是完成此操作的主要工具:它会将 Series 或 DataFrame 中的每个 NaN 替换为您指定的值。与删除不同,插补可以保留所有行;当数据稀缺或缺失模式本身包含重要信息时,这一点尤其重要。
最简单的形式是传入一个标量:df['col'].fillna(0)。
import pandas as pd
import numpy as np
df = pd.DataFrame({
'product': ['A', 'B', 'C', 'D'],
'price': [10.0, np.nan, 30.0, np.nan]
})
# Fill all NaN in 'price' with 0
filled = df['price'].fillna(0)
print(filled)
# 0 10.0
# 1 0.0
# 2 30.0
# 3 0.0使用列均值或中位数填充
使用列的均值(适用于对称分布)或中位数(适用于偏斜分布)进行填充,是最常见的插补策略之一。这些统计量代表数据的集中趋势,因此可以尽量减少对列分布的扭曲。为避免数据泄漏,请始终在训练集分片上计算统计量。
import pandas as pd
import numpy as np
df = pd.DataFrame({
'salary': [50000, np.nan, 70000, 80000, np.nan, 60000]
})
mean_salary = df['salary'].mean()
median_salary = df['salary'].median()
df['salary_mean_filled'] = df['salary'].fillna(mean_salary)
df['salary_median_filled'] = df['salary'].fillna(median_salary)
print(df)
# salary salary_mean_filled salary_median_filled
# 0 50000.0 50000.0 50000.0
# 1 NaN 65000.0 65000.0
# 2 70000.0 70000.0 70000.0使用众数填充分类数据
对于分类列,使用均值或中位数没有意义。此时应使用众数,即出现频率最高的值。Series.mode()[0] 会返回最常见的值([0] 用于处理存在多个众数的情况)。
import pandas as pd
import numpy as np
df = pd.DataFrame({
'status': ['active', 'inactive', None, 'active', None, 'active']
})
most_common = df['status'].mode()[0]
print('Mode:', most_common) # active
df['status'] = df['status'].fillna(most_common)
print(df['status'].tolist())
# ['active', 'inactive', 'active', 'active', 'active', 'active']使用 ffill() 向前填充
向前填充(也称为向前携带最后一次观测值,LOCF)会将最后一个有效(非 NaN)值向后传播,以填充后续的 NaN 位置。这非常适合时间序列数据,其中测量值会保持不变,直到发生更新——例如设备状态、价格水平,或只在特定事件发生时变化的传感器读数。
import pandas as pd
import numpy as np
price = pd.Series(
[100, np.nan, np.nan, 105, np.nan, 110],
index=pd.date_range('2024-01', periods=6, freq='ME')
)
filled = price.ffill()
print(filled)
# 2024-01-31 100.0
# 2024-02-29 100.0
# 2024-03-31 100.0
# 2024-04-30 105.0
# 2024-05-31 105.0
# 2024-06-30 110.0使用 bfill() 向后填充
向后填充(向后携带下一次观测值,NOCB)会将下一个有效值向前传播,以填充之前的 NaN 位置。当您知道未来数据可以补足过去的缺失值时,这种方法很有用——例如,收到月末数据后,需要回填报告到达前该月前几天的数据。
import pandas as pd
import numpy as np
df = pd.DataFrame({'value': [np.nan, np.nan, 3, np.nan, 5]})
print(df['value'].bfill())
# 0 3.0
# 1 3.0
# 2 3.0
# 3 5.0
# 4 5.0
# dtype: float64向前和向后填充的 limit 参数
ffill() 和 bfill() 都接受 limit 参数,用于限制连续填充的 NaN 值数量。当您只希望在短暂间隔内延续某个值时,这一点非常重要;较长的间隔应保留为 NaN,以表明数据确实缺失,而不只是延迟到达。
import pandas as pd
import numpy as np
s = pd.Series([1.0, np.nan, np.nan, np.nan, 5.0])
# Fill only the first NaN gap, leave the rest
print(s.ffill(limit=1))
# 0 1.0
# 1 1.0 <- filled
# 2 NaN <- still NaN (limit reached)
# 3 NaN
# 4 5.0对不同列采用不同的填充方式
在实际的 DataFrame 中,不同列可能需要不同的填充策略。向 fillna() 传入一个字典,其中键是列名,值是填充值。这样一次调用就能对各列分别进行插补,比连续多次单独调用 fillna 更清晰。
import pandas as pd
import numpy as np
df = pd.DataFrame({
'age': [25, np.nan, 30],
'income': [50000, np.nan, 70000],
'country': ['USA', np.nan, 'UK']
})
fill_values = {
'age': df['age'].median(),
'income': df['income'].mean(),
'country': 'Unknown'
}
filled = df.fillna(fill_values)
print(filled)
# age income country
# 0 25.0 50000.0 USA
# 1 27.5 60000.0 Unknown
# 2 30.0 70000.0 UK分组感知插补
一种更高级的策略是使用组均值或中位数填充 NaN,而不是使用整列均值。例如,可以使用相应职位类别的工资中位数来填充缺失的工资。这种方法能够保留子群体结构,比使用全局统计量得到更符合实际的插补结果。
import pandas as pd
import numpy as np
df = pd.DataFrame({
'dept': ['Eng', 'Eng', 'HR', 'HR', 'Eng'],
'salary': [90000, np.nan, 50000, np.nan, 110000]
})
# Fill salary NaN with the median salary for each department
df['salary'] = df.groupby('dept')['salary'].transform(
lambda x: x.fillna(x.median())
)
print(df)
# dept salary
# 0 Eng 90000.0
# 1 Eng 100000.0 <- group median (90k+110k)/2
# 2 HR 50000.0
# 3 HR 50000.0
# 4 Eng 110000.0使用常量哨兵值填充
有时,合适的插补值是用于表示“未知”的哨兵值,而不是真实测量值。例如,用 -1 表示未知年龄,用 'N/A' 表示未知类别,或用 False 表示未知的布尔标志。只有在后续代码会明确检查这些哨兵值,并将其与真实数据区别对待时,使用哨兵值才是合理的。
import pandas as pd
import numpy as np
df = pd.DataFrame({
'user_id': [1, 2, 3],
'referral_source': ['email', np.nan, 'ad'],
'trial_days': [14, np.nan, 7]
})
df['referral_source'] = df['referral_source'].fillna('unknown')
df['trial_days'] = df['trial_days'].fillna(-1).astype(int)
print(df)
# user_id referral_source trial_days
# 0 1 email 14
# 1 2 unknown -1
# 2 3 ad 7在管道中串联 fillna()
与所有 Pandas 方法一样,fillna() 会返回一个新的 DataFrame,并且可以很好地融入方法链。在 dropna() 后调用 .fillna() 可以应用两步策略:先删除缺少关键列的行,再用合理的默认值填充剩余的可选 NaN 值——整个过程都在一个易读的管道中完成。
import pandas as pd
import numpy as np
df = pd.DataFrame({
'user_id': [1, None, 3, 4],
'score': [88, 95, np.nan, 76],
'label': ['A', 'B', None, 'D']
})
cleaned = (
df
.dropna(subset=['user_id'])
.fillna({'score': df['score'].mean(), 'label': 'Unknown'})
)
print(cleaned)
# user_id score label
# 0 1.0 88.0 A
# 2 3.0 86.3 Unknown
# 3 4.0 76.0 D验证不再存在 NaN
完成插补后,请始终验证目标列中是否还存在 NaN 值。可以调用 df.isna().sum(),或断言计数为零。意外的非零计数表示 fillna 遗漏了某种情况——可能是某列的数据类型阻止了填充,也可能是您忘记在字典中加入某一列。
import pandas as pd
import numpy as np
df = pd.DataFrame({'a': [1.0, np.nan, 3.0], 'b': [np.nan, 2.0, 3.0]})
filled = df.fillna(0)
# Verify
assert filled.isna().sum().sum() == 0, 'Some NaN remain!'
print('All NaN filled successfully')
print(filled.isna().sum())
# a 0
# b 0
# dtype: int64快速检查
检验您对 Pandas 中填充缺失值的理解。
课程回顾
本课您学到了:fillna(scalar) 会用常量替换所有 NaN,fillna(mean/median) 会使用列统计量进行插补,而 ffill()/bfill() 会为时间序列传播相邻值。向 fillna() 传入字典可以为不同列指定不同策略,使用 groupby().transform() 可以进行分组感知插补。接下来,我们将介绍插值,以及何时应选择高级插补技术。
用 AI 导师学习 Python — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 30
- 课程
- 120
常见问题解答
「填充缺失值」课时是免费的吗?
是的 — 「填充缺失值」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Pandas & NumPy Academy 课程的其余内容,请升级到 CoddyKit PRO。 Pandas & NumPy Academy 课程共包含 4 节课。
「填充缺失值」这节课中我会学到什么?
使用 fillna() 及其 method 参数,将 NaN 替换为常量、列均值,或使用向前填充、向后填充。 你通过在浏览器中直接运行的动手代码来练习 Pandas & NumPy Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Pandas & NumPy Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Pandas & NumPy Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「填充缺失值」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Pandas & NumPy Academy 课中编写并运行代码吗?
能。每节 Pandas & NumPy Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 检测缺失值
- 删除缺失值
- 填充缺失值
- 插值与高级缺失值填补