pandas建造在NumPy之上,它使得以NumPy为中心的应用很容易使用。

In [4]:
import numpy as np
import pandas as pd
from pandas import Series, DataFrame

Pandas 数据结构入门

Series

Series 是一个一维的类似的数组对象,包含一个数组的数据(任何 NumPy 的数据类型)和一个与数组关联的数据标签,被叫做 索引 。最简单的 Series 是由一个数组的数据构成:

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

Seriers 的交互式显示的字符窜表示形式是索引在左边,值在右边。
因为我们没有给数据指定索引,一个包含整数 0 到 N-1 (这里 N 是数据的长度)的默认索引被创建。 可以分别的通过它的 values 和 index 属性来获取 Series 的数组表示和索引对象:

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

通常,需要创建一个带有索引来确定没一个数据点的Series:

In [8]:
obj2 = Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
obj2
Out[8]:
d    4
b    7
a   -5
c    3
dtype: int64

与正规的 NumPy 数组相比,你可以使用索引里的值来选择一个单一值或一个值集:

In [11]:
obj2['a']
Out[11]:
-5
In [12]:
obj2['d'] = 6
obj2[['c', 'a', 'd']]
Out[12]:
c    3
a   -5
d    6
dtype: int64

NumPy 数组操作,例如通过一个布尔数组过滤,纯量乘法,或使用数学函数,将会保持索引和值间的关联:

In [13]:
obj2
Out[13]:
d    6
b    7
a   -5
c    3
dtype: int64
In [14]:
obj2[obj2 > 0]
Out[14]:
d    6
b    7
c    3
dtype: int64
In [15]:
obj2 * 2
Out[15]:
d    12
b    14
a   -10
c     6
dtype: int64
In [16]:
np.exp(obj2)
Out[16]:
d     403.428793
b    1096.633158
a       0.006738
c      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)
obj3
Out[21]:
Ohio      35000
Oregon    16000
Texas     71000
Utah       5000
dtype: int64

只传递一个字典的时候,结果 Series 中的索引将是排序后的字典的键。

In [24]:
states = ['California', 'Ohio', 'Oregon', 'Texas']
obj4 = Series(sdata, index=states)
obj4
Out[24]:
California        NaN
Ohio          35000.0
Oregon        16000.0
Texas         71000.0
dtype: float64

在这种情况下, sdata 中的3个值被放在了合适的位置,但因为没有发现对应于 ‘California’ 的值,就出现了 NaN (不是一个数),这在 pandas 中被用来标记数据缺失或 NA 值。使用 “missing” 或 “NA” 来表示数度丢失。
在 pandas 中用函数 isnull 和 notnull 来检测数据丢失:

In [26]:
pd.isnull(obj4)
Out[26]:
California     True
Ohio          False
Oregon        False
Texas         False
dtype: bool
In [27]:
pd.notnull(obj4)
Out[27]:
California    False
Ohio           True
Oregon         True
Texas          True
dtype: bool
In [28]:
obj4.isnull()
Out[28]:
California     True
Ohio          False
Oregon        False
Texas         False
dtype: bool

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

In [29]:
obj3
Out[29]:
Ohio      35000
Oregon    16000
Texas     71000
Utah       5000
dtype: int64
In [30]:
obj4
Out[30]:
California        NaN
Ohio          35000.0
Oregon        16000.0
Texas         71000.0
dtype: float64
In [31]:
obj3 + obj4
Out[31]:
California         NaN
Ohio           70000.0
Oregon         32000.0
Texas         142000.0
Utah               NaN
dtype: float64

Series 对象本身和它的索引都有一个 name 属性,它和 pandas 的其它一些关键功能整合在一起:

In [32]:
obj4.name = 'population'
In [33]:
obj4.index.name = 'state'
obj4
Out[33]:
state
California        NaN
Ohio          35000.0
Oregon        16000.0
Texas         71000.0
Name: population, dtype: float64

Series 的索引可以通过赋值就地更改:

In [34]:
obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']
In [35]:
obj
Out[35]:
Bob      4
Steve    7
Jeff    -5
Ryan     3
dtype: int64

DataFrame

一个 Datarame 表示一个表格,类似电子表格的数据结构,包含一个经过排序的列表集,它们每一个都可以有不同的类型值(数字,字符串,布尔等等)。
Datarame 有行和列的索引;它可以被看作是一个 Series 的字典(每个 Series 共享一个索引)。
与其它你以前使用过的(如 R 的 data.frame )类似 Datarame 的结构相比,在 DataFrame 里的面向行和面向列的操作大致是对称的。
在底层,数据是作为一个或多个二维数组存储的,而不是列表,字典,或其它一维的数组集合。
因为 DataFrame 在内部把数据存储为一个二维数组的格式,因此你可以采用分层索引以表格格式来表示高维的数据。

有很多方法来构建一个 DataFrame,但最常用的一个是用一个相等长度列表的字典或 NumPy 数组:

In [229]:
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)

由此产生的 DataFrame 和 Series 一样,它的索引会自动分配,并且对列进行了排序:

In [230]:
frame
Out[230]:
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 的列将会精确的按照你所传递的顺序排列:

In [38]:
DataFrame(data, columns=['year', 'state', 'pop'])
Out[38]:
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 一样,如果你传递了一个行,但不包括在 data 中,在结果中它会表示为 NA 值:

In [64]:
frame2 = DataFrame(data, columns=['year', 'state', 'pop', 'debt'],index=['one', 'two', 'three', 'four', 'five'])
frame2
Out[64]:
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

和 Series 一样,在 DataFrame 中的一列可以通过字典记法或属性来检索:

In [41]:
frame2['state'] 
Out[41]:
one        Ohio
two        Ohio
three      Ohio
four     Nevada
five     Nevada
Name: state, dtype: object
In [40]:
frame2.year
Out[40]:
one      2000
two      2001
three    2002
four     2001
five     2002
Name: year, dtype: int64

注意,返回的 Series 包含和 DataFrame 相同的索引,并它们的 name 属性也被正确的设置了。

行也可以使用一些方法通过位置或名字来检索,例如 ix 索引成员(field)(更多的将在后面介绍):

In [42]:
frame2.ix['three']
Out[42]:
year     2002
state    Ohio
pop       3.6
debt      NaN
Name: three, dtype: object

列可以通过赋值来修改。例如,空的 ‘debt’ 列可以通过一个纯量或一个数组来赋值:

In [65]:
frame2['debt'] = 16.5
frame2
Out[65]:
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 [66]:
frame2['debt'] = np.arange(5.)
frame2
Out[66]:
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 的长度相匹配。否则全部为 NA

如果你使用 Series 来赋值,它会代替在 DataFrame 中精确匹配的索引的值,并在说有的空洞插入丢失数据:

In [58]:
val2 = Series([-1.2, -1.5, -1.7])
In [60]:
frame2['debt'] = val2
frame2
Out[60]:
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
In [62]:
val = Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
In [67]:
frame2['debt'] = val
frame2
Out[67]:
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 [68]:
frame2['eastern'] = frame2.state == 'Ohio'
frame2
Out[68]:
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

注意:索引 DataFrame 时返回的列是底层数据的一个视窗,而不是一个拷贝。因此,任何在 Series 上的就地修改都会影响 DataFrame。列可以使用 Series 的 copy 函数来显式的拷贝。

另一种通用的数据形式是一个嵌套的字典的字典格式:

In [69]:
pop = {'Nevada': {2001: 2.4, 2002: 2.9},
   ....: 'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
In [70]:
pop
Out[70]:
{'Nevada': {2001: 2.4, 2002: 2.9}, 'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}

如果被传递到 DataFrame,它的外部键会被解释为列索引,内部键会被解释为行索引:

In [72]:
frame3 = DataFrame(pop)
frame3
Out[72]:
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6

当然,总是可以对结果转置:

In [73]:
frame3.T
Out[73]:
2000 2001 2002
Nevada NaN 2.4 2.9
Ohio 1.5 1.7 3.6

内部字典的键被结合并排序来形成结果的索引。如果指定了一个特定的索引,就不是这样的了:

In [74]:
DataFrame(pop, index=[2001, 2002, 2003])
Out[74]:
Nevada Ohio
2001 2.4 1.7
2002 2.9 3.6
2003 NaN NaN

Series 的字典也以相同的方式来处理:

In [75]:
pdata = {'Ohio': frame3['Ohio'][:-1],
  ....: 'Nevada': frame3['Nevada'][:2]}
In [76]:
pdata
Out[76]:
{'Nevada': 2000    NaN
 2001    2.4
 Name: Nevada, dtype: float64, 'Ohio': 2000    1.5
 2001    1.7
 Name: Ohio, dtype: float64}
In [77]:
DataFrame(pdata)
Out[77]:
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7

如果一个 DataFrame 的 index 和 columns 有它们的 name ,也会被显示出来:

In [79]:
frame3.index.name = 'year'; frame3.columns.name = 'state'
frame3
Out[79]:
state Nevada Ohio
year
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6

像 Series 一样, values 属性返回一个包含在 DataFrame 中的数据的二维 ndarray:

In [80]:
frame3.values
Out[80]:
array([[ nan,  1.5],
       [ 2.4,  1.7],
       [ 2.9,  3.6]])

如果 DataFrame 的列有不同的 dtypes,返回值数组将会给所有的列选择一个合适的 dtyps:

In [82]:
frame2
Out[82]:
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 [81]:
frame2.values
Out[81]:
array([[2000, 'Ohio', 1.5, nan, True],
       [2001, 'Ohio', 1.7, -1.2, True],
       [2002, 'Ohio', 3.6, nan, True],
       [2001, 'Nevada', 2.4, -1.5, False],
       [2002, 'Nevada', 2.9, -1.7, False]], dtype=object)

可能的传递到DataFrame的构造器

二维ndarray 一个数据矩阵,有可选的行标和列标
数组,列表或元组的字典 每一个序列成为DataFrame中的一列。所有的序列必须有相同的长度。
NumPy的结构/记录数组 和“数组字典”一样处理
Series的字典 每一个值成为一列。如果没有明显的传递索引,将结合每一个Series的索引来形成结果的行索引。
字典的字典 每一个内部的字典成为一列。和“Series的字典”一样,结合键值来形成行索引。
字典或Series的列表 每一项成为DataFrame中的一列。结合字典键或Series索引形成DataFrame的列标。
列表或元组的列表 和“二维ndarray”一样处理
另一个DataFrame DataFrame的索引将被使用,除非传递另外一个
NumPy伪装数组(MaskedArray) 除了蒙蔽值在DataFrame中成为NA/丢失数据之外,其它的和“二维ndarray”一样

索引对象

pandas 的索引对象用来保存坐标轴标签和其它元数据(如坐标轴名或名称)。构建一个 Series 或 DataFrame 时任何数组或其它序列标签在内部转化为索引:

In [84]:
obj = Series(range(3), index=['a', 'b', 'c'])
index = obj.index
index
Out[84]:
Index([u'a', u'b', u'c'], dtype='object')
In [86]:
index[1:]
Out[86]:
Index([u'b', u'c'], dtype='object')

索引对象是不可变的,因此不能由用户改变:

In [87]:
index[1] = 'd'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-87-676fdeb26a68> in <module>()
----> 1 index[1] = 'd'

/home/evil_rabbit/anaconda2/lib/python2.7/site-packages/pandas/indexes/base.pyc in __setitem__(self, key, value)
   1235 
   1236     def __setitem__(self, key, value):
-> 1237         raise TypeError("Index does not support mutable operations")
   1238 
   1239     def __getitem__(self, key):

TypeError: Index does not support mutable operations

索引对象的不可变性非常重要,这样它可以在数据结构中结构中安全的共享:

In [88]:
index = pd.Index(np.arange(3))
obj2 = Series([1.5, -2.5, 0], index=index)
obj2.index is index
Out[88]:
True

下表是库中内建的索引类清单。通过一些开发努力,索引可以被子类化,来实现特定坐标轴索引功能。

索引类型 说明
Index 最通用的索引对象,使用Python对象的NumPy数组来表示坐标轴标签。
Int64Index 对整形值的特化索引。
MultiIndex “分层”索引对象,表示单个轴的多层次的索引。可以被认为是类似的元组的数组。
DatetimeIndex 存储纳秒时间戳(使用NumPy的datetime64 dtyppe来表示)。
PeriodIndex 对周期数据(时间间隔的)的特化索引。

除了类似于阵列,索引也有类似固定大小集合一样的功能:

In [92]:
frame3
Out[92]:
state Nevada Ohio
year
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
In [93]:
'Ohio' in frame3.columns
Out[93]:
True
In [94]:
2003 in frame3.index
Out[94]:
False

每个索引都有许多关于集合逻辑的方法和属性,且能够解决它所包含的数据的常见问题。这些都总结在下表中。

方法 属性
append 链接额外的索引对象,产生一个新的索引
diff 计算索引的差集
intersection 计算交集
union 计算并集
isin 计算出一个布尔数组表示每一个值是否包含在所传递的集合里
delete 计算删除位置i的元素的索引
drop 计算删除所传递的值后的索引
insert 计算在位置i插入元素后的索引
is_monotonic 返回True,如果每一个元素都比它前面的元素大或相等
is_unique 返回True,如果索引没有重复的值
unique 计算索引的唯一值数组

重新索引:reindex

pandas 对象的一个关键的方法是 reindex ,意味着使数据符合一个新的索引来构造一个新的对象。来看一下下面一个简单的例子:

In [105]:
obj = Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
obj
Out[105]:
d    4.5
b    7.2
a   -5.3
c    3.6
dtype: float64

在 Series 上调用 reindex 重排数据,使得它符合新的索引,如果那个索引的值不存在就引入缺失数据值:
注意:reindex 并不改变 index 的数值,只是重排数据。(索引对象的不可变性)

In [106]:
obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])
obj2
Out[106]:
a   -5.3
b    7.2
c    3.6
d    4.5
e    NaN
dtype: float64
In [107]:
obj.reindex(['a', 'b', 'c', 'd', 'e'], fill_value=0)
Out[107]:
a   -5.3
b    7.2
c    3.6
d    4.5
e    0.0
dtype: float64

为了对时间序列这样的数据排序,当重建索引的时候可能想要对值进行内插或填充。 method 选项可以是你做到这一点,使用一个如 ffill 的方法来向前填充值:

In [110]:
obj3 = Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
In [111]:
obj3
Out[111]:
0      blue
2    purple
4    yellow
dtype: object
In [109]:
obj3.reindex(range(6), method='ffill')
Out[109]:
0      blue
1      blue
2    purple
3    purple
4    yellow
5    yellow
dtype: object

下是可用的 method 选项的清单。在此,内差比正向和反向填充更复杂。

  • reindex 的 method(内插)选项
参数 描述
ffill或pad 前向(或进位)填充
bfill或backfill 后向(或进位)填充

对于 DataFrame, reindex 可以改变(行)索引,列或两者。当只传入一个序列时,结果中的行被重新索引了:

In [112]:
frame = DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'],
....: columns=['Ohio', 'Texas', 'California'])
In [113]:
frame
Out[113]:
Ohio Texas California
a 0 1 2
c 3 4 5
d 6 7 8
In [114]:
frame2 = frame.reindex(['a', 'b', 'c', 'd'])
In [115]:
frame2
Out[115]:
Ohio Texas California
a 0.0 1.0 2.0
b NaN NaN NaN
c 3.0 4.0 5.0
d 6.0 7.0 8.0

使用 columns 关键字可以使列重新索引:

In [116]:
states = ['Texas', 'Utah', 'California']
In [118]:
frame.reindex(columns=states)
# 再次注意索引对象的不可变性
Out[118]:
Texas Utah California
a 1 NaN 2
c 4 NaN 5
d 7 NaN 8

一次可以对两个重新索引,可是插值只在行侧(0坐标轴)进行:

In [121]:
frame
Out[121]:
Ohio Texas California
a 0 1 2
c 3 4 5
d 6 7 8
In [119]:
frame.reindex(index=['a', 'b', 'c', 'd'], method='ffill',
   ....: columns=states)
Out[119]:
Texas Utah California
a 1 NaN 2
b 1 NaN 2
c 4 NaN 5
d 7 NaN 8

正如你将看到的,使用带标签索引的 ix 可以把重新索引做的更简单:

In [120]:
frame.ix[['a', 'b', 'c', 'd'], states]
Out[120]:
Texas Utah California
a 1.0 NaN 2.0
b NaN NaN NaN
c 4.0 NaN 5.0
d 7.0 NaN 8.0
  • reindex 函数的参数
参数 说明
index 作为索引的新序列。可以是索引实例或任何类似序列的Python数据结构。一个索引被完全使用,没有任何拷贝。
method 插值(填充)方法,见表格5-4的选项
fill_value 代替重新索引时引入的缺失数据值
limit 当前向或后向填充时,最大的填充间隙
level 在多层索引上匹配简单索引,否则选择一个子集
copy 如果新索引与就的相等则底层数据不会拷贝。默认为True(即始终拷贝)

从一个坐标轴删除条目

从坐标轴删除一个多或多个条目是很容易的,如果你有一个索引数组或列表且没有这些条目,但是这可能需要一点修改和集合逻辑。 drop 方法将会返回一个新的对象并从坐标轴中删除指定的一个或多个值:

In [122]:
obj = Series(np.arange(5.), index=['a', 'b', 'c', 'd', 'e'])
In [124]:
new_obj = obj.drop('c')
new_obj
Out[124]:
a    0.0
b    1.0
d    3.0
e    4.0
dtype: float64
In [125]:
obj.drop(['d', 'c'])
Out[125]:
a    0.0
b    1.0
e    4.0
dtype: float64

对于 DataFrame,可以从任何坐标轴删除索引值:

In [126]:
data = DataFrame(np.arange(16).reshape((4, 4)),
   ....: index=['Ohio', 'Colorado', 'Utah', 'New York'],
   ....: columns=['one', 'two', 'three', 'four'])
In [127]:
data.drop(['Colorado', 'Ohio'])
Out[127]:
one two three four
Utah 8 9 10 11
New York 12 13 14 15
In [128]:
data.drop('two', axis=1)
Out[128]:
one three four
Ohio 0 2 3
Colorado 4 6 7
Utah 8 10 11
New York 12 14 15
In [129]:
data.drop(['two', 'four'], axis=1)
Out[129]:
one three
Ohio 0 2
Colorado 4 6
Utah 8 10
New York 12 14

索引,挑选和过滤

Series 索引 ( obj[...] )的工作原理类似与 NumPy 索引,除了可以使用 Series 的索引值,也可以仅使用整数来索引。下面是关于这一点的一些例子:

In [138]:
obj = Series([2,3,1,5], index=['a', 'b', 'c', 'd'])
obj
Out[138]:
a    2
b    3
c    1
d    5
dtype: int64
In [139]:
obj['b'], obj[1]
Out[139]:
(3, 3)
In [140]:
obj[['b', 'a', 'd']]
Out[140]:
b    3
a    2
d    5
dtype: int64
In [142]:
obj[[1, 3]] # 索引位置
Out[142]:
b    3
d    5
dtype: int64
In [143]:
obj[obj < 2]
Out[143]:
c    1
dtype: int64

使用标签来切片和正常的 Python 切片并不一样,它会把结束点也包括在内

In [144]:
obj['b':'c']
Out[144]:
b    3
c    1
dtype: int64
In [146]:
obj['b':'c'] = 5
obj
Out[146]:
a    2
b    5
c    5
d    5
dtype: int64

正如上面你所见到的,索引 DataFrame 来检索一个或多个列,可以使用一个单一值或一个序列:

In [256]:
data = DataFrame(np.arange(16).reshape((4, 4)),
   .....: index=['Ohio', 'Colorado', 'Utah', 'New York'],
   .....: columns=['one', 'two', 'three', 'four'])
In [257]:
data
Out[257]:
one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
In [258]:
data['two']
Out[258]:
Ohio         1
Colorado     5
Utah         9
New York    13
Name: two, dtype: int64
In [259]:
data[['three', 'one']]
Out[259]:
three one
Ohio 2 0
Colorado 6 4
Utah 10 8
New York 14 12

像这样的索引有一些特殊的情况。首先,可以通过切片或一个布尔数组来选择行:

In [151]:
data[:2] 
Out[151]:
one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
In [260]:
data[(data.one >=1 ) & (data.one < 7) ] # 多个逻辑条件组合
Out[260]:
one two three four
Colorado 4 5 6 7
In [152]:
data[data['three'] > 5]
Out[152]:
one two three four
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15

另一种用法是在索引中使用一个布尔 DataFrame,例如通过纯量比较产生的:

In [153]:
data < 5
Out[153]:
one two three four
Ohio True True True True
Colorado True False False False
Utah False False False False
New York False False False False
In [156]:
data[data <5] = 0
In [157]:
data
Out[157]:
one two three four
Ohio 0 0 0 0
Colorado 0 5 6 7
Utah 8 9 10 11
New York 12 13 14 15

在这种情况下使得 DataFrame 的语法更像一个 ndarry。为了使 DataFrame 可以在行上进行标签索引,我将介绍特殊的索引字段 ix 。这使你可以从 DataFrame 选择一个行和列的子集,使用像 NumPy 的记法再加上轴标签。正如我早先提到的,这也是一种不是很冗长的重新索引的方法:

In [158]:
data.ix['Colorado', ['two', 'three']]
Out[158]:
two      5
three    6
Name: Colorado, dtype: int64
In [161]:
data.ix[['Colorado', 'Utah'], [3, 0, 1]] # 3,0,1 表示位置顺序
Out[161]:
four one two
Colorado 7 0 5
Utah 11 8 9
In [163]:
data.ix[2] # 第 2 行
Out[163]:
one       8
two       9
three    10
four     11
Name: Utah, dtype: int64
In [166]:
data.ix[:,2] # 第 2 列
Out[166]:
Ohio         0
Colorado     6
Utah        10
New York    14
Name: three, dtype: int64
In [167]:
data.ix[:'Utah', 'two']
Out[167]:
Ohio        0
Colorado    5
Utah        9
Name: two, dtype: int64
In [173]:
data.ix[data.three > 5, :]
Out[173]:
one two three four
Colorado 0 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
In [174]:
data.ix[data.three > 5, :3]
Out[174]:
one two three
Colorado 0 5 6
Utah 8 9 10
New York 12 13 14

因此,有很多方法来选择和重排包含在 pandas 对象中的数据。对于 DataFrame , 下表是这些方法的简短概要。稍后你将接触到分层索引,那时你会有一些额外的选项。

注意:在设计 pandas 时,我觉得不得不敲下 frame[:, col] 来选择一列,是非常冗余的(且易出错的),因此列选择是最常见的操作之一。
因此,我做了这个设计权衡,把所有的富标签索引引入到 ix 。

切片命令 说明
obj[val] 从DataFrame选择单一列或连续列。特殊情况下的便利:布尔数组(过滤行),切片(行切片),或布尔DataFrame(根据一些标准来设置值)。
obj.ix[val] 从DataFrame的行集选择单行
obj.ix[:, val] 从列集选择单列
obj.ix[val1, val2] 选择行和列
reindex 方法 转换一个或多个轴到新的索引
xs 方法 通过标签选择单行或单列到一个Series
icol, irow 方法 通过整数位置,分别的选择单行或单列到一个Series
get_value, set_value 方法 通过行和列标选择一个单值

其他切片方式:

In [185]:
data
Out[185]:
one two three four
Ohio 0 0 0 0
Colorado 0 5 6 7
Utah 8 9 10 11
New York 12 13 14 15

使用标签选取数据

In [183]:
# df.loc[行标签,列标签]
data.loc['Colorado':'New York'] # 选取 a:b 行数据
Out[183]:
one two three four
Colorado 0 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
In [182]:
data.loc[:,'one'] # 选取 one 列的数据
Out[182]:
Ohio         0
Colorado     0
Utah         8
New York    12
Name: one, dtype: int64

使用位置选取数据

In [184]:
# df.iloc[行位置,列位置]
data.iloc[1,1] # 选取第二行,第二列的值,返回的为单个值
Out[184]:
5
In [189]:
data.iloc[[0,2], :] #选取第一行及第三行的数据
Out[189]:
one two three four
Ohio 0 0 0 0
Utah 8 9 10 11
In [190]:
data.iloc[0:2,:] # 选取第一行到第三行(不包含)的数据,就是前两行的数据
Out[190]:
one two three four
Ohio 0 0 0 0
Colorado 0 5 6 7
In [191]:
data.iloc[:,1] # 选取所有记录的第一列的值,返回的为一个 Series
Out[191]:
Ohio         0
Colorado     5
Utah         9
New York    13
Name: two, dtype: int64
In [192]:
data.iloc[1,:] # 选取第二行数据,返回的为一个 Series
Out[192]:
one      0
two      5
three    6
four     7
Name: Colorado, dtype: int64

算术运算

当把对象加起来时,如果有任何的索引对不相同的话,在结果中将会把各自的索引联合起来。
在索引不重合的地方引入了 NA 值。

广播

In [197]:
arr = np.arange(12.).reshape(3,4)
In [198]:
arr[0]
Out[198]:
array([ 0.,  1.,  2.,  3.])
In [199]:
arr-arr[0]
Out[199]:
array([[ 0.,  0.,  0.,  0.],
       [ 4.,  4.,  4.,  4.],
       [ 8.,  8.,  8.,  8.]])

文件操作

In [ ]:
# 从 CSV 中读取数据
df = pd.read_csv('foo.csv')
In [ ]:
#将 DataFrame 写入 CSV
df.to_csv('foo.csv')
In [ ]:
# 从 Excel 中读取数据:先定义一个 Excel 文件,
# 用 xls.parse 解析 sheet1 的内容,index_col 用于指定 index 列,na_values 定义缺失值的标识。
xls = ExcelFile('foo.xlsx')
xls.parse('sheet1', index_col=None, na_values=['NA'])
In [ ]:
 # 将DataFrame 写入 Excel 文件 
df.to_excel('foo.xlsx', sheet_name='sheet1')

基本运算

In [142]:
data = DataFrame(np.arange(16).reshape((4, 4)),
   ....: index=['Ohio', 'Colorado', 'Utah', 'New York'],
   ....: columns=['one', 'two', 'three', 'four'])
In [16]:
data
Out[16]:
one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
In [7]:
data.mean() # 计算列的平均值,参数为轴,可选值为 0 或 1.默认为 0,即按照列运算
Out[7]:
one      6.0
two      7.0
three    8.0
four     9.0
dtype: float64
In [8]:
data.sum(1) # 计算行的和
Out[8]:
Ohio         6
Colorado    22
Utah        38
New York    54
dtype: int64
In [9]:
# 将一个函数应用到 DataFrame 的每一列,这里使用的是匿名 lambda 函数,与 R 中 apply 函数类似
data.apply(lambda x: x.max() - x.min())
Out[9]:
one      12
two      12
three    12
four     12
dtype: int64
In [95]:
# 应用到某一列
# 推荐
data['one'] = data['one'].apply(lambda x: x+1)
data
Out[95]:
one two three four
Ohio 1 1 2 3
Colorado 5 5 6 7
Utah 9 9 10 11
New York 13 13 14 15
In [143]:
# 应用到某一列
# 首元素会多执行一遍
def addone(v):
    v[0] += 1
    return v
data.apply(addone, axis=1)
Out[143]:
one two three four
Ohio 2 1 2 3
Colorado 5 5 6 7
Utah 9 9 10 11
New York 13 13 14 15
In [73]:
def addone(v):
    v += 1
    return v
data['one'] = data['one'].map(addone)
data
Out[73]:
one two three four
Ohio 1 1 2 3
Colorado 5 5 6 7
Utah 9 9 10 11
New York 13 13 14 15

常用操作

排序

In [234]:
df = DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'],
....: columns=['Ohio', 'Texas', 'California'])
In [235]:
df
Out[235]:
Ohio Texas California
a 0 1 2
c 3 4 5
d 6 7 8
In [238]:
df.ix["a"] = [10,11,12]
In [251]:
df
Out[251]:
Ohio Texas California
a 10 11 12
c 3 9 5
d 6 7 8

sort_index 可以以轴的标签进行排序。axis 是指用于排序的轴,可选的值有 0 和 1,默认为 0 即行标签(Y 轴),1 为按照列标签排序。 ascending 是排序方式,默认为 True 即降序排列。

In [252]:
df.sort_index(axis=0, ascending=False)   # 对行进行排序 d,c,a
Out[252]:
Ohio Texas California
d 6 7 8
c 3 9 5
a 10 11 12
In [212]:
df
Out[212]:
Ohio          10
Texas         11
California    12
Name: a, dtype: int64
In [254]:
df.sort_index(axis=1, ascending=False)    # 对列进行排序 Texas, Ohio, California
Out[254]:
Texas Ohio California
a 11 10 12
c 9 3 5
d 7 6 8

DataFrame 也提供按照指定列进行排序,可以仅指定一个列作为排序标准(以单独列名作为 columns 的参数),也可以进行多重排序(columns 的参数为一个列名的 List,列名的出现顺序决定排序中的优先级),在多重排序中 ascending 参数也为一个 List,分别与 columns 中的 List 元素对应。

In [243]:
df.sort_values(by='Ohio', ascending=False)
Out[243]:
Ohio Texas California
a 10 11 12
d 6 7 8
c 3 4 5
In [246]:
df.ix[1,1]=9
In [247]:
df
Out[247]:
Ohio Texas California
a 10 11 12
c 3 9 5
d 6 7 8
In [250]:
df.sort_values(by=['Ohio','Texas'],ascending=[0,1])
Out[250]:
Ohio Texas California
a 10 11 12
d 6 7 8
c 3 9 5

重命名列

In [ ]:
df.rename(columns={u'one':'1'}, inplace=True)

设置索引

In [ ]:
df.set_index('one')

重设索引

In [ ]:
df.reset_index(inplace=True)

查看最大最小值

In [ ]:
pd.Series.max()
pd.Series.idxmax()

改变数据类型

In [ ]:
df['A'].astype(float)

计算 Series 每个值的频率

In [ ]:
df['A'].value_counts()

DataFrame 的合并

Concat

In [267]:
ds = [{'one' : 4,'two':2},{'one' : 5,'two' : 3},{'one' : 6,'two' : 4},{'two' : 7,'three':10}]
dfs = pd.DataFrame(ds,index=['e','f','g','h'])
In [269]:
dfs
Out[269]:
one three two
e 4.0 NaN 2
f 5.0 NaN 3
g 6.0 NaN 4
h NaN 10.0 7
In [292]:
##构建一个新的 DataFrame,dfs
df_t=pd.concat([dfs,dfs],axis=1) # 合并两个 DataFrame
In [293]:
df_t
Out[293]:
one three two one three two
e 4.0 NaN 2 4.0 NaN 2
f 5.0 NaN 3 5.0 NaN 3
g 6.0 NaN 4 6.0 NaN 4
h NaN 10.0 7 NaN 10.0 7
In [294]:
##构建一个新的 DataFrame,dfs
df_t=pd.concat([dfs,dfs],axis=0) # 合并两个 DataFrame
In [295]:
df_t
Out[295]:
one three two
e 4.0 NaN 2
f 5.0 NaN 3
g 6.0 NaN 4
h NaN 10.0 7
e 4.0 NaN 2
f 5.0 NaN 3
g 6.0 NaN 4
h NaN 10.0 7

Merge

In [296]:
left = pd.DataFrame({'key': ['foo1', 'foo2'], 'lval': [1, 2]})
right = pd.DataFrame({'key': ['foo1', 'foo2'], 'rval': [4, 5]})
#构建了两个DataFrame
pd.merge(left, right, on='key')#按照key列将两个DataFrame join在一起
Out[296]:
key lval rval
0 foo1 1 4
1 foo2 2 5
In [297]:
left
Out[297]:
key lval
0 foo1 1
1 foo2 2
In [298]:
right
Out[298]:
key rval
0 foo1 4
1 foo2 5

Groupby

In [300]:
import random
In [305]:
df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar','foo', 'bar', 'foo', 'foo'],
                    'B' : ['one', 'one', 'two', 'three','two', 'two', 'one', 'three'],
                    'C' :np.random.randn(8), 'D' : np.random.randn(8)});
In [306]:
df
Out[306]:
A B C D
0 foo one 0.584419 -0.594567
1 bar one -1.331418 -0.167330
2 foo two 0.125558 0.744053
3 bar three 0.850646 -0.741091
4 foo two -0.033590 -0.239762
5 bar two 0.332681 0.567786
6 foo one 1.051195 1.509953
7 foo three 0.374087 -0.318311
In [307]:
df.groupby('A').sum() # 按照 A 列的值分组求和
Out[307]:
C D
A
bar -0.148091 -0.340636
foo 2.101669 1.101366
In [308]:
df.groupby(['A','B']).sum() # 按照 A、B 两列的值分组求和
Out[308]:
C D
A B
bar one -1.331418 -0.167330
three 0.850646 -0.741091
two 0.332681 0.567786
foo one 1.635614 0.915386
three 0.374087 -0.318311
two 0.091968 0.504291

在实际应用中,先定义 groups,然后再对不同的指标指定不同计算方式。

In [ ]:
groups = df.groupby('A') # 按照 A 列的值分组求和
groups['B'].sum() # 按照 A 列的值分组求 B 组和
groups['B'].count() # 按照 A 列的值分组 B 组计数
In [309]:
groups = df.groupby('A') # 按照 A 列的值分组求和
In [312]:
groups['C'].sum() # 按照 A 列的值分组求 B 组和
Out[312]:
A
bar   -0.148091
foo    2.101669
Name: C, dtype: float64
In [314]:
groups['B'].count() # 按照 A 列的值分组 B 组计数
Out[314]:
A
bar    3
foo    5
Name: B, dtype: int64

默认会以 groupby 的值作为索引,如果不将这些值作为索引,则需要使用 as_index=False

In [316]:
df
Out[316]:
A B C D
0 foo one 0.584419 -0.594567
1 bar one -1.331418 -0.167330
2 foo two 0.125558 0.744053
3 bar three 0.850646 -0.741091
4 foo two -0.033590 -0.239762
5 bar two 0.332681 0.567786
6 foo one 1.051195 1.509953
7 foo three 0.374087 -0.318311
In [317]:
df.groupby(['A','B'], as_index=False).sum()
# 注意与 In [308] 对比
Out[317]:
A B C D
0 bar one -1.331418 -0.167330
1 bar three 0.850646 -0.741091
2 bar two 0.332681 0.567786
3 foo one 1.635614 0.915386
4 foo three 0.374087 -0.318311
5 foo two 0.091968 0.504291

透视表

使用 pivot_table 和 crosstab 都可以创建数据透视表

pivot_table

In [318]:
df = pd.DataFrame({'A' : ['one', 'one', 'two', 'three'] * 3,'B' : ['A', 'B', 'C'] * 4, 
                'C' : ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 2, 
                'D' : np.random.randn(12), 'E' : np.random.randn(12)})
In [319]:
df
Out[319]:
A B C D E
0 one A foo 0.081074 0.358511
1 one B foo -1.741607 -1.105890
2 two C foo -1.220509 -0.241541
3 three A bar -0.663041 0.087185
4 one B bar -0.259216 -1.891769
5 one C bar -0.810547 1.456797
6 two A foo -0.507784 1.801202
7 three B foo 0.602052 1.740630
8 one C foo 0.671181 -0.210367
9 one A bar 0.615852 -0.947002
10 two B bar -0.209238 -1.500853
11 three C bar 1.050343 0.837500
In [324]:
pd.pivot_table(df, values = 'D', index = ['A', 'B'], columns = ['C']) #以 A、B 为行标签,以 C 为列标签将 D 列的值汇总求和
Out[324]:
C bar foo
A B
one A 0.615852 0.081074
B -0.259216 -1.741607
C -0.810547 0.671181
three A -0.663041 NaN
B NaN 0.602052
C 1.050343 NaN
two A NaN -0.507784
B -0.209238 NaN
C NaN -1.220509

crosstab

In [336]:
df
Out[336]:
A B C D E
0 one A foo 0.081074 0.358511
1 one B foo -1.741607 -1.105890
2 two C foo -1.220509 -0.241541
3 three A bar -0.663041 0.087185
4 one B bar -0.259216 -1.891769
5 one C bar -0.810547 1.456797
6 two A foo -0.507784 1.801202
7 three B foo 0.602052 1.740630
8 one C foo 0.671181 -0.210367
9 one A bar 0.615852 -0.947002
10 two B bar -0.209238 -1.500853
11 three C bar 1.050343 0.837500
In [335]:
pd.crosstab([df.A, df.B], df.C, margins=True) # 以 A、B 为行标签,以 C 为列标签将 D 列的值汇总求个数
Out[335]:
C bar foo All
A B
one A 1 1 2
B 1 1 2
C 1 1 2
three A 1 0 1
B 0 1 1
C 1 0 1
two A 0 1 1
B 1 0 1
C 0 1 1
All 6 6 12
In [338]:
pd.crosstab([df.A, df.B], df.C, margins=False) # 以 A、B 为行标签,以 C 为列标签将 D 列的值汇总求个数
Out[338]:
C bar foo
A B
one A 1 1
B 1 1
C 1 1
three A 1 0
B 0 1
C 1 0
two A 0 1
B 1 0
C 0 1

时间序列分析

pandas 提供 to_datetime 方法将代表时间的字符转化为 Timestamp 对象:

In [339]:
s = '2013-09-16 21:00:00'
ts = pd.to_datetime(s)
In [340]:
ts
Out[340]:
Timestamp('2013-09-16 21:00:00')

有时我们需要处理时区问题:

In [342]:
ts=pd.to_datetime(s,utc=True).tz_convert('Asia/Shanghai')
In [343]:
ts
Out[343]:
Timestamp('2013-09-17 05:00:00+0800', tz='Asia/Shanghai')

构建时间序列:

In [345]:
rng = pd.date_range('1/1/2012', periods=5, freq='M')
ts = pd.Series(np.random.randn(len(rng)), index=rng)
In [346]:
rng
Out[346]:
DatetimeIndex(['2012-01-31', '2012-02-29', '2012-03-31', '2012-04-30',
               '2012-05-31'],
              dtype='datetime64[ns]', freq='M')
In [347]:
ts
Out[347]:
2012-01-31    0.839176
2012-02-29   -0.631665
2012-03-31   -0.941336
2012-04-30    0.754626
2012-05-31   -2.149063
Freq: M, dtype: float64

Pandas 提供 resample 方法对时间序列的时间粒度进行调整:

In [349]:
ts_h=ts.resample('H').count() # M,5Min,1s
# 以上是将时间序列调整为小时,还可以支持月(M),分钟(Min)甚至秒(s)等。
In [351]:
ts_h.head()
Out[351]:
2012-01-31 00:00:00    1
2012-01-31 01:00:00    0
2012-01-31 02:00:00    0
2012-01-31 03:00:00    0
2012-01-31 04:00:00    0
Freq: H, dtype: int64
In [353]:
type(ts_h)
Out[353]:
pandas.core.series.Series
In [ ]: