专业术语-中英文对照
英语 | 汉语 |
---|---|
merge | 合并 |
join | 连接 |
concat | 拼接 |
index | 索引 |
list | 列表 |
dict | 字典 |
pandas axis解释
官方:It specifies the axis along which the means are computed. 沿着轴操作。
默认axis=0,也就是竖轴,操作的结果是行数的增加或减少
axis=1,也就是横轴,操作的结果每一列属性增加或减少
In [ ]:
pandas中concat对DataFrame操作, 由axis和join两个参数共同控制得到结果。
axis=0, 结果是行数等于两个子DataFrame的行数之和(结果的索引是两个子DF 索引的罗列,即使子DF的索引重复也无所谓)。而每一行的列数 由join参数控制,如果join=‘outer’,会对两个子DataFrame的列求并集,得到结果的每一行属性;如果join=‘inner’,会对两个子DataFrame的列求交集,得到结果的每一行属性
axis=1, 结果中每一行的属性个数等于两个子DF中的属性相加。而行数由join参数控制,具体地,对子DF的索引进行outer或inner。
In [1]:
import pandas as pd
import numpy as np
In [2]:
df1 = pd.DataFrame({'A':['A0','A1','A2','A3'],
'B':['B0','B1','B2','B3'],
'C':['C0','C1','C2','C3'],
'D':['D0','D1','D2','D3']},
index=[0,1,2,3])
In [3]:
df1
Out[3]:
In [4]:
df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'],
'B': ['B4', 'B5', 'B6', 'B7'],
'C': ['C4', 'C5', 'C6', 'C7'],
'D': ['D4', 'D5', 'D6', 'D7']},
index=[4, 5, 6, 7])
In [5]:
df2
Out[5]:
In [6]:
df3 = pd.DataFrame({'A': ['A8', 'A9', 'A10', 'A11'],
'B': ['B8', 'B9', 'B10', 'B11'],
'C': ['C8', 'C9', 'C10', 'C11'],
'D': ['D8', 'D9', 'D10', 'D11']},
index=[8, 9, 10, 11])
In [7]:
df3
Out[7]:
In [8]:
frames = [df1, df2, df3] #产生一个list对象
In [9]:
results = pd.concat(frames)
In [10]:
results
Out[10]:
In [11]:
res = pd.concat(frames, join='inner')
res
Out[11]:
修改df3的index,看看结果
In [12]:
df5 = pd.DataFrame({'A': ['A8', 'A9', 'A10', 'A11'],
'B': ['B8', 'B9', 'B10', 'B11'],
'C': ['C8', 'C9', 'C10', 'C11'],
'D': ['D8', 'D9', 'D10', 'D11']},
index=[2, 3, 10, 11])
df5
Out[12]:
In [13]:
df1
Out[13]:
In [14]:
results2 = pd.concat([df1,df2,df5])
results2
Out[14]:
修改df5,使得某几行和df2一样,再看看结果
In [15]:
df5 = pd.DataFrame({'A': ['A2', 'A9', 'A10', 'A11'],
'B': ['B2', 'B9', 'B10', 'B11'],
'C': ['C2', 'C9', 'C10', 'C11'],
'D': ['D2', 'D9', 'D10', 'D11']},
index=[2, 3, 10, 11])
df5
Out[15]:
In [16]:
results3 = pd.concat([df1,df2,df5])
results3
Out[16]:
如同numpy.concatenate()方法, pandas.concat方法接收一个列表或者字典对象然后进行拼接操作,注意列表或字典中每个对象要是同构的。拼接的本质就是沿着一条轴并且根据对另一条轴上进行的操作 将列表中的对象堆叠。
concat方法的参数:
pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False)
如果不结合例子来看,上面介绍的参数真没法解释。
先来看一下keys参数 用于构建层次化索引时起到的作用。
In [17]:
#层次化索引, 用处是给列表中每个对象一个map标记,这样在结果中还能方便的调用每个子Series或DataFrame
result = pd.concat(frames, keys=['x','y','z'])
In [18]:
result
Out[18]:
注意到结果中的索引是层次化的。
In [19]:
result.ix['y'] #查看df2
Out[19]:
注意:concat()方法在拼接使要复制所有的数据,因此对于它的性能你要容忍。为了方便起见,如果对多个数据集拼接,可以使用列表解析式。
In [20]:
frames = [process_your_file(f) for f in files]
result = pd.concat(frames)
如果是对DataFrame或Panel对象进行拼接操作,你可以同时对非拼接轴进行逻辑运算。由于Series只有一个轴,所以此功能不适用于Series对象。
有三种方式能够对非拼接轴进行逻辑运算:
针对上面三种方法,各举一例说明:
In [21]:
df4 = pd.DataFrame({'B': ['B2', 'B3', 'B6', 'B7'],
'D': ['D2', 'D3', 'D6', 'D7'],
'F': ['F2', 'F3', 'F6', 'F7']},
index=[2, 3, 6, 7])
In [22]:
result = pd.concat([df1, df4], axis=1) #这里axis=1
解释:
axis=1,即拼接轴是横轴,先将df1的列和df4的列名进行堆叠,即每一行有7列。由于join='outer', 故将df1和df4的索引取取并集,得到{0,1,2,3,6,7},共6行。
还要注意结果的索引值是排好序的。
In [23]:
df4 = pd.DataFrame({'B': ['B2', 'B3', 'B6', 'B7'],
'D': ['D2', 'D3', 'D6', 'D7'],
'F': ['F2', 'F3', 'F6', 'F7']},
index=[3, 2, 7, 6]) #注意这里的索引值序列
df4
Out[23]:
In [24]:
result = pd.concat([df1, df4], axis=1)
result #结果中的索引值已排序
Out[24]:
再来看看join='inner'的例子:
In [25]:
result = pd.concat([df1, df4], axis=1, join='inner')
result
Out[25]:
解释:
axis=1,即拼接轴是横轴,先将df1的列和df4的列名进行堆叠,即每一行有7列。由于join='inner', 故将df1和df4的索引取取并集,得到{2,3},共2行。
还要注意结果的索引值没有排序。
最后,看一下使用 join_axes参数的例子:
In [26]:
result = pd.concat([df1, df4], axis=1, join_axes=[df1.index])
解释:
axis=1,即拼接轴是横轴,先将df1的列和df4的列名进行堆叠,即每一行有7列。由于join_axes=[df1.index],故结果的索引取值和df1相同,{0,1,2,3}。
如果只想对Series或DataFrame对象进行行拼接(axis=0),推荐使用append()方法。 append()方法实际上就是沿着索引轴(axis=0)进行拼接的concat()。
注意:
如果是对DataFrame对象进行append操作,要注意他们的索引值交集必须为空!即每个DataFrame对象的索引值都不相同。列名不作要求。
其实,对DataFrame进行append操作时是可以忽略索引的,result = df1.append(df4, ignore_index=True)
In [27]:
result = df1.append(df2)
In [28]:
result = df1.append(df4)
#由于df1和df2的索引值交集不为空,导致最后result的索引值有重复!
append()方法可以一次拼接多个对象。
In [29]:
result = df1.append([df2,df3])
append()操作并不是直接对df1对象进行操作,而是在df1副本的基础上进行拼接操作。
In [30]:
df1
Out[30]:
In [31]:
df4
Out[31]:
In [32]:
result = pd.concat([df1, df4],ignore_index=True)
result
Out[32]:
In [33]:
df1
Out[33]:
In [34]:
df4
Out[34]:
In [35]:
result2 = pd.concat([df1, df4],axis=1, ignore_index=True) #99.9999%不推荐大家列拼接时使用ignore_index
result2
Out[35]:
DataFrame.append方法也有ignore_index参数哦
In [36]:
result = df1.append(df4, ignore_index=True)
In [37]:
s1 = pd.Series(['X0','X1','X2','X3','X4'],name='X')
In [38]:
s1
Out[38]:
In [39]:
result = pd.concat([df1,s1],axis=1)
result
Out[39]:
如果Series的列没有名字,会默认生成数字用于列名。
In [40]:
s2 = pd.Series(['_0', '_1', '_2', '_3'])
result = pd.concat([df1, s2, s2, s2], axis=1)
In [41]:
s3 = pd.Series([0, 1, 2, 3], name='foo')
s4 = pd.Series([0, 1, 2, 3])
s5 = pd.Series([0, 1, 4, 5])
In [42]:
pd.concat([s3,s4,s5],axis=1)
Out[42]:
通过keys参数,来设置生成的DataFrame的列名
In [43]:
pd.concat([s3,s4,s5],axis=1,keys=['red','blue','yellos'])
Out[43]:
回顾一下我们的第一个例子:
In [44]:
result = pd.concat(frames, keys=['x', 'y', 'z'])
可以用字典代替上面concat方法中的frames和keys:
In [46]:
pieces = {'x':df1, 'y':df2, 'z':df3}
result = pd.concat(pieces)
result
Out[46]:
In [48]:
result = pd.concat(pieces, keys=['z', 'y']) #只对'z','y'对应的DataFrame进行拼接
result
Out[48]:
In [49]:
s2 = pd.Series(['X0', 'X1', 'X2', 'X3'], index=['A', 'B', 'C', 'D'])
s2
Out[49]:
In [50]:
df1
Out[50]:
In [52]:
result = df1.append(s2, ignore_index=True) #推荐忽略现有的索引值
result
Out[52]:
In [53]:
dicts = [{'A': 1, 'B': 2, 'C': 3, 'X': 4},
{'A': 5, 'B': 6, 'C': 7, 'Y': 8}]
In [54]:
result = df1.append(dicts, ignore_index=True)
pandas提供了非常高效的DataFrame连接(join)操作,并且使用风格和SQL非常类似。相对于其他的开源实现,pandas无疑是相当高效的, 这要归功于对DataFrame对象的优秀的算法设计和高效的内部数据部署。
如果你之前有过SQL开发经验而首次使用pandas,你可能想先了解二者的对比。
pandas仅提供了一个merge()方法,就能够对DataFrame对象进行类似关系数据库的连接(join)操作,先看merge()参数
merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=True, suffixes=('_x', '_y'), copy=True, indicator=False)
merger方法的返回的对象类型同left。
merge()方法是pandas中的全局方法,你可以通过DataFrame对象调用它。
和merge()方法很相似的是DataFrame.join()方法,它内部使用merge方法来实现 索引与索引、索引与列 的拼接操作,默认是对索引进行拼接,而merge方法默认是对列进行拼接,无疑,对列进行拼接更常见。除非你要对索引进行拼接,通常都是使用merge()方法。
大家有必要花时间理解多对多拼接操作的情况。在SQL/关系代数中,如果连接时的键值(key)在两个表中值不唯一,拼接结果是两个表的笛卡尔积。
看一个简单的例子来理解笛卡尔积。
In [56]:
left = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3']
})
In [57]:
right = pd.DataFrame({'key': ['K0', 'K2', 'K1', 'K3'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']
})
In [58]:
pd.merge(left, right, on='key')
Out[58]:
解释:
拼接的键值是'key', left中key这一列的取值是{K0, k1, K2, K3},right中key这一列的取值是{K0, K1, K2, K3}, 由于how参数默认值是'inner', 即内连接,所以笛卡尔积是{K0, K1, K2, K3}
In [ ]:
再看一个复杂点的例子, 多个列名作为key
In [59]:
left = pd.DataFrame({
'key1':['K0', 'K0', 'K1', 'K2'],
'key2':['K0', 'K1', 'K0', 'K1'],
'A':['A0', 'A1', 'A2', 'A3'],
'B':['B0', 'B1', 'B2', 'B3']
})
In [60]:
right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
'key2': ['K0', 'K0', 'K0', 'K0'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']})
In [62]:
pd.merge(left, right, on=['key1', 'key2'])
Out[62]:
解释:
此时拼接操作的键值是['key1', 'key2'],在left中['key1','key2']的取值是{['K0','K0'], ['K0', 'K1'], ['K1', 'K0'], ['K2', 'K1']},在right中['key1', 'key2']的取值是{['K0', 'K0'], ['K1', 'K0'], ['K2', 'K0']}, 默认进行内连接,所以取二者的交集{['K0', 'K0'], ['K1', 'K0']}, 并且left中['K1', 'K0']出现了两次,所以拼接结果是3行。
In [ ]:
merge方法中的参数how决定了哪些键值(keys)会被保留到结果中。注意如果on参数接收的键值在left和right中都没有出现,拼接结果是NA。
下面总结了how参数在SQL中对应的操作。
参数how取值 | SQL拼接操作 | 操作描述 |
---|---|---|
left | LEFT OUTER JOIN | 只使用来自left中的键值 |
right | RIGHT OUTER JOIN | 只使用来自right中的键值 |
outer | FULL OUTER JOIN | 使用left、right中键值的并集 |
inner | INNER JOIN | 使用left、right中键值的交集 |
In [68]:
result = pd.merge(left, right, how='left', on=['key1', 'key2'])
解释:
on的参数是['key1', 'key2'],所以拼接的键值是['key1', 'key2'],how参数是'left',所以进行的是左拼接,只关注left中键值取值。
过程:left中第一行键值是['K0', 'K1'],发现right有此取值,拼接后得到result中的第一行;
left中第二行键值是['K0', 'K1'],发现right中没有此取值,仍进行拼接得到result中第二行,注意'C' 'D'取值NaN
left中第三行键值是['K1', 'K0'], 发现right中有此取值切出现了两次,分别进行拼接得到result中第三行、第四行
left中第四行取值是['K2', 'K1'], 发现right中没有此取值,仍进行拼接得到result中第五行,'C', 'D'取值NaN
In [ ]:
In [69]:
result = pd.merge(left, right, how='right', on=['key1', 'key2'])
In [ ]:
In [70]:
result = pd.merge(left, right, how='outer', on=['key1', 'key2'])
In [71]:
result = pd.merge(left, right, how='inner', on=['key1', 'key2'])
merge方法在0.17.0版本中新增了一个参数indicator。这个参数取值True,False或字符串。如果取值True,会在拼接结果中多出一列'_merge', 显示 每一行的键值来自left还是right。
_merge值 | 含义 |
---|---|
left_only | 键值仅来自left |
right_only | 键值仅来自right |
both | 键值来自left和both |
In [77]:
df1 = pd.DataFrame({'col1':[0,1], 'col_left':['a','b']})
df2 = pd.DataFrame({'col1':[1,2,2],'col_right':[2,2,2]})
In [78]:
df1
Out[78]:
In [79]:
df2
Out[79]:
In [80]:
pd.merge(df1, df2, on='col1', how='outer', indicator=True)
Out[80]:
上面提到indicator参数取值也可以是字符串,没啥特别的,就是在拼接结果中用接收的字符串作为'_merge'的列名罢了。
In [81]:
pd.merge(df1, df2, on='col1', how='outer', indicator='indicator_column')
Out[81]:
DataFrame.join方法的作用是对两个DataFrame对象进行基于索引值的拼接操作。下面是一个简单的例子:
把索引也看做是一列,再来看下面的操作就就没啥了
In [82]:
left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
'B': ['B0', 'B1', 'B2']},
index=['K0', 'K1', 'K2'])
right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],
'D': ['D0', 'D2', 'D3']},
index=['K0', 'K2', 'K3'])
result = left.join(right)
In [83]:
result = left.join(right, how='outer')
In [84]:
result = left.join(right, how='inner')
merge方法中提供了left_index, right_index参数同样实现了基于索引的拼接操作。
In [85]:
result = pd.merge(left, right, left_index=True, right_index=True, how='outer')
In [86]:
result = pd.merge(left, right, left_index=True, right_index=True, how='inner')
很多情况下,left和right中除了拼接键值之外,还会有其他列名也相同,为了在结果中加以区分,这个时候suffixes参数就派上用场了。好消息是suffixes有默认值,即使不为它赋值在结果中也能够区分。
举例如下:
In [87]:
left = pd.DataFrame({'k': ['K0', 'K1', 'K2'], 'v': [1, 2, 3]})
In [88]:
right = pd.DataFrame({'k': ['K0', 'K0', 'K3'], 'v': [4, 5, 6]})
In [90]:
result = pd.merge(left, right, on='k')
默认情况下:
In [91]:
result = pd.merge(left, right, on='k', suffixes=['_l', '_r']) #为suffixes参数赋值
DataFrame.join方法也提供了lsuffix和rsuffix参数来实现同样的功能:
In [92]:
left = left.set_index('k')
right = right.set_index('k')
In [93]:
result = left.join(right, lsuffix='_l', rsuffix='_r')
DataFrame.join方法能够接收DataFrame对象构成的元组或列表,对列表内所有DF对象进行基于索引的拼接。Panel.join方法也有此功能。
In [94]:
right2 = pd.DataFrame({'v': [7, 8, 9]}, index=['K1', 'K1', 'K2'])
In [96]:
left.join([right, right2])
Out[96]:
In [103]:
left = pd.DataFrame({'k': ['K0', 'K1', 'K1', 'K2'],
'lv': [1, 2, 3, 4],
's': ['a', 'b', 'c', 'd']})
right = pd.DataFrame({'k': ['K1', 'K2', 'K4'],
'rv': [1, 2, 3]})
left
Out[103]:
In [104]:
right
Out[104]:
In [102]:
pd.ordered_merge(left, right, fill_method='ffill', left_by='s')
Out[102]:
In [105]:
df1 = pd.DataFrame([[np.nan, 3., 5.], [-4.6, np.nan, np.nan],
[np.nan, 7., np.nan]])
df1
Out[105]:
In [106]:
df2 = pd.DataFrame([[-42.6, np.nan, -8.2], [-5., 1.6, 4]],
index=[1, 2])
df2
Out[106]:
先使用combine_first方法:
In [108]:
df1.combine_first(df2)
Out[108]:
In [109]:
df1
Out[109]:
df1和df2列名完全相同,索引值也相似。
由于df2中不存在索引值=0,所以df1中第一行的值原封不动;
对于df1中不等于NaN的值,也不需要改变;
对于df1中等于NaN的值,用df2中同索引同列名的值替换, 得到结果。
注意combine_first()方法不改变df1的值。
如果想改变df1的值,使用update()方法。
In [110]:
df1.update(df2)
In [111]:
df1
Out[111]:
In [ ]: