Python数据分析_Pandas02_数据框的合并和重整

主要内容:
  • 数据拼接:join、merge、contact、append
  • 数据重整:reshape -- stuck、unstuck
  • 数据透视表:pivot tables

数据拼接

1. concat

参数介绍:

pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,
          keys=None, levels=None, names=None, verify_integrity=False,
          copy=True)

axis:要粘在哪个轴上。默认0,粘贴行。
join:默认outer,合集;inner,交集。
ignore_index:布尔型,默认False。如果为Ture的话,会重新分配index从0...n-1。
keys:一个序列,默认None。建立等级索引,作为最外层的level。
levels:序列sequences构成的list,默认None。

示例:

In [41]: 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 [42]: 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 [43]: 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 [44]: frames = [df1, df2, df3]

In [45]: result = pd.concat(frames)

In [46]: result
Out[46]:
      A    B    C    D
0    A0   B0   C0   D0
1    A1   B1   C1   D1
2    A2   B2   C2   D2
3    A3   B3   C3   D3
4    A4   B4   C4   D4
5    A5   B5   C5   D5
6    A6   B6   C6   D6
7    A7   B7   C7   D7
8    A8   B8   C8   D8
9    A9   B9   C9   D9
10  A10  B10  C10  D10
11  A11  B11  C11  D11

In [47]:  result2 = pd.concat(frames, keys=['x', 'y', 'z'])

In [48]: result2
Out[48]:
        A    B    C    D
x 0    A0   B0   C0   D0
  1    A1   B1   C1   D1
  2    A2   B2   C2   D2
  3    A3   B3   C3   D3
y 4    A4   B4   C4   D4
  5    A5   B5   C5   D5
  6    A6   B6   C6   D6
  7    A7   B7   C7   D7
z 8    A8   B8   C8   D8
  9    A9   B9   C9   D9
  10  A10  B10  C10  D10
  11  A11  B11  C11  D11

In [51]: result2.index    # result2的shape是(12,4),多重索引,如下:
Out[51]:
MultiIndex(levels=[['x', 'y', 'z'], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]],
           labels=[[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]])

In [49]: result2.ix['y']                # .ix 等级索引
Out[49]:
    A   B   C   D
4  A4  B4  C4  D4
5  A5  B5  C5  D5
6  A6  B6  C6  D6
7  A7  B7  C7  D7

contact会生成一个copy,比较费内存。如果要用的话,最好把所有要拼接的数据框放一list中,一次concat所有。像这样:

frames = [ process_your_file(f) for f in files ]
result = pd.concat(frames)

2. append

和python中list的append不同,这里的append不改变原来的数据框,返回一个拼接后的copy。

In [57]: appended = df1.append([df2, df3])

In [58]: appended
Out[58]:
      A    B    C    D
0    A0   B0   C0   D0
1    A1   B1   C1   D1
2    A2   B2   C2   D2
3    A3   B3   C3   D3
4    A4   B4   C4   D4
5    A5   B5   C5   D5
6    A6   B6   C6   D6
7    A7   B7   C7   D7
8    A8   B8   C8   D8
9    A9   B9   C9   D9
10  A10  B10  C10  D10
11  A11  B11  C11  D11

In [59]: df1
Out[59]:
    A   B   C   D
0  A0  B0  C0  D0
1  A1  B1  C1  D1
2  A2  B2  C2  D2
3  A3  B3  C3  D3

添加一行:【注】ignore_index=True

可以添加Series或list(放着dicts的list)

In [80]: s2 = pd.Series(['X0', 'X1', 'X2', 'X3'],index=df1.columns)
In [83]: df1_s2 =  df1.append(s2,ignore_index=True)

In [84]: df1_s2
Out[84]:
    A   B   C   D
0  A0  B0  C0  D0
1  A1  B1  C1  D1
2  A2  B2  C2  D2
3  A3  B3  C3  D3
4  X0  X1  X2  X3

dicts = [{'A': 1, 'B': 2, 'C': 3, 'X': 4},
         {'A': 5, 'B': 6, 'C': 7, 'Y': 8}]
result = df1.append(dicts, ignore_index=True)

下面的merge和join是针对数据框合并的,一般都是列合并。

3. merge

参数介绍:

pd.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)
         
left: 一个dataframe对象
right: 另一个dataframe对象
how: 可以是'left', 'right', 'outer', 'inner'. 默认为inner。
on: 列名,两个dataframe都有的列。如果不传参数,
    而且left_index和right_index也等于False,
    则默认把两者交叉/共有的列作为链接键(join keys)。
    可以是一个列名,也可以是包含多个列名的list。
left_on: 左边dataframe的列会用做keys。可以是列名,
    或者与dataframe长度相同的矩阵array。
right_on: 右边同上。
left_index: 如果为Ture,用左侧dataframe的index作为
    连接键。如果是多维索引,level数要跟右边相同才行。
right_index: 右边同上。
sort: 对合并后的数据框排序,以连接键。
suffixes: 一个tuple,包字符串后缀,用来加在重叠的列名后面。
    默认是('_x','_y')。
copy: 默认Ture,复制数据。
indicator: 布尔型(True/FALSE),或是字符串。
    如果为True,合并之后会增加一列叫做'_merge'。
    是分类数据,用left_only, right_only, both来标记
    来自左边,右边和两边的数据。

示例:

In [4]: left = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],
   ...:                      'A': ['A0', 'A1', 'A2', 'A3'],
   ...:                      'B': ['B0', 'B1', 'B2', 'B3']})
   ...:

In [6]: right = pd.DataFrame({'key': ['K1', 'K2', 'K3', 'K4'],
   ...:                       'C': ['C0', 'C1', 'C2', 'C3'],
   ...:                       'D': ['D0', 'D1', 'D2', 'D3']})
   ...:

#默认inner合并,只保留共同的部分。
In [7]: pd.merge(left, right, on='key')
Out[7]:
    A   B key   C   D
0  A1  B1  K1  C0  D0
1  A2  B2  K2  C1  D1
2  A3  B3  K3  C2  D2

#outer方式合并
In [8]: pd.merge(left, right, how='outer', on='key')
Out[8]:
     A    B key    C    D
0   A0   B0  K0  NaN  NaN
1   A1   B1  K1   C0   D0
2   A2   B2  K2   C1   D1
3   A3   B3  K3   C2   D2
4  NaN  NaN  K4   C3   D3

#indicator,用来标示数据来源。
In [11]: In [8]: pd.merge(left, right, how='outer', on='key', indicator = 'indicator_colomn')
Out[11]:
     A    B key    C    D indicator_colomn
0   A0   B0  K0  NaN  NaN        left_only
1   A1   B1  K1   C0   D0             both
2   A2   B2  K2   C1   D1             both
3   A3   B3  K3   C2   D2             both
4  NaN  NaN  K4   C3   D3       right_only

4. Join

另一个便捷的合并数据框的方法。

参数介绍:

DataFrame.join(other, on=None, how='left', lsuffix='', rsuffix='', sort=False)

other:一个DataFrame、Series(要有命名),或者DataFrame组成的list。
on:列名,包含列名的list或tuple,或矩阵样子的列
    (如果是多列,必须有MultiIndex)。
    跟上面的几种方法一样,用来指明依据哪一列进行合并。
    如果没有赋值,则依据两个数据框的index合并。
how:合并方式, {‘left’, ‘right’, ‘outer’, ‘inner’},
    默认 ‘left’调用函数的数据框。
lsuffix:字符串。用于左侧数据框的重复列。
    把重复列重新命名,原来的列名+字符串。
    【如果有重复列,必须添加这个参数。】
rsuffix:同上。右侧。
sort:布尔型,默认False。如果为True,将链接键(on的那列)按字母排序。

示例:

In [3]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
   ...:                      'B': ['B0', 'B1', 'B2'],
   ...:                      'D': ['D3', 'D4', 'D5']},
   ...:                      index=['K0', 'K1', 'K2'])
   ...:
   ...: right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],
   ...:                       'D': ['D0', 'D2', 'D3']},
   ...:                       index=['K0', 'K2', 'K3'])
   ...:
   
In [5]: left.join(right, lsuffix='_left', rsuffix='_right')
Out[5]:
     A   B D_left    C D_right
K0  A0  B0     D3   C0      D0
K1  A1  B1     D4  NaN     NaN
K2  A2  B2     D5   C2      D2

In [8]: left.join(right, on='D', how='outer', lsuffix='_left', rsuffix='_right')
Out[8]:
     D    A    B D_left    C D_right
K0  D3   A0   B0     D3  NaN     NaN
K1  D4   A1   B1     D4  NaN     NaN
K2  D5   A2   B2     D5  NaN     NaN
K2  K0  NaN  NaN    NaN   C0      D0
K2  K2  NaN  NaN    NaN   C2      D2
K2  K3  NaN  NaN    NaN   C3      D3

#对比没有'on'的情况。对于上面第8行输出有点儿懵逼。
In [9]: left.join(right, how='outer', lsuffix='_left', rsuffix='_right')
Out[9]:
      A    B D_left    C D_right
K0   A0   B0     D3   C0      D0
K1   A1   B1     D4  NaN     NaN
K2   A2   B2     D5   C2      D2
K3  NaN  NaN    NaN   C3      D3

# 使用默认索引的时候:
In [10]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],
    ...:                      'B': ['B0', 'B1', 'B2'],
    ...:                      'D': ['D3', 'D4', 'D5']})
    ...: right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],
    ...:                       'D': ['D0', 'D2', 'D3']})
    ...:

In [11]: left.join(right, lsuffix='_left', rsuffix='_right')
Out[11]:
    A   B D_left   C D_right
0  A0  B0     D3  C0      D0
1  A1  B1     D4  C2      D2
2  A2  B2     D5  C3      D3

合并数据框这些方法大同小异,选一个能满足需要就行啦。


数据重整

pivot

用于生成一个数据透视表。

参数介绍:

DataFrame.pivot(index=None, columns=None, values=None)[source]

index:字符串或对象,可选。列名,用来当新数据框index的列,可以是多个列名的list。
columns:字符串或对象。列名,当做新数据框的列。
values:字符串或对象,可选。列名,生成新数据框的值。
    如果没有指定,则使用余下的所有列,会生成等级索引列。

示例:

In [16]: df = pd.DataFrame({'foo': ['one','one','one','two','two','two'],
    ...:                    'bar': ['A', 'B', 'C', 'A', 'B', 'C'],
    ...:                    'baz': [1, 2, 3, 4, 5, 6]})

In [20]: df
Out[20]:
  bar  baz  foo
0   A    1  one
1   B    2  one
2   C    3  one
3   A    4  two
4   B    5  two
5   C    6  two

In [21]: df.pivot(index='foo', columns='bar', values='baz')
    ...:
Out[21]:
bar  A  B  C
foo
one  1  2  3
two  4  5  6

# 有多列数值的情况
In [22]: df['baz_2'] = df['baz']*2

In [23]: df.pivot(index='foo', columns='bar')
Out[23]:
    baz       baz_2
bar   A  B  C     A   B   C
foo
one   1  2  3     2   4   6
two   4  5  6     8  10  12

# 另一种选择数值value的方法
In [24]: df.pivot(index='foo', columns='bar')['baz_2']
Out[24]:
bar  A   B   C
foo
one  2   4   6
two  8  10  12

升级版pivot:pandas.DataFrame.pivot_table。有更多的参数。个人感觉比较鸡肋,复杂的分类汇总有其他的函数可用。

stack 和 unstack

另一种重整数据的方法。stack和unstack是互逆方式。参数很简单。直接贴个例子好了

In [41]: df2 = df.pivot(index='foo', columns='bar')['baz_2']
    ...: df2
    ...:
Out[41]:
bar  A   B   C
foo
one  2   4   6
two  8  10  12

In [42]: stacked = df2.stack()

In [43]: stacked
Out[43]:
foo  bar
one  A       2
     B       4
     C       6
two  A       8
     B      10
     C      12
dtype: int64

In [44]: stacked.unstack()
Out[44]:
bar  A   B   C
foo
one  2   4   6
two  8  10  12

推荐阅读更多精彩内容