这章重点了
在数据分析和建模的过程中,相当多的时间要用在数据准备上:加载、清理、转换以及重塑。这些⼯作会占到分析师时间的80%或更多。
本章讨论处理缺失数据、重复数据、字符串操作和其它分析数据转换的工具。
7.1 处理缺失数据
在许多数据分析工作中,缺失数据是经常发生的。pandas的目标之一就是尽量轻松地处理缺失数据。
下表列出了⼀些关于缺失数据处理的函数。
1.滤除缺失数据
过滤掉缺失数据的办法有很多种。你可以通过pandas.isnull或布尔索引的手工⽅法,但dropna可能会更实用⼀些。对于⼀个Series,dropna返回⼀个仅含非空数据和索引值的Series
from numpy import nan as NA
data=pd.Series([1,NA,3.5,NA,7])
data.dropna()
#等价data[data.notnull()]
#输出
"""
0 1.0
2 3.5
4 7.0
dtype: float64
"""
对于DataFrame对象,事情就有点复杂了。你可能希望丢弃全NA或含有NA的行或列。dropna默认丢弃任何含有缺失值的行
data=pd.DataFrame([[1.,6.5,3.],[1.,NA,NA],
[NA,NA,NA],[NA,6.5,3.]])
cleaned=data.dropna()
cleaned
#输出
0 1 2
0 1.0 6.5 3.0
2.填充缺失数据
你可能不想滤除缺失数据(有可能会丢弃跟它有关的其他数据),而是希望通过其他方式填补那些“空洞”。对于大多数情况而言,fillna方法是最主要的函数。
data=pd.DataFrame([[1.,6.5,3.],[1.,NA,NA],
[NA,NA,NA],[NA,6.5,3.]])
cleaned=data.fillna(0)#用0替换NA
cleaned
#输出
0 1 2
0 1.0 6.5 3.0
1 1.0 0.0 0.0
2 0.0 0.0 0.0
3 0.0 6.5 3.0
若是通过⼀个字典调用fillna,就可以实现对不同的列填充不同的值:
cleaned=data.fillna({0:0.5,1:10})#字典
#输出
0 1 2
0 1.0 6.5 3.0
1 1.0 10.0 NaN
2 0.5 10.0 NaN
3 0.5 6.5 3.0
也可赋值data的中位数data.mean()等等等等
7.2 数据转换
1.移除重复数据
DataFrame的duplicated方法返回⼀个布尔型Series,表示各行是否是重复行(前⾯出现过的行)drop_duplicated
2.利用函数或映射进行数据转换
Series使用map是⼀种实现元素级转换以及其他数据清理工作的便捷方式。
3.替换值
利用fillna方法填充缺失数据可以看做值替换的⼀种特殊情况。前⾯已经看到,map可用于修改对象的数据子集,而replace则提供了⼀种实现该功能的更简单、更灵活的方式。
4.重命名轴索引
轴索引也有⼀个map方法
创建数据集的转换版(而不是修改原始数据),比较实用的方法是rename,data.rename()
5.离散化和面元划分
为了便于分析,连续数据常常被离散化或拆分为“面元”(bin),pandas的cut函数, pd.cut(data1,data2,right=True)
#把年龄归类到不同的年龄段,“18到25”、“26到35”、“35到60”以及“60以上”⼏个⾯元
import pandas as pd
ages=[20,22,25,27,21,23,37,31,61,45,41,63]
bins=[18,25,35,60,100]
cats=pd.cut(ages,bins)
cats
#
[(18, 25], (18, 25], (18, 25], (25, 35], (18, 25],
..., (25, 35], (60, 100], (35, 60], (35, 60], (60, 100]]
Length: 12
Categories (4, interval[int64, right]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]
聚合和分组运算时会用到cut和qcut。
6.检测和过滤异常值
过滤或变换异常值(outlier)在很大程度上就是**运用数组运算。**
import pandas as pd
import random
data=pd.DataFrame(np.random.randn(100,4)) #符合正态分布的100行4列的矩阵
col=data[2]
col[np.abs(col)>2] #第三列绝对值大于2的值
#数组运算结果
18 2.792078
47 2.641366
77 -2.423284
92 -2.002038
Name: 2, dtype: float64
7.排列和随机采样
利用numpy.random.permutation函数可以轻松实现对Series或DataFrame的列的排列工作(permuting,随机重排序),得到一个随机重排序的新数组,然后就可以在基于iloc的索引操作或take函数中使用该数组
df=pd.DataFrame(np.arange(5*4).reshape(5,4))
arr=np.random.permutation(5) #输出0-4数的随机重排序,作为下面take函数的索引
arr1=df.take(arr) #dataframe.take(indices, axis=None, out=None, mode='raise')用法,返回一个由给定索引处的元素组成的数组
arr1
#输出
0 1 2 3
4 16 17 18 19
2 8 9 10 11
1 4 5 6 7
0 0 1 2 3
3 12 13 14 15
8.计算指标/哑变量
- List item
7.3 字符串操作
对于许多字符串处理和脚本应用,内置的字符串方法已经能够满足要求了。
详看下表
以逗号分隔的字符串可以用split拆分成数段; split常常与strip⼀起使用,以去除空白符(包括换行符);
加号可以连接字符串,但并不是很实用。⼀种更快更符合Python风格的方式是,向字符串"::“的join方法传入⼀个列表或元组,”::".join([]);
关注的是子串定位。检测子串的最佳方式是利用Python的in关键字,还可以使用index和find;
count可以返回指定子串的出现次数;x.count()
replace用于将指定模式替换为另⼀个模式。通过传入空字符串,它也常常用于删除模式;
casefold 将字符转换为小写,
1.正则表达式
正则表达式提供了一种灵活的在文本中搜索或匹配字符串模式的方式。
Python内置的re模块负责对字符串应用正则表达式。re模块的函数可以分为三个大类:模式匹配、替换以及拆分。
如果打算对许多字符串应⽤同⼀条正则表达式,强烈建议通过re.compile创建regex对象。这样将可以节省大量的CPU时间。
- List item
2.pandas的矢量化字符串函数
清理待分析的散乱数据时,常常需要做⼀些字符串规整化工作。更为复杂的情况是,含有字符串的列有时还含有缺失数据.。Series有⼀些能够跳过NA值的面向数组方法,进行字符串操作。通过Series的str属性即可访问这些方法。
import pandas as pd
import numpy as np
data={'Dave':'dave@google.com',
'Steve':'steve@gmail.com',
'Rob':'rob@gmail.com',
'Wes':np.nan}
data=pd.Series(data)
matches=data.str.contains('gmail') #Series的str属性
matches
#输出
Dave False
Steve True
Rob True
Wes NaN
dtype: object
有两个办法可以实现矢量化的元素获取操作:要么使用str.get,要么在str属性上使用索引:
matches=data.str.get(1) #获取第2个字符
matches
#输出
Dave a
Steve t
Rob o
Wes NaN
dtype: object
下表介绍了更多的pandas字符串方法。