Pandas 基础入门
pandas 是基于 Numpy 构建的,让以 Numpy 为中心的应用变得更加简单。「Series」 和「DataFrame」 是它的两个主要数据结构,不同于 Numpy 数组,这两种数据结构包含有数据和索引两种对象。后面的介绍将使用下面的引入约定。
import pandas as pd
from pandas import Series, DataFrame
Series
- 仅由一组数据即可产生最简单的 Series:
In [5]: obj = Series([1, 2, 3, 4]) # obj = Series([1, 2, 3, 4], index=[...])
In [6]: obj
Out[6]:
0 1
1 2
2 3
3 4
dtype: int64
你可以通过 Series 的values
和index
属性获取其数组表示形式和索引对象,也可以用index
参数在创建 Series 的时候指定索引。Series 的索引还可以通过赋值的方式就地修改:
In [11]: obj.index = ['a', 'b', 'c', 'd']
In [12]: obj
Out[12]:
a 1
b 2
c 3
d 4
dtype: int64
- 通过字典创建 Series
In [7]: sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
In [8]: obj = Series(sdata)
In [9]: obj
Out[9]:
Ohio 35000
Texas 71000
Oregon 16000
Utah 5000
dtype: int64
原字典中的键成为 Series 的索引
DataFrame
DataFrame 是一个表格型的数据结构,既有行索引又有列索引。
- 等长列表或 Numpy 数组组成的字典构建 DataFrame
In [13]: data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],'year': [2000, 2001, 2002, 2001, 2002], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}
In [14]: frame = DataFrame(data)
In [15]: frame
Out[15]:
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
字典的键会被解释为列索引,而行索引以整数的形式自动加上。如果想更改列之间的顺序,可以在创建的时候指定顺序进行排列:
In [18]: frame = DataFrame(data, columns=['pop', 'state', 'year'])
In [19]: frame
Out[19]:
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 [20]: pop = {'Nevada': {2001: 2.4, 2002: 2.9}, 'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
In [21]: frame = DataFrame(pop)
In [22]: frame
Out[22]:
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
外层字典的键作为列,内层键则作为行索引,缺失部分用NaN
填充
上述都是一些常用的创建 Series 和 DataFrame 的方式。「索引对象」是 pandas 和 Numpy 的一个重要区别,可以在创建的时候用参数(index
、columns
)指定,也可以之后用属性方法更改(frame.index = []
frame.columns = []
)。用参数指定的时候如果在源数据中找不到对应的索引名,该行或该列会被自动填充NaN
In [25]: frame = DataFrame(pop, index = [2000, 2001, 2002, 2080])
In [26]: frame
Out[26]:
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
2080 NaN NaN
重新索引
在创建好 Series 和 DataFrame 数据结构后,如果想更改数据之间的顺序或者增加新的索引,都可以使用重新索引reindex
In [31]: obj = Series([1, 2, 3, 4], index=['d', 'b', 'a', 'c'])
In [32]: obj
Out[32]:
d 1
b 2
a 3
c 4
dtype: int64
In [33]: obj.reindex(['a', 'b', 'c', 'd', 'e'])
Out[33]:
a 3.0
b 2.0
c 4.0
d 1.0
e NaN
dtype: float64
DataFrame 默认对行重新索引,可使用关键字columns
对列重新索引
In [36]: frame
Out[36]:
Ohio Texas California
a 0 1 2
b 3 4 5
c 6 7 8
In [37]: frame.reindex(['b', 'c','a', 'd'])
Out[37]:
Ohio Texas California
b 3.0 4.0 5.0
c 6.0 7.0 8.0
a 0.0 1.0 2.0
d NaN NaN NaN
In [38]: frame.reindex(columns=['California', 'Ohio', 'Texas', 'Beijing'])
Out[38]:
California Ohio Texas Beijing
a 2 0 1 NaN
b 5 3 4 NaN
c 8 6 7 NaN
reindex 函数常用的一些参数
参数 | 说明 |
---|---|
method | 插值(填充)方式,包括ffill 、bfill |
fill_value | 需要引入缺失值时使用的替代值 |
limit | 前向或后向填充时的最大填充量 |
丢弃某条轴上的一个或多个项很简单,drop
方法返回的是一个在指定轴上删除了指定值的新对象。
In [39]: frame.drop(['Ohio'], axis=1)
Out[39]:
Texas California
a 1 2
b 4 5
c 7 8
索引、选取、过滤
Series 索引工作方式类似于 Numpy数组的索引,只不过 Series 的索引值不只是整数,还可用标签进行索引。
In [42]: obj = Series(np.arange(4), index=['a', 'b', 'c', 'd'])
In [43]: obj[0]
Out[43]: 0
In [44]: obj['a']
Out[44]: 0
In [45]: obj[0:2]
Out[45]:
a 0
b 1
dtype: int32
In [46]: obj['a':'b']
Out[46]:
a 0
b 1
dtype: int32
标签的切片运算末端是包含的。
对 DataFrame 进行索引其实就是获取一个或多个列
In [47]: data = DataFrame(np.arange(16).reshape((4, 4)), index=['Ohio', 'Colorado', 'Uta
...: h', 'New York'], columns=['one', 'two', 'three', 'four'])
In [48]: data
Out[48]:
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 [49]: data['one']
Out[49]:
Ohio 0
Colorado 4
Utah 8
New York 12
Name: one, dtype: int32
In [51]: data[['two', 'four']]
Out[51]:
two four
Ohio 1 3
Colorado 5 7
Utah 9 11
New York 13 15
这种索引方式有几个特殊情况,通过切片或布尔型数组选取行
In [9]: data[:2]
Out[9]:
one two three four
Ohio 0 1 2 3
Colorado 4 5 6 7
In [10]: data[data['three']>5]
Out[10]:
one two three four
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
另一个是通过布尔型 DataFrame 进行索引
In [10]: data[data['three']>5]
Out[10]:
one two three four
Colorado 4 5 6 7
Utah 8 9 10 11
New York 12 13 14 15
In [11]: data<5
Out[11]:
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 [12]: data[data<5]=0
In [13]: data
Out[13]:
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 的行上进行标签索引,引入了专门 的索引字段ix
。它使你可以通过Numpy 式的标记法以及 轴标签从 DataFrame 中选取行和列的子集。ix
也是一种重新索引的简单手段。
In [14]: data.ix['Colorado', ['two', 'three']]
Out[14]:
two 5
three 6
Name: Colorado, dtype: int32
In [15]: data.ix[1, ['two', 'three']]
Out[15]:
two 5
three 6
Name: Colorado, dtype: int32
In [16]: data.ix[['Colorado', 'Utah'], [3, 0, 1]]
Out[16]:
four one two
Colorado 7 0 5
Utah 11 8 9
算数运算和数据对齐
Pandas 最重要的一个功能是,它可以对不同索引的对象进行算术运算。如果存在不同的索引对,则结果的索引就是该索引对的并集。
In [18]: df1 = DataFrame(np.arange(9).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'])
In [19]: df2 = DataFrame(np.arange(12).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])
In [20]: df1+df2
Out[20]:
b c d e
Colorado NaN NaN NaN NaN
Ohio 3.0 NaN 6.0 NaN
Oregon NaN NaN NaN NaN
Texas 9.0 NaN 12.0 NaN
Utah NaN NaN NaN NaN
DataFrame 和 Series 之间的运算
In [21]: frame = DataFrame(np.arange(12).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])
In [22]: series = frame.ix[0]
In [23]: frame-series
Out[23]:
b d e
Utah 0 0 0
Ohio 3 3 3
Texas 6 6 6
Oregon 9 9 9
默认情况 DataFrame 和 Series 之间的算术运算会将 Series 的索引匹配到 DataFrame 的列,然后沿着行一直向下广播。如果希望匹配行且在列上广播,则必须使用算数运算方法。(frame.sub(series2, axis=0)
,传入的轴号就是希望匹配的轴)
函数应用和映射
- Numpy 的 ufunc(元素级数组方法)也可用于操作 Pandas 对象;
- 将函数应用到由各列或行所形成的一维数组上,DataFrame 的 apply 方法即可实现此功能。
In [26]: frame = DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])
In [27]: f = lambda x: x.max() - x.min()
In [28]: frame.apply(f)
Out[28]:
b 1.481984
d 1.243776
e 2.650541
dtype: float64
In [29]: frame.apply(f, axis=1)
Out[29]:
Utah 1.220759
Ohio 1.666172
Texas 2.557103
Oregon 1.243161
dtype: float64
In [30]: frame
Out[30]:
b d e
Utah -1.737583 -0.516824 -1.048557
Ohio -0.793110 0.605487 -1.060684
Texas -0.967246 0.311923 1.589857
Oregon -0.255599 0.726952 0.987563
- 元素级的 Python 函数可以使用 applymap
In [31]: format = lambda x: '%.2f' % x
In [32]: frame.applymap(format)
Out[32]:
b d e
Utah -1.74 -0.52 -1.05
Ohio -0.79 0.61 -1.06
Texas -0.97 0.31 1.59
Oregon -0.26 0.73 0.99
之所以叫做 applymap,是因为 Series 有一个用于应用元素级函数的 map 方法。
排序
要对行或列索引进行排序,可使用 sort_index 方法,返回一个已排序的新对象。
In [33]: frame = DataFrame(np.arange(8).reshape((2, 4)), index=['three', 'one'], columns=['d', 'a', 'b', 'c'])
In [34]: frame
Out[34]:
d a b c
three 0 1 2 3
one 4 5 6 7
In [35]: frame.sort_index()
Out[35]:
d a b c
one 4 5 6 7
three 0 1 2 3
In [36]: frame.sort_index(axis=1)
Out[36]:
a b c d
three 1 2 3 0
one 5 6 7 4
- 若要按值对 Series 排序,可使用其 order 方法
- DataFrame 根据一个或多个列中的值进行排序,将一个或多个列的名字传递给 by 选项即可达到该目的,默认升序。
In [37]: frame.sort_index(by='b')
Out[37]:
d a b c
three 0 1 2 3
one 4 5 6 7
汇总和计算描述统计
Pandas 对象拥有一组常用的数学和统计方法,大部分属于约简和汇总统计,它们都是基于没有缺失数据的假设而构建的。
方法 | 说明 |
---|---|
count | 非 NaN 值的数量 |
describe | 针对 Series 和DataFrame 各列计算汇总统计 |
min、max | 计算最小值和最大值 |
… |
约简方法的选项
选项 | 说明 |
---|---|
axis | 约简的轴 |
skipna | 排除缺失值,默认值为 True |
level | 如果轴是层次化索引的,则根据 level 分组约简 |
唯一值、值计数以及成员资格
还有一类方法可以从一维 Series 的值中抽取信息。
- unique
In [39]: obj = Series(['c','a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
In [40]: uniques = obj.unique()
In [41]: uniques
Out[41]: array(['c', 'a', 'd', 'b'], dtype=object)
- value_counts
In [42]: obj.value_counts()
Out[42]:
a 3
c 3
b 2
d 1
dtype: int64
value_counts 还是 Pandas 的顶级方法,可用于任何数组或序列。
- isin
In [43]: mask = obj.isin(['b', 'c'])
In [44]: mask
Out[44]:
0 True
1 False
2 False
3 False
4 False
5 True
6 True
7 True
8 True
dtype: bool
In [45]: obj[mask]
Out[45]:
0 c
5 b
6 b
7 c
8 c
dtype: object
处理缺失数据
Pandas 使用 NaN(Not a Number) 表示浮点和非浮点数组中的缺失数据,它只是一个便于被检测出来的标记而已。
NA 处理方法
方法 | 说明 |
---|---|
dropna | 滤除缺失数据,可通过阈值调节对缺失值的容忍度(thresh 、how ) |
fillna | 用指定值或插值方法( method = ffill 或 bfill )填充缺失数据 |
isnull/notnull | 返回布尔对象,表示是否是缺失值 |
填充缺失数据 fillna 函数的参数
参数 | 说明 |
---|---|
value | 用于填充缺失值的标量值或字典对象 |
method | 插值方式 |
axis | 待填充的轴,默认 axis=0 |
inplace | 修改调用者对象而不产生副本( inplace = True ) |
limit | 可以连续填充的最大数量 |