1、Pandas-Series-and-DataFrame

Pandas的数据结构

1
2
3
4
# 导入数据分析三剑客
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

1. Series

  • Series是一种类似与一维数组的对象,由下面两部分组成:
    • values:一组数组(ndarray类型)
    • index:相关的数据索引标签

1.1 Series的创建

  • 两种创建方式:
  • (1)由列表或numpy数组创建
    • 默认索引为0到N-1的整数类型索引
1
2
3
4
5
6
7
8
9
10
11
In [1]: import pandas as pd

In [2]: s = pd.Series([x for x in range(1,5)])

In [3]: s
Out[3]:
0 1
1 2
2 3
3 4
dtype: int64
1
2
3
4
5
6
7
8
9
10
# 通过index指定索引
In [4]: s.index = list('abcd')

In [5]: s
Out[5]:
a 1
b 2
c 3
d 4
dtype: int64
1
2
3
4
5
6
7
8
9
In [6]: s1 = pd.Series(['zhangsan','lisi','wangwu','zhaoliu'],index=list('abcd'))

In [7]: s1
Out[7]:
a zhangsan
b lisi
c wangwu
d zhaoliu
dtype: object
1
2
3
4
5
6
7
8
9
10
11
12
13
#Series只能存放一维数据
In [9]: import numpy as np

In [10]: s2 = pd.Series(np.random.randint(0,10,size=5),index=list('abcde'))

In [11]: s2
Out[11]:
a 2
b 7
c 9
d 2
e 7
dtype: int32
  • (2)由字典创建
1
2
3
4
5
6
7
8
9
In [12]: s3 = pd.Series({'zhangsan':23,'lisi':22,'wangwu':24,'zhaoliu':21})

In [13]: s3
Out[13]:
zhangsan 23
lisi 22
wangwu 24
zhaoliu 21
dtype: int64

1.2 Series的索引和切片

  • 可以使用中括号取单个索引(此时返回的是元素类型),或者中括号里面一个列表取多个索引(此时返回的仍然是一个Series类型)。
  • 显示索引:
    • 使用index中的元素作为索引值
    • 使用.loc[] 推荐
  • 注意,此时是闭区间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
In [14]: s4 = pd.Series(np.random.random(10),index=list('abcdefghij'))

In [15]: s4
Out[15]:
a 0.901201
b 0.026940
c 0.596118
d 0.732741
e 0.050395
f 0.550084
g 0.390146
h 0.592242
i 0.724512
j 0.585712
dtype: float64
1
2
3
#使用index中的元素索引
In [16]: s4['a']
Out[16]: 0.9012012103671466
1
2
3
4
5
6
7
8
#显示索引
In [17]: s4.loc['a':'d']
Out[17]:
a 0.901201
b 0.026940
c 0.596118
d 0.732741
dtype: float64
1
2
3
#通过Series默认索引序号也可
In [18]: s4[1]
Out[18]: 0.026939806463515903
  • 隐式索引:
    • 使用整数作为索引值
    • 使用.ilco[]推荐
  • 注意:此时是半开区间
1
2
3
4
5
6
7
In [19]: s4.iloc[0:4]
Out[19]:
a 0.901201
b 0.026940
c 0.596118
d 0.732741
dtype: float64

1.3 Series的基本概念

  • 可以把Series看成一个定长的有序字典
  • 可以通过shape,size,index,values等得到series的属性
1
2
3
4
5
6
7
#Series.values就是一个ndarray
In [20]: display(s4.shape,s4.size,s4.index,s4.values)
(10,)
10
Index(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'], dtype='object')
array([0.90120121, 0.02693981, 0.59611828, 0.73274146, 0.05039477,
0.55008443, 0.39014647, 0.59224205, 0.72451164, 0.58571199])
  • 可以通过head(),tail()快速查看Series对象的样式
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
#查看Series前几行
In [21]: import numpy as np

In [22]: import pandas as pd

In [23]: df = pd.read_excel('D:\myProject\Python\Jupyter\pydata\people.xlsx')

In [24]: type(df)
Out[24]: pandas.core.frame.DataFrame
#通过列索引获得age数据
In [25]: age = df['age']

In [26]: type(age)
Out[26]: pandas.core.series.Series
#利用head()获得前几行数据
In [27]: age.head(5)
Out[27]:
0 43
1 29
2 25
3 50
4 48
Name: age, dtype: int64
#利用tail()获得后几行数据
In [28]: age.tail(5)
Out[28]:
495 24
496 30
497 57
498 39
499 42
Name: age, dtype: int64
  • 可以使用pd.isnull(),pd.notnull(),或自带isnull()notnull()函数检测缺失数据
1
2
3
4
5
6
7
8
9
In [29]: s5 = pd.Series([1,2,None,np.nan])

In [30]: s5
Out[30]:
0 1.0
1 2.0
2 NaN
3 NaN
dtype: float64
1
2
3
4
5
6
7
8
#检测缺失数据
In [31]: s5.isnull()
Out[31]:
0 False
1 False
2 True
3 True
dtype: bool
1
2
3
4
5
6
7
8
9
In [32]: s6 = s5.notnull()

In [33]: s6
Out[33]:
0 True
1 True
2 False
3 False
dtype: bool
1
2
3
4
5
6
#notnull相当于过滤,将为false的过滤掉
In [34]: s5[s6]
Out[34]:
0 1.0
1 2.0
dtype: float64
  • Series对象本身及其实例都有一个name属性
1
2
3
4
5
6
7
8
9
10
#name在DateFrame中用于区分,在DateFrame中是指其列名
In [36]: s5.name = 'Test'

In [37]: s5
Out[37]:
0 1.0
1 2.0
2 NaN
3 NaN
Name: Test, dtype: float64
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
In [38]: df
Out[38]:
name city age height weight
0 危琳 兴城市 43 164 156
1 颛春梅 潜江县 29 181 114
2 韶璐 深圳县 25 170 149
3 父想 大冶县 50 172 138
4 逄建国 彬县 48 169 110
5 车静 宁德县 56 177 119
6 俟玉梅 莉县 47 176 125
7 岳博 通辽县 51 162 118
8 璩柳 建县 31 189 154
9 空龙 西宁县 23 179 150
10 濮婷 文县 50 172 121
11 勾婷 武汉县 50 184 141
12 苍萍 凯市 27 174 120
13 邰帆 上海县 45 174 151
14 东红 华县 30 166 123
15 孙文 华县 50 169 110
16 松飞 华县 57 174 116
17 水琳 阳县 36 163 142
18 简平 辽阳市 57 181 110
19 慕雪 海口市 22 177 150
20 籍凯 杰县 52 175 133
21 阎洋 敏县 46 180 107
22 良文 六安县 59 169 114
23 师金凤 宁市 20 173 149
24 马婷婷 晶县 40 174 145
25 红莉 昆明市 49 175 106
26 弘玉英 郑州县 54 160 117
27 包芳 呼和浩特县 22 188 136
28 茹秀兰 贵阳县 39 168 136
29 充英 红市 35 189 125
.. ... ... ... ... ...
470 于雪梅 晨市 47 189 141
471 宇柳 沈阳县 24 164 140
472 孙宁 哈尔滨县 23 180 132
473 柯龙 鹏县 57 171 158
474 宰红霞 西安县 34 183 154
475 夏玉英 邯郸县 58 176 103
476 郎杰 合山市 50 165 112
477 蒯玉 南昌县 51 167 148
478 虞勇 合肥市 53 160 144
479 习雷 静市 40 163 132
480 邢建 超市 40 182 105
481 燕华 玉珍县 50 161 146
482 伯彬 凯市 47 177 129
483 尹婷婷 太原县 52 168 144
484 粱建军 北京县 55 179 134
485 后娜 飞县 21 180 148
486 西亮 英县 45 173 136
487 荆淑珍 兴安盟市 52 188 118
488 驷淑华 嘉禾市 57 166 133
489 孙萍 昆明县 57 160 103
490 邬秀兰 澳门市 45 176 135
491 璩林 淮安县 42 166 101
492 葛英 北京县 28 183 139
493 农瑞 健市 53 171 139
494 安雷 秀梅县 49 184 158
495 涂玲 兵县 24 168 124
496 于建平 洋市 30 175 137
497 彭凤英 桂花市 57 170 119
498 干阳 帅县 39 173 149
499 雷俊 柳州县 42 175 116

[500 rows x 5 columns]
1
2
3
4
5
6
7
8
In [39]: df.head(5)
Out[39]:
name city age height weight
0 危琳 兴城市 43 164 156
1 颛春梅 潜江县 29 181 114
2 韶璐 深圳县 25 170 149
3 父想 大冶县 50 172 138
4 逄建国 彬县 48 169 110
  • Series之间进行运算
    • 在Series中自动对齐不同索引的数据
    • 如果索引不对应,则补NaN
1
2
3
In [40]: s1 = pd.Series([2,4,6,8],index=['a','b','c','d'])

In [41]: s2 = pd.Series([1,3,5,7],index=['a','b','e','f'])
1
2
3
4
5
6
7
8
9
10
#Series相加时,是将其索引值相同的进行相加
In [42]: s1 + s2
Out[42]:
a 3.0
b 7.0
c NaN
d NaN
e NaN
f NaN
dtype: float64
  • 注意:想要保留所有的index,则需要使用.add()函数
1
2
3
4
5
6
7
8
9
In [43]: s1.add(s2,fill_value=0)
Out[43]:
a 3.0
b 7.0
c 6.0
d 8.0
e 5.0
f 7.0
dtype: float64

2. DataFrame

  • DataFrame是一个【表格型】的数据结构,可以看做是【由Series组成的字典】(共用同一索引)。DataFrame由按一定顺序排列的多列数据组成。设计初衷是将Series的使用场景从一维拓展到多维。DataFrame既有行索引,也有列索引。
    • 行索引:index
    • 列索引:columns
    • 值:values(numpy的二维数组)
1
2
3
4
5
6
7
8
In [101]: df.head(5)
Out[101]:
name city age height weight
0 危琳 兴城市 43 164 156
1 颛春梅 潜江县 29 181 114
2 韶璐 深圳县 25 170 149
3 父想 大冶县 50 172 138
4 逄建国 彬县 48 169 110
1
2
3
4
5
6
7
8
9
10
11
12
13
14
In [44]: display(df.index,df.columns,df.values,df.values.shape)
Int64Index([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
...
490, 491, 492, 493, 494, 495, 496, 497, 498, 499],
dtype='int64', length=500)
Index(['name', 'city', 'age', 'height', 'weight'], dtype='object')
array([['危琳', '兴城市', 43, 164, 156],
['颛春梅', '潜江县', 29, 181, 114],
['韶璐', '深圳县', 25, 170, 149],
...,
['彭凤英', '桂花市', 57, 170, 119],
['干阳', '帅县', 39, 173, 149],
['雷俊', '柳州县', 42, 175, 116]], dtype=object)
(500, 5)

2.1 DataFrame的创建

  • 最常用的方法是传递一个字典来创建。DataFrame以字典的键作为每一【列】的名称,以字典的值(一个数组)作为每一列。此外,DataFrame会自动加上每一行的索引(和Series一样)。
  • 同Series一样,若传入的列与字典的键不匹配,则相应的值为NaN。
1
2
3
4
5
6
7
8
9
10
11
12
In [48]: df = pd.DataFrame({'name':['zhangsan','lisi','wangwu','zhaoliu'],
...: 'age': np.random.randint(20,26,size=4),
...: 'sex':['男','女','女','男']},index= list('ABCD'),
...: columns = ['name','age','sex'])

In [49]: df
Out[49]:
name age sex
A zhangsan 25
B lisi 20
C wangwu 24
D zhaoliu 25
  • DataFrame的属性:values、columns、index、shape
1
2
In [50]: df.shape
Out[50]: (4, 3)
1
2
3
4
5
6
7
#练习
根据以下考试成绩表,创建一个DataFrame,命名为df:
张三 李四
语文 150 0
数学 150 0
英语 150 0
理综 300 0
1
2
3
4
5
6
7
8
9
10
In [51]: df = pd.DataFrame({'张三':[150,150,150,300],'李四':[0,0,0,0]},index=['语文','数学','英语',
...: '理综'])

In [52]: df
Out[52]:
张三 李四
语文 150 0
数学 150 0
英语 150 0
理综 300 0

2.2 DataFrame的索引

  • 1.对列进行索引
    • 通过类似字典的方式
    • 通过属性的方式
  • 可以将DataFrame的列获取为一个Series。返回的Series拥有原DataFrame相同的索引,且name属性也已经设置好了,就是相应的列名。
1
2
3
4
5
6
7
8
9
10
11
12
13
In [53]: df = pd.DataFrame({'name':['zhangsan','lisi','wangwu','zhaoliu'],
...: 'age': np.random.randint(20,26,size=4),
...: 'sex':['男','女','女','男']},index= list('ABCD'),
...: columns = ['name','age','sex'])
...:

In [54]: df
Out[54]:
name age sex
A zhangsan 20
B lisi 25
C wangwu 22
D zhaoliu 21
1
2
3
4
5
6
7
8
9
10
#t通过字典的方式对列进行索引,返回一个Series
In [55]: name = df['name']

In [56]: display(type(name),name)
pandas.core.series.Series
A zhangsan
B lisi
C wangwu
D zhaoliu
Name: name, dtype: object
1
2
3
4
5
6
7
8
9
10
#通过属性的方式对列进行索引,返回一个Series
In [57]: age = df.age

In [58]: display(type(age),age)
pandas.core.series.Series
A 20
B 25
C 22
D 21
Name: age, dtype: int32
  • 2.对行进行索引
    • 使用.ix[]来进行行索引
    • 使用.loc[]加index来进行行索引
    • 使用.iloc[]加整数来进行行索引
  • 同样返回一个Series,index为原来的columns。
1
2
3
4
5
6
7
#对行的检索,返回值还是Series
In [59]: df.loc['A']
Out[59]:
name zhangsan
age 20
sex 男
Name: A, dtype: object
1
2
3
4
5
6
#检索多行返回的数据是DataFrame
In [61]: df.loc[['A','B']]
Out[61]:
name age sex
A zhangsan 20
B lisi 25
1
2
3
4
5
6
7
#对行进行切片索引
In [62]: df.loc['A':'C']
Out[62]:
name age sex
A zhangsan 20
B lisi 25
C wangwu 22
  • 3.对元素索引的方法
    • 使用列索引
    • 使用行索引(iloc[3,1]相当于两个参数;iloc[[3,3]]里面的[3,3]看做一个参数)
    • 使用values属性(二维numpy数组)
1
2
3
#使用列索引
In [63]: df['name']['B']
Out[63]: 'lisi'
1
2
3
4
5
6
7
8
9
#使用行索引
In [64]: df.loc['C']['age']
Out[64]: 22

In [65]: df.iloc[3,0]
Out[65]: 'zhaoliu'

In [66]: df.values[0,1]
Out[66]: 20

【注意】直接使用中括号时:

  • 索引表示的是列索引
  • 切片表示的是行切片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
In [67]: df['name']
Out[67]:
A zhangsan
B lisi
C wangwu
D zhaoliu
Name: name, dtype: object

#对列使用切片,只显示列名
In [68]: df['name':'sex']
Out[68]:
Empty DataFrame
Columns: [name, age, sex]
Index: []

In [69]: df['A':'C']
Out[69]:
name age sex
A zhangsan 20
B lisi 25
C wangwu 22

3. DataFrame的运算

3.1 DataFrame之间的运算

  • 同Series一样:
    • 在运算中自动对齐不同索引的数据
    • 如果索引不对应,则补NaN
1
2
3
4
5
6
7
8
9
10
11
12
13
#创建DataFrame df1 不同人员的各科目成绩,月考一
In [70]: df1 = pd.DataFrame(np.random.randint(0,150,size=(4,4)),
...: index=['zhangsan','lisi','wangwu','zhaoliu'],
...: columns=['语文','数学','英语','理综'])
...:

In [71]: df1
Out[71]:
语文 数学 英语 理综
zhangsan 138 101 26 146
lisi 39 45 26 59
wangwu 143 75 10 98
zhaoliu 117 7 19 8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#创建DataFrame df2 不同人员的各科目成绩,月考二
#有新生转入
In [72]: df2 = pd.DataFrame(np.random.randint(0,150,size=(5,4)),
...: index=['zhangsan','lisi','wangwu','zhaoliu','tianqi'],
...: columns=['语文','数学','英语','理综'])
...:

In [73]: df2
Out[73]:
语文 数学 英语 理综
zhangsan 51 16 3 147
lisi 19 22 70 85
wangwu 83 106 79 101
zhaoliu 132 9 135 29
tianqi 106 120 2 89
1
2
3
4
5
6
7
8
In [75]: df1 + df2
Out[75]:
语文 数学 英语 理综
lisi 58.0 67.0 96.0 144.0
tianqi NaN NaN NaN NaN
wangwu 226.0 181.0 89.0 199.0
zhangsan 189.0 117.0 29.0 293.0
zhaoliu 249.0 16.0 154.0 37.0
1
2
3
4
5
6
7
8
9
10
In [76]: df3 = df1.add(df2,fill_value=0)

In [77]: df3
Out[77]:
语文 数学 英语 理综
lisi 58.0 67.0 96.0 144.0
tianqi 106.0 120.0 2.0 89.0
wangwu 226.0 181.0 89.0 199.0
zhangsan 189.0 117.0 29.0 293.0
zhaoliu 249.0 16.0 154.0 37.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
In [78]: df4 = pd.DataFrame(np.random.randint(0,150,size=(5,3)),
...: index=['zhangsan','lisi','wangwu','zhaoliu','tianqi'],
...: columns=['语文','数学','英语'])
...:

In [79]: df4
Out[79]:
语文 数学 英语
zhangsan 33 134 71
lisi 144 0 28
wangwu 15 140 72
zhaoliu 5 140 20
tianqi 46 36 40

In [80]: df1.add(df4)
Out[80]:
数学 理综 英语 语文
lisi 45.0 NaN 54.0 183.0
tianqi NaN NaN NaN NaN
wangwu 215.0 NaN 82.0 158.0
zhangsan 235.0 NaN 97.0 171.0
zhaoliu 147.0 NaN 39.0 122.0

3.2 Series与DataFrame之间的运算

  • 使用Python操作符:以行位单位操作(参数必须是行),对所有行都有效。(类似与numpy中二维数组与一维数组的运算,但可能出现NaN)
  • 使用pandas操作函数:
    • axis=0:以列为单位操作(参数必须是列),对所有列都有效。
    • axis=1:以行位单位操作(参数必须是行),对所有行都有效。
1
2
3
4
5
6
7
8
9
10
In [81]: s1 = df3['语文']

In [82]: s1
Out[82]:
lisi 58.0
tianqi 106.0
wangwu 226.0
zhangsan 189.0
zhaoliu 249.0
Name: 语文, dtype: float64
1
2
3
4
5
6
7
8
In [83]: df3 + s1
Out[83]:
lisi tianqi wangwu zhangsan zhaoliu 数学 理综 英语 语文
lisi NaN NaN NaN NaN NaN NaN NaN NaN NaN
tianqi NaN NaN NaN NaN NaN NaN NaN NaN NaN
wangwu NaN NaN NaN NaN NaN NaN NaN NaN NaN
zhangsan NaN NaN NaN NaN NaN NaN NaN NaN NaN
zhaoliu NaN NaN NaN NaN NaN NaN NaN NaN NaN
1
2
3
In [84]: display(df3.columns,s1.index)
Index(['语文', '数学', '英语', '理综'], dtype='object')
Index(['lisi', 'tianqi', 'wangwu', 'zhangsan', 'zhaoliu'], dtype='object')
1
2
3
4
5
6
7
8
9
In [85]: s2 = df3.loc['lisi']

In [86]: s2
Out[86]:
语文 58.0
数学 67.0
英语 96.0
理综 144.0
Name: lisi, dtype: float64
1
2
3
4
5
6
7
8
In [87]: df3 + s2
Out[87]:
语文 数学 英语 理综
lisi 116.0 134.0 192.0 288.0
tianqi 164.0 187.0 98.0 233.0
wangwu 284.0 248.0 185.0 343.0
zhangsan 247.0 184.0 125.0 437.0
zhaoliu 307.0 83.0 250.0 181.0
1
2
3
In [88]: display(df3.columns,s2.index)
Index(['语文', '数学', '英语', '理综'], dtype='object')
Index(['语文', '数学', '英语', '理综'], dtype='object')
1
2
axis=0:以列为单位操作(参数必须是列),对所有列都有效。
axis=1:以行位单位操作(参数必须是行),对所有行都有效。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
In [89]: ss = df3.语文

In [90]: display(df3,ss)
语文 数学 英语 理综
lisi 58.0 67.0 96.0 144.0
tianqi 106.0 120.0 2.0 89.0
wangwu 226.0 181.0 89.0 199.0
zhangsan 189.0 117.0 29.0 293.0
zhaoliu 249.0 16.0 154.0 37.0
lisi 58.0
tianqi 106.0
wangwu 226.0
zhangsan 189.0
zhaoliu 249.0
Name: 语文, dtype: float64
1
2
3
4
5
6
7
8
9
10
11
12
13
#index/0代表行索引
In [91]: n1 = df3.add(ss,axis='index')

In [92]: n2 = df3.add(ss,axis=0)

In [93]: n2
Out[93]:
语文 数学 英语 理综
lisi 116.0 125.0 154.0 202.0
tianqi 212.0 226.0 108.0 195.0
wangwu 452.0 407.0 315.0 425.0
zhangsan 378.0 306.0 218.0 482.0
zhaoliu 498.0 265.0 403.0 286.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
In [94]: ss1 = df3.loc['zhangsan']

In [95]: display(df3,ss1)
语文 数学 英语 理综
lisi 58.0 67.0 96.0 144.0
tianqi 106.0 120.0 2.0 89.0
wangwu 226.0 181.0 89.0 199.0
zhangsan 189.0 117.0 29.0 293.0
zhaoliu 249.0 16.0 154.0 37.0
语文 189.0
数学 117.0
英语 29.0
理综 293.0
Name: zhangsan, dtype: float64
1
2
3
4
5
6
7
8
9
10
In [96]: n3 = df3.add(ss1,axis=1)

In [97]: n3
Out[97]:
语文 数学 英语 理综
lisi 247.0 184.0 125.0 437.0
tianqi 295.0 237.0 31.0 382.0
wangwu 415.0 298.0 118.0 492.0
zhangsan 378.0 234.0 58.0 586.0
zhaoliu 438.0 133.0 183.0 330.0