数据结构介绍
Pandas的数据对象中都包含最基本的属性,如数据类型,索引,标签等。
要使用Pandas的数据结构首先需要引入pandas和numpy:
In [1]: import numpy as np
In [2]: import pandas as pd
有一个基本原则要牢记:数据对齐是默认的。数据和标签的关联不会被破坏,除非认为更改。
本章将做一个关于数据结构的简介,然后在其他章节中做更全面的介绍。
Series
Series 是一维标签数组,能够保存任何数据类型(整型,浮点型,字符串或其他Python对象类型)。轴标签被称为索引。创建一个最基本的Series结构,代码如下:
s = pd.Series(data, index=index)
data可以是很多类型:
- 一个 Python 字典
- 一个 ndarray 对象
- 一个标量值(如5)
index是轴标签的列表。因此,这将根据data的不同分为几种情况:
由ndarray构造
如果传递的data是一个ndarray对象,index的长度必须和data的长度保持一致。如果没有对index参数赋值,那么索引值会默认为[0, … , len(data) -1],即由0开始,与data数据等长的递增列表。
In [3]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
这里构造了一个名为s的Serise对象,其data为5个随机数,那么对应的index长度也为5, 分别为a至e的小写字母。
那么s打印出来的结果如下:
In [4]: s
Out[4]:
a -1.317092
b 0.898475
c -0.026741
d -0.090660
e -0.783084
dtype: float64
通过输入s.index可以查看索引
In [6]: s.index
Out[6]: Index([u'a', u'b', u'c', u'd', u'e'], dtype='object')
如果不为index参数赋值,那么构造的Series对象结果为
In [7]: s = pd.Series(np.random.randn(5))
In [8]: s
Out[8]:
0 -2.750907
1 2.402623
2 -2.479244
3 1.826535
4 -1.270192
dtype: float64
注意:从v0.8.0开始,pandas可以支持索引值不唯一。
如:
In [6]: s = pd.Series(np.random.randn(5), index=[‘a’, ‘b’, ‘b’, ‘c’, ‘d’])
In [7]: s
Out[7]:
a 0.285951
b -0.153731
b 0.536586
c 2.156944
d -0.113776
dtype: float64
由dict 字典类型构造
如果传递的data是一个dict字典类型对象,并且传递了index参数,那么对应的值将从字典中取出。
In [8]: d = {
'a':0, 'b':1, 'c':2}
In [11]: pd.Series(d, index=['b','c','d', 'a'])
Out[11]:
b 1
c 2
d NaN
a 0
dtype: float64
注意:NaN(not a number)是Pandas中使用的数据缺失的标记,由于data中没有包含key为’d’的数据,所以返回数据缺失,标记为NaN。
否则,index的值将由字典对象里的key值进行构造。
In [8]: d = {
'a':0, 'b':1, 'c':2}
In [9]: pd.Series(d)
Out[9]:
a 0
b 1
c 2
dtype: int64
由标量值构造
如果传递的data是一个标量值,那么Index参数必须提供。其构造的二维数组对象将根据索引的长度进行重复。
In [12]: pd.Series(5, index=['b', 'c', 'd', 'a'])
Out[12]:
b 5
c 5
d 5
a 5
dtype: int64
Series类似于ndarray
Serise扮演的角色非常类似ndarray,并且它可以作为大多数Numpy函数的参数。也可以通过对索引切割来进行数据切片。
In [14]: s[0]
Out[14]: 0.28595142701029524
In [15]: s[:3]
Out[15]:
a 0.285951
b -0.153731
b 0.536586
dtype: float64
In [16]: s[s > s.median()]
Out[16]:
b 0.536586
c 2.156944
dtype: float64
In [17]: s[[4, 3, 1]]
Out[17]:
d -0.113776
c 2.156944
b -0.153731
dtype: float64
In [18]: np.exp(s)
Out[18]:
a 1.331028
b 0.857502
b 1.710159
c 8.644678
d 0.892458
dtype: float64
Series类似于dict
Series类似于定长的字典对象,你可以通过index标签获取或设置值。
In [19]: s['a']
Out[19]: 0.28595142701029524
In [20]: s['c'] = 12
In [21]: s
Out[21]:
a 0.285951
b -0.153731
b 0.536586
c 12.000000
d -0.113776
In [22]: 'b' in s
Out[22]: True
In [23]: 'e' in s
Out[23]: False
如果输入的标签不存在,那么将报异常:
In [24]: s['e']
KeyError: 'e'
如果使用get方法,不存在的标签将会返回空值或指定默认值:
In [25]: s.get('e')
In [26]: s.get('e', np.nan)
Out[26]: nan
向量操作和标签对齐
当做数据分析时, 和Numpy的数组一样,一个一个的循环遍历Series中的值通常是不必要的。Series对象也可以像ndarray一样,传递到大多数Numpy方法中。
In [27]: s + s
Out[27]:
a 0.571903
b -0.307463
b 1.073173
c 24.000000
d -0.227552
dtype: float64
In [28]: s * 2
Out[28]:
a 0.571903
b -0.307463
b 1.073173
c 24.000000
d -0.227552
dtype: float64
In [29]: np.exp(s)
Out[29]:
a 1.331028
b 0.857502
b 1.710159
c 162754.791419
d 0.892458
dtype: float64
Series和ndarray关键的区别在于,Series间的操作会自动根据标签对齐数据。因此,你可以直接编写计算,而不用考虑所涉及到的Series是否具有相同的标签。
In [30]: s[1:] + s[:-1]
Out[30]:
a NaN
b -0.307463
b 0.382855
b 0.382855
b 1.073173
c 24.000000
d NaN
dtype: float64
在未对齐的Series间操作,结果将包含索引的集合。如果标签在一个或另一个Series中未找到,结果将标记为缺失NaN。所以可以在不进行任何显示数据对齐的情况下编写代码,在交互数据分析和研究中提供了巨大的自由度和灵活性。Pandas数据结构的综合数据排列特征使Pandas有别于大多数用于标记数据的相关工具。
Name 属性
Series也有Name属性
In [31]: s = pd.Series(np.random.randn(5), name='something')
In [32]: s
Out[32]:
0 1.522774
1 0.733561
2 -0.702462
3 0.022205
4 1.704067
Name: something, dtype: float64
许多情况下,Series的Name将被自动分配,特别是下面即将看到的对于DataFrame的一维切片时。
可以通过方法pandas.Series.rename()对Series进行重命名。
In [33]: s2 = s.rename("different")
In [34]: s2.name
Out[35]: 'different'
注意s和s2分别引用的是两个不同的对象。
DataFrame
DataFrame是一个2维标签的数据结构,它的列可以存在不同的类型。你可以把它简单的想成Excel表格或SQL Table,或者是包含字典类型的Series。它是最常用的Pandas对象。和Series一样,DataFrame接受许多不同的类型输入:
- 包含1维ndarray,列表对象,字典对象或者Series对象的字典对象
- 2维的ndarray对象
- 结构化或记录型的ndarray
- Series对象
- 另一个DataFrame对象
可以通过传递索引(行标签)和列(列标签)参数来操作数据。如果传递了索引和/或列,可以得到包含索引和/或列的DataFrame结果集。因此,一个字典类型的Series加上一个特定的索引,将会丢弃所有与传递的所以不匹配的数据。
如果没有传递轴标签,他们将基于常用规则的输入数据进行创建。
由包含Series的字典或嵌套字典构造
结果的索引将是各个Series索引的并集。如果有任何嵌套的字典对象,都将先转换成Series。如果没有传递任何列,那么列将是已排序的字典对象的Key值。
In [20]: d = {
'one' : pd.Series([1., 2., 3.], index=['a', 'b', 'c']),
...: 'two': pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
In [21]: df = pd.DataFrame(d)
In [22]: df
Out[22]:
one two
a 1 1
b 2 2
c 3 3
d NaN 4
In [23]: pd.DataFrame(d, index=['d', 'b', 'a'])
Out[23]:
one two
d NaN 4
b 2 2
a 1 1
In [24]: pd.DataFrame(d, index=['d', 'b', 'a'], columns=['two', 'three'])
Out[24]:
two three
d 4 NaN
b 2 NaN
a 1 NaN
通过访问索引和列属性,可以分别访问行和列标签:
In [25]: df.index
Out[25]: Index([u'a', u'b', u'c', u'd'], dtype='object')
df.columns
Out[26]: Index([u'one', u'two'], dtype='object')
由包含ndarray或列表的字典构造
ndarray的长度必须一致。如果一个索引被传递,它必须与数组的长度相同。如果没有索引被传递,结果将是range(n),n是数组的长度。
In [27]: d = {
'one':[1., 2., 3., 4.],
...: 'two': [4., 3., 2., 1.]}
In [28]: pd.DataFrame(d)
Out[28]:
one two
0 1 4
1 2 3
2 3 2
3 4 1
In [29]: pd.DataFrame(d, index=['a', 'b', 'c', 'd'])
Out[29]:
one two
a 1 4
b 2 3
c 3 2
d 4 1
由数组构造
这个例子的处理与数组字典的完全相同
In [39]: data = np.zeros((2,), dtype=[('A', 'i4'), ('B', 'f4'), ('C', 'a10')])
In [40]: data[:] = [(1, 2., 'Hello'), (2, 3., 'World')]
In [41]: pd.DataFrame(data)
Out[41]:
A B C
0 1 2 Hello
1 2 3 World
In [42]: pd.DataFrame(data, index=['first', 'second'])
Out[42]:
A B C
first 1 2 Hello
second 2 3 World
In [43]: pd.DataFrame(data, columns=['C', 'A', 'B'])
Out[43]:
C A B
0 Hello 1 2
1 World 2 3
注意:DataFrame的工作方式与2维的ndarray并不一样
由包含字典的列表构造
In [44]: data = [{
'a': 1, 'b': 2}, {
'a': 5, 'b': 10, 'c': 20}]
In [45]: pd.DataFrame(data)
Out[45]:
a b c
0 1 2 NaN
1 5 10 20
In [47]: pd.DataFrame(data, index=['first', 'second'])
Out[47]:
a b c
first 1 2 NaN
second 5 10 20
In [48]: pd.DataFrame(data, columns=['a', 'b'])
Out[48]:
a b
0 1 2
1 5 10
由包含元组的字典构造
In [49]: pd.DataFrame({('a', 'b'): {('A', 'B'): 1, ('A', 'C'): 2},
...: ('a', 'a'): {('A', 'C'): 3, ('A', 'B'): 4},
...: ('a', 'c'): {('A', 'B'): 5, ('A', 'C'): 6},
...: ('b', 'a'): {('A', 'C'): 7, ('A', 'B'): 8},
...: ('b', 'b'): {('A', 'D'): 9, ('A', 'B'): 10}})
Out[49]:
a b
a b c a b
A B 4 1 5 8 10
C 3 2 6 7