利用Python进行数据分析:缺失数据
最近在做一个数据分析类项目,涉及处理7万+名学生的全学程数据,数据以表格型结构化数据为主,涉及学生基本信息、成绩和课程信息、评奖评优、勤工助学及行为数据。借此机会,对项目中频繁使用的基于DataFrame 的Python 数据分析语句进行梳理。此篇主要针对缺失值的处理、过滤及填补方法。
import pandas as pd
import numpy as np
以下为pandas中一些关于缺失数据处理的函数。
方法 | 说明 |
---|
dropna | 根据各标签的值中是否存在缺失数据对轴标签进行过滤,可通过阈值调节对缺失值的容忍度 |
fillna | 用指定值或插值方法(如ffill或bfill填充缺失数据) |
isnull | 返回一个含有布尔值的对象,这些布尔值表示哪些值是缺失值/NA,该对象的类型与源类型一样 |
notnull | isnull的否定式 |
from numpy import nan as NA
data = pd.DataFrame([[1., 6.5, 3.,NA], [1., NA, NA,NA],
[NA, NA, NA,NA], [NA, 6.5, 3.,NA]])
data
| 0 | 1 | 2 | 3 |
---|
0 | 1.0 | 6.5 | 3.0 | NaN |
---|
1 | 1.0 | NaN | NaN | NaN |
---|
2 | NaN | NaN | NaN | NaN |
---|
3 | NaN | 6.5 | 3.0 | NaN |
---|
滤除缺失数据
查找缺失数据:
data.isnull()
| 0 | 1 | 2 | 3 |
---|
0 | False | False | False | True |
---|
1 | False | True | True | True |
---|
2 | True | True | True | True |
---|
3 | True | False | False | True |
---|
可以逐列统计数据缺失情况:
for col in data.columns:
print(f'{col}:{len(data[data[col].isnull()])/len(data)}')
0:0.5
1:0.5
2:0.5
3:1.0
滤除缺失数据,dropna
默认丢弃任何含有缺失值的行:
data.dropna()
传入how='all’将只丢弃全为NA的那些行:
data.dropna(how='all')
| 0 | 1 | 2 | 3 |
---|
0 | 1.0 | 6.5 | 3.0 | NaN |
---|
1 | 1.0 | NaN | NaN | NaN |
---|
3 | NaN | 6.5 | 3.0 | NaN |
---|
用这种方式丢弃列,只需传入axis=1
即可:
data.dropna(how='all',axis=1)
| 0 | 1 | 2 |
---|
0 | 1.0 | 6.5 | 3.0 |
---|
1 | 1.0 | NaN | NaN |
---|
2 | NaN | NaN | NaN |
---|
3 | NaN | 6.5 | 3.0 |
---|
可以通过thresh
参数控制保留至少几个非缺失值,这种在处理涉及时间序列类数据时会用到,用于留下部分观测数据以保留基本数据趋势。
data.dropna(thresh=1)
| 0 | 1 | 2 | 3 |
---|
0 | 1.0 | 6.5 | 3.0 | NaN |
---|
1 | 1.0 | NaN | NaN | NaN |
---|
3 | NaN | 6.5 | 3.0 | NaN |
---|
data.dropna(thresh=2)
| 0 | 1 | 2 | 3 |
---|
0 | 1.0 | 6.5 | 3.0 | NaN |
---|
3 | NaN | 6.5 | 3.0 | NaN |
---|
通过inplace=True
直接改变原数据:
data
| 0 | 1 | 2 | 3 |
---|
0 | 1.0 | 6.5 | 3.0 | NaN |
---|
1 | 1.0 | NaN | NaN | NaN |
---|
2 | NaN | NaN | NaN | NaN |
---|
3 | NaN | 6.5 | 3.0 | NaN |
---|
data.dropna(thresh=2,inplace = True)
data
| 0 | 1 | 2 | 3 |
---|
0 | 1.0 | 6.5 | 3.0 | NaN |
---|
3 | NaN | 6.5 | 3.0 | NaN |
---|
填充缺失数据
df = pd.DataFrame(np.random.randn(7, 3))
df.iloc[:4,1] = NA
df.iloc[:2,2] = NA
df
| 0 | 1 | 2 |
---|
0 | -0.393415 | NaN | NaN |
---|
1 | -0.174198 | NaN | NaN |
---|
2 | -0.877172 | NaN | -1.278562 |
---|
3 | -0.499985 | NaN | -0.096270 |
---|
4 | 1.195530 | 0.428747 | 0.230859 |
---|
5 | 0.346750 | 0.020427 | -0.676320 |
---|
6 | 1.701942 | -0.100233 | 0.674782 |
---|
统一将缺失值填充为0:
df.fillna(0)
| 0 | 1 | 2 |
---|
0 | -0.393415 | 0.000000 | 0.000000 |
---|
1 | -0.174198 | 0.000000 | 0.000000 |
---|
2 | -0.877172 | 0.000000 | -1.278562 |
---|
3 | -0.499985 | 0.000000 | -0.096270 |
---|
4 | 1.195530 | 0.428747 | 0.230859 |
---|
5 | 0.346750 | 0.020427 | -0.676320 |
---|
6 | 1.701942 | -0.100233 | 0.674782 |
---|
通过字典调用fillna,实现对不同列填充不同的值:
df.fillna({1:0.5,2:0})
| 0 | 1 | 2 |
---|
0 | -0.393415 | 0.500000 | 0.000000 |
---|
1 | -0.174198 | 0.500000 | 0.000000 |
---|
2 | -0.877172 | 0.500000 | -1.278562 |
---|
3 | -0.499985 | 0.500000 | -0.096270 |
---|
4 | 1.195530 | 0.428747 | 0.230859 |
---|
5 | 0.346750 | 0.020427 | -0.676320 |
---|
6 | 1.701942 | -0.100233 | 0.674782 |
---|
使用插值方法进行缺失值填充:
df.fillna(method='bfill')
| 0 | 1 | 2 |
---|
0 | -0.393415 | 0.428747 | -1.278562 |
---|
1 | -0.174198 | 0.428747 | -1.278562 |
---|
2 | -0.877172 | 0.428747 | -1.278562 |
---|
3 | -0.499985 | 0.428747 | -0.096270 |
---|
4 | 1.195530 | 0.428747 | 0.230859 |
---|
5 | 0.346750 | 0.020427 | -0.676320 |
---|
6 | 1.701942 | -0.100233 | 0.674782 |
---|
df.fillna(method='bfill', limit=2)
| 0 | 1 | 2 |
---|
0 | -0.393415 | NaN | -1.278562 |
---|
1 | -0.174198 | NaN | -1.278562 |
---|
2 | -0.877172 | 0.428747 | -1.278562 |
---|
3 | -0.499985 | 0.428747 | -0.096270 |
---|
4 | 1.195530 | 0.428747 | 0.230859 |
---|
5 | 0.346750 | 0.020427 | -0.676320 |
---|
6 | 1.701942 | -0.100233 | 0.674782 |
---|
只要有些创新,你就可以利用fillna实现许多别的功能。比如说,使用均值进行缺失值填充,也可以传入最小值、中位数:
df.fillna(df.mean(axis=0))
| 0 | 1 | 2 |
---|
0 | -0.393415 | 0.116314 | -0.229102 |
---|
1 | -0.174198 | 0.116314 | -0.229102 |
---|
2 | -0.877172 | 0.116314 | -1.278562 |
---|
3 | -0.499985 | 0.116314 | -0.096270 |
---|
4 | 1.195530 | 0.428747 | 0.230859 |
---|
5 | 0.346750 | 0.020427 | -0.676320 |
---|
6 | 1.701942 | -0.100233 | 0.674782 |
---|
又比如,使用其他列的值对某列的缺失值进行填充:
df[2].fillna(df[0])
0 -0.393415
1 -0.174198
2 -1.278562
3 -0.096270
4 0.230859
5 -0.676320
6 0.674782
Name: 2, dtype: float64
fillna默认会返回新对象,但也可以对现有对象进行就地修改:
df.fillna(0, inplace = True)
df
| 0 | 1 | 2 |
---|
0 | -0.393415 | 0.000000 | 0.000000 |
---|
1 | -0.174198 | 0.000000 | 0.000000 |
---|
2 | -0.877172 | 0.000000 | -1.278562 |
---|
3 | -0.499985 | 0.000000 | -0.096270 |
---|
4 | 1.195530 | 0.428747 | 0.230859 |
---|
5 | 0.346750 | 0.020427 | -0.676320 |
---|
6 | 1.701942 | -0.100233 | 0.674782 |
---|