索引与分层索引

接下来会用到的数据:

链接:https://pan.baidu.com/s/1RAqFCxWcl4OEChlRtSBooA
提取码:612s

索引

  • 查看索引:df.index
1
2
3
4
5
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.random.randint(60,100,size=(4,2)),index=["bob","amy","cheney","jerry"])

print(df1.index)
  • 指定索引:df.index = [,] 个数必须一致否则error
1
2
3
4
5
6
7
8
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.random.randint(60,100,size=(4,2)),index=["bob","amy","cheney","jerry"])

# print(df1.index)
print(df1)
df1.index=["amy","bob","jerry","cheney"]
print(df1)
1
2
3
4
5
6
7
8
9
10
         0   1
bob 99 61
amy 65 94
cheney 82 98
jerry 74 97
0 1
amy 99 61
bob 65 94
jerry 82 98
cheney 74 97
  • 重置索引:df.reindex([,]) 无需个数一致
1
2
3
4
5
6
7
8
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.random.randint(60,100,size=(4,2)),index=["bob","amy","cheney","jerry"])

print(df1)

s = df1.reindex(["bob","jerry","cheney"])
print(s)
1
2
3
4
5
6
7
8
9
         0   1
bob 92 72
amy 86 92
cheney 64 84
jerry 89 92
0 1
bob 92 72
jerry 89 92
cheney 64 84
  • 指定某一列作为index:df.set_index(“M”,drop=False) drop表示是否删除原M列
1
2
3
4
5
6
7
8
9
import pandas as pd
import numpy as np
df1 = pd.DataFrame(np.random.randint(60,100,size=(4,2)),index=["bob","amy","cheney","jerry"],columns=['M','N'])


print(df1)

df1.set_index('M',inplace=True)
print(df1)
1
2
3
4
5
6
7
8
9
10
11
         M   N
bob 62 69
amy 97 94
cheney 74 99
jerry 67 97
N
M
62 69
97 94
74 99
67 97
  • 返回index的唯一值:df.set_index(“M”).index.unique()
  • df.reset_index():将分层索引层级移动到列中
1
2
3
4
5
6
7
8
9
10
import pandas as pd
import numpy as np


df1 = pd.DataFrame(np.random.randint(60,100,size=(4,2)),index=["bob","amy","cheney","jerry"],columns=['M','N'])

df1.set_index('M',inplace=True)
print(df1)
df1.reset_index(inplace=True)
print(df1)
1
2
3
4
5
6
7
8
9
10
11
     N
M
95 76
94 88
92 62
99 98
M N
0 95 76
1 94 88
2 92 62
3 99 98

分层索引

分层索引是Pandas一个重要的特性,允许在一个轴上拥有多个所以层级。

1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd
import numpy as np

df = pd.DataFrame({
'a':range(7),
'b':range(7,0,-1),
'c':['one','one','one','two','two','two','two'],
'd':list("hjklmno")
})
print(df)
df.set_index(["c","d"],inplace=True)
print(df)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   a  b    c  d
0 0 7 one h
1 1 6 one j
2 2 5 one k
3 3 4 two l
4 4 3 two m
5 5 2 two n
6 6 1 two o
a b
c d
one h 0 7
j 1 6
k 2 5
two l 3 4
m 4 3
n 5 2
o 6 1

数据合并

数据合并也就是说将多个数据集拼接在一起,但是合并的方式主要分为:pandas.merge,pandas.concat,df.join。以下,我们来详细的介绍。

merge()

基于进行关联,是最常用的一种方法。函数为:

1
2
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
left_index=False, right_index=False)
  • left:拼接左侧的DataFrame对象;
  • right:拼接右侧的DataFrame对象;
  • on:待关联的同名列名,存在于左右两个DataFrame对象中;
  • how:连接方式,inner(默认),其他可选:outer、left、right ;左右连接 交集并集
  • left_on:左侧DataFarme中用作连接键的列名;
  • right_on:右侧DataFarme中用作连接键的列;
  • left_index:将左侧的行索引用作其连接键;
  • right_index:将右侧的行索引用作其连接键;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd


polls = {"sites": ["迈皋桥", "草场门", "浦口", "奥体中心", "仙林大学城"],
"AQI": [55, 75, 69, 74, 58],
"PM25": [30, 54, 47, 40, 27],
"SO2": [10, 15, 13, 17, 10]}

sites = {"names": ["迈皋桥", "草场门", "浦口", "奥体中心", "玄武湖"],
"regions": ["栖霞区", "鼓楼区", "浦口区", "建邺区", "玄武区"],
"weather": ["晴", "晴", "多云", "阴", "晴"]}

# 读取数据集,把字典格式转变为DataFrame格式
df_polls = pd.DataFrame(polls)
df_sites = pd.DataFrame(sites)

print(df_polls)
print(df_sites)
s = pd.merge(df_polls,df_sites,left_on='sites',right_on='names',how='left')#左连接
print(s)
  • 左连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   sites  AQI  PM25  SO2
0 迈皋桥 55 30 10
1 草场门 75 54 15
2 浦口 69 47 13
3 奥体中心 74 40 17
4 仙林大学城 58 27 10
names regions weather
0 迈皋桥 栖霞区 晴
1 草场门 鼓楼区 晴
2 浦口 浦口区 多云
3 奥体中心 建邺区 阴
4 玄武湖 玄武区 晴
sites AQI PM25 SO2 names regions weather
0 迈皋桥 55 30 10 迈皋桥 栖霞区 晴
1 草场门 75 54 15 草场门 鼓楼区 晴
2 浦口 69 47 13 浦口 浦口区 多云
3 奥体中心 74 40 17 奥体中心 建邺区 阴
4 仙林大学城 58 27 10 NaN NaN NaN
  • 内连接
1
2
3
4
5
  sites  AQI  PM25  SO2 names regions weather
0 迈皋桥 55 30 10 迈皋桥 栖霞区 晴
1 草场门 75 54 15 草场门 鼓楼区 晴
2 浦口 69 47 13 浦口 浦口区 多云
3 奥体中心 74 40 17 奥体中心 建邺区 阴
  • 外连接
1
2
3
4
5
6
   sites  AQI_x  PM25_x  SO2_x  AQI_y  PM25_y  SO2_y
0 迈皋桥 55 30 10 55 30 10
1 草场门 75 54 15 75 54 15
2 浦口 69 47 13 69 47 13
3 奥体中心 74 40 17 74 40 17
4 仙林大学城 58 27 10 58 27 10
  • 使用重复键进行连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pandas as pd

df_left = pd.DataFrame({"sites":["迈皋桥", "草场门", "浦口", "迈皋桥", "草场门", "浦口"],
"date":["2020-12-08", "2020-12-08", "2020-12-08", "2020-12-07", "2020-12-07", "2020-12-07"],
"AQI":[55, 75, 69, 45, 35, 53]})
# 定义右侧数据集
df_right = pd.DataFrame({"sites":["迈皋桥", "草场门", "迈皋桥", "草场门"],
"date":["2020-12-08", "2020-12-08", "2020-12-09", "2020-12-09"],
"weather":["晴", "晴", "多云", "阴"]})

print(df_left)
print(df_right)
x = pd.merge(df_left,df_right,on=['sites','date']) #只有两个字段都满足的时候才可以拼接
print(x)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  sites        date  AQI
0 迈皋桥 2020-12-08 55
1 草场门 2020-12-08 75
2 浦口 2020-12-08 69
3 迈皋桥 2020-12-07 45
4 草场门 2020-12-07 35
5 浦口 2020-12-07 53
sites date weather
0 迈皋桥 2020-12-08 晴
1 草场门 2020-12-08 晴
2 迈皋桥 2020-12-09 多云
3 草场门 2020-12-09 阴
sites date AQI weather
0 迈皋桥 2020-12-08 55 晴
1 草场门 2020-12-08 75 晴
1
2
3
4
5
6
7
8
9
10
11
12
import pandas as pd

sites_with_index = pd.DataFrame({"regions":["栖霞区", "鼓楼区", "浦口区", "建邺区", "玄武区"]},
index=["迈皋桥", "草场门", "浦口", "奥体中心", "玄武湖"])
df_left = pd.DataFrame({"sites":["迈皋桥", "草场门", "浦口", "迈皋桥", "草场门", "浦口"],
"date":["2020-12-08", "2020-12-08", "2020-12-08", "2020-12-07", "2020-12-07", "2020-12-07"],
"AQI":[55, 75, 69, 45, 35, 53]})

print(sites_with_index)
print(df_left)
s = pd.merge(df_left,sites_with_index,left_on='sites',right_index=True) #左site连接右index
print(s)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  sites        date  AQI
0 迈皋桥 2020-12-08 55
1 草场门 2020-12-08 75
2 浦口 2020-12-08 69
3 迈皋桥 2020-12-07 45
4 草场门 2020-12-07 35
5 浦口 2020-12-07 53
sites date AQI regions
0 迈皋桥 2020-12-08 55 栖霞区
3 迈皋桥 2020-12-07 45 栖霞区
1 草场门 2020-12-08 75 鼓楼区
4 草场门 2020-12-07 35 鼓楼区
2 浦口 2020-12-08 69 浦口区
5 浦口 2020-12-07 53 浦口区

join()

join方法是基于index连接dataframe。join连接方法有内连接,外连接,左连接和右连接,与merge一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pandas as pd

sites_with_index = pd.DataFrame({"regions":["栖霞区", "鼓楼区", "浦口区", "建邺区", "玄武区"]},
index=["迈皋桥", "草场门", "浦口", "奥体中心", "玄武湖"])

print(sites_with_index)

polls_with_index = pd.DataFrame({"AQI":[55, 75, 69, 74, 58],
"PM25":[30, 54, 47,40 ,27],
"SO2":[10, 15, 13, 17, 10]},
index=["迈皋桥", "草场门", "浦口", "奥体中心", "仙林大学城"])
print(polls_with_index)
s = polls_with_index.join(sites_with_index,how='inner')
print(s)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
     regions
迈皋桥 栖霞区
草场门 鼓楼区
浦口 浦口区
奥体中心 建邺区
玄武湖 玄武区
AQI PM25 SO2
迈皋桥 55 30 10
草场门 75 54 15
浦口 69 47 13
奥体中心 74 40 17
仙林大学城 58 27 10
AQI PM25 SO2 regions
迈皋桥 55 30 10 栖霞区
草场门 75 54 15 鼓楼区
浦口 69 47 13 浦口区
奥体中心 74 40 17 建邺区

concat()

另外一种常用的数据整合方法是concat,即我希望按照某种方式把两个规整的数据集进行拼接。拼接原型函数非常简单:

1
pd.concat(objs, axis=0, join='outer', keys=None)
  • objs:带拼接的数据集,通常以列表的形式传入;
  • join:可选inner、outer,含义同merge函数;
  • keys:定义新的分组索引,用来区分传入的数据集;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd
new_polls = {"sites": ["迈皋桥", "草场门", "浦口", "奥体中心", "仙林大学城"],
"AQI": [65, 85, 79, 78, 78],
"PM25": [50, 74, 67, 60, 47],
"O2": [20, 35, 23, 37, 15]}
polls = {"sites": ["迈皋桥", "草场门", "浦口", "奥体中心", "仙林大学城"],
"AQI": [55, 75, 69, 74, 58],
"PM25": [30, 54, 47, 40, 27],
"SO2": [10, 15, 13, 17, 10]}
df_polls = pd.DataFrame(polls)
df_polls_new = pd.DataFrame(new_polls)
print(df_polls)
print(df_polls_new)

s = pd.concat([df_polls_new,df_polls],join='inner') #默认axis = 0
print(s)

v = pd.concat([df_polls_new,df_polls],join='inner',axis=1) #指定axis = 1
print(v)

w = pd.concat([df_polls_new,df_polls],join='inner',keys=['2020-12-08','2020-12-09'])#指定数据集
print(w)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
   sites  AQI  PM25  SO2
0 迈皋桥 55 30 10
1 草场门 75 54 15
2 浦口 69 47 13
3 奥体中心 74 40 17
4 仙林大学城 58 27 10
sites AQI PM25 O2
0 迈皋桥 65 50 20
1 草场门 85 74 35
2 浦口 79 67 23
3 奥体中心 78 60 37
4 仙林大学城 78 47 15


sites AQI PM25
0 迈皋桥 65 50
1 草场门 85 74
2 浦口 79 67
3 奥体中心 78 60
4 仙林大学城 78 47
0 迈皋桥 55 30
1 草场门 75 54
2 浦口 69 47
3 奥体中心 74 40
4 仙林大学城 58 27


sites AQI PM25 O2 sites AQI PM25 SO2
0 迈皋桥 65 50 20 迈皋桥 55 30 10
1 草场门 85 74 35 草场门 75 54 15
2 浦口 79 67 23 浦口 69 47 13
3 奥体中心 78 60 37 奥体中心 74 40 17
4 仙林大学城 78 47 15 仙林大学城 58 27 10

sites AQI PM25
2020-12-08 0 迈皋桥 65 50
1 草场门 85 74
2 浦口 79 67
3 奥体中心 78 60
4 仙林大学城 78 47
2020-12-09 0 迈皋桥 55 30
1 草场门 75 54
2 浦口 69 47
3 奥体中心 74 40
4 仙林大学城 58 27

数据分组与聚合

数据包含在Series、DataFrame数据结构中,可以根据一个或多个键分离到各个组中。分组操作之后,一个函数就可以应用到各个组中,产生新的值。如下图则是简单的分组聚合过程。

pic

  • df.groupby(‘key’) key为指定分组的列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pandas as pd
import numpy as np

df1 = pd.DataFrame(
{
"names":["菲菲","小可爱","mia","牛哥","老王","mia","狼人","药水哥","药水哥"],
"classes":["一班","二班","三班"]*3,
"grades":np.random.randint(60,100,size=9)
}
)
print(df1)
print(df1.groupby('classes')['grades'].mean()) #以classes进行分组 返回的是一个groupby对象

print(df1.groupby(by=['classes','names']).mean())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  names classes  grades
0 菲菲 一班 64
1 小可爱 二班 93
2 mia 三班 85
3 牛哥 一班 82
4 老王 二班 60
5 mia 三班 61
6 狼人 一班 92
7 药水哥 二班 91
8 药水哥 三班 79
classes
一班 79.333333
三班 75.000000
二班 81.333333
Name: grades, dtype: float64

classes names
一班 牛哥 60.0
狼人 90.0
菲菲 92.0
三班 mia 65.5
药水哥 83.0
二班 小可爱 98.0
老王 74.0
药水哥 81.0

聚合函数如下:

jpg

自定义聚合函数

实现步骤:

  • 自定义函数
  • 分组后通过agg或者aggregate进行聚合
1
2
3
4
5
def classes_ptp(x):
return x.max()-x.min()

df1.groupby(by="classes")["grades"].agg(classes_ptp)
df1.groupby(by="classes")["grades"].aggregate(classes_ptp)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import pandas as pd
import numpy as np

df1 = pd.DataFrame(
{
"names":["菲菲","小可爱","mia","牛哥","老王","mia","狼人","药水哥","药水哥"],
"classes":["一班","二班","三班"]*3,
"grades":np.random.randint(60,100,size=9)
}
)

def ptp(x):
return x.max() - x.min()

print(df1.groupby('classes')['grades'].agg(ptp))

agg = [ptp,np.max,np.min]
print(df1.groupby('classes')['grades'].agg(agg))
1
2
3
4
5
6
7
8
9
10
11
classes
一班 15
三班 17
二班 33
Name: grades, dtype: int32

ptp amax amin
classes
一班 21 83 62
三班 23 91 68
二班 28 91 63

分组块上应用函数

实现步骤:

  • 定义函数
  • 通过apply方法将函数应用到分组后的数组
1
2
3
4
def sort_df(df):
return df.sort_values(by="grades")

df1.groupby(by="classes").apply(sort_df)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd
import numpy as np

df1 = pd.DataFrame(
{
"names":["菲菲","小可爱","mia","牛哥","老王","mia","狼人","药水哥","药水哥"],
"classes":["一班","二班","三班"]*3,
"grades":np.random.randint(60,100,size=9)
}
)

def sort_value(df):
return df.sort_values(by='grades',ascending=False)
df2 = df1.groupby('classes').apply(sort_value)
print(df2)
1
2
3
4
5
6
7
8
9
10
11
          names classes  grades
classes
一班 6 狼人 一班 86
3 牛哥 一班 75
0 菲菲 一班 65
三班 2 mia 三班 79
5 mia 三班 79
8 药水哥 三班 66
二班 7 药水哥 二班 84
1 小可爱 二班 73
4 老王 二班 67

除了以上分组形式,还可以通过字典、series、函数进行分组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd
import numpy as np

df2 = pd.DataFrame(
np.random.randint(60,100,size=(5,3)),
index=["菲菲","小可爱","mia","牛哥","老王"],
columns=["语文","数学","英语"]
)
g_dic = {
'菲菲':'一班',
'mia':'二班',
'小可爱':'一班',
'牛哥':'三班'
}
dd = df2.groupby(g_dic).mean()
print(dd)
1
2
3
4
      语文    数学    英语
一班 74.5 74.5 89.0
三班 82.0 73.0 75.0
二班 94.0 61.0 81.0
1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd
import numpy as np

df1 = pd.DataFrame(
{
"names":["菲菲","小可爱","mia","牛哥","老王","mia","狼人","药水哥","药水哥"],
"classes":["一班","二班","三班"]*3,
"grades":np.random.randint(60,100,size=9)
}
)
df1.set_index('names',inplace=True)
dd = df1.groupby(by=len).count() #以index长度作为分组对象
print(dd)
1
2
3
   classes  grades
2 4 4
3 5 5