第五章 pandas入门
锣鼓喧天,鞭炮齐鸣,终于第五章了。
pandas支持大部分NumPy语言风格的数组计算,尤其是数组函数以及没有for循环的各种数据处理。尽管pandas采用了很多NumPy的代码风格,但最大的不同在于pandas是用来处理表格型或异质型数据的,而NumPy更适合处理同质型的数值数组数据
。
使用前先导入pandas模块:
>>>import pandas as pd
5.1 pandas数据结构介绍
pandas含有两个最常用的数据结构:Series
和DataFrame
。
5.1.1 Series
Series
是一种一维的数组型对象,它包含一个值序列
(与NumPy中的类型相似),并且包含了数据标签,称为索引
。
最简单的序列可以仅仅由一个数组组成:
>>>obj = pd.Series([5, 6, -7, -8])
>>>obj
0 5
1 6
2 -7
3 -8
dtype: int64
左边的是索引,右边的是值,当我们不为数据指定索引时,默认生成的是0到N-1(N为数据长度)。可以通过values
属性和index
属性分别获得Series
对象的值和索引:
#obj的值是一个一维数组
>>>obj.values
array([ 5, 6, -7, -8], dtype=int64)
#obj的索引与range(4)类似
>>>obj.index
RangeIndex(start=0, stop=4, step=1)
我们也可以创建一个索引序列
,为每个数据添加一个标签:
>>>obj2 = pd.Series([5, 6, -7, -8], index=['b', 'd', 'c', 'a'])
>>>obj2
b 5
d 6
c -7
a -8
dtype: int64
这时候,我们可以在选择数据时使用标签来进行索引
:
>>>obj2['a']
-8
>>>obj2[['a', 'b', 'c']]
a -8
b 5
c -7
dtype: int64
Series
数据同样可以使用NumPy函数或NumPy风格的操作,比如使用布尔值数组进行过滤,与标量相乘或者应用数学函数,这些操作仍然会保留索引值:
>>>obj2[obj2 > 0]
b 5
d 6
dtype: int64
>>>obj2 / 2
b 2.5
d 3.0
c -3.5
a -4.0
dtype: float64
>>>np.sum(obj2)
-4
>>>np.exp(obj2)
b 148.413159
d 403.428793
c 0.000912
a 0.000335
dtype: float64
从另一方面考虑Series
,其实它相当于是一个长度固定且有序的字典,它的索引值与数据值是按位置配对的,在可能使用字典的上下文中,也可以使用Series
:
>>>'b' in obj2
True
>>>'f' in obj2
False
同样的,如果我们的数据保存在字典中,可以用字典生成一个Series
:
>>>citys = {
'JiNan':1234, 'Taian':4352, 'QingDao':9172, 'YanTai':1329}
>>>obj3 = pd.Series(citys)
>>>obj3
JiNan 1234
Taian 4352
QingDao 9172
YanTai 1329
dtype: int64
当将一个字典传递给Series
时,产生的Series
的索引值是排序好的字典键,我们可以将字典的键按我们希望的顺序传递给构造函数
,从而使Series
的索引符合我们的预期:
>>>city = ['Taian', 'JiNan', 'QingDao', 'WeiHai']
>>>obj4 = pd.Series(citys, index=city)
>>>obj4
Taian 4352.0
JiNan 1234.0
QingDao 9172.0
WeiHai NaN
dtype: float64
上面的例子中,因为’WeiHai’没有出现在字典的键中,因此它在Series
中对应的是NaN
,这是pandas标记缺失值的方法。同时,因为’YanTai’不在city中,所以在Series
中它被排除了。
通常在数据分析中使用术语‘缺失
’或者‘NA’
表示缺失数据,在pandas中使用isnull
(是缺失)和notnull
(不是缺失)函数来检查缺失数据:
>>>pd.isnull(obj4)
Taian False
JiNan False
QingDao False
WeiHai True
dtype: bool
>>>pd.notnull(obj4)
Taian True
JiNan True
QingDao True
WeiHai False
dtype: bool
同时,isnull
和notnull
也是pandas的实例方法:
obj4.isnull()
Taian False
JiNan False
QingDao False
WeiHai True
dtype: bool
自动对齐索引
是Series
的一个非常有用的特性,类似于合并数据,但仅仅是将在两个Series
中都存在的数据对齐了,而
>>>obj3
JiNan 1234
Taian 4352
QingDao 9172
YanTai 1329
dtype: int64
>>>obj4
Taian 4352.0
JiNan 1234.0
QingDao 9172.0
WeiHai NaN
dtype: float64
>>>obj3 + obj4
JiNan 2468.0
QingDao 18344.0
Taian 8704.0
WeiHai NaN
YanTai NaN
dtype: float64
Series
对象自身和其索引都有name
属性。
>>>obj4.name = 'population'
>>>obj4.index.name = 'city'
>>>obj4
city
Taian 4352.0
JiNan 1234.0
QingDao 9172.0
WeiHai NaN
Name: population, dtype: float64
最后,Series
的索引可以通过按位置赋值的方式进行改变:
>>>obj
0 5
1 6
2 -7
3 -8
dtype: int64
>>>obj.index = ['z', 'x', 'c', 'v']
>>>obj
z 5
x 6
c -7
v -8
dtype: int64
5.1.2 DataFrame
`DataFrame是表示矩阵的数据表,它包含
已排序的序列集合``,每一列可以是不同的值类型(数值,字符串,布尔值等)。
DataFrame
既有行索引也有列索引,可以被视为一个共享相同索引的Series字典
。
DataFrame
的数据被存储为一个以上的二维块,而不是列表、字典或者奇特一维数组的集合。
有多种方式可以构建DataFrame
,最常用的方式是利用包含等长度列表或者NumPy数组的字典 来形成DataFrame
:
data = {
'city': ['Jinan', 'jinan', 'jinan', 'qingdao', 'qingdao', 'qingdao'],
'year': [2018, 2019, 2020, 2018, 2019, 2020],
'pop': ['1.5', '1.7', '3.6', '2.4', '2.0', '3.2']}
>>>frame = pd.DataFrame(data)
>>>frame
city year pop
0 Jinan 2018 1.5
1 jinan 2019 1.7
2 jinan 2020 3.6
3 qingdao 2018 2.4
4 qingdao 2019 2.0
5 qingdao 2020 3.2
产生的DataFrame
会自动为Series
分配索引并按排序的顺序排序,如果指定了顺序,则DataFrame
会按照指定顺序排列,如果传入的列不在字典中,则会出现缺失值:
>>>pd.DataFrame(data, columns=['year', 'city', 'pop', 'debt'])
year city pop debt
0 2018 Jinan 1.5 NaN
1 2019 jinan 1.7 NaN
2 2020 jinan 3.6 NaN
3 2018 qingdao 2.4 NaN
4 2019 qingdao 2.0 NaN
5 2020 qingdao 3.2 NaN
同样的,可以指定DataFrame
的索引值:
>>>frame2 = pd.DataFrame(data, columns=['year', 'city', 'pop', 'debt'],
index=['one', 'two', 'three', 'four', 'five', 'six'])
#‘行名’和‘列名’都有了,看上去像一个数据表了
>>>frame2
year city pop debt
one 2018 Jinan 1.5 NaN
two 2019 jinan 1.7 NaN
three 2020 jinan 3.6 NaN
four 2018 qingdao 2.4 NaN
five 2019 qingdao 2.0 NaN
six 2020 qingdao 3.2 NaN
DataFrame中的一列可以按字典型标
记或者属性
那样检索为Series
,要注意的是:frame2[colunm]
对于任意列名均有效,但是frame2.colunm
只有在列名是有效地pytho变量时有效。
>>>frame2['city']
one Jinan
two jinan
three jinan
four qingdao
five qingdao
six qingdao
Name: city, dtype: object
>>>frame2.year
one 2018
two 2019
three 2020
four 2018
five 2019
six 2020
Name: year, dtype: int64
DataFrame中
的行可以通过位置或特殊属性loc
进行选取,返回一行数据组成的Series
:
>>>frame2.loc['three']
year 2020
city jinan
pop 3.6
debt NaN
Name: three, dtype: object
当然,DataFrame
中列的引用是可以修改的,我们可以给空的debt列赋值为标量值或者值数组:
>>>frame2['debt'] = np.arange(6.)
>>>frame2
year city pop debt
one 2018 Jinan 1.5 0.0
two 2019 jinan 1.7 1.0
three 2020 jinan 3.6 2.0
four 2018 qingdao 2.4 3.0
five 2019 qingdao 2.0 4.0
six 2020 qingdao 3.2 5.0
当我们将列表或者数组赋值给一个列时,值的长度必读和DataFrame的长度匹配
,否则会产生异常。如果是将Series
赋值给一列,Series
的索引会按照DataFrame
的索引重新排列,并在空的地方填充缺失值:
>>>val = pd.Series([-1.2, -1.5, -6.6], index=['three', 'five', 'six'])
>>>frame2['debt'] = val
frame2
year city pop debt
one 2018 Jinan 1.5 NaN
two 2019 jinan 1.7 NaN
three 2020 jinan 3.6 -1.2
four 2018 qingdao 2.4 NaN
five 2019 qingdao 2.0 -1.5
six 2020 qingdao 3.2 -6.6
同样,如果被赋值的列并不存在,则会生成一个新的列
,我们增加一列,判断条件是city是否为沿海城市‘coastal city’:
>>>frame2['coastal city'] = frame2.city == 'qingdao'
>>>frame2
year city pop debt coastal city
one 2018 Jinan 1.5 NaN False
two 2019 jinan 1.7 NaN False
three 2020 jinan 3.6 -1.2 False
four 2018 qingdao 2.4 NaN True
five 2019 qingdao 2.0 -1.5 True
six 2020 qingdao 3.2 -6.6 True
在DataFrame
中,使用del
关键字可以像在字典中那样对其的列进行删除:
>>>del frame2['coastal city']
>>>frame2.columns
Index(['year', 'city', 'pop', 'debt'], dtype='object')
还有一种常用的数据形式是包含字典的嵌套字典,如果嵌套字典被赋值给DataFrame
,pandas会将字典的键作为列索引
,将内部字典的键作为行索引
:
>>>pop = {
'jinan':{
2018:2.2, 2019:2.3},'qingdao':{
2018:3.5, 2019:3.6, 2020:3.7}}
>>>frame3 = pd.DataFrame(pop)
>>>frame3
jinan qingdao
2018 2.2 3.5
2019 2.3 3.6
2020 NaN 3.7
在这里可以使用类似NumPy的语法对DataFrame
进行转置操作(行列互换):
>>>frame3.T
2018 2019 2020
jinan 2.2 2.3 NaN
qingdao 3.5 3.6 3.7
嵌套列表传入DataFrame
时,内部的字典的键会被联合、排序
成为行的索引,如果这时显式的指明索引的话,内部字典的键则不会被排序,如果传入的index
对象不在内部字典的键中,则会新建一个缺失值的行。
>>>pd.DataFrame(pop, index=[2021, 2020, 2019, 2018])
jinan qingdao
2021 NaN NaN
2020 NaN 3.7
2019 2.3 3.6
2018 2.2 3.5
与嵌套字典相同,包含Series
的字典也可以用来构造DataFrame
:
pdata = {
'jinan':frame3['jinan'][:-1], 'qingdao':frame3['qingdao'][:2]}
pd.DataFrame(pdata)
jinan qingdao
2018 2.2 3.5
2019 2.3 3.6
DataFrame
的索引和列也拥有name
属性,当被赋值时,这些name
属性也会被显示:
>>>frame3.index.name = 'year'
>>>frame3.columns.name = 'city'
#更像一个表格的样子了!
>>>frame3
city jinan qingdao
year
2018 2.2 3.5
2019 2.3 3.6
2020 NaN 3.7
最后,和Series
类似,DataFrame
的values
属性会将包含早在DataFrame
中数据以二维数组的形式返回,如果DataFrame
的列是不同的dtype
,那values
的dtype
会自动选择适合所有列的类型:
>>>frame2.values
array([[2018, 'Jinan', '1.5', nan],
[2019, 'jinan', '1.7', nan],
[2020, 'jinan', '3.6', -1.2],
[2018, 'qingdao', '2.4', nan],
[2019, 'qingdao', '2.0', -1.5],
[2020, 'qingdao', '3.2', -6.6]], dtype=object)
DataFrame构造函数的有效输入
类型 | 说明 |
---|---|
2D nadarry | 数据的矩阵,行和列的标签是可选参数 |
数组、列表和元组构成的字典 | 每个序列成为DataFrame的一列,要求所有序列必须长度相等 |
NumPy结构化/记录化数组 | 与构成数组的字典一致 |
Series构成的字典 | 每个值成为一列,每个Series的索引联合起来形成结果行的索引,也可以显示的传递索引 |
字典构成的字典 | 每一个内部字典成为一列,键联合起来形成结果的行索引 |
字典或者Series构成的列表 | 列表中的一个元素形成DataFrame的一行,字典的键或者Series索引联合起来形成DataFrame的列标签 |
列表或者元组构成的列表 | 与2D nadarry情况一致 |
其他DataFrame | 如果不显式的传递索引,则会使用原DataFrame的索引 |
NumPy MaskedArry | 与2D nadarry情况类似,但隐蔽值会在结果DataFrame中成为NA/缺失值 |
文章评论