Python for Data Analysis Note II

Posted by Gloomymoon on 2016-11-14

5 pandas入门

约定:

1
2
from pandas import Series, DataFrame
import pandas as pd

5.1 pandas的数据机构介绍

pandas两个主要数据结构SeriesDataFrame

Series
Series有两个属性valuesindex,表示数据(各种NumPy数据类型)及与之相关的标签(索引),因此可以从一个Python字典中直接创建Series

1
2
3
sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
obj3 = Series(sdata)
obj3

Output:

1
2
3
4
5
Ohio      35000
Oregon 16000
Texas 71000
Utah 5000
dtype: int64

可以指定index,注意只有index中的数据保留:

1
2
3
states = ['California', 'Ohio', 'Oregon', 'Texas']
obj4 = Series(sdata, index=states)
obj4

Output:

1
2
3
4
5
California      NaN
Ohio 35000
Oregon 16000
Texas 71000
dtype: float64

Series最重要的一个功能是:在算术运算中自动对齐不同索引的数据。

1
obj3 + obj4

Output:

1
2
3
4
5
6
California       NaN
Ohio 70000
Oregon 32000
Texas 142000
Utah NaN
dtype: float64

Series对象本省及其索引都有一个name属性,这跟pandas其他关键功能关系密切。

1
2
3
obj4.name = 'population'
obj4.index.name = 'state'
obj4

Output:

1
2
3
4
5
6
state
California NaN
Ohio 35000
Oregon 16000
Texas 71000
Name: population, dtype: float64

DataFrame
DataFrame是一个表格型数据结构,它含有一组有序的列,每列可以是不同的类型。DataFrame既有行索引也有列索引,可以看作是由Series组成的字典。
构建DataFrame最直接的方式是传入一个由等长列表或NumPy数组组成的字典:

1
2
3
4
5
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

Output:

1
2
3
4
5
6
 	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会按照指定顺序排列列。

1
frame2 = DataFrame(data, columns=['year', 'state', 'pop'], index=['one', 'two', 'three', 'four', 'five'])

如果传入的列在数据中找不到,就会产生NaN值。

通过字典标记的方式或属性的方式,可以已Series的方式获取DataFrame的列。

1
2
frame2['state']
frame2.year

通过ix可以获取行。

1
frame2.ix['three']

Output:

1
2
3
4
year     2002
state Ohio
pop 3.6
Name: three, dtype: object

用索引方式返回的都是源数据的视图,并非副本,因此所有的修改都会全部反映到源DataFrame中。

索引对象

5.2 基本功能

重新索引
pandas对象一个重要方法是reindex,创建一个适应新索引的新对象。

丢弃指定轴上的项
drop防范可以删除任意轴上的索引项。

索引、选取和过滤
Series索引用标签切片的运算与普通Python切片不同,是末端包含的。
DataFrame进行索引就是获取一个或多个列,但是通过切片或布尔数组方式选取的是行,这是逻辑用法是来源于

算术运算和数据对齐
pandas对象相加时,如果存在不同的索引树,结果的索引就是该索引对的并集。
在算术方法中填充值时,如果希望对缺失值赋予一个特殊值,可以使用fill_value参数,该参数在重新索引时也可以使用。

1
2
3
4
df1 = DataFrame(np.arange(12.).reshape((3,4)), columns=list('abcd'))
df2 = DataFrame(np.arange(20.).reshape((4,5)), columns=list('abcde'))
df1 + df2
df1.add(df2, fill_value=0)

Output:

1
2
3
4
5
6
7
8
9
10
11
 	a 	b 	c 	d 	e
0 0 2 4 6 NaN
1 9 11 13 15 NaN
2 18 20 22 24 NaN
3 NaN NaN NaN NaN NaN

a b c d e
0 0 2 4 6 4
1 9 11 13 15 9
2 18 20 22 24 14
3 15 16 17 18 19

DataFrame和Series之间的运算
和NumPy中不同维度数组之间的广播机制类似,DataFrame和Series之间的算术运算会将Series的索引匹配到DataFrame的列,然后沿着行的防线一直向下广播。

1
2
3
frame = DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['Utah','Ohio','Texas','Oregon'])
series = frame.ix[0]
frame - series

Output:

1
2
3
4
5
 	b 	d 	e
Utah 0 0 0
Ohio 3 3 3
Texas 6 6 6
Oregon 9 9 9

如果希望匹配行在列上广播,必须使用算术运算方法。

1
2
series3 = frame['d']
frame.sub(series3, axis=0)

Output:

1
2
3
4
5
 		b 	d 	e
Utah -1 0 1
Ohio -1 0 1
Texas -1 0 1
Oregon -1 0 1

函数应用和映射
NumPy的ufuncs(元素级数组方法)也可用于操作pandas对象。另外一个常见的用法是将函数应用到各类或各行所在的一维数组上,DataFrame的.apply()方法可以实现此功能。

1
2
3
4
5
frame = DataFrame(np.random.randn(4,3), columns=list('bde'), index=['Utah','Ohio','Texas','Oregon'])
f = lambda x: x.max() - x.min()
frame
frame.apply(f)
frame.apply(f, axis=1)

Output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 		b 			d 			e
Utah 0.062492 -1.727616 -0.079996
Ohio 1.313402 0.658781 -0.992717
Texas -1.954599 2.428276 1.372190
Oregon -0.821649 0.896800 2.221896

b 2.389651
d 3.365110
e 2.934581
dtype: float64

Utah 0.263963
Ohio 1.964547
Texas 1.133140
Oregon 1.777723
dtype: float64

除此之外,传递给apply的函数还可以是返回多个值的Series。

1
2
3
4
def f(x):
return Series([x.min(), x.max()], index=['min','max'])

frame.apply(f)

Output:

1
2
3
 	b 	d 	e
min -0.274731 -2.239277 -2.157811
max 0.408729 0.724984 0.180029

元素级的函数也可以使用.applymap方法实现。

排序和排名
使用.sort_index方法对行或列索引排序,将返回一个已排序的新对象。
如果希望对一个或多个列中的值进行排序,将列名传递给by选项即可。

1
2
frame = DataFrame({'b':[4,7-3,2], 'a':[0,1,0,1]})
frame.sort_index(by=['a','b'])

Output:

1
2
3
4
5
 		a 	b
2 0 -3
0 0 4
3 1 2
1 1 7

带有重复值的轴索引
可以使用index.is_unique属性来看轴索引是否有重复值。在数据选取时,如果索引对应多个值,则会返回Series,否则返回一个标量值。

5.3 汇总和计算描述统计

pandas的常用数学统计方法,都是基于没有缺失数据的假设而构建的。

1
2
3
4
5
df = DataFrame([[1.4, np.nan], [7.1, -4.5],
[np.nan, np.nan], [0.75, -1.3]],
index=['a', 'b', 'c', 'd'],
columns=['one', 'two'])
df

Output:

1
2
3
4
5
  one	  two
a 1.40 NaN
b 7.10 -4.5
c NaN NaN
d 0.75 -1.3

相关系数与协方差

唯一值、值计数以及成员资格
这类方法可以从一维Series的值中抽取信息,例如unique返回唯一值数组,value_counts计算各值出现的频率,isin用于判断矢量化集合的成员资格

1
2
3
4
obj = Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
mask = obj.isin(['b', 'c'])
mask
obj[mask]

Output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0     True
1 False
2 False
3 False
4 False
5 True
6 True
7 True
8 True
dtype: bool

0 c
5 b
6 b
7 c
8 c
dtype: object

1
2
3
4
5
data = DataFrame({'Qu1': [1, 3, 4, 3, 4],
'Qu2': [2, 3, 1, 2, 3],
'Qu3': [1, 5, 2, 4, 4]})
result = data.apply(pd.value_counts).fillna(0)
result

Output:

1
2
3
4
5
6
  Qu1	Qu2	Qu3
1 1.0 1.0 1.0
2 0.0 2.0 1.0
3 2.0 2.0 0.0
4 2.0 0.0 2.0
5 0.0 0.0 1.0

5.4 处理缺失数据

pandas使用浮点值NaN(Not a Number)表示浮点和非浮点数组中的缺失数字,Python内置的None也会被当作NA处理

滤除缺失数据
.dropna方法或者使用[data.notnull()]布尔型索引都可以直接过滤掉缺失数据。对于DataFrame对象,dtopna()默认丢弃任何含有缺失的行。

填充缺失数据
fillna方法是最主要的填充缺失数据的函数。通过传入一个字典,可以实现对不同列填充不同的值。传入inplace=True参数可以就地修改而不是默认返回新对象。

1
2
3
df.fillna({1: 0.5, 3: -1})
# always returns a reference to the filled object
_ = df.fillna(0, inplace=True)

5.5 层次化索引

对于一个DataFrame,每条轴都可以有分层索引

1
2
frame = DataFrame(np.arange(12).reshape((4,3)), index=[['a','a','b','b'], [1,2,1,2]], columns=[['Ohio','Ohio','Colorado'],['Green','Red','Green']])
frame

Output

1
2
3
4
5
6
 		Ohio 			Colorado
Green Red Green
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11

各层都可以有名字,并且可以单独创建MultiIndex然后复用。

1
2
3
frame.index.names = ['key1','key2']
frame.columns.names = ['state', 'color']
MultiIndex.from_array([['Ohio','Ohio','Colorado'],['Green','Red','Green'], names=['statue','color'])

重排分级顺序
如果需要调整某条轴上各级别的顺序时可以使用swaplevel方法,它接受两个级别编号或名称,斌返回互换级别的新对象(但数据不会变化)

1
frame.swaplevel('key1', 'key2')

Output:

1
2
3
4
5
6
7
state 		Ohio 			Colorado
color Green Red Green
key2 key1
1 a 0 1 2
2 a 3 4 5
1 b 6 7 8
2 b 9 10 11

sortlevel方法则根据单个级别中的值对数据进行排序(稳定的)。注意这里的参数是索引的编号,索引编号是从外向内方向计数的。

1
frame.sortlevel(1)

Output:

1
2
3
4
5
6
7
state 			Ohio 			Colorado
color Green Red Green
key1 key2
a 1 0 1 2
b 1 6 7 8
a 2 3 4 5
b 2 9 10 11

对层次化索引的分级重排是为了提升数据选取操作的效率,按照索引的顺序选取性能要好很多。

根据级别汇总统计
DataFrame和Series的描绘和汇总统计有一个level选项,用于指定在某条轴上求和的级别,这其实是利用了pandas的groupby功能

1
frame.sum(level='color', axis=1)

Output:

1
2
3
4
5
6
color 		Green 	Red
key1 key2
a 1 2 1
2 8 4
b 1 14 7
2 20 10

使用DataFrame的列
通常情况下,我们会将DataFrame的一个或多个列当作行索引,或者可以希望将行索引变成DataFrame的列。
set_index会将一个或多个列专为行索引,并创建一个新的DataFrame。

1
2
3
frame = DataFrame({'a': range(7), 'b': range(7, 0, -1), 'c': ['one','one','one','two','two','two','tow'], 'd': [0,1,2,0,1,2,3]})
frame2 = frame.set_index(['c','d'])
frame2

Output:

1
2
3
4
5
6
7
8
9
 		a 	b
c d
one 0 0 7
1 1 6
2 2 5
two 0 3 4
1 4 3
2 5 2
tow 3 6 1

默认情况下这些列会从DataFrame中移除,但通过添加dtop参数可以将其保留。

1
frame2 = frame.set_index(['c','d'], drop=False)

Output:

1
2
3
4
5
6
7
8
9
 		a 	b 	c 		d
c d
one 0 0 7 one 0
1 1 6 one 1
2 2 5 one 2
two 0 3 4 two 0
1 4 3 two 1
2 5 2 two 2
tow 3 6 1 tow 3

reset_indexset_index功能相反,将层次化的索引转移到列里面。

5.6 其他有关pandas的话题

整数索引
操作由整数索引的pandas对象要注意,因为跟内置Python数据结构在索引语义上的不同,经常会产生一个错误。

1
2
ser = Series(np.arange(3.))
ser[-1]

上述代码会产生一个错误,但是如果设置了非整数索引,就不会产生问题。

1
2
ser = Series(np.arange(3.), index['a','b','c'])
ser[-1]

Output:

1
2.0

如果你不考虑索引,而是完全基于位置的索引方法,可以使用Series的iget_value和DataFrame的irowicol方法。

面板数据
pandas有一个Panel数据结果,可以视作是一个三维版的DataFrame,Panel中的每一项(类似于DataFrame的列)都是一个DataFrame。