pandas的数据结构介绍

纵饮孤独 提交于 2019-12-03 08:57:00

本文目录概要为:Series,DataFrame,索引对象。

引用约定:

from pandas import Series,DataFrame
import pandas as pd

因此,只要你在代码中看到pd,就得想到这是pandas。因为Series和DataFrame用的次数非常多,所以将其引入本地命名空间会更方便。

要使用pandas,你首先就得熟悉它的两个主要数据结构:Series和DataFrame。虽然它们并不能解决所有问题,但它们为大多数应用提供了一种可靠的、易于使用的基础。

Series

Series是一种类似于一维数组的对象,它由一组数据(各种Numpy数据类型)以及一组与之相关的数据标签(即索引)组成。仅由一组数据即可产生最简单的Series

>>> obj=Series([4,7,-5,3])
>>> obj
0    4
1    7
2   -5
3    3
dtype: int64

Series的字符串表现形式为:索引在左边,值在右边。由于我们没有为数据指定索引,于是会自动创建一个0到N-1(N为数据的长度)的整数型索引。你可以通过Series的values和index属性获取其数组表示形式和索引对象:

>>> obj.values
array([ 4,  7, -5,  3])
>>> obj.index
RangeIndex(start=0, stop=4, step=1)

通常,我们希望所创建的Series带有一个可以对各个数据点进行标记的索引

>>> obj2=Series([4,7,-5,3],index=['d','b','a','c'])
>>> obj2
d    4
b    7
a   -5
c    3
dtype: int64
>>> obj2.index
Index(['d', 'b', 'a', 'c'], dtype='object')

Series对象本身及其索引都有一个name属性,该属性跟pandas其他的关键功能关系非常密切。
Series的索引也可以通过赋值的方式就地修改:

>>> obj2.name='obj2Name'
>>> obj2.index=['one','two','three','four']
>>> obj2.index.name='obj2IndexName'
>>> obj2
obj2IndexName
one      4
two      7
three   -5
four     3
Name: obj2Name, dtype: int64

与普通的Numpy数组相比,你可以通过索引的方式选取Series中的单个或一组值

Numpy数组运算(如根据布尔型数组进行过滤、标量乘法、应用数学函数等)都会保留索引和值之间的链接。
>>> obj2['one']
4
>>> obj2[['two','one']]
obj2IndexName
two    7
one    4
Name: obj2Name, dtype: int64
>>> obj2[['two','one']]=6
>>> obj2
obj2IndexName
one      6
two      6
three   -5
four     3
Name: obj2Name, dtype: int64

还可以将Series看做是一个定长的有序字典,因为它是索引值到数据值的一个映射。它可以用在许多原本需要字典参数的函数

>>> 'one' in obj2
True

如果数据被存放在一个Python字典中,也可以直接通过这个字典来创建Series
传入字典,则结果Series的索引就是原字典的键(有序排列)

>>> sdata={'Ohio':35000,'Texas':72000,'Oregon':16000,'Utah':5000}
>>> obj3=Series(sdata)
>>> obj3
Ohio      35000
Oregon    16000
Texas     72000
Utah       5000
dtype: int64

如果索引列所对应的数据找不到,其结果就为NaN(即“非数字”not a number,在pandas中,它用于表示缺失或NA值 not available)。

>>> states=['California','Ohio','Oregon','Texas']
>>> obj4=Series(sdata,index=states)
>>> obj4
California        NaN
Ohio          35000.0
Oregon        16000.0
Texas         72000.0
dtype: float64

pandas的isnull和notnull函数可用于检测缺失数据:

>>> obj4.isnull()
California     True
Ohio          False
Oregon        False
Texas         False
dtype: bool
>>> pd.notnull(obj4)
California    False
Ohio           True
Oregon         True
Texas          True
dtype: bool

对于许多应用而言,Series最重要的一个功能是:它在算术运算中会自动对齐不同索引的数据

>>> obj3
Ohio      35000
Oregon    16000
Texas     72000
Utah       5000
dtype: int64
>>> obj4
California        NaN
Ohio          35000.0
Oregon        16000.0
Texas         72000.0
dtype: float64
>>> obj3+obj4
California         NaN
Ohio           70000.0
Oregon         32000.0
Texas         144000.0
Utah               NaN
dtype: float64

DataFrame

DataFrame是一个表格型的数据结构,它含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔值等)。DataFrame既有行索引也有列索引,它可以被看做由Series组成的字典(共用同一个索引)。跟其他类似的数据结构相比(如R的data.frame),DataFrame中面向行和面向列的操作基本上是平衡的。其实,DataFrame中的数据是以一个或多个二维块存放的(而不是列表、字典或别的一维数据结构)。

虽然DataFrame是以二维结构保存数据的,但你仍然可以轻松地将其表示为更高维度的数据(层次化索引的表格型结构,这是pandas中许多高级数据处理功能的关键要素)。

构建DataFrame的方式很多,最常用的一种是直接传入一个由等长列表或Numpy数组组成的字典,结果DataFrame会自动加上索引(跟Series一样),且全部列会被有序排列:

>>> data={'state':['Ohio','Ohio','Ohio','Nevada','Nevada'],
...       'year':[2000,2001,2002,2001,2002],
...       'pop':[1.5,1.7,3.6,2.4,2.9]}
>>> frame=DataFrame(data)
>>> frame
   pop   state  year
0  1.5    Ohio  2000
1  1.7    Ohio  2001
2  3.6    Ohio  2002
3  2.4  Nevada  2001
4  2.9  Nevada  2002

如果指定了列序列,则DataFrame的列就会按照指定顺序进行排列:

>>> DataFrame(data,columns=['year','state','pop'])
   year   state  pop
0  2000    Ohio  1.5
1  2001    Ohio  1.7
2  2002    Ohio  3.6
3  2001  Nevada  2.4
4  2002  Nevada  2.9

跟Series一样,如果传入的列在数据中找不到,就会产生NA值:

>>> frame2=DataFrame(data,columns=['year','state','pop','debt'],
...                  index=['one','two','three','four','five'])
>>> frame2
       year   state  pop debt
one    2000    Ohio  1.5  NaN
two    2001    Ohio  1.7  NaN
three  2002    Ohio  3.6  NaN
four   2001  Nevada  2.4  NaN
five   2002  Nevada  2.9  NaN
>>> frame2.columns
Index(['year', 'state', 'pop', 'debt'], dtype='object')
>>> frame2.index
Index(['one', 'two', 'three', 'four', 'five'], dtype='object')

通过类似字典标记的方式或属性的方式,可以将DataFrame的列获取为一个Series。返回的Series拥有原DataFrame相同的索引,且其name属性也已经被相应的设置好了:


也可以通过位置或名称的方式进行获取,比如用索引字段ix


可以通过赋值的方式进行修改。例如,我们可以给那个空的“debt”列赋上一个标量值或一组值:

>>> frame2.debt=16.5
>>> frame2
       year   state  pop  debt
one    2000    Ohio  1.5  16.5
two    2001    Ohio  1.7  16.5
three  2002    Ohio  3.6  16.5
four   2001  Nevada  2.4  16.5
five   2002  Nevada  2.9  16.5
>>> import numpy as np
>>> frame2['debt']=np.arange(5.)
>>> frame2
       year   state  pop  debt
one    2000    Ohio  1.5   0.0
two    2001    Ohio  1.7   1.0
three  2002    Ohio  3.6   2.0
four   2001  Nevada  2.4   3.0
five   2002  Nevada  2.9   4.0

列表或数组赋值给某个列时,其长度必须跟DataFrame的长度相匹配。如果赋值的是一个Series,就会精确匹配DataFrame的索引,所有的空位都将被填上缺失值


不存在的列赋值会创建出一个新列。关键字del用于删除列:

>>> frame2['eastern']=frame2.state=='Ohio'
>>> frame2
       year   state  pop  debt  eastern
one    2000    Ohio  1.5   NaN     True
two    2001    Ohio  1.7  -1.2     True
three  2002    Ohio  3.6   NaN     True
four   2001  Nevada  2.4  -1.5    False
five   2002  Nevada  2.9  -1.7    False
>>> del frame2['eastern']
>>> frame2.columns
Index(['year', 'state', 'pop', 'debt'], dtype='object')

警告:通过索引方式返回的列只是相应数据的视图而已,并不是副本。因此,对返回的Series所做的任何就地修改全都会反映到源DataFrame上。通过Series的copy方法即可显示的复制列

另一种常见的数据形式是嵌套字典(也就是字典的字典)。如果将它传给DataFrame,他就会被解释为:外层字典的键作为列内层键作为行索引:内层字典的键会被合并、排序以形成最终的索引。

>>> pop={'Nevada':{2001:2.4,2002:2.9},
... 'Ohio':{2000:1.5,2001:1.7,2002:3.6}}
>>> frame3=DataFrame(pop)
>>> frame3
      Nevada  Ohio
2000     NaN   1.5
2001     2.4   1.7
2002     2.9   3.6

当然,你也可以对该结果进行转置

>>> frame3T=frame3.T
>>> frame3T.columns
Int64Index([2000, 2001, 2002], dtype='int64')

如果显示指定了索引,则会进行数据对齐:

>>> DataFrame(pop,index=[2001,2002,2003])
      Nevada  Ohio
2001     2.4   1.7
2002     2.9   3.6
2003     NaN   NaN

Series组成的字典也差不多一样的用法:

>>> pdata={'Ohio':frame3['Ohio'][:-1],'Nevada':frame3['Nevada'][0:2]}
>>> DataFrame(pdata)
      Nevada  Ohio
2000     NaN   1.5
2001     2.4   1.7

如果设置了DataFrame的index和columns的name属性,这些信息会被显示出来。跟Series一样,values属性也会以二维ndarray的形式返回DataFrame中的数据:

>>> frame3.index.name='year'
>>> frame3.columns.name='state'
>>> frame3
state  Nevada  Ohio
year               
2000      NaN   1.5
2001      2.4   1.7
2002      2.9   3.6
>>> frame3.values
array([[nan, 1.5],
       [2.4, 1.7],
       [2.9, 3.6]])

下表列出可以输入给DataFrame构造器的数据:

二维ndarray
由数组、列表或元组组成的字典
Numpy结构化、记录数组
由Series组成的字典
由字典组成的字典
字典或Series的列表
由列表或元组组成的列表
另一个DataFrame
Numpy的MaskedArray

索引对象

pandas的索引对象负责管理轴标签和其他元数据(比如轴名称等)。构建Series或DataFrame时,所用到的任何数组或其他序列的标签都会被转换成一个Index:

>>> obj=Series(range(3),index=['a','b','c'])
>>> index=obj.index
>>> index
Index(['a', 'b', 'c'], dtype='object')
>>> index[1:]
Index(['b', 'c'], dtype='object')

Index对象是不可修改的(immutable),因此用户不能对其进行修改。不可修改性非常重要,这使Index对象在多个数据结构之间安全共享。

>>> index[1]='d'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.6/dist-packages/pandas/core/indexes/base.py", line 1724, in __setitem__
    raise TypeError("Index does not support mutable operations")
TypeError: Index does not support mutable operations

虽然大部分用户都不需要知道太多关于Index对象的细节,但它们确实是pandas数据模型的重要组成部分。

下表列出了pandas中内置的Index类。由于开发人员的不懈努力,Index甚至可以被继承从而实现特别的轴索引功能。

Index最泛化的Index对象,将轴标签表示为一个由Python对象组成的Numpy数组
Int64Index针对整数的特殊Index
MultiIndex“层次化”索引对象,表示单个轴上的多层索引。可以看做由元组组成的数组
DatetimeIndex存储纳秒级时间戳(用Numpy的datetime64类型表示)
PeriodIndex针对Period数据(时间间隔)的特殊Index

除了长得像数组,Index的功能也类似一个固定大小的集合。

>>> frame3
state  Nevada  Ohio
year               
2000      NaN   1.5
2001      2.4   1.7
2002      2.9   3.6
>>> 'Ohio' in frame3.columns
True
>>> 2003 in frame3.index
False

每个索引都有一些方法和属性,它们可用于设置逻辑并回答有关该索引所包含的数据的常见问题。下表列出了Index的方法和属性

append连接另一个Index对象,产生一个新的Index
diff计算差集,并得到一个Index
intersection计算交集
union计算并集
isin计算一个指示各值是否都包含在参数集合中的布尔型数组
delete删除索引i处的元素,并得到新的Index
drop删除传入的值,并得到新的Index
insert将元素插入到索引i处,并得到新的Index
is_monotonic当各元素均大于等于前一个元素时,返回True
is_unique当Index没有重复值时,返回True
unique计算Index中唯一值的数组

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!