深入浅出Pandas读书笔记
C10 Pandas数据清洗
10.1 缺失值的认定
10.1.1 缺失值类型
一般使用NaN代表缺失值, 可以使用Numpy定义为np.nan或np.NaN. 在Pandas 1.0以后的版本中, 实验性的使用标量pd.NA来代表
df = pd.DataFrame({
'A': ['a1', 'a1', 'a2', 'a2'],
'B': ['b1', 'b2', None, 'b2'],
'C': [1, 2, 3, 4],
'D': [5, 6, None, 8],
'E': [5, None, 7, 8]
})
# 可以将无穷值设置为缺失值
pd.options.mode.use_inf_as_na = True
10.1.2 缺失值判断
df.isna()及其别名df.isnull(), df.notna()
df.isna()
df.D.isna()
df.notna()
df.D.notna()
10.1.3 缺失值统计
利用sum, 将False当做0, 将True当做1
pd.Series([True, True, False]).sum()
# 每列有多少个缺失值
df.isnull().sum() # 每行 df.isnull().sum(1)
# 总共多少个缺失值
df.isnull().sum().sum()
10.1.4 缺失值筛选
# 筛选有缺失值的行
df[df.isnull().any(1)]
# 有缺失值的列
df.loc[:, df.isnull().any(0)]
10.1.5 NA标量
pd.NA 它代表空整数, 空布尔, 空字符. pd.NA的目标是提供一个缺失值的指示器, 该提示器可以在各种数中一致使用(而不是np.nan, None, 或者pd.NaT, 具体取决于数据类型)
s = pd.Series([1, 2, None, 4], dtype='Int64')
s[2] is pd.NA # True
10.1.6 时间数据中的缺失值
Pandas提供了一个NaT来表示, 并且NaT和NaN是兼容的
# None 根据整体的数据类型, 自动推断为NaT
pd.Series([pd.Timestamp('20200101'), None, pd.Timestamp('20200103')])
10.1.7 整型数据中的缺失值
pd.Series([1, 2, np.nan, 4], dtype='Int64')
10.1.8 插入缺失值
10.2 缺失值的操作
10.2.1 缺失值的填充 df.fillna()
df.fillna(0)
df.fillna('missing')
df.one.fillna('暂无')
df.fillna(0, limit=1) # 只替换1个
# 将不同列的缺失值替换为不同的值
values = {'A': 0, 'B': 1, 'C': 2, 'D': 3}
df.fillna(value=values)
- pad / ffill 向前填充, 使用前一个有效值填充, df.fillna(method=‘ffill’)可以简写为df.ffill()
- bfill / backfill 向后填充, 使用后一个有效值填充, df.fillna(method=‘fill’)可以简写为df.bfill()
df.fillna(method='bfill')
df.fillna(method='ffill')
# 填充列的平均值
df.fillna(df.mean())
# 将指定列的空值替换为指定值
df.replace({'toy': {np.nan: 100}})
10.2.2 插值填充 interpolate线性插值
插值interpolate是离散函数拟合的重要方法, 利用它可以根据函数在有限个点处的取值状况, 估算出函数在其他点处的近似值. Series和DataFrame对象都有interpolate()方法, 默认情况下, 该方法在缺失值处执行线性插值.它利用数学方法来估计缺失值, 对于较大的数据非常有用.
s = pd.Series([0, 1, np.nan, 3])
s.interpolate()
'''
0 0.0
1 1.0
2 2.0
3 3.0
dtype: float64
'''
10.2.3 缺失值删除 df.dropna()
df # 原数据
'''
A B C D E
0 a1 b1 1 5.0 5.0
1 a1 b2 2 6.0 NaN
2 a2 None 3 NaN 7.0
3 a2 b2 4 8.0 8.0
'''
# 删除有缺失值的行
df.dropna()
'''
A B C D E
0 a1 b1 1 5.0 5.0
3 a2 b2 4 8.0 8.0
'''
# 删除有缺失值的列
df.dropna(axis=1)
'''
A C
0 a1 1
1 a1 2
2 a2 3
3 a2 4
'''
# 删除所有值都缺失的行
df.dropna(how='all')
# 删除至少有2个缺失值的行
df.dropna(thresh=2)
# 指定判断缺失值的列范围
df.dropna(subset=['name', 'born'])
# 指定列的缺失值删除
df.col.dropna()
10.2.4 缺失值参与计算
加法会忽略缺失值, 或者将其按0处理
cumsum()和cumprod()会忽略NA值, 但值会保留在序列中, 可以使用skipna=False跳过有缺失值的计算并返回缺失值
df.count()在统计时, 缺失值不计数
缺失值在做聚合分组操作时, 如果聚合分组的列里有空值, 则会自动忽略这些值. 如果需要计入有空值的分组, 使用dropna=False
10.3 数据替换 replace
10.3.1 指定值替换
s = pd.Series([0, 1, 2, 3, 4,])
s.replace(0, 5)
# 一一对应进行替换
s.replace([0, 1, 2, 3, 4], [4, 3, 2, 1, 0])
# 用字典映射对应替换值
s.replace({0: 10, 1: 100})
# 将a的0, b的5替换为100
df.replace({'a': 0, 'b': 5}, 100)
# 指定a里面的替换规则
df.replace({'a': {0: 100, 4: 400}})
10.3.2 使用替换方式
# 将1, 2, 3替换为他们前一个值
s.replace([1, 2, 3], method='ffill')
s.replace([1, 2, 3], method='bfill') # 替换为后一个值
如果指定的要替换的值不存在, 则不起作用, 也不会报错, 以上的替换也适用于字符类型数据
10.3.3 字符替换 df.replace()正则
# 利用正则表达式将ba开头的值替换为new
df.replace(to_replace=r'^ba.$', value='new', regex=True)
# 如果多列规则不一, 可以按以下格式对应传入
df.replace({'A': r'1$', 'B': r'2$'}, {'A': 'new', 'B': 'new2'}, regex=True)
# 多个规则均替换为同样的值
df.replace(regex=[r'^ba.$', 'foo'], value='new')
# 多个规则及对应的替换内容
df.replace(regex={r'^ba.$': 'new', 'foo': 'xyz'})
10.3.4 缺失值替换
列如我们可以先将无效的值替换为nan, 再进行缺失值处理
d = {'a': list(range(4)),
'b': list('ab..'),
'c': ['a', 'b', np.nan, 'd']
}
df = pd.DataFrame(d)
# 将.替换为NaN
df.replace('.', np.nan)
# 对应替换, a换b, 点换NaN
df.replace(['a', '.'], ['b', np.nan])
# a后面加上stuff
df.replace([r'\.', r'(a)'], ['dot', r'\1stuff'], regex=True)
# b中的点替换为np.nan
df.replace({'b': '.'}, {'b': np.nan})
# b列的b替换为空
df.replace({'b': {'b': ''}})
10.3.5 数字替换
# 生成数据
df = pd.DataFrame(np.random.rand(10, 2))
df[np.random.rand(df.shape[0]) > 0.5] = 1.5 # 将某些数字改成1.5
df.replace(1.5, np.nan) # 将1.5 修改为np.nan
df.replace([1.5, df.iloc[0, 0]], [np.nan, 'a']) # 将1.5改成NaN, 将左上角改成'a'
10.3.6 数据修剪
对于数据中存在的极端值, 过大或者过小, 可以使用df.clip(lower, upper)来修剪, 当数据大于upper时使用upper的值, 小于lower使用lower的值, 与numpy.clip方法一样
df = pd.DataFrame({'a': [-1, 2, 5], 'b': [6, 1, -3]})
df.clip(0, 3)
10.4 重复值及删除数据
10.4.1 重复值识别 df.duplicated()
df.duplicated(subset=None, keep='first')
它可以返回表示重复行的布尔值序列, 默认为一行的所有内容, subset可以指定列, keep参数用来确定要标记的重复值
- first
- last
- False
df = pd.DataFrame({'A': ['x', 'x', 'z'], 'B': ['x', 'x', 'x'], 'C': [1, 1, 2]})
df
'''
A B C
0 x x 1
1 x x 1
2 z x 2
'''
# 全行检测, 除第一次出现的外, 重复的为True
df.duplicated()
'''
0 False
1 True
2 False
dtype: bool
'''
# 除最后一次出现的外, 重复的True
df.duplicated(keep='last')
'''
0 True
1 False
2 False
dtype: bool
'''
# 所有重复的都为True
df.duplicated(keep=False)
'''
0 True
1 True
2 False
dtype: bool
'''
# 指定列检测
df.duplicated(subset=['B'], keep=False)
'''
0 True
1 True
2 True
dtype: bool
'''
10.4.2 删除重复值 df.drop_duplicates()
df.drop_duplicates(subset=None, keep='first', inplace=False, ignore_index=False)
参数说明
- subset 指定的标签或标签序列, 仅删除这些列重复值, 默认情况为所有列
- keep
- first 保留一地刺出现的重复值
- last 最后
- False 删除所有重复值
- inplace
- ignore_index 处理后, 重新分配自然索引
10.4.3 删除数据 df.drop()
df.drop()通过指定标签名称和相应的轴, 或直接给定索引或列名称来删除行或列, 使用多层索引时, 可以通过指定级别来删除不同级别上的标签
df.drop(labels=None, axis=0, index=None, columns=None, level=None, inplace=False, errors='raise')
参数说明
- labels 要删除的列或者行, 如果要删除多个, 传入列表
- axis
- index
- column
- level 索引层级, 将删除此层级
- inplace
- errors ignore或者raise, 默认raise, 如果为ignore, 则容忍错误, 仅删除现有标签
df.drop([0, 1])
'''
A B C
2 z x 2
'''
df.drop(['B', 'C'], axis=1)
df.drop(columns=['B', 'C']) # 同上
10.5 NumPy格式转换
10.5.1 转换方法
- ds.to_numpy() 可以用在Index, Series和DataFrame对象
- s.array 为PandasArray, 用在Index和Series
不在推荐使用pandas的values和as_matrix()
10.5.2 DataFrame转为ndarray
df.values和df.to_numpy()返回的是一个array类型
df.values # 不推荐
df.to_numpy() # 结果同上
type(df.to_numpy()) # numpy.ndarray
# 转换指定的列
df[['name', 'Q1']].to_numpy()
10.5.3 Series转为ndarray
s.values和s.to_numpy()返回的是一个array类型
10.5.4 df.to_records()
10.5.5 np.array
可以用np.array直接读取DataFrame或者Series数据, 最终也会转换为array类型