PandasPython小推车python模块

03-pandas-Ⅱ

2018-12-13  本文已影响9人  郑元吉

一.pandas层次化索引

1.1 创建多层索引
1.1.1 隐式构造
最常见的方法是给DataFrame构造函数的index参数传递两个或更多的数组

columns = [['期中', '期中','期中','期末','期末','期末'],['语文','数学','英语','语文','数学','英语']]
data = np.random.randint(0,150,size=(10,6))
# index = [['一班', 1],['一班', 1],['一班', 1],['一班', 1],['一班', 1],['二班', 1],['二班', 1],['二班', 1],['二班', 1],['二班', 1]]
index = [['一班','一班','一班','一班','一班','二班','二班','二班','二班','二班'], np.arange(10)]
df = DataFrame(data=data,columns=columns, index=index)
df
输出:
                期中        期末
        语文 数学  英语 语文  数学  英语
一班    0 83  23 23  41   85  16
        1 82 143 63 69 51 12
        2 142 21 4 19 52 124
        3 63    99 89 106 30 8
        4 142 126 51 111 42 83
二班    5 89 47   139 131 133 115
        6  76 34 30 67  15 38
        7   116 93  81  45  74  76
        8   83  21  64  83  40  1
        9   99  79  83  48  42  68

Series也可以创建多层索引

index = [['一班','一班','一班','一班','一班','二班','二班','二班','二班','二班'], np.arange(10)]
s = Series(data=np.random.randint(150,size=10),index=index)
s

输出:
一班  0    127
    1    129
    2     15
    3    148
    4    112
二班  5     91
    6     59
    7     80
    8    130
    9    140
dtype: int32
1.1.2 显式构造MultiIndex
  1. 使用数组
columns = pd.MultiIndex.from_arrays([['期中', '期中','期中','期末','期末','期末'],['语文','数学','英语','语文','数学','英语']])
data = np.random.randint(0,150,size=(10,6))
# index = [['一班', 1],['一班', 1],['一班', 1],['一班', 1],['一班', 1],['二班', 1],['二班', 1],['二班', 1],['二班', 1],['二班', 1]]
index = pd.MultiIndex.from_arrays([['一班','一班','一班','一班','一班','二班','二班','二班','二班','二班'], np.arange(10)])
df = DataFrame(data=data,columns=columns, index=index)
df

输出:

                          期中    期末
          语文  数学  英语  语文  数学    英语
一班     0    119 8   81  109 117 30
        1   5   35  149 47  114 31
        2   128 60  148 55  96  101
        3   65  92  94  147 145 72
        4   48  108 74  50  48  86
二班  5   81  85  93  92  57  10
        6   52  67  83  76  104 59
        7   125 23  57  103 27  22
        8   7   39  79  114 12  90
        9   30  140 20  71  0   42
  1. 使用tuple
columns = [['期中', '期中','期中','期末','期末','期末'],['语文','数学','英语','语文','数学','英语']]
data = np.random.randint(0,150,size=(10,6))
# index = [['一班', 1],['一班', 1],['一班', 1],['一班', 1],['一班', 1],['二班', 1],['二班', 1],['二班', 1],['二班', 1],['二班', 1]]
# index = pd.MultiIndex.from_arrays([['一班','一班','一班','一班','一班','二班','二班','二班','二班','二班'], np.arange(10)])
index = pd.MultiIndex.from_tuples([('一班', 1),('一班', 2),('一班', 3),('一班', 4),('一班', 5),('二班', 6),('二班', 7),('二班', 8),('二班', 9),('二班', 10)])
df = DataFrame(data=data,columns=columns, index=index)
df

输出:
              期中       期末
         语文 数学 英语 语文 数学 英语
一班    1 147 10  49  41  120 45
        2   35  134 120 125 90  31
        3   133 93  80  49  56  68
        4   65  137 147 1   134 33
        5   2   5   111 16  51  108
二班    6 89  90  81  90  66  79
        7   87  125 124 88  32  49
        8   120 15  124 47  46  6
        9   45  12  35  103 108 87
      10    95  21  92  14  72  46
  1. 使用product(最简单,推荐使用)
columns = pd.MultiIndex.from_product([['期中','期末'],['语文','数学','英语']])
data = np.random.randint(0,150,size=(10,6))
# index = [['一班', 1],['一班', 1],['一班', 1],['一班', 1],['一班', 1],['二班', 1],['二班', 1],['二班', 1],['二班', 1],['二班', 1]]
# index = pd.MultiIndex.from_arrays([['一班','一班','一班','一班','一班','二班','二班','二班','二班','二班'], np.arange(10)])
index = pd.MultiIndex.from_product([['一班','二班'],np.arange(5)])
df = DataFrame(data=data,columns=columns, index=index)
df

输出:
               期中       期末
         语文 数学 英语 语文 数学 英语
一班  0   92  46  64  56  130 38
        1   62  137 48  107 2   111
        2   96  0   117 2   83  16
        3   109 21  28  135 67  111
        4   86  123 118 0   108 105
二班  0   52  118 38  140 119 82
        1   101 75  75  69  43  87
        2   61  25  65  68  106 63
        3   63  83  106 81  34  113
        4   25  97  53  118 35  137
1.2 多层列索引

除了行索引index,列索引columns也能用同样的方法创建多层索引

a = np.random.randint(0,150,(2,8))
Mindex = pd.MultiIndex.from_product([['语文','数学','英语','理综'],['期中','期末']])
ddd = DataFrame(data = a,
                index = ['张三','李四'],
                columns = Mindex)
ddd

输出:
      语文    数学  英语  理综
      期中    期末  期中  期末  期中  期末  期中  期末
张三  57  110 65  3   127 66  146 32
李四  73  24  57  19  35  133 57  127
1.3 多层索引对象的索引与切片操作
1.3.1 Series的操作

【重要】对于Series来说,直接中括号[]与使用.loc()完全一样,推荐使用.loc中括号索引和切片。

  1. 索引
s
一班  0    127
    1    129
    2     15
    3    148
    4    112
二班  5     91
    6     59
    7     80
    8    130
    9    140
dtype: int32

s['一班']
输出:
0    127
1    129
2     15
3    148
4    112
dtype: int32

s.loc['一班']
输出:
0    127
1    129
2     15
3    148
4    112
dtype: int32
  1. 切片
s[2:6]
输出:
一班  2     15
    3    148
    4    112
二班  5     91
1.3.2 DataFrame的操作
  1. 可以直接使用列名称来进行列索引
df
输出:
                期中           期末
        语文  数学  英语  语文  数学  英语
一班  张三  133 82  139 86  83  112
        李四  129 85  23  131 4   18
        王五  9   15  96  131 72  77
二班  张三  4   142 104 48  81  108
        李四  75  60  108 126 85  122
        王五  24  31  53  72  49  

行多级索引的索引和切片操作

# DataFrame中操作行要调用loc[]
df.loc['一班'].loc[['李四']]
输出:
                  期中    期末
      语文    数学  英语  语文  数学  英语
李四  129 85  23  131 4   18

df.loc['一班': '二班']
输出:
              期中    期末
        语文  数学  英语  语文  数学  英语
一班  张三  133 82  139 86  83  112
        李四  129 85  23  131 4   18
        王五  9   15  96  131 72  77
二班  张三  4   142 104 48  81  108
        李四  75  60  108 126 85  122
        王五  24  31  53  72  49  46

# 和Series一样,直接切内层索引,会没有结果.不会报错.
df.loc['张三': '李四']
输出:
          期中    期末
语文  数学  英语  语文  数学  英语

# 隐式索引不涉及外层索引
df.iloc[[0]]
输出:
              期中    期末
        语文  数学  英语  语文  数学  英语
一班  张三  133 82  139 86  83  112

列多级索引的索引和切片操作

df['期中'][['语文', '数学']]
输出:
            语文 数学
一班  张三  133 82
      李四    129 85
      王五    9   15
 二班 张三  4   142
      李四    75  60
      王五    24  31

# 列索引,直接切片,没有报错,但是没有结果.
df['期中': '期末']
输出:
         期中         期末
语文  数学  英语  语文  数学  英语
  1. 使用行索引需要用loc()函数

【极其重要】推荐使用loc()函数

注意在对行索引的时候,若一级行索引还有多个,对二级行索引会遇到问题!也就是说,无法直接对二级索引进行索引,必须让二级索引变成一级索引后才能对其进行索引!

df.loc['一班', '张三'].loc['期中', '语文'] = 88
输出:
                        期中  期末
              语文    数学  英语  语文  数学  英语
一班  张三  88.0    82.0    88.0    86.0    83.0    112.0
        李四  129.0   85.0    23.0    131.0   4.0 18.0
        王五  9.0 15.0    96.0    131.0   72.0    77.0
二班  张三  4.0 142.0   104.0   48.0    81.0    108.0
        李四  75.0    60.0    108.0   126.0   85.0    122.0
        王五  24.0    31.0    53.0    72.0    49.0    46.0
1.4 索引的堆

stack()
unstack()

# stack就是把列索引,变成最内层的行索引.从水平变成垂直.
【小技巧】使用stack()的时候,level等于哪一个,哪一个就消失,出现在行里。
# unstack把最内层的行索引变成列索引.
【小技巧】使用unstack()的时候,level等于哪一个,哪一个就消失,出现在列里。
df.stack()
1.5 聚合操作

【注意】

# 聚合操作的时候,默认算的是列的聚合.
df.sum()
输出:
期中  语文    329.0
    数学    415.0
    英语    472.0
期末  语文    594.0
    数学    374.0
    英语    483.0
dtype: float64

# 聚合操作的时候.axis=0表示列,=1表示行
df.sum(axis=0)
输出:
期中  语文    329.0
    数学    415.0
    英语    472.0
期末  语文    594.0
    数学    374.0
    英语    483.0
dtype: float64

# 聚合操作的时候,level等于哪一层,就保留哪一层.
df.sum(level=1)
输出:
                  期中    期末
      语文    数学  英语  语文  数学  英语
张三  92.0    224.0   192.0   134.0   164.0   220.0
李四  204.0   145.0   131.0   257.0   89.0    140.0
王五  33.0    46.0    149.0   203.0   121.0   123.0

所谓的聚合操作:平均数,方差,最大值,最小值……

df.mean(level=1, axis=1)
输出:
            语文  数学  英语
一班  张三  87.0    82.5    100.0
      李四    130.0   44.5    20.5
      王五    70.0    43.5    86.5
二班  张三  26.0    111.5   106.0
      李四    100.5   72.5    115.0
      王五    48.0    40.0    49.5

df.max(level=1, axis=1)
输出:
              语文    数学  英语
一班  张三  88.0    83.0    112.0
        李四  131.0   85.0    23.0
        王五  131.0   72.0    96.0
二班  张三  48.0    142.0   108.0
        李四  126.0   85.0    122.0
        王五  72.0    49.0    53.0

二.pandas拼接操作

# 传入行索引和列索引,返回一个DataFrame
def mk_df(inds, cols):
    data = {col: [col + str(i) for i in inds]  for col in cols}
    return DataFrame(data=data, index=inds, columns=cols)

mk_df([1,2,3,4], list('ABCD'))
输出:
    A   B   C   D
1   A1  B1  C1  D1
2   A2  B2  C2  D2
3   A3  B3  C3  D3
4   A4  B4  C4  D4
2.1 级联:pd.concat, pd.append
1) 简单级联

和np.concatenate一样,优先增加行数(默认axis=0)

df1 = mk_df([1,2,3,4], list('ABCD'))
df2 = mk_df([1,2,3,4], list('ABCD'))
输出:
    A   B   C   D
1   A1  B1  C1  D1
2   A2  B2  C2  D2
3   A3  B3  C3  D3
4   A4  B4  C4  D4

    A   B   C   D
1   A1  B1  C1  D1
2   A2  B2  C2  D2
3   A3  B3  C3  D3
4   A4  B4  C4  D4

pd.concat((df1,df2))
输出:
    A   B   C   D
1   A1  B1  C1  D1
2   A2  B2  C2  D2
3   A3  B3  C3  D3
4   A4  B4  C4  D4
1   A1  B1  C1  D1
2   A2  B2  C2  D2
3   A3  B3  C3  D3
4   A4  B4  C4  D4

#忽略原索引,重新进行索引
pd.concat((df1,df2), ignore_index=True)
输出:
    A   B   C   D
0   A1  B1  C1  D1
1   A2  B2  C2  D2
2   A3  B3  C3  D3
3   A4  B4  C4  D4
4   A1  B1  C1  D1
5   A2  B2  C2  D2
6   A3  B3  C3  D3
7   A4  B4  C4  D4

#可以通过设置axis来改变级联方向
pd.concat((df1,df2), axis=1, ignore_index=True)
输出:
    0   1   2   3   4   5   6   7
1   A1  B1  C1  D1  A1  B1  C1  D1
2   A2  B2  C2  D2  A2  B2  C2  D2
3   A3  B3  C3  D3  A3  B3  C3  D3
4   A4  B4  C4  D4  A4  B4  C4  D4

#或者使用多层索引 keys
#concat([x,y],keys=['x','y'])
# 通过keys可以给拼接起来的索引做一个说明.
pd.concat((df1,df2), keys=['df1', 'df2'])
输出:
        A   B   C   D
df1 1   A1  B1  C1  D1
    2   A2  B2  C2  D2
    3   A3  B3  C3  D3
    4   A4  B4  C4  D4
df2 1   A1  B1  C1  D1
    2   A2  B2  C2  D2
    3   A3  B3  C3  D3
    4   A4  B4  C4  D4
2) 不匹配级联

不匹配指的是级联的维度的索引不一致。例如纵向级联时列索引不一致,横向级联时行索引不一致

df3 = mk_df([3,4,5,6], list('CDEF'))
df3
输出:
    C   D   E   F
3   C3  D3  E3  F3
4   C4  D4  E4  F4
5   C5  D5  E5  F5
6   C6  D6  E6  F6

pd.concat((df1,df3), sort=True)
输出:
    A   B   C   D   E   F
1   A1  B1  C1  D1  NaN NaN
2   A2  B2  C2  D2  NaN NaN
3   A3  B3  C3  D3  NaN NaN
4   A4  B4  C4  D4  NaN NaN
3   NaN NaN C3  D3  E3  F3
4   NaN NaN C4  D4  E4  F4
5   NaN NaN C5  D5  E5  F5
6   NaN NaN C6  D6  E6  F6

pd.concat((df1,df3), sort=True, axis=1)
输出:
    A   B   C   D   C   D   E   F
1   A1  B1  C1  D1  NaN NaN NaN NaN
2   A2  B2  C2  D2  NaN NaN NaN NaN
3   A3  B3  C3  D3  C3  D3  E3  F3
4   A4  B4  C4  D4  C4  D4  E4  F4
5   NaN NaN NaN NaN C5  D5  E5  F5
6   NaN NaN NaN NaN C6  D6  E6  F6

有3种连接方式:

# 内连接,只有匹配的索引才显示
pd.concat((df1,df3), sort=True, axis=1, join='inner')
输出:
    A   B   C   D   C   D   E   F
3   A3  B3  C3  D3  C3  D3  E3  F3
4   A4  B4  C4  D4  C4  D4  E4  F4
# 相当于左外连接
pd.concat((df1,df3), sort=True, axis=1, join_axes=[df1.index])
输出:
    A   B   C   D   C   D   E   F
1   A1  B1  C1  D1  NaN NaN NaN NaN
2   A2  B2  C2  D2  NaN NaN NaN NaN
3   A3  B3  C3  D3  C3  D3  E3  F3
4   A4  B4  C4  D4  C4  D4  E4  F4

# 右外连接
pd.concat((df1,df3), sort=True, axis=1, join_axes=[df3.index])
输出:
    A   B   C   D   C   D   E   F
3   A3  B3  C3  D3  C3  D3  E3  F3
4   A4  B4  C4  D4  C4  D4  E4  F4
5   NaN NaN NaN NaN C5  D5  E5  F5
6   NaN NaN NaN NaN C6  D6  E6  F6
3) 使用append()函数添加

由于在后面级联的使用非常普遍,因此有一个函数append专门用于在后面添加

df1.append(df3)
2.2 合并:pd.merge

merge与concat的区别在于,merge需要依据某一共同的行或列来进行合并
使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。
注意每一列元素的顺序不要求一致

1) 一对一合并
df1 = DataFrame({'name':['张三','李四','Chales'],'id':[1,2,3],'age':[22,21,25]})

df2 = DataFrame({'sex':['男','男','女'],'id':[2,3,4],'group':['sale','search','service']})
display(df1,df2)
输出:
   name id  age
0   张三  1   22
1   李四  2   21
2   Chales 3 25

    sex id  group
0   男   2   sale
1   男   3   search
2   女   4   service

pd.merge(df1, df2)
输出:
    name    id  age sex group
0   李四  2   21  男   sale
1   Chales  3   25  男   search
2) 多对一合并
df1 = DataFrame({'name':['张三','李四','Chales'],'id':[1,2,2],'age':[22,21,25]})

df2 = DataFrame({'sex':['男','男','女'],'id':[2,3,4],'group':['sale','search','service']})
display(df1,df2)
输出:
   name id  age
0   张三  1   22
1   李四  2   21
2   Chales  2   25

  sex   id  group
0   男   2   sale
1   男   3   search
2   女   4   service
#merge,即可用pd.merge,也可以df1.merge
df1.merge(df2)
输出:
    name    id  age sex group
0   李四  2   21  男   sale
1   Chales  2   25  男   sale
3) 多对多合并
df1 = DataFrame({'name':['张三','李四','张三'],'salary':[10000,12000,20000],'age':[22,21,25]})

df2 = DataFrame({'sex':['男','男','女'],'name':['张三','张三','凡凡'],'group':['sale','search','service']})
display(df1,df2)
输出:
  name  salary  age
0   张三  10000   22
1   李四  12000   21
2   张三  20000   25

  sex   name    group
0   男   张三  sale
1   男   张三  search
2   女   凡凡  service

pd.merge(df1,df2)
输出:
  name  salary  age sex group
0   张三  10000   22  男   sale
1   张三  10000   22  男   search
2   张三  20000   25  男   sale
3   张三  20000   25  男   search
4) key的规范化
df1 = DataFrame({'name':['张三','李四','张三'],'salary':[10000,12000,20000],'age':[22,21,25]})

df2 = DataFrame({'age':[21,18,29],'name':['张三','张三','凡凡'],'group':['sale','search','service']})
display(df1,df2)
输出:
  name  salary  age
0   张三  10000   22
1   李四  12000   21
2   张三  20000   25

    age name    group
0   21  张三  sale
1   18  张三  search
2   29  凡凡  service

pd.merge(df1,df2, on='name', suffixes=['_df1', '_df2'])
输出:
  name  salary  age_df1 age_df2 group
0   张三  10000   22  21  sale
1   张三  10000   22  18  search
2   张三  20000   25  21  sale
3   张三  20000   25  18  search
df1 = DataFrame({'name':['张三','李四','张三'],'salary':[10000,12000,20000],'age':[22,21,25]})

df2 = DataFrame({'年龄':[21,18,29],'名字':['张三','张三','凡凡'],'group':['sale','search','service']})
display(df1,df2)
输出:
  name  salary  age
0   张三  10000   22
1   李四  12000   21
2   张三  20000   25

  年龄    名字  group
0   21  张三  sale
1   18  张三  search
2   29  凡凡  service

pd.merge(df1,df2, left_on='name', right_on='名字')
输出:
  name  salary  age 年龄  名字  group
0   张三  10000   22  21  张三  sale
1   张三  10000   22  18  张三  search
2   张三  20000   25  21  张三  sale
3   张三  20000   25  18  张三  search
df1 = DataFrame({'name':['张三','李四','张三'],'salary':[10000,12000,20000],'age':[22,21,25]})

df2 = DataFrame({'年龄':[21,18,29],'名字':['张三','张三','凡凡'],'group':['sale','search','service']},
                index = [22,21,25])
display(df1,df2)
输出:
  name  salary  age
0   张三  10000   22
1   李四  12000   21
2   张三  20000   25

    年龄  名字  group
22  21  张三  sale
21  18  张三  search
25  29  凡凡  service

pd.merge(df1, df2, left_on='age', right_index=True)
输出:
  name  salary  age 年龄  名字  group
0   张三  10000   22  21  张三  sale
1   李四  12000   21  18  张三  search
2   张三  20000   25  29  凡凡  service
5) 内合并与外合并
df1 = DataFrame({'name':['张三','李四','张三'],'salary':[10000,12000,20000],'age':[22,21,25]})

df2 = DataFrame({'age':[21,18,29],'名字':['张三','张三','凡凡'],'group':['sale','search','service']})
display(df1,df2)
输出:
    name    salary  age
0   张三  10000   22
1   李四  12000   21
2   张三  20000   25

    age 名字  group
0   21  张三  sale
1   18  张三  search
2   29  凡凡  service

pd.merge(df1,df2,left_on='name', right_on='名字') 
# 默认是内连接 ,即显示匹配的内容,不匹配的内容不显示.
输出:
  name  salary  age_x   age_y   名字  group
0   张三  10000   22  21  张三  sale
1   张三  10000   22  18  张三  search
2   张三  20000   25  21  张三  sale
3   张三  20000   25  18  张三  search
# 外合并会显示两张表的全部信息.
pd.merge(df1,df2,left_on='name', right_on='名字', how='outer') 
输出:
  name  salary  age_x   age_y   名字  group
0   张三  10000.0 22.0    21.0    张三  sale
1   张三  10000.0 22.0    18.0    张三  search
2   张三  20000.0 25.0    21.0    张三  sale
3   张三  20000.0 25.0    18.0    张三  search
4   李四  12000.0 21.0    NaN NaN NaN
5   NaN NaN NaN 29.0    凡凡  service
# left左合并只显示左侧表的所有信息.
pd.merge(df1,df2,left_on='name', right_on='名字', how='left') 
输出:
    name    salary  age_x   age_y   名字  group
0   张三  10000   22  21.0    张三  sale
1   张三  10000   22  18.0    张三  search
2   李四  12000   21  NaN NaN NaN
3   张三  20000   25  21.0    张三  sale
4   张三  20000   25  18.0    张三  search

# right 右合并,只显示右侧表的所有信息. 
pd.merge(df1,df2,left_on='name', right_on='名字', how='right') 
输出:

  name  salary  age_x   age_y   名字  group
0   张三  10000.0 22.0    21  张三  sale
1   张三  20000.0 25.0    21  张三  sale
2   张三  10000.0 22.0    18  张三  search
3   张三  20000.0 25.0    18  张三  search
4   NaN NaN NaN 29  凡凡  service
6) 列冲突的解决

当列冲突时,即有多个列名称相同时,需要使用on=来指定哪一个列作为key,配合suffixes指定冲突列名

#期中
df1 = DataFrame({'name':['张三','李四','张三'],'degree':[120,118,149],'age':[22,21,25]})

#期末考试
df2 = DataFrame({'degree':[99,97,129],'name':['张三','张三','凡凡'],'group':['sale','search','service']})
display(df1,df2)
输出:

  name  degree  age
0   张三  120 22
1   李四  118 21
2   张三  149 25

  degree    name    group
0   99  张三  sale
1   97  张三  search
2   129 凡凡  service

pd.merge(df1,df2,on='name', suffixes=['_df1','_df2'])
输出:
    name    degree_df1  age degree_df2  group
0   张三  120 22  99  sale
1   张三  120 22  97  search
2   张三  149 25  99  sale
3   张三  149 25  97  search

可以使用suffixes=自己指定后缀

上一篇下一篇

猜你喜欢

热点阅读