pandas是本书后续内容的首选库。它含有使数据分析工作变得更快更简单的高级数据结构和操作工具。pandas是基于NumPy构建的,让以NumPy为中心的应用变得更加简单。
要使用pandas,你首先就得熟悉它的两个主要数据结构:Series和DataFrame。虽然它们并不能解决所有问题,但它们为大多数应用提供了一种可靠的、易于使用的基础。
Series是一种类似于一维数组的对象,它由一组数据(各种NumPy数据类型)以及一组与之相关的数据标签(即索引)组成。仅由一组数据即可产生最简单的Series:
from pandas import Series,DataFrame
import pandas as pd
obj=Series([1,2,5,4,3])
print(obj)
#output
0 1
1 2
2 5
3 4
4 3
dtype: int64
Series的字符串表现形式为:索引在左边,值在右边。由于我们没有为数据指定索引,于是会自动创建一个0到N1(N为数据的长度)的整数型索引。你可以通过Series 的values和index属性获取其数组表示形式和索引对象:
In [6]: obj.values
Out[6]: array([ 4, 7, -5, 3])
In [7]: obj.index
Out[7]: Int64Index([0, 1, 2, 3])
通常,我们希望所创建的Series带有一个可以对各个数据点进行标记的索引:
obj2=Series([4,7,-6,3],['a','b','c','d'])
print(obj2.index)
#output
Index(['a', 'b', 'c', 'd'], dtype='object')
与普通NumPy数组相比,你可以通过索引的方式选取Series中的单个或一组值:
print(obj2['a'])
#output
4
NumPy数组运算(如根据布尔型数组进行过滤、标量乘法、应用数学函数等)都会保留索引和值之间的链接:
print(obj2[obj2<0])
print(obj2*2)
print(np.exp(obj2))
#output
c -6
dtype: int64
a 8
b 14
c -12
d 6
dtype: int64
a 54.598150
b 1096.633158
c 0.002479
d 20.085537
dtype: float64
还可以将Series看成是一个定长的有序字典,因为它是索引值到数据值的一个映射。它可以用在许多原本需要字典参数的函数中:
In [18]: 'b' in obj2
Out[18]: True
In [19]: 'e' in obj2
Out[19]: False
如果数据被存放在一个Python字典中,也可以直接通过这个字典来创建Series:
In [20]: sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
In [21]: obj3 = Series(sdata)
In [22]: obj3
Out[22]:
Ohio 35000
Oregon 16000
Texas 71000
Utah 5000
如果只传入一个字典,则结果Series中的索引就是原字典的键(有序排列)。
In [23]: states = ['California', 'Ohio', 'Oregon', 'Texas']
In [24]: obj4 = Series(sdata, index=states)
In [25]: obj4
Out[25]:
California NaN
Ohio 35000
Oregon 16000
Texas 71000
在这个例子中,sdata中跟states索引相匹配的那3个值会被找出来并放到相应的位置上,但由于"California"所对应的sdata值找不到,所以其结果就为NaN(即“非数字”(not a number),在pandas中,它用于表示缺失或NA值)。我将使用缺失(missing)或NA表示缺失数据。
pandas的isnull和notnull函数可用于检测缺失数据:
Series也有类似的实例方法:
In [28]: obj4.isnull()
Out[28]:
California True
Ohio False
Oregon False
Texas False
对于许多应用而言,Series最重要的一个功能是:它在算术运算中会自动对齐不同索引的数据。
In [31]: obj3 + obj4
Out[31]:
California NaN
Ohio 70000
Oregon 32000
Texas 142000
Utah NaN
Series对象本身及其索引都有一个name属性,该属性跟pandas其他的关键功能关系非常密切:
obj2=Series([4,7,-6,3],['a','b','c','d'])
obj2.name='obj2_index'
obj2.index.name='state'
print(obj2)
#output
state
a 4
b 7
c -6
d 3
Name: obj2_index, dtype: int64
Series的索引可以通过赋值的方式就地修改:
obj2.index=['Alice','Bob','Cris','David']
print(obj2)
#output
Alice 4
Bob 7
Cris -6
David 3
Name: obj2_index, dtype: int64
构建DataFrame的办法有很多,最常用的一种是直接传入一个由等长列表或NumPy数组组成的字典:
from pandas import DataFrame
import pandas as pd
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)
print(frame)
#output
state year pop
0 Ohio 2000 1.5
1 Ohio 2001 1.7
2 Ohio 2002 3.6
3 Nevada 2001 2.4
4 Nevada 2002 2.9
如果指定了列序列,则DataFrame的列就会按照指定顺序进行排列:
frame = DataFrame(data,columns=['year','pop','state'])
print(frame)
#output
year pop state
0 2000 1.5 Ohio
1 2001 1.7 Ohio
2 2002 3.6 Ohio
3 2001 2.4 Nevada
4 2002 2.9 Nevada
跟Series一样,如果传入的列在数据中找不到,就会产生N/A值:
frame2 = DataFrame(data, columns=['year', 'state', 'pop', 'debt'],index=['one', 'two', 'three', 'four', 'five'])
print(frame2)
#output
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
通过类似字典标记的方式或属性的方式,可以将DataFrame的列获取为一个Series:
print(frame2['year'])
print(frame2.state)
#output
one 2000
two 2001
three 2002
four 2001
five 2002
Name: year, dtype: int64
one Ohio
two Ohio
three Ohio
four Nevada
five Nevada
Name: state, dtype: object
注意,返回的Series拥有原DataFrame相同的索引,且其name属性也已经被相应地设置好了。
行也可以通过位置或名称的方式进行获取,比如用索引字段ix:
print(frame2.ix['one'])
#output
year 2000
state Ohio
pop 1.5
debt NaN
Name: one, dtype: object
列可以通过赋值的方式进行修改。例如,我们可以给那个空的"debt"列赋上一个标量值或一组值:
In [46]: frame2['debt'] = 16.5
In [47]: frame2
Out[47]:
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
In [48]: frame2['debt'] = np.arange(5.)
In [49]: frame2
Out[49]:
year state pop debt
one 2000 Ohio 1.5 0
two 2001 Ohio 1.7 1
three 2002 Ohio 3.6 2
four 2001 Nevada 2.4 3
five 2002 Nevada 2.9 4
将列表或数组赋值给某个列时,其长度必须跟DataFrame的长度相匹配。如果赋值的是一个Series,就会精确匹配DataFrame的索引,所有的空位都将被填上缺失值:
In [50]: val = Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
In [51]: frame2['debt'] = val
In [52]: frame2
Out[52]:
year state pop debt
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 -1.2
three 2002 Ohio 3.6 NaN
four 2001 Nevada 2.4 -1.5
five 2002 Nevada 2.9 -1.7
为不存在的列赋值会创建出一个新列。关键字del用于删除列:
In [53]: frame2['eastern'] = frame2.state == 'Ohio'
In [54]: frame2
Out[54]:
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
In [55]: del frame2['eastern']
In [56]: frame2.columns
Out[56]: Index([year, state, pop, debt], dtype=object)
通过索引方式返回的列只是相应数据的视图而已,并不是副本。因此,对返回的Series所做的任何就地修改全都会反映到源DataFrame上。通过Series的copy方法即可显式地复制列。
另一种常见的数据形式是嵌套字典(也就是字典的字典):
from pandas import DataFrame
import pandas as pd
pop = {'Nevada': {2001: 2.4, 2002: 2.9},'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
frame3=DataFrame(pop)
print(frame3)
#output
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
当然,你也可以对该结果进行转置:
In [60]: frame3.T
Out[60]:
2000 2001 2002
Nevada NaN 2.4 2.9
Ohio 1.5 1.7 3.6
内层字典的键会被合并、排序以形成最终的索引。如果显式指定了索引,则不会这样:
In [61]: DataFrame(pop, index=[2001, 2002, 2003])
Out[61]:
Nevada Ohio
2001 2.4 1.7
2002 2.9 3.6
2003 NaN NaN
由Series组成的字典差不多也是一样的用法:
In [62]: pdata = {'Ohio': frame3['Ohio'][:-1],
....: 'Nevada': frame3['Nevada'][:2]}
In [63]: DataFrame(pdata)
Out[63]:
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
下表列出了DataFrame构造函数所能接受的各种数据。
跟Series一样,values属性也会以ndarray的形式返回DataFrame中的数据:
In [66]: frame3.values
Out[66]:
array([[ nan, 1.5],
[ 2.4, 1.7],
[ 2.9, 3.6]])