pandas建造在NumPy之上,它使得以NumPy为中心的应用很容易使用。
import numpy as np
import pandas as pd
from pandas import Series, DataFrame
Series 是一个一维的类似的数组对象,包含一个数组的数据(任何 NumPy 的数据类型)和一个与数组关联的数据标签,被叫做 索引 。最简单的 Series 是由一个数组的数据构成:
obj = Series([4, 7, -5, 3])
obj
0 4 1 7 2 -5 3 3 dtype: int64
Seriers 的交互式显示的字符窜表示形式是索引在左边,值在右边。
因为我们没有给数据指定索引,一个包含整数 0 到 N-1 (这里 N 是数据的长度)的默认索引被创建。 可以分别的通过它的 values 和 index 属性来获取 Series 的数组表示和索引对象:
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
与正规的 NumPy 数组相比,你可以使用索引里的值来选择一个单一值或一个值集:
obj2['a']
-5
obj2['d'] = 6
obj2[['c', 'a', 'd']]
c 3 a -5 d 6 dtype: int64
NumPy 数组操作,例如通过一个布尔数组过滤,纯量乘法,或使用数学函数,将会保持索引和值间的关联:
obj2
d 6 b 7 a -5 c 3 dtype: int64
obj2[obj2 > 0]
d 6 b 7 c 3 dtype: int64
obj2 * 2
d 12 b 14 a -10 c 6 dtype: int64
np.exp(obj2)
d 403.428793 b 1096.633158 a 0.006738 c 20.085537 dtype: float64
另一种思考的方式是,Series 是一个定长的,有序的字典,因为它把索引和值映射起来了。它可以适用于许多期望一个字典的函数:
'b' in obj2
True
'e' in obj2
False
如果你有一些数据在一个 Python 字典中,你可以通过传递字典来从这些数据创建一个 Series:
sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
obj3 = Series(sdata)
obj3
Ohio 35000 Oregon 16000 Texas 71000 Utah 5000 dtype: int64
只传递一个字典的时候,结果 Series 中的索引将是排序后的字典的键。
states = ['California', 'Ohio', 'Oregon', 'Texas']
obj4 = Series(sdata, index=states)
obj4
California NaN Ohio 35000.0 Oregon 16000.0 Texas 71000.0 dtype: float64
在这种情况下, sdata 中的3个值被放在了合适的位置,但因为没有发现对应于 ‘California’ 的值,就出现了 NaN (不是一个数),这在 pandas 中被用来标记数据缺失或 NA 值。使用 “missing” 或 “NA” 来表示数度丢失。
在 pandas 中用函数 isnull 和 notnull 来检测数据丢失:
pd.isnull(obj4)
California True Ohio False Oregon False Texas False dtype: bool
pd.notnull(obj4)
California False Ohio True Oregon True Texas True dtype: bool
obj4.isnull()
California True Ohio False Oregon False Texas False dtype: bool
在许多应用中 Series 的一个重要功能是在算术预算中它会自动对齐不同索引的数据:
obj3
Ohio 35000 Oregon 16000 Texas 71000 Utah 5000 dtype: int64
obj4
California NaN Ohio 35000.0 Oregon 16000.0 Texas 71000.0 dtype: float64
obj3 + obj4
California NaN Ohio 70000.0 Oregon 32000.0 Texas 142000.0 Utah NaN dtype: float64
Series 对象本身和它的索引都有一个 name 属性,它和 pandas 的其它一些关键功能整合在一起:
obj4.name = 'population'
obj4.index.name = 'state'
obj4
state California NaN Ohio 35000.0 Oregon 16000.0 Texas 71000.0 Name: population, dtype: float64
Series 的索引可以通过赋值就地更改:
obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']
obj
Bob 4 Steve 7 Jeff -5 Ryan 3 dtype: int64
一个 Datarame 表示一个表格,类似电子表格的数据结构,包含一个经过排序的列表集,它们每一个都可以有不同的类型值(数字,字符串,布尔等等)。
Datarame 有行和列的索引;它可以被看作是一个 Series 的字典(每个 Series 共享一个索引)。
与其它你以前使用过的(如 R 的 data.frame )类似 Datarame 的结构相比,在 DataFrame 里的面向行和面向列的操作大致是对称的。
在底层,数据是作为一个或多个二维数组存储的,而不是列表,字典,或其它一维的数组集合。
因为 DataFrame 在内部把数据存储为一个二维数组的格式,因此你可以采用分层索引以表格格式来表示高维的数据。
有很多方法来构建一个 DataFrame,但最常用的一个是用一个相等长度列表的字典或 NumPy 数组:
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 一样,它的索引会自动分配,并且对列进行了排序:
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 一样,如果你传递了一个行,但不包括在 data 中,在结果中它会表示为 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 |
和 Series 一样,在 DataFrame 中的一列可以通过字典记法或属性来检索:
frame2['state']
one Ohio two Ohio three Ohio four Nevada five Nevada Name: state, dtype: object
frame2.year
one 2000 two 2001 three 2002 four 2001 five 2002 Name: year, dtype: int64
注意,返回的 Series 包含和 DataFrame 相同的索引,并它们的 name 属性也被正确的设置了。
行也可以使用一些方法通过位置或名字来检索,例如 ix 索引成员(field)(更多的将在后面介绍):
frame2.ix['three']
year 2002 state Ohio pop 3.6 debt NaN Name: three, dtype: object
列可以通过赋值来修改。例如,空的 ‘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 |
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 的长度相匹配。否则全部为 NA。
如果你使用 Series 来赋值,它会代替在 DataFrame 中精确匹配的索引的值,并在说有的空洞插入丢失数据:
val2 = Series([-1.2, -1.5, -1.7])
frame2['debt'] = val2
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 |
val = Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
frame2['debt'] = val
frame2
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 关键字将会删除列:
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 |
注意:索引 DataFrame 时返回的列是底层数据的一个视窗,而不是一个拷贝。因此,任何在 Series 上的就地修改都会影响 DataFrame。列可以使用 Series 的 copy 函数来显式的拷贝。
另一种通用的数据形式是一个嵌套的字典的字典格式:
pop = {'Nevada': {2001: 2.4, 2002: 2.9},
....: 'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
pop
{'Nevada': {2001: 2.4, 2002: 2.9}, 'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
如果被传递到 DataFrame,它的外部键会被解释为列索引,内部键会被解释为行索引:
frame3 = DataFrame(pop)
frame3
Nevada | Ohio | |
---|---|---|
2000 | NaN | 1.5 |
2001 | 2.4 | 1.7 |
2002 | 2.9 | 3.6 |
当然,总是可以对结果转置:
frame3.T
2000 | 2001 | 2002 | |
---|---|---|---|
Nevada | NaN | 2.4 | 2.9 |
Ohio | 1.5 | 1.7 | 3.6 |
内部字典的键被结合并排序来形成结果的索引。如果指定了一个特定的索引,就不是这样的了:
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'][:2]}
pdata
{'Nevada': 2000 NaN 2001 2.4 Name: Nevada, dtype: float64, 'Ohio': 2000 1.5 2001 1.7 Name: Ohio, dtype: float64}
DataFrame(pdata)
Nevada | Ohio | |
---|---|---|
2000 | NaN | 1.5 |
2001 | 2.4 | 1.7 |
如果一个 DataFrame 的 index 和 columns 有它们的 name ,也会被显示出来:
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 |
像 Series 一样, values 属性返回一个包含在 DataFrame 中的数据的二维 ndarray:
frame3.values
array([[ nan, 1.5], [ 2.4, 1.7], [ 2.9, 3.6]])
如果 DataFrame 的列有不同的 dtypes,返回值数组将会给所有的列选择一个合适的 dtyps:
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 |
frame2.values
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 时任何数组或其它序列标签在内部转化为索引:
obj = Series(range(3), index=['a', 'b', 'c'])
index = obj.index
index
Index([u'a', u'b', u'c'], dtype='object')
index[1:]
Index([u'b', u'c'], dtype='object')
索引对象是不可变的,因此不能由用户改变:
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
索引对象的不可变性非常重要,这样它可以在数据结构中结构中安全的共享:
index = pd.Index(np.arange(3))
obj2 = Series([1.5, -2.5, 0], index=index)
obj2.index is index
True
下表是库中内建的索引类清单。通过一些开发努力,索引可以被子类化,来实现特定坐标轴索引功能。
索引类型 | 说明 |
---|---|
Index | 最通用的索引对象,使用Python对象的NumPy数组来表示坐标轴标签。 |
Int64Index | 对整形值的特化索引。 |
MultiIndex | “分层”索引对象,表示单个轴的多层次的索引。可以被认为是类似的元组的数组。 |
DatetimeIndex | 存储纳秒时间戳(使用NumPy的datetime64 dtyppe来表示)。 |
PeriodIndex | 对周期数据(时间间隔的)的特化索引。 |
除了类似于阵列,索引也有类似固定大小集合一样的功能:
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
每个索引都有许多关于集合逻辑的方法和属性,且能够解决它所包含的数据的常见问题。这些都总结在下表中。
方法 | 属性 |
---|---|
append | 链接额外的索引对象,产生一个新的索引 |
diff | 计算索引的差集 |
intersection | 计算交集 |
union | 计算并集 |
isin | 计算出一个布尔数组表示每一个值是否包含在所传递的集合里 |
delete | 计算删除位置i的元素的索引 |
drop | 计算删除所传递的值后的索引 |
insert | 计算在位置i插入元素后的索引 |
is_monotonic | 返回True,如果每一个元素都比它前面的元素大或相等 |
is_unique | 返回True,如果索引没有重复的值 |
unique | 计算索引的唯一值数组 |
pandas 对象的一个关键的方法是 reindex ,意味着使数据符合一个新的索引来构造一个新的对象。来看一下下面一个简单的例子:
obj = Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
obj
d 4.5 b 7.2 a -5.3 c 3.6 dtype: float64
在 Series 上调用 reindex 重排数据,使得它符合新的索引,如果那个索引的值不存在就引入缺失数据值:
注意:reindex 并不改变 index 的数值,只是重排数据。(索引对象的不可变性)
obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])
obj2
a -5.3 b 7.2 c 3.6 d 4.5 e NaN dtype: float64
obj.reindex(['a', 'b', 'c', 'd', 'e'], fill_value=0)
a -5.3 b 7.2 c 3.6 d 4.5 e 0.0 dtype: float64
为了对时间序列这样的数据排序,当重建索引的时候可能想要对值进行内插或填充。 method 选项可以是你做到这一点,使用一个如 ffill 的方法来向前填充值:
obj3 = Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
obj3
0 blue 2 purple 4 yellow dtype: object
obj3.reindex(range(6), method='ffill')
0 blue 1 blue 2 purple 3 purple 4 yellow 5 yellow dtype: object
下是可用的 method 选项的清单。在此,内差比正向和反向填充更复杂。
参数 | 描述 |
---|---|
ffill或pad | 前向(或进位)填充 |
bfill或backfill | 后向(或进位)填充 |
对于 DataFrame, reindex 可以改变(行)索引,列或两者。当只传入一个序列时,结果中的行被重新索引了:
frame = DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'],
....: columns=['Ohio', 'Texas', 'California'])
frame
Ohio | Texas | California | |
---|---|---|---|
a | 0 | 1 | 2 |
c | 3 | 4 | 5 |
d | 6 | 7 | 8 |
frame2 = frame.reindex(['a', 'b', 'c', 'd'])
frame2
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 关键字可以使列重新索引:
states = ['Texas', 'Utah', 'California']
frame.reindex(columns=states)
# 再次注意索引对象的不可变性
Texas | Utah | California | |
---|---|---|---|
a | 1 | NaN | 2 |
c | 4 | NaN | 5 |
d | 7 | NaN | 8 |
一次可以对两个重新索引,可是插值只在行侧(0坐标轴)进行:
frame
Ohio | Texas | California | |
---|---|---|---|
a | 0 | 1 | 2 |
c | 3 | 4 | 5 |
d | 6 | 7 | 8 |
frame.reindex(index=['a', 'b', 'c', 'd'], method='ffill',
....: columns=states)
Texas | Utah | California | |
---|---|---|---|
a | 1 | NaN | 2 |
b | 1 | NaN | 2 |
c | 4 | NaN | 5 |
d | 7 | NaN | 8 |
正如你将看到的,使用带标签索引的 ix 可以把重新索引做的更简单:
frame.ix[['a', 'b', 'c', 'd'], states]
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 |
参数 | 说明 |
---|---|
index | 作为索引的新序列。可以是索引实例或任何类似序列的Python数据结构。一个索引被完全使用,没有任何拷贝。 |
method | 插值(填充)方法,见表格5-4的选项 |
fill_value | 代替重新索引时引入的缺失数据值 |
limit | 当前向或后向填充时,最大的填充间隙 |
level | 在多层索引上匹配简单索引,否则选择一个子集 |
copy | 如果新索引与就的相等则底层数据不会拷贝。默认为True(即始终拷贝) |
从坐标轴删除一个多或多个条目是很容易的,如果你有一个索引数组或列表且没有这些条目,但是这可能需要一点修改和集合逻辑。 drop 方法将会返回一个新的对象并从坐标轴中删除指定的一个或多个值:
obj = Series(np.arange(5.), index=['a', 'b', 'c', 'd', 'e'])
new_obj = obj.drop('c')
new_obj
a 0.0 b 1.0 d 3.0 e 4.0 dtype: float64
obj.drop(['d', 'c'])
a 0.0 b 1.0 e 4.0 dtype: float64
对于 DataFrame,可以从任何坐标轴删除索引值:
data = DataFrame(np.arange(16).reshape((4, 4)),
....: index=['Ohio', 'Colorado', 'Utah', 'New York'],
....: columns=['one', 'two', 'three', 'four'])
data.drop(['Colorado', 'Ohio'])
one | two | three | four | |
---|---|---|---|---|
Utah | 8 | 9 | 10 | 11 |
New York | 12 | 13 | 14 | 15 |
data.drop('two', axis=1)
one | three | four | |
---|---|---|---|
Ohio | 0 | 2 | 3 |
Colorado | 4 | 6 | 7 |
Utah | 8 | 10 | 11 |
New York | 12 | 14 | 15 |
data.drop(['two', 'four'], axis=1)
one | three | |
---|---|---|
Ohio | 0 | 2 |
Colorado | 4 | 6 |
Utah | 8 | 10 |
New York | 12 | 14 |
Series 索引 ( obj[...] )的工作原理类似与 NumPy 索引,除了可以使用 Series 的索引值,也可以仅使用整数来索引。下面是关于这一点的一些例子:
obj = Series([2,3,1,5], index=['a', 'b', 'c', 'd'])
obj
a 2 b 3 c 1 d 5 dtype: int64
obj['b'], obj[1]
(3, 3)
obj[['b', 'a', 'd']]
b 3 a 2 d 5 dtype: int64
obj[[1, 3]] # 索引位置
b 3 d 5 dtype: int64
obj[obj < 2]
c 1 dtype: int64
使用标签来切片和正常的 Python 切片并不一样,它会把结束点也包括在内:
obj['b':'c']
b 3 c 1 dtype: int64
obj['b':'c'] = 5
obj
a 2 b 5 c 5 d 5 dtype: int64
正如上面你所见到的,索引 DataFrame 来检索一个或多个列,可以使用一个单一值或一个序列:
data = DataFrame(np.arange(16).reshape((4, 4)),
.....: index=['Ohio', 'Colorado', 'Utah', 'New York'],
.....: columns=['one', 'two', 'three', 'four'])
data
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 |
data['two']
Ohio 1 Colorado 5 Utah 9 New York 13 Name: two, dtype: int64
data[['three', 'one']]
three | one | |
---|---|---|
Ohio | 2 | 0 |
Colorado | 6 | 4 |
Utah | 10 | 8 |
New York | 14 | 12 |
像这样的索引有一些特殊的情况。首先,可以通过切片或一个布尔数组来选择行:
data[:2]
one | two | three | four | |
---|---|---|---|---|
Ohio | 0 | 1 | 2 | 3 |
Colorado | 4 | 5 | 6 | 7 |
data[(data.one >=1 ) & (data.one < 7) ] # 多个逻辑条件组合
one | two | three | four | |
---|---|---|---|---|
Colorado | 4 | 5 | 6 | 7 |
data[data['three'] > 5]
one | two | three | four | |
---|---|---|---|---|
Colorado | 4 | 5 | 6 | 7 |
Utah | 8 | 9 | 10 | 11 |
New York | 12 | 13 | 14 | 15 |
另一种用法是在索引中使用一个布尔 DataFrame,例如通过纯量比较产生的:
data < 5
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 |
data[data <5] = 0
data
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 的记法再加上轴标签。正如我早先提到的,这也是一种不是很冗长的重新索引的方法:
data.ix['Colorado', ['two', 'three']]
two 5 three 6 Name: Colorado, dtype: int64
data.ix[['Colorado', 'Utah'], [3, 0, 1]] # 3,0,1 表示位置顺序
four | one | two | |
---|---|---|---|
Colorado | 7 | 0 | 5 |
Utah | 11 | 8 | 9 |
data.ix[2] # 第 2 行
one 8 two 9 three 10 four 11 Name: Utah, dtype: int64
data.ix[:,2] # 第 2 列
Ohio 0 Colorado 6 Utah 10 New York 14 Name: three, dtype: int64
data.ix[:'Utah', 'two']
Ohio 0 Colorado 5 Utah 9 Name: two, dtype: int64
data.ix[data.three > 5, :]
one | two | three | four | |
---|---|---|---|---|
Colorado | 0 | 5 | 6 | 7 |
Utah | 8 | 9 | 10 | 11 |
New York | 12 | 13 | 14 | 15 |
data.ix[data.three > 5, :3]
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 方法 | 通过行和列标选择一个单值 |
其他切片方式:
data
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 |
# df.loc[行标签,列标签]
data.loc['Colorado':'New York'] # 选取 a:b 行数据
one | two | three | four | |
---|---|---|---|---|
Colorado | 0 | 5 | 6 | 7 |
Utah | 8 | 9 | 10 | 11 |
New York | 12 | 13 | 14 | 15 |
data.loc[:,'one'] # 选取 one 列的数据
Ohio 0 Colorado 0 Utah 8 New York 12 Name: one, dtype: int64
# df.iloc[行位置,列位置]
data.iloc[1,1] # 选取第二行,第二列的值,返回的为单个值
5
data.iloc[[0,2], :] #选取第一行及第三行的数据
one | two | three | four | |
---|---|---|---|---|
Ohio | 0 | 0 | 0 | 0 |
Utah | 8 | 9 | 10 | 11 |
data.iloc[0:2,:] # 选取第一行到第三行(不包含)的数据,就是前两行的数据
one | two | three | four | |
---|---|---|---|---|
Ohio | 0 | 0 | 0 | 0 |
Colorado | 0 | 5 | 6 | 7 |
data.iloc[:,1] # 选取所有记录的第一列的值,返回的为一个 Series
Ohio 0 Colorado 5 Utah 9 New York 13 Name: two, dtype: int64
data.iloc[1,:] # 选取第二行数据,返回的为一个 Series
one 0 two 5 three 6 four 7 Name: Colorado, dtype: int64
当把对象加起来时,如果有任何的索引对不相同的话,在结果中将会把各自的索引联合起来。
在索引不重合的地方引入了 NA 值。
arr = np.arange(12.).reshape(3,4)
arr[0]
array([ 0., 1., 2., 3.])
arr-arr[0]
array([[ 0., 0., 0., 0.], [ 4., 4., 4., 4.], [ 8., 8., 8., 8.]])
以下内容参考至:Python中的结构化数据分析利器-Pandas简介
# 从 CSV 中读取数据
df = pd.read_csv('foo.csv')
#将 DataFrame 写入 CSV
df.to_csv('foo.csv')
# 从 Excel 中读取数据:先定义一个 Excel 文件,
# 用 xls.parse 解析 sheet1 的内容,index_col 用于指定 index 列,na_values 定义缺失值的标识。
xls = ExcelFile('foo.xlsx')
xls.parse('sheet1', index_col=None, na_values=['NA'])
# 将DataFrame 写入 Excel 文件
df.to_excel('foo.xlsx', sheet_name='sheet1')
data = DataFrame(np.arange(16).reshape((4, 4)),
....: index=['Ohio', 'Colorado', 'Utah', 'New York'],
....: columns=['one', 'two', 'three', 'four'])
data
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 |
data.mean() # 计算列的平均值,参数为轴,可选值为 0 或 1.默认为 0,即按照列运算
one 6.0 two 7.0 three 8.0 four 9.0 dtype: float64
data.sum(1) # 计算行的和
Ohio 6 Colorado 22 Utah 38 New York 54 dtype: int64
# 将一个函数应用到 DataFrame 的每一列,这里使用的是匿名 lambda 函数,与 R 中 apply 函数类似
data.apply(lambda x: x.max() - x.min())
one 12 two 12 three 12 four 12 dtype: int64
# 应用到某一列
# 推荐
data['one'] = data['one'].apply(lambda x: x+1)
data
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 |
# 应用到某一列
# 首元素会多执行一遍
def addone(v):
v[0] += 1
return v
data.apply(addone, axis=1)
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 |
def addone(v):
v += 1
return v
data['one'] = data['one'].map(addone)
data
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 |
df = DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'],
....: columns=['Ohio', 'Texas', 'California'])
df
Ohio | Texas | California | |
---|---|---|---|
a | 0 | 1 | 2 |
c | 3 | 4 | 5 |
d | 6 | 7 | 8 |
df.ix["a"] = [10,11,12]
df
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 即降序排列。
df.sort_index(axis=0, ascending=False) # 对行进行排序 d,c,a
Ohio | Texas | California | |
---|---|---|---|
d | 6 | 7 | 8 |
c | 3 | 9 | 5 |
a | 10 | 11 | 12 |
df
Ohio 10 Texas 11 California 12 Name: a, dtype: int64
df.sort_index(axis=1, ascending=False) # 对列进行排序 Texas, Ohio, California
Texas | Ohio | California | |
---|---|---|---|
a | 11 | 10 | 12 |
c | 9 | 3 | 5 |
d | 7 | 6 | 8 |
DataFrame 也提供按照指定列进行排序,可以仅指定一个列作为排序标准(以单独列名作为 columns 的参数),也可以进行多重排序(columns 的参数为一个列名的 List,列名的出现顺序决定排序中的优先级),在多重排序中 ascending 参数也为一个 List,分别与 columns 中的 List 元素对应。
df.sort_values(by='Ohio', ascending=False)
Ohio | Texas | California | |
---|---|---|---|
a | 10 | 11 | 12 |
d | 6 | 7 | 8 |
c | 3 | 4 | 5 |
df.ix[1,1]=9
df
Ohio | Texas | California | |
---|---|---|---|
a | 10 | 11 | 12 |
c | 3 | 9 | 5 |
d | 6 | 7 | 8 |
df.sort_values(by=['Ohio','Texas'],ascending=[0,1])
Ohio | Texas | California | |
---|---|---|---|
a | 10 | 11 | 12 |
d | 6 | 7 | 8 |
c | 3 | 9 | 5 |
df.rename(columns={u'one':'1'}, inplace=True)
df.set_index('one')
df.reset_index(inplace=True)
pd.Series.max()
pd.Series.idxmax()
df['A'].astype(float)
df['A'].value_counts()
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'])
dfs
one | three | two | |
---|---|---|---|
e | 4.0 | NaN | 2 |
f | 5.0 | NaN | 3 |
g | 6.0 | NaN | 4 |
h | NaN | 10.0 | 7 |
##构建一个新的 DataFrame,dfs
df_t=pd.concat([dfs,dfs],axis=1) # 合并两个 DataFrame
df_t
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 |
##构建一个新的 DataFrame,dfs
df_t=pd.concat([dfs,dfs],axis=0) # 合并两个 DataFrame
df_t
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 |
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在一起
key | lval | rval | |
---|---|---|---|
0 | foo1 | 1 | 4 |
1 | foo2 | 2 | 5 |
left
key | lval | |
---|---|---|
0 | foo1 | 1 |
1 | foo2 | 2 |
right
key | rval | |
---|---|---|
0 | foo1 | 4 |
1 | foo2 | 5 |
import random
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)});
df
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 |
df.groupby('A').sum() # 按照 A 列的值分组求和
C | D | |
---|---|---|
A | ||
bar | -0.148091 | -0.340636 |
foo | 2.101669 | 1.101366 |
df.groupby(['A','B']).sum() # 按照 A、B 两列的值分组求和
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,然后再对不同的指标指定不同计算方式。
groups = df.groupby('A') # 按照 A 列的值分组求和
groups['B'].sum() # 按照 A 列的值分组求 B 组和
groups['B'].count() # 按照 A 列的值分组 B 组计数
groups = df.groupby('A') # 按照 A 列的值分组求和
groups['C'].sum() # 按照 A 列的值分组求 B 组和
A bar -0.148091 foo 2.101669 Name: C, dtype: float64
groups['B'].count() # 按照 A 列的值分组 B 组计数
A bar 3 foo 5 Name: B, dtype: int64
默认会以 groupby 的值作为索引,如果不将这些值作为索引,则需要使用 as_index=False
df
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 |
df.groupby(['A','B'], as_index=False).sum()
# 注意与 In [308] 对比
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 都可以创建数据透视表
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)})
df
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 |
pd.pivot_table(df, values = 'D', index = ['A', 'B'], columns = ['C']) #以 A、B 为行标签,以 C 为列标签将 D 列的值汇总求和
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 |
df
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 |
pd.crosstab([df.A, df.B], df.C, margins=True) # 以 A、B 为行标签,以 C 为列标签将 D 列的值汇总求个数
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 |
pd.crosstab([df.A, df.B], df.C, margins=False) # 以 A、B 为行标签,以 C 为列标签将 D 列的值汇总求个数
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 对象:
s = '2013-09-16 21:00:00'
ts = pd.to_datetime(s)
ts
Timestamp('2013-09-16 21:00:00')
有时我们需要处理时区问题:
ts=pd.to_datetime(s,utc=True).tz_convert('Asia/Shanghai')
ts
Timestamp('2013-09-17 05:00:00+0800', tz='Asia/Shanghai')
构建时间序列:
rng = pd.date_range('1/1/2012', periods=5, freq='M')
ts = pd.Series(np.random.randn(len(rng)), index=rng)
rng
DatetimeIndex(['2012-01-31', '2012-02-29', '2012-03-31', '2012-04-30', '2012-05-31'], dtype='datetime64[ns]', freq='M')
ts
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 方法对时间序列的时间粒度进行调整:
ts_h=ts.resample('H').count() # M,5Min,1s
# 以上是将时间序列调整为小时,还可以支持月(M),分钟(Min)甚至秒(s)等。
ts_h.head()
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
type(ts_h)
pandas.core.series.Series