在数据分析和建模的过程中,大量的时间花在数据准备上:加载、清理、转换和重新排列。这样的工作占了分析师80%以上的时间。
本章内容主要讲解pandas中用于缺失值、重复值、字符串操作和其他分析数据转换的工具。
1. 处理缺失值
pandas对象的所有描述性统计信息默认情况下是排除缺失值的。对于数值型数据,pandas使用浮点值NaN来表示缺失值,所以NaN是容易检测到的标识值。
1.1 过滤缺失值
a. 在Series上使用dropna,可以返回Series中素有的非空数据及其索引值:
data = pd.Series([1, np.nan, 3.5, np.nan, 7])
data
0 1.0
1 NaN
2 3.5
3 NaN
4 7.0
dtype: float64
cleaned = data.dropna() # 原数组不发生改变, 与data.notnull()等价
cleaned
0 1.0
2 3.5
4 7.0
dtype: float64
b. 对与DataFrame来说有一些选项可以操作:
from numpy import nan as NA # 使用NA来代替np.nan
data = pd.DataFrame([[1., 6.5, 3.], [1., NA, NA], [NA, NA, NA], [NA, 6.5, 3.]])
data
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
data.dropna() # 参数默认的情况下删除包含缺失值的所有行
0 1 2
0 1.0 6.5 3.0
data.dropna(how='all') # 仅删除所有值都是NA的行
0 1 2
0 1.0 6.5 3.0
1 1.0 NaN NaN
3 NaN 6.5 3.0
data[4] = NA
data
0 1 2 4
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(axis=1, how='all') # 指定轴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
df = pd.DataFrame(np.random.randn(7, 3))
df.iloc[:4, 1] = NA
df.iloc[:2, 2] = NA
df
0 1 2
0 -0.049375 NaN NaN
1 -0.557540 NaN NaN
2 -0.079590 NaN 1.016858
3 0.035582 NaN 0.562665
4 1.023047 0.485505 -0.086212
5 0.315884 -1.314378 0.916748
6 0.479718 -0.704622 -1.252934
df.dropna(thresh=2) # 保留至少有2个非空值数据的行
0 1 2
2 -0.079590 NaN 1.016858
3 0.035582 NaN 0.562665
4 1.023047 0.485505 -0.086212
5 0.315884 -1.314378 0.916748
6 0.479718 -0.704622 -1.252934
1.2 补全缺失值
除了将缺失值直接过滤掉,还可以通过fillna方法来补全。
a. 使用常数来替代缺失值:
df
0 1 2
0 -0.049375 NaN NaN
1 -0.557540 NaN NaN
2 -0.079590 NaN 1.016858
3 0.035582 NaN 0.562665
4 1.023047 0.485505 -0.086212
5 0.315884 -1.314378 0.916748
6 0.479718 -0.704622 -1.252934
df.fillna(0) # 原数据未改变
0 1 2
0 -0.049375 0.000000 0.000000
1 -0.557540 0.000000 0.000000
2 -0.079590 0.000000 1.016858
3 0.035582 0.000000 0.562665
4 1.023047 0.485505 -0.086212
5 0.315884 -1.314378 0.916748
6 0.479718 -0.704622 -1.252934
b. 可以为不同列设定不同的填充值:
df.fillna({
1: 0.5, 2: 0})
0 1 2
0 -0.049375 0.500000 0.000000
1 -0.557540 0.500000 0.000000
2 -0.079590 0.500000 1.016858
3 0.035582 0.500000 0.562665
4 1.023047 0.485505 -0.086212
5 0.315884 -1.314378 0.916748
6 0.479718 -0.704622 -1.252934
c. fillna返回的是一个新对象,原对象不变,也可以修改已经存在的对象:
df.fillna(0, inplace=True) # 修改原数据
d. 支持插值法填充
df = pd.DataFrame(np.random.randn(6, 3))
df.iloc[2:, 1] = NA
df.iloc[4:, 2] = NA
df
0 1 2
0 0.951068 0.878024 0.837684
1 0.231418 -1.218248 -0.986771
2 1.115496 NaN 0.536248
3 -1.295515 NaN -1.474961
4 0.101957 NaN NaN
5 -2.015696 NaN NaN
df.fillna(method='ffill') # 向前填充,bfill向后填充
0 1 2
0 0.951068 0.878024 0.837684
1 0.231418 -1.218248 -0.986771
2 1.115496 -1.218248 0.536248
3 -1.295515 -1.218248 -1.474961
4 0.101957 -1.218248 -1.474961
5 -2.015696 -1.218248 -1.474961
df.fillna(method='ffill', limit=2) # 向前填充两个数据
0 1 2
0 0.951068 0.878024 0.837684
1 0.231418 -1.218248 -0.986771
2 1.115496 -1.218248 0.536248
3 -1.295515 -1.218248 -1.474961
4 0.101957 NaN -1.474961
5 -2.015696 NaN -1.474961
e. 还可以使用统计学数据来填充,如平均值/中位数等:
data = pd.Series([1., NA, 3.5, NA, 7])
data
0 1.0
1 NaN
2 3.5
3 NaN
4 7.0
dtype: float64
data.fillna(data.mean())
0 1.000000
1 3.833333
2 3.500000
3 3.833333
4 7.000000
dtype: float64
2. 数据转换
2.1 删除重复值
a. DataFrame 的duplicated方法返回的是一个布尔值Series,反映每一行是否存在与之前出现过的行相同的情况:
data = pd.DataFrame({
'k1': ['one', 'two'] * 3 + ['two'],
'k2': [1, 1, 2, 3, 3, 4, 4]})
data
k1 k2
0 one 1
1 two 1
2 one 2
3 two 3
4 one 3
5 two 4
6 two 4
data.duplicated()
0 False
1 False
2 False
3 False
4 False
5 False
6 True
dtype: bool
b. drop_duplicates 返回的是DataFrame,内容是duplicated返回数组中为False的部分,即删除了重复行
data.drop_duplicates() # 去除重复行
k1 k2
0 one 1
1 two 1
2 one 2
3 two 3
4 one 3
5 two 4
c. 可以基于特定的列去删除数据:
data['v1'] = range(7)
data
k1 k2 v1
0 one 1