合并数据集
pandas对象中的数据可以通过一些内置的方式进行合并:
pandas.merge根据一个或多个键将不同DataFrame的行连接起来;
它实现数据库的连接操作
pandas.concat可以沿着一条轴将多个对象堆叠在一起
实例方法combine_first可以将重复数据编接在一起,用一个对象中的值填充另一个对象中的缺失值
数据库风格的DataFrame合并
pd.merge(df1, df2, on='key') #这里是列名相同,指定'key'列当做键的内连接(对键取交集)
当两个列名不同时,需要分别指定:
pd.merge(df3, df4, left_on='key1', right_on='key2')
如果是左连接\右连接\外连接(取并集),也需要分别指定
how = 'left'\'right'\'outer'
要根据多个键进行合并,传入一个由列名组成的列表即可
on=['key1', 'key2']
警告:在进行列-列连接时,DataFrame对象中的索引会被丢弃
对重复列名的处理(如何重命名轴标签)
merge有一个suffixes选项,可以指定附加到左右连个DataFrame对象的重叠列名的字符串
suffixes =('_left', '_right') #这里就是分别添加字符串到重叠列名后面,可自定义(默认为_x, _y)
表7-1: merge函数的参数
索引上的合并
若连接键位于索引中,可以传入left_index=True\right_index=True
pd.merge(df1, df2, left_on='key', right_index=True)
对于层次化索引的数据,必须以列表的形式指明用作合并键的多个列(注意对重复索引值的处理)
pd.merge(lefth,righth,left_on=['key1','key2'],right_index=True)
DataFrame的join实例方法,能更为方便的实现按索引合并
left2.join(right2, how='outer')
对于简单的索引合并,还可以向join传入一组DataFrame(后面会介绍更为通用的concat函数)
left2.join([right2,another],how='outer')
轴向连接
另一种数据合并运算被称作连接(concatenation)\绑定(binding)或堆叠(stacking).
NumPy有一个用于合并原始NumPy数组的concatenation函数
np.concatenate([arr,arr],axis=1) #如果没有axis=1,会从上往下拼接\否则从左到右拼接
对于pandas对象,需要考虑:
1. 如果各对象其他轴上的索引不同,那些轴应该是做并集还是交集
2. 结果对象中的分组需要各不相同吗
3. 用于连接的轴重要吗
对于Series:
pd.concat([s1,s2,s3]) #默认是在axis=0上工作,产生新的Series(从上往下拼接);
如果传入axis=1,结果变成一个DataFrame;
默认是外连接,传入join='inner'可得到交集(内连接)
pd.concat([s1,s4],axis=1,join='inner')
可以通过join_axes指定要在其他轴上使用的索引
pd.concat([s1,s4],axis=1,join_axes=[['a','c','b','e']])
如果想创建层次化索引,将参与连接的片段在结果中区分开,使用keys参数
result=pd.concat([s1,s1,s3],keys=['one','two','three'])
同样的逻辑对于DataFrame对象也是一样
pd.concat([df1,df2],axis=1,keys=['level1','level2'])
pd.concat({'level1':df1,'level2':df2},axis=1) #这两个表达式效果是一样的
可以传入ignore_index=True,不保留连接轴上的索引,产生一组新索引range(total_length)
表7-2: concat函数的参数
合并重叠数据
np.where(pd.isnull(a),b,a) #NumPy的where函数,pd.isnull(a)表示判断条件,若为True,返回b\False则返回a
Series的combine_first方法实现同样功能
b.combine_first(a) #可以对a\b进行切片;这里表示若b不为空返回b,否则返回a
对于DataFrame,combine_first也是做同样的事情,可以看做用参数对象(a)中的数据为调用者对象(b)的缺失数据'打补丁'
df1.combine_first(df2)
重塑和轴向旋转
有许多用于重新排列表格型数据的基础运算,这些函数成为重塑(reshape)或轴向旋转(pivot)运算
重塑层次化索引
层次化索引为DataFrame数据的重排提供一种良好的一致性方式
1. stack: 将数据的列'转换'为行
2. unstack: 将数据的行'转换'为列
如果不是所有的级别值都能在各分组中找到,unstack操作可能引入缺失数据
stack会默认滤除缺失数据,可以传入dropna=False选择不滤除缺失数据
将「长格式」旋转为「宽格式」
pivoted=ldata.pivot('date','item','value')
前两个参数值分别作为行和列索引的列名,最后一个参数用于填充DataFrame的数据列的列名
假设有两个需要参与重塑的数据列,如果忽略最后一个参数,得到的DataFrame就会带有层次化的索引
注意,pivot其实只是一个快捷方式,用set_index创建层次化索引,再用unstack重塑
数据转换
过滤、清理以及其他的转换
移除重复数据
data.duplicated()
返回一个布尔型Series,表示各行是否有重复行
data.drop_duplicates()
可以传入根据某一列来过滤: data.drop_duplicates(['k1'])
默认保留第一个出现值组合,传入take_last=True,则保留最后一个
利用函数或映射进行数据转换
data=DataFrame({'food':['bacon','pulled pork','bacon','Pastrami','corned beef','Bacon','pastrami','honey ham','nova lox'],'ounces':[4,3,12,6,7.5,8,3,5,6]})
meat_to_animal={'bacon':'pig','pulled pork':'pig','pastrami':'cow','corned beef':'cow','honey ham':'pig','nova lox':'salmon'}
data['animal']=data['food'].map(str.lower).map(meat_to_animal)data
data['food'].map(lambda x:meat_to_animal[x.lower()])
替换值
利用fillna方法填充缺失数据可以看做值替换的一种特殊情况
data=Series([1.,-999.,2.,-999.,-1000.,3.])
data.replace(-999,np.nan)
data.replace([-999,-1000],np.nan)
替换多个值
data.replace([-999,-1000],[np.nan,0])
可以是列表形式
data.replace({-999:np.nan,-1000:0})
可以是字典形式
重命名轴索引
In [9]: data.index.map(str.upper)
Out[9]: array(['OHIO', 'COLORADO', 'NEW YORK'], dtype=object)
返回值为array类型
也可以直接修改data = ***In[9]***
In [28]: data.rename(index=str.title, columns=str.upper)
Out[28]:
ONE TWO THREE FOUR
Indiana 0 1 2 3
Colorado 4 5 6 7
New York 8 9 10 11
修改columns标签值,返回Dataframe类型
特别说明,rename可以结合字典型对象实现对部分轴标签的更新
In [31]: data.rename(index={'INDIANA':'Los Angeles'},columns={'four':'peekaboo'})
如果想直接修改,可以传入inplace=True
离散化和面元划分
为了便于分析,连续数据常常被离散化或拆分为「面元」(bin),比如年龄组的划分.
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
bins = [18, 25, 35, 60, 100]
cats = pd.cut(ages, bins)
cats
pandas返回一个特殊的Categorical对象,包含不同分类名称的categories数组和一个为年龄数据进行标号的labels属性
cats.labels
array([0, 0, 0, 1, 0, 0, 2, 1, 3, 2, 2, 1], dtype=int8)
In [45]: cats.categories(书中是levels,py3不包含该方法)
Out[45]: Index(['(18, 25]', '(25, 35]', '(35, 60]', '(60, 100]'], dtype='object')
In [50]: pd.value_counts(cats)
Out[50]:
(18, 25] 5
(35, 60] 3
(25, 35] 3
(60, 100] 1
dtype: int64
区间默认是左开右闭,传入right = False表示左闭右开
可以设置面元名称,将labels选项设置为一个列表或数组即可
即在cut函数中,传入labels=***列表或元祖***
pd.cut(data,4,precision=2)
表示将data计算4个等长面元,precision表示小数点精确度
qcut可以根据样本分位数对数据进行划分
也可以设置自定义的分位数,传入0到1的数值列表即可,比如[0, 0.1 ,0.5, 0.9, 1]
检测和过滤异常值(孤立点或离群值outlier)
data = DataFrame(np.random.randn(1000, 4))
col = data[3]
col[np.abs(col) > 3]
找出某列中绝对值超过3的值
data[(np.abs(data)>3).any(1)]
找出全部绝对值超过3的行(存在超过3的数值的行即返回)
data[np.abs(data)>3]=np.sign(data)*3
将最大最小值改为3和-3
其中np.sign返回一个由1和-3组成的数组
排列和随机采样
numpy.random.permutation函数可以返回一个新顺序的数组
比如***permutation***(5)返回的是0,1,2,3,4的随机顺序的数组
然后就可以基于ix的索引操作或take函数使用该数组对DataFrame进行排序
df = DataFrame(np.arange(5 * 4).reshape((5, 4)))
sampler = np.random.permutation(5)
df.take(sampler)
选取随机子集
df.take(np.random.permutation(len(df))[:3])黑体可以用上文的sampler代替
计算指标/哑变量
常用于统计建模或机器学习的转换方式:
将分类变量(categorical variable)转换为哑变量矩阵(dummy matrix)或指标矩阵(indicator matrix)
如果DataFrame的某一列中含有k个不同的值,则可以派生出一个k列矩阵或DataFrame,其值全为1或0
df = DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'],'data1': range(6)})
pd.get_dummies(df['key'])
data1这一列没有重复的,将key这一列的所有元素展开到column,0和1为布尔值
加前缀
dummies=pd.get_dummies(df['key'],prefix='key')
df_with_dummy=df[['data1']].join(dummies)
df_with_dummy
将get_dummies和诸如cut之类的离散化结合起来使用
values=np.random.rand(10)
values
bins=[0,0.2,0.4,0.6,0.8,1]
pd.get_dummies(pd.cut(values,bins))
(0, 0.2] (0.2, 0.4] (0.4, 0.6] (0.6, 0.8] (0.8, 1]
0 0 0 0 0 1
1 0 1 0 0 0
2 1 0 0 0 0
3 0 1 0 0 0
4 0 0 1 0 0
5 0 0 1 0 0
6 0 0 0 0 1
7 0 0 0 1 0
8 0 0 0 1 0
9 0 0 0 1 0
返回的结果为某一栏在第几个Categorial array中出现
字符串操作
字符串对象方法
表7-3
包含count\join等等
正则表达式
pandas中矢量化的字符串函数
清理散乱数据时,需要做一些字符串的规整化工作(比如处理缺失数据)
data.map,所有字符串和正则表达式方法能被用于各个值(传入lambda表达式或其他函数),但是遇到NA就回报错;
Series的str属性可以访问这些方法跳过NA值
data.str.contains('gmail') 返回布尔值True False
有两个办法可以实现矢量化的元素获取操作:str.get或者str属性上使用索引