数据分析之Pandas——数据结构

来源:互联网 发布:数据库审计产品排名 编辑:程序博客网 时间:2024/06/07 05:23

数据结构介绍

Pandas的数据对象中都包含最基本的属性,如数据类型,索引,标签等。
要使用Pandas的数据结构首先需要引入pandas和numpy:

In [1]: import numpy as npIn [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]: sOut[4]: a   -1.317092b    0.898475c   -0.026741d   -0.090660e   -0.783084dtype: float64

通过输入s.index可以查看索引

In [6]: s.indexOut[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]: sOut[8]: 0   -2.7509071    2.4026232   -2.4792443    1.8265354   -1.270192dtype: 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     1c     2d   NaNa     0dtype: 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    0b    1c    2dtype: int64

由标量值构造

如果传递的data是一个标量值,那么Index参数必须提供。其构造的二维数组对象将根据索引的长度进行重复。

In [12]: pd.Series(5, index=['b', 'c', 'd', 'a'])Out[12]: b    5c    5d    5a    5dtype: int64

Series类似于ndarray

Serise扮演的角色非常类似ndarray,并且它可以作为大多数Numpy函数的参数。也可以通过对索引切割来进行数据切片。

In [14]: s[0]Out[14]: 0.28595142701029524In [15]: s[:3]Out[15]: a    0.285951b   -0.153731b    0.536586dtype: float64In [16]: s[s > s.median()]Out[16]: b    0.536586c    2.156944dtype: float64In [17]: s[[4, 3, 1]]Out[17]: d   -0.113776c    2.156944b   -0.153731dtype: float64In [18]: np.exp(s)Out[18]: a    1.331028b    0.857502b    1.710159c    8.644678d    0.892458dtype: float64

Series类似于dict

Series类似于定长的字典对象,你可以通过index标签获取或设置值。

In [19]: s['a']Out[19]: 0.28595142701029524In [20]: s['c'] = 12In [21]: sOut[21]: a     0.285951b    -0.153731b     0.536586c    12.000000d    -0.113776In [22]: 'b' in sOut[22]: TrueIn [23]: 'e' in sOut[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 + sOut[27]: a     0.571903b    -0.307463b     1.073173c    24.000000d    -0.227552dtype: float64In [28]: s * 2Out[28]: a     0.571903b    -0.307463b     1.073173c    24.000000d    -0.227552dtype: float64In [29]: np.exp(s)Out[29]: a         1.331028b         0.857502b         1.710159c    162754.791419d         0.892458dtype: float64

Series和ndarray关键的区别在于,Series间的操作会自动根据标签对齐数据。因此,你可以直接编写计算,而不用考虑所涉及到的Series是否具有相同的标签。

In [30]: s[1:] + s[:-1]Out[30]: a          NaNb    -0.307463b     0.382855b     0.382855b     1.073173c    24.000000d          NaNdtype: float64

在未对齐的Series间操作,结果将包含索引的集合。如果标签在一个或另一个Series中未找到,结果将标记为缺失NaN。所以可以在不进行任何显示数据对齐的情况下编写代码,在交互数据分析和研究中提供了巨大的自由度和灵活性。Pandas数据结构的综合数据排列特征使Pandas有别于大多数用于标记数据的相关工具。

Name 属性

Series也有Name属性

In [31]: s = pd.Series(np.random.randn(5), name='something')In [32]: sOut[32]: 0    1.5227741    0.7335612   -0.7024623    0.0222054    1.704067Name: something, dtype: float64

许多情况下,Series的Name将被自动分配,特别是下面即将看到的对于DataFrame的一维切片时。
可以通过方法pandas.Series.rename()对Series进行重命名。

In [33]: s2 = s.rename("different")In [34]: s2.nameOut[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]: dfOut[22]:    one  twoa    1    1b    2    2c    3    3d  NaN    4In [23]: pd.DataFrame(d, index=['d', 'b', 'a'])Out[23]:    one  twod  NaN    4b    2    2a    1    1In [24]: pd.DataFrame(d, index=['d', 'b', 'a'], columns=['two', 'three'])Out[24]:    two threed    4   NaNb    2   NaNa    1   NaN

通过访问索引和列属性,可以分别访问行和列标签:

In [25]: df.indexOut[25]: Index([u'a', u'b', u'c', u'd'], dtype='object')df.columnsOut[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  two0    1    41    2    32    3    23    4    1In [29]: pd.DataFrame(d, index=['a', 'b', 'c', 'd'])Out[29]:    one  twoa    1    4b    2    3c    3    2d    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      C0  1  2  Hello1  2  3  WorldIn [42]: pd.DataFrame(data, index=['first', 'second'])Out[42]:         A  B      Cfirst   1  2  Hellosecond  2  3  WorldIn [43]: pd.DataFrame(data, columns=['C', 'A', 'B'])Out[43]:        C  A  B0  Hello  1  21  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   c0  1   2 NaN1  5  10  20In [47]: pd.DataFrame(data, index=['first', 'second'])Out[47]:         a   b   cfirst   1   2 NaNsecond  5  10  20In [48]: pd.DataFrame(data, columns=['a', 'b'])Out[48]:    a   b0  1   21  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   bA B   4   1   5   8  10  C   3   2   6   7 NaN  D NaN NaN NaN NaN   9

由Series构造

结果将是索引与输入的Series相同,并且有一列数据,列名与Series的名称一致(仅在没有提供其他列名的情况下)。

In [58]: s = pd.Series([1, 2, 3], index=['a', 'b', 'c'], name='first')In [59]: sOut[59]: a    1b    2c    3Name: first, dtype: int64In [60]: pd.DataFrame(s)Out[60]:    firsta      1b      2c      3

缺失数据

跟多的缺失数据相关内容将在其他章节介绍。为了构造一个包含缺失数据的DataFrame,对于那些缺失的值需要用到np.nan。或者,将numpy.MaskedArray作为data参数传递给DataFrame的构造函数,它所遮盖的条目将被认为是缺失的。

其他构造方式

DataFrame.from_dict

DataFrame.from_dict将获取一个嵌套字典或者数组字典,并返回一个DataFrame。它的操作方式类似于DataFrame的构造函数,除了orient参数默认为column,但是可以将它设置为index,让字典的key值作为行标签。

DataFrame.from_records
DataFrame.from_records将获取一个元组构成的列表或者一个结构化的ndarray对象。与普通的DataFrame构造函数类似,除了索引可能是结构化的dtype的特定字段。例如:

In [61]: dataOut[61]: [{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]In [62]: data = np.zeros((2,), dtype=[('A', 'i4'),('B', 'f4'),('C', 'a10')])In [63]: data[:] = [(1, 2, 'Hello'), (2, 3, 'World')]In [64]: dataOut[64]: array([(1, 2.0, 'Hello'), (2, 3.0, 'World')],       dtype=[('A', '<i4'), ('B', '<f4'), ('C', 'S10')])In [66]: pd.DataFrame.from_records(data, index='C')Out[66]:        A  BC          Hello  1  2World  2  3

DataFrame.from_items
DataFrame.from_items 运行机制类似于dict的构造函数,传递一个键值对序列作为参数。Key是列名(或索引名,orient=’index’),Value是列的值(或行的值)。这对于构造具有特定顺序的列的DataFrame是很有用的,而不用传递列的明确列表:

In [68]: pd.DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])])Out[68]:    A  B0  1  41  2  52  3  6

如果传递orient=’index’,key值将作为索引标签。但是在下面的例子中任需要列名:

In [73]: pd.DataFrame.from_items([('A', [1, 2, 3]), ('B', [4, 5, 6])], orient='index', columns=['one', 'two', 'three'])Out[73]:    one  two  threeA    1    2      3B    4    5      6

列的选择、添加和删除

类似于对字典操作的语法,你可以对一个DataFrame进行获取列的值,对列赋值或删除列。

In [74]: df['one']Out[74]: a     1b     2c     3d   NaNName: one, dtype: float64In [75]: df['three'] = df['one'] * df['two']In [76]: df['flag'] = df['one'] > 2In [77]: dfOut[77]:    one  two  three   flaga    1    1      1  Falseb    2    2      4  Falsec    3    3      9   Trued  NaN    4    NaN  False

列可以类似于dict一样,删除或者取出

In [78]: del df['two']In [79]: three = df.pop('three')In [80]: dfOut[80]:    one   flaga    1  Falseb    2  Falsec    3   Trued  NaN  FalseIn [81]: threeOut[81]: a     1b     4c     9d   NaNName: three, dtype: float64

当插入一个标量值时,它会自动的填满整列

In [82]: df['foo'] = 'bar'In [83]: dfOut[83]:    one   flag  fooa    1  False  barb    2  False  barc    3   True  bard  NaN  False  bar

当插入一个与DataFrame没有相同索引的Series时,它将匹配DataFrame的索引

In [84]: df['one_trunc'] = df['one'][:2]In [85]: dfOut[85]:    one   flag  foo  one_trunca    1  False  bar          1b    2  False  bar          2c    3   True  bar        NaNd  NaN  False  bar        NaN

也可以插入ndarray,但是它的长度必须与DataFrame的索引长度匹配。

默认情况下,列在最后插入。insert函数可用于插入在列的制定位置:

In [87]: dfOut[87]:    one  bar   flag  foo  one_trunca    1    1  False  bar          1b    2    2  False  bar          2c    3    3   True  bar        NaNd  NaN  NaN  False  bar        NaN

通过方法分配新列

DataFrame具有assign()方法,允许你很方便的创建从现有列派生出来的新列。

In [47]: iris = pd.read_csv(u'data/iris.csv')In [48]: iris.head()Out[48]:    SepalLength  SepalWidth  PetalLength  PetalWidth         Name0          5.1         3.5          1.4         0.2  Iris-setosa1          4.9         3.0          1.4         0.2  Iris-setosa2          4.7         3.2          1.3         0.2  Iris-setosa3          4.6         3.1          1.5         0.2  Iris-setosa4          5.0         3.6          1.4         0.2  Iris-setosaIn [49]: (iris.assign(sepal_ratio = iris['SepalWidth'] / iris['SepalLength']).head())Out[49]:    SepalLength  SepalWidth  PetalLength  PetalWidth         Name  sepal_ratio0          5.1         3.5          1.4         0.2  Iris-setosa     0.6862751          4.9         3.0          1.4         0.2  Iris-setosa     0.6122452          4.7         3.2          1.3         0.2  Iris-setosa     0.6808513          4.6         3.1          1.5         0.2  Iris-setosa     0.6739134          5.0         3.6          1.4         0.2  Iris-setosa     0.720000

以上的例子中,先原有的数据中增加了一个预先计算的值。我们同样还可以传递带有一个参数的函数

In [50]: iris.assign(sepal_ratio = lambda x: (x['SepalWidth']/x['SepalLength'])).head()Out[50]:    SepalLength  SepalWidth  PetalLength  PetalWidth         Name  sepal_ratio0          5.1         3.5          1.4         0.2  Iris-setosa     0.6862751          4.9         3.0          1.4         0.2  Iris-setosa     0.6122452          4.7         3.2          1.3         0.2  Iris-setosa     0.6808513          4.6         3.1          1.5         0.2  Iris-setosa     0.6739134          5.0         3.6          1.4         0.2  Iris-setosa     0.720000

assign 始终返回数据的副本,让原始的DataFrame保持原样。

传递一个可调用的,而不是要插入的实际值,当你没有对DataFrame引用时,这是非常有帮助的。在操作链中使用assign,这是很常见的。例如,我们可以把DataFrame限定为花萼长度大于5的数据,然后计算这个比例,进行绘图:

In [51]: (iris.query('SepalLength > 5')    ...:     .assign(SepalRatio = lambda x: x.SepalWidth / x.SepalLength,    ...:             PetalRatio = lambda x: x.PetalWidth / x.PetalLength)    ...:     .plot(kind='scatter', x='SepalRatio', y='PetalRatio'))Out[51]: <matplotlib.axes._subplots.AxesSubplot at 0x1049b8b0>

这里写图片描述
当函数被传入,函数将在分配给DataFrame时进行计算。重点时,这是将数据过滤为Sepal 长度大于5的行。数据首先被过滤,然后再进行比例的计算。

assign方法的参数 **kwargs。key是列名,value是要插入的值(如Series或Numpy的 array),或者是含有一个参数的函数。调用后将返回,原有的DataFrame的副本加上新增的值。

警告:由于方法的参数为**kwargs,一个字典类型,所以产生的DataFrame中的新列的顺序不能保证与你传入的顺序相同。为了让结果可以预测,在DataFrame的末尾,数据条目将按字母顺序插入。

所有的表达式先行计算,再分配。因此,不能引用另一个在调用时分配的列。比如:

`In [74]: # 不用这样做, 无法引用‘C’列
df.assign(C = lambda x: x[‘A’] + x[‘B’],
D = lambda x: x[‘A’] + x[‘C’])
In [2]: # 更改为调用两次assign方法
(df.assign(C = lambda x: x[‘A’] + x[‘B’])
.assign(D = lambda x: x[‘A’] + x[‘C’]))’

索引/选择

索引的基本操作如下:

操作 语法 结果 选择列 df[col] Series 根据标签选择行 df.loc[lable] Series 根据位置选择行 df.iloc[loc] Series 行切片 df[5:10] DataFrame 根据条件选择行 df[bool_vec] DataFrame

行选择器,如,根据索引返回列的Series:

#沿用之前的df对象In [63]: dfOut[63]:    one  bar   flag  foo  one_trunca    1    1  False  bar          1b    2    2  False  bar          2c    3    3   True  bar        NaNd  NaN  NaN  False  bar        NaN#根据索引标签选择In [64]: df.loc['b']Out[64]: one              2bar              2flag         Falsefoo            barone_trunc        2Name: b, dtype: object#根据位置选择In [65]: df.iloc[2]Out[65]: one             3bar             3flag         Truefoo           barone_trunc     NaNName: c, dtype: object

数据对齐和运算

DataFrame对象之间的数据对齐会自动在列和索引(行标签)上对齐。同样,生产的对象将是列和行标签的并集。

In [69]: df = pd.DataFrame(np.random.randn(10, 4), columns=['A', 'B', 'C', 'D'])In [70]: dfOut[70]:           A         B         C         D0 -1.081213  0.964799 -1.526936  0.8570951  0.786559 -0.824999  0.373886  0.3831982 -0.026515 -0.539306  0.987269  0.0451013 -0.726887 -1.176843 -0.799625 -0.1921554 -1.180493  2.145532  0.682645  0.3172005  1.041298 -1.334093  0.346744 -0.2224026 -0.553535 -1.031090 -1.738747 -0.4042987  0.367074 -1.312607  0.811453 -0.8290418  1.150281 -0.435246  0.686140  1.6727139 -2.811454 -0.064040 -0.173748  0.156016In [71]: df2 = pd.DataFrame(np.random.randn(7, 3), columns=['A', 'B', 'C'])In [72]: df2Out[72]:           A         B         C0 -0.116847  2.508202 -0.2060531 -0.264634 -0.440654  0.3559292 -0.805070  1.162288  0.6372933 -0.423643  0.854117 -0.3854284  0.790752  0.084708 -0.6994945  2.139285 -0.546327  0.3814956 -0.086828  1.019701  0.448619In [73]: df + df2Out[73]:           A         B         C   D0 -1.198059  3.473001 -1.732989 NaN1  0.521925 -1.265653  0.729814 NaN2 -0.831585  0.622982  1.624562 NaN3 -1.150530 -0.322726 -1.185053 NaN4 -0.389741  2.230240 -0.016849 NaN5  3.180583 -1.880420  0.728239 NaN6 -0.640363 -0.011389 -1.290128 NaN7       NaN       NaN       NaN NaN8       NaN       NaN       NaN NaN9       NaN       NaN       NaN NaN

当在DataFrame和Series之间进行操作时,默认的行为是在DataFrame列上对其Series索引,然后安装行的宽度进行广播。例如:

In [74]: df.iloc[0]Out[74]: A   -1.081213B    0.964799C   -1.526936D    0.857095Name: 0, dtype: float64In [75]: df - df.iloc[0]Out[75]:           A         B         C         D0  0.000000  0.000000  0.000000  0.0000001  1.867771 -1.789798  1.900821 -0.4738972  1.054698 -1.504105  2.514205 -0.8119943  0.354326 -2.141642  0.727311 -1.0492504 -0.099280  1.180733  2.209580 -0.5398965  2.122511 -2.298892  1.873680 -1.0794986  0.527677 -1.995888 -0.211811 -1.2613937  1.448286 -2.277405  2.338389 -1.6861368  2.231494 -1.400045  2.213076  0.8156189 -1.730241 -1.028839  1.353188 -0.701080

在处理时间Series数据的特殊情况下,并且DataFrame索引也包含日期,将根据列的宽度进行广播:

In [76]: index = pd.date_range('1/1/2000', periods=8)In [77]: indexOut[77]: DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03', '2000-01-04',               '2000-01-05', '2000-01-06', '2000-01-07', '2000-01-08'],              dtype='datetime64[ns]', freq='D', tz=None)In [78]: df = pd.DataFrame(np.random.randn(8, 3), index=index, columns=list('ABC'))In [79]: dfOut[79]:                    A         B         C2000-01-01  1.658336  0.312690  0.4343802000-01-02  1.588613  1.044227 -0.5480432000-01-03  1.453697  0.634530 -1.1254642000-01-04  1.799968 -0.579391  0.0478572000-01-05 -0.053769  0.067639  0.1956622000-01-06 -1.863360  0.772522  0.6907782000-01-07 -0.157916 -0.605435  0.3247582000-01-08 -1.265800  0.157990  0.022863In [80]: type(df['A'])Out[80]: pandas.core.series.SeriesIn [81]: df - df['A']Out[81]:             2000-01-01 00:00:00  2000-01-02 00:00:00  2000-01-03 00:00:00  \2000-01-01                  NaN                  NaN                  NaN   2000-01-02                  NaN                  NaN                  NaN   2000-01-03                  NaN                  NaN                  NaN   2000-01-04                  NaN                  NaN                  NaN   2000-01-05                  NaN                  NaN                  NaN   2000-01-06                  NaN                  NaN                  NaN   2000-01-07                  NaN                  NaN                  NaN   2000-01-08                  NaN                  NaN                  NaN               2000-01-04 00:00:00 ...  2000-01-08 00:00:00   A   B   C  2000-01-01                  NaN ...                  NaN NaN NaN NaN  2000-01-02                  NaN ...                  NaN NaN NaN NaN  2000-01-03                  NaN ...                  NaN NaN NaN NaN  2000-01-04                  NaN ...                  NaN NaN NaN NaN  2000-01-05                  NaN ...                  NaN NaN NaN NaN  2000-01-06                  NaN ...                  NaN NaN NaN NaN  2000-01-07                  NaN ...                  NaN NaN NaN NaN  2000-01-08                  NaN ...                  NaN NaN NaN NaN  [8 rows x 11 columns]

警告
df-df['A']
现在已被弃用,并将被删除。实现这种行为的最佳方式
df.sub(df['A'], axis=0)

标量的操作正如你期望的那样:

In [85]: df * 5 + 2Out[85]:                     A         B         C2000-01-01  10.291678  3.563450  4.1719002000-01-02   9.943063  7.221136 -0.7402132000-01-03   9.268486  5.172651 -3.6273192000-01-04  10.999838 -0.896953  2.2392862000-01-05   1.731153  2.338194  2.9783082000-01-06  -7.316800  5.862611  5.4538922000-01-07   1.210420 -1.027175  3.6237912000-01-08  -4.329001  2.789950  2.114315In [86]: 1 / dfOut[86]:                     A          B          C2000-01-01   0.603014   3.198056   2.3021322000-01-02   0.629480   0.957646  -1.8246752000-01-03   0.687901   1.575969  -0.8885232000-01-04   0.555566  -1.725951  20.8954892000-01-05 -18.597913  14.784416   5.1108672000-01-06  -0.536665   1.294461   1.4476422000-01-07  -6.332484  -1.651705   3.0792152000-01-08  -0.790014   6.329511  43.738650In [87]: df ** 4Out[87]:                     A         B             C2000-01-01   7.562925  0.009560  3.560239e-022000-01-02   6.369012  1.188995  9.021058e-022000-01-03   4.465763  0.162110  1.604450e+002000-01-04  10.496843  0.112690  5.245535e-062000-01-05   0.000008  0.000021  1.465621e-032000-01-06  12.055550  0.356159  2.276957e-012000-01-07   0.000622  0.134360  1.112346e-022000-01-08   2.567206  0.000623  2.732364e-07

布尔运算同样有效

In [88]: df1 = pd.DataFrame({'a': [1, 0, 1], 'b': [0, 1, 1]}, dtype=bool)In [89]: df2 = pd.DataFrame({'a': [0, 1, 1], 'b': [1, 1, 0]}, dtype=bool)In [90]: df1 & df2Out[90]:        a      b0  False  False1  False   True2   True  FalseIn [91]: df1 | df2Out[91]:       a     b0  True  True1  True  True2  True  TrueIn [92]: df1 ^ df2Out[92]:        a      b0   True   True1   True  False2  False   TrueIn [93]: -df1Out[93]:        a      b0  False   True1   True  False2  False  False

行列转换

对于行列转换,访问T属性(也就是transpose函数),类似于ndarray:

In [95]: df[:5]Out[95]:                    A         B         C2000-01-01  1.658336  0.312690  0.4343802000-01-02  1.588613  1.044227 -0.5480432000-01-03  1.453697  0.634530 -1.1254642000-01-04  1.799968 -0.579391  0.0478572000-01-05 -0.053769  0.067639  0.195662In [96]: df[:5].TOut[96]:    2000-01-01  2000-01-02  2000-01-03  2000-01-04  2000-01-05A    1.658336    1.588613    1.453697    1.799968   -0.053769B    0.312690    1.044227    0.634530   -0.579391    0.067639C    0.434380   -0.548043   -1.125464    0.047857    0.195662

DataFrame与Numpy函数的互操作

如果对象中的数据是数值型的,那么可以在DataFrame上使用Numpy的ufunc(log, exp, sqrt,…)和其他各种函数:

In [97]: np.exp(df)Out[97]:                    A         B         C2000-01-01  5.250565  1.367098  1.5440052000-01-02  4.896950  2.841202  0.5780802000-01-03  4.278905  1.886136  0.3245022000-01-04  6.049451  0.560240  1.0490212000-01-05  0.947651  1.069979  1.2161152000-01-06  0.155150  2.165220  1.9952682000-01-07  0.853922  0.545837  1.3836962000-01-08  0.282014  1.171155  1.023126In [98]: np.asarray(df)Out[98]: array([[ 1.65833568,  0.31269   ,  0.43437997],       [ 1.58861263,  1.04422716, -0.54804266],       [ 1.45369711,  0.63453025, -1.12546386],       [ 1.79996757, -0.57939064,  0.04785722],       [-0.05376948,  0.06763879,  0.19566152],       [-1.86335996,  0.77252217,  0.69077835],       [-0.15791591, -0.60543491,  0.3247581 ],       [-1.26580024,  0.15799008,  0.02286307]])

DataFrame上的dot方法,实现了矩阵的点积运算:

In [99]: df.T.dot(df)Out[99]:            A         B         CA  15.729075  0.509448 -3.078136B   0.509448  2.919385 -0.824455C  -3.078136 -0.824455  2.379445

类似的,Series的dot方法也实现了点积运算:

In [101]: s1 = pd.Series(np.arange(5, 10))In [102]: s1Out[102]: 0    51    62    73    84    9dtype: int32In [103]: s1.dot(s1)Out[103]: 255

控制台显示

非常大的DataFrame将在控制台中被截断显示。你可以使用info()来获取摘要信息。

In [108]: iris = pd.read_csv(u'data/iris.csv')In [109]: print(iris)     SepalLength  SepalWidth  PetalLength  PetalWidth         Name0            5.1         3.5          1.4         0.2  Iris-setosa1            4.9         3.0          1.4         0.2  Iris-setosa2            4.7         3.2          1.3         0.2  Iris-setosa3            4.6         3.1          1.5         0.2  Iris-setosa4            5.0         3.6          1.4         0.2  Iris-setosa5            5.2         3.5          1.4         0.2  Iris-setosa6            4.9         3.0          1.7         0.2  Iris-setosa7            5.4         3.2          1.5         0.3  Iris-setosa8            4.6         3.1          1.4         0.2  Iris-setosa9            5.3         3.6          1.4         0.2  Iris-setosa10           5.1         3.5          1.4         0.2  Iris-setosa11           4.9         3.0          1.4         0.3  Iris-setosa12           4.7         3.6          1.3         0.2  Iris-setosa13           4.6         3.1          1.5         0.2  Iris-setosa14           5.0         3.6          1.4         0.2  Iris-setosa15           5.2         3.5          1.4         0.2  Iris-setosa16           4.9         3.0          1.6         0.2  Iris-setosa17           5.4         3.2          1.7         0.3  Iris-setosa18           4.6         3.2          1.5         0.2  Iris-setosa19           5.3         3.1          1.4         0.4  Iris-setosa20           5.3         3.6          1.4         0.2  Iris-setosa21           5.1         3.0          1.4         0.2  Iris-setosa22           4.9         3.2          1.4         0.2  Iris-setosa23           4.7         3.1          1.4         0.5  Iris-setosa24           4.9         3.6          1.3         0.2  Iris-setosa25           4.7         3.5          1.5         0.3  Iris-setosa26           4.6         3.0          1.4         0.2  Iris-setosa27           5.3         3.6          1.3         0.2  Iris-setosa28           5.3         3.1          1.8         0.2  Iris-setosa29           5.3         3.0          1.4         0.7  Iris-setosa..           ...         ...          ...         ...          ...573          5.1         3.5          1.4         0.2  Iris-setosa574          4.9         3.0          1.4         0.3  Iris-setosa575          4.7         3.6          1.3         0.2  Iris-setosa576          4.6         3.1          1.5         0.2  Iris-setosa577          5.0         3.6          1.4         0.2  Iris-setosa578          5.2         3.5          1.4         0.2  Iris-setosa579          4.9         3.0          1.6         0.2  Iris-setosa580          5.4         3.2          1.7         0.3  Iris-setosa581          4.6         3.2          1.5         0.2  Iris-setosa582          5.3         3.1          1.4         0.4  Iris-setosa583          5.3         3.6          1.4         0.2  Iris-setosa584          5.1         3.0          1.4         0.2  Iris-setosa585          4.9         3.2          1.4         0.2  Iris-setosa586          4.7         3.1          1.4         0.5  Iris-setosa587          4.9         3.6          1.3         0.2  Iris-setosa588          4.7         3.5          1.5         0.3  Iris-setosa589          4.6         3.0          1.4         0.2  Iris-setosa590          5.3         3.6          1.3         0.2  Iris-setosa591          5.3         3.1          1.8         0.2  Iris-setosa592          5.3         3.0          1.4         0.7  Iris-setosa593          5.1         3.2          1.4         0.2  Iris-setosa594          4.9         3.1          1.4         0.2  Iris-setosa595          4.7         3.6          1.3         0.2  Iris-setosa596          5.1         3.1          1.5         0.2  Iris-setosa597          4.9         3.6          1.4         0.3  Iris-setosa598          5.2         3.5          1.4         0.2  Iris-setosa599          4.9         3.0          1.6         0.2  Iris-setosa600          5.4         3.2          1.4         0.2  Iris-setosa601          4.6         3.1          1.3         0.7  Iris-setosa602          5.3         3.6          1.8         0.2  Iris-setosa[603 rows x 5 columns]In [110]: iris.info()<class 'pandas.core.frame.DataFrame'>Int64Index: 603 entries, 0 to 602Data columns (total 5 columns):SepalLength    603 non-null float64SepalWidth     603 non-null float64PetalLength    603 non-null float64PetalWidth     603 non-null float64Name           603 non-null objectdtypes: float64(4), object(1)memory usage: 25.9+ KBIn [111]: iris = pd.read_csv(u'data/iris.csv')In [112]: print(iris)     SepalLength  SepalWidth  PetalLength  PetalWidth         Name0            5.1         3.5          1.4         0.2  Iris-setosa1            4.9         3.0          1.4         0.2  Iris-setosa2            4.7         3.2          1.3         0.2  Iris-setosa3            4.6         3.1          1.5         0.2  Iris-setosa..           ...         ...          ...         ................600          5.4         3.2          1.4         0.2  Iris-setosa601          4.6         3.1          1.3         0.7  Iris-setosa602          5.3         3.6          1.8         0.2  Iris-setosa[603 rows x 5 columns]In [113]: iris.info()<class 'pandas.core.frame.DataFrame'>Int64Index: 603 entries, 0 to 602Data columns (total 5 columns):SepalLength    603 non-null float64SepalWidth     603 non-null float64PetalLength    603 non-null float64PetalWidth     603 non-null float64Name           603 non-null objectdtypes: float64(4), object(1)memory usage: 25.9+ KB

然而,使用to_string将以字符串的形式显示DataFrame,虽然它并不总是适合于控制台的宽度

In [116]: print(iris.iloc[-20:, ].to_string())     SepalLength  SepalWidth  PetalLength  PetalWidth         Name583          5.3         3.6          1.4         0.2  Iris-setosa584          5.1         3.0          1.4         0.2  Iris-setosa585          4.9         3.2          1.4         0.2  Iris-setosa586          4.7         3.1          1.4         0.5  Iris-setosa587          4.9         3.6          1.3         0.2  Iris-setosa588          4.7         3.5          1.5         0.3  Iris-setosa589          4.6         3.0          1.4         0.2  Iris-setosa590          5.3         3.6          1.3         0.2  Iris-setosa591          5.3         3.1          1.8         0.2  Iris-setosa592          5.3         3.0          1.4         0.7  Iris-setosa593          5.1         3.2          1.4         0.2  Iris-setosa594          4.9         3.1          1.4         0.2  Iris-setosa595          4.7         3.6          1.3         0.2  Iris-setosa596          5.1         3.1          1.5         0.2  Iris-setosa597          4.9         3.6          1.4         0.3  Iris-setosa598          5.2         3.5          1.4         0.2  Iris-setosa599          4.9         3.0          1.6         0.2  Iris-setosa600          5.4         3.2          1.4         0.2  Iris-setosa601          4.6         3.1          1.3         0.7  Iris-setosa602          5.3         3.6          1.8         0.2  Iris-setosa

如果DataFrame有10列,他们超过控制台宽度的列默认将隔行显示:

In [117]: pd.DataFrame(np.random.randn(3, 12))Out[117]:          0         1         2         3         4         5         6   \0 -0.119700  0.086073 -1.741760  0.115469 -0.264237 -0.191981 -1.666531   1 -0.650737  0.689219 -1.286211  0.165378  1.189919  0.871147 -0.109856   2  0.507395  0.339061 -1.119778  1.177230  0.046027  0.339424  1.027529            7         8         9         10        11  0  0.156251 -0.839636  1.287716  0.354855 -0.288980  1  0.824025  0.533401 -0.438582 -0.217816 -1.026814  2 -0.302536  1.702276  0.560161 -1.123736 -0.498265  

通过设置display.with选项,可以改变控制台每一行显示的列个数

In [118]: pd.set_option('display.width', 40) #默认为80In [119]: pd.DataFrame(np.random.randn(3, 12))Out[119]:          0         1         2   \0  1.217084 -0.558679 -1.257722   1 -0.214153  1.239619  0.903324   2 -0.290766  0.698407  0.009694            3         4         5   \0  0.308694 -0.057101  0.572316   1  0.475061 -1.139262  2.080925   2  1.201881 -0.486657 -1.642377            6         7         8   \0 -0.547218 -1.311481  0.778549   1 -0.633969  0.764801 -1.325743   2  0.854663  1.932424 -0.146767            9         10        11  0  0.613871  1.603854 -0.992278  1 -0.848804  0.358653 -0.689318  2  0.204168  1.043873 -0.345096  

可以通过设置display.max_colwidth来调整各个列的最大宽度

In [120]: datafile={'filename': ['filename_01','filename_02'],     ...:    .....:           'path': ["media/user_name/storage/folder_01/filename_01",     ...:    .....:                    "media/user_name/storage/folder_02/filename_02"]}In [121]: pd.set_option('display.max_colwidth', 30)In [122]: pd.DataFrame(datafile)Out[122]:       filename  \0  filename_01   1  filename_02                               path  0  media/user_name/storage/fo...  1  media/user_name/storage/fo...  In [123]: pd.set_option('display.max_colwidth', 100)In [124]: pd.DataFrame(datafile)Out[124]:       filename  \0  filename_01   1  filename_02                                               path  0  media/user_name/storage/folder_01/filename_01  1  media/user_name/storage/folder_02/filename_02  

还可以通过扩展framerepr选项禁用此功能。这将在一个块中打印表。

DataFrame列属性访问

如果DataFrame的列标签是一个Python的变量名,那么列可以像属性一样访问:

In [125]: df = pd.DataFrame({'foo1': np.random.randn(5),     ...:                     'foo2': np.random.randn(5)})In [126]: dfOut[126]:        foo1      foo20  1.095587 -0.1351471  1.049579 -0.1178082  1.029435  1.4387573  0.177883  0.1231954 -0.964396 -2.319625In [127]: df.foo1Out[127]: 0    1.0955871    1.0495792    1.0294353    0.1778834   -0.964396Name: foo1, dtype: float64

Panel

Panel很少用到,但它仍然是三维数据的重要容器。术语panel data来源于计量经济学,它对pandas的命名有部分借鉴意义:pan(el)-da(ta)-s。三个轴的名称旨在为描述panel data的操作提供一些语义上的描述,尤其是,panel data的计量经济分析。但是,为了严格的分割DataFrame对象的集合,你可能会发现这些轴的名称有些随意:

  • items: 轴0, 每个item相当于一个DataFrame包含在其中
  • major_axis: 轴1,它是每个DataFrame的索引(行)
  • minor_axis: 轴2, 它是每个DataFrame的列

Panel的构造方式和你想的一样:

从带有可选轴标签的3D ndarray构造

In [135]: wp = pd.Panel(np.random.randn(2, 5, 4), items=['item1', 'item2'],     ...:                 major_axis=pd.date_range('1/1/2000', periods=5),     ...:                 minor_axis=['A', 'B', 'C', 'D'])In [136]: wpOut[136]: <class 'pandas.core.panel.Panel'>Dimensions: 2 (items) x 5 (major_axis) x 4 (minor_axis)Items axis: item1 to item2Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00Minor_axis axis: A to D

从包含DataFrame的字典类型构造

In [137]: data = {'Item1': pd.DataFrame(np.random.randn(4, 3)),     ...:         'Item2': pd.DataFrame(np.random.randn(4, 2))}In [138]: pd.Panel(data)Out[138]: <class 'pandas.core.panel.Panel'>Dimensions: 2 (items) x 4 (major_axis) x 3 (minor_axis)Items axis: Item1 to Item2Major_axis axis: 0 to 3Minor_axis axis: 0 to 2

注意,字典中的Value只需要可以被转换为DataFrame。因此,他们可以是DataFrame的任何其他有效输入。

一个有效的工厂方法是Panel.from_dict,它使用了上面的DataFrame字典,以及下面的命名参数:

参数名 默认值 描述 intersect False 删除索引没有对其的元素 orient items 使用minor来让DataFrame的列作为panel的item

例如,与前面的构造方式比较:

In [139]: pd.Panel.from_dict(data, orient='minor')Out[139]: <class 'pandas.core.panel.Panel'>Dimensions: 3 (items) x 4 (major_axis) x 2 (minor_axis)Items axis: 0 to 2Major_axis axis: 0 to 3Minor_axis axis: Item1 to Item2

orient对于混合类型的DataFrame尤其有帮助。如果你传递了一个含有混合类型列DataFrame的字典对象,所有的数据都将被显示为dtype=object,除非你将设置orient=’minor’:

In [140]: df = pd.DataFrame({'a': ['foo', 'bar', 'baz'],     ...:                     'b': np.random.randn(3)})In [141]: dfOut[141]:      a         b0  foo  0.0758891  bar -0.4502202  baz  1.570256In [142]: data = {'item1': df, 'item2': df}In [143]: panel = pd.Panel.from_dict(data, orient='minor')In [144]: panel['a']Out[144]:   item1 item20   foo   foo1   bar   bar2   baz   bazIn [145]: panel['b']Out[145]:       item1     item20  0.075889  0.0758891 -0.450220 -0.4502202  1.570256  1.570256In [146]: panel['b'].dtypesOut[146]: item1    float64item2    float64dtype: object

注意:不幸的是,panel相较于Series和DataFrame更少被使用,因为它在功能的完整性上被忽视了。DataFrame中的许多有效的方法和选项在panel中都不能使用。当然,这将在未来的版本中得到解决。

使用to_panel方法从DataFrame构造

这个方法是在v0.7中引进的,用于取代LongPanel.to_long,将一个带有双级索引的DataFrame转换为一个Panel。

In [149]: midx = pd.MultiIndex(levels=[['one', 'two'], ['x', 'y']], labels=[[1, 1, 0, 0], [1, 0, 1, 0]])In [150]: df = pd.DataFrame({'A': [1, 2, 3, 4], 'B': [5, 6, 7, 8]}, index=midx)In [151]: dfOut[151]:        A  Btwo y  1  5    x  2  6one y  3  7    x  4  8In [152]: df.to_panel()Out[152]: <class 'pandas.core.panel.Panel'>Dimensions: 2 (items) x 2 (major_axis) x 2 (minor_axis)Items axis: A to BMajor_axis axis: one to twoMinor_axis axis: x to y

Item的选择/添加/删除

正如DataFrame的操作类似于含有字典类型的Series, 而Penel则类似于含有字典类型的DataFrame:

In [156]: wp['item1']Out[156]:                    A         B         C         D2000-01-01 -1.459119 -0.167279 -0.105919 -1.5891552000-01-02 -1.224224 -0.500770 -0.169742  0.2475582000-01-03 -1.064092 -1.832947  0.094414 -0.4458642000-01-04 -0.092463 -1.629868  0.183957 -0.7023272000-01-05  1.086481 -2.833691  0.010039 -0.101303In [157]: wp['item3'] = wp['item1'] / wp['item2']In [158]: wpOut[158]: <class 'pandas.core.panel.Panel'>Dimensions: 3 (items) x 5 (major_axis) x 4 (minor_axis)Items axis: item1 to item3Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00Minor_axis axis: A to D

插入和删除的API和DataFrame相同。同DataFrame一样,如果item是一个有效的标识符,那么可以将它作为属性来访问。

转换

Panel可以通过transpose方法来进行重新排列(除非数据是异构的,否则默认情况下不会生成副本)

In [160]: wpOut[160]: <class 'pandas.core.panel.Panel'>Dimensions: 3 (items) x 5 (major_axis) x 4 (minor_axis)Items axis: item1 to item3Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00Minor_axis axis: A to DIn [161]: wp.transpose(2, 0, 1)Out[161]: <class 'pandas.core.panel.Panel'>Dimensions: 4 (items) x 3 (major_axis) x 5 (minor_axis)Items axis: A to DMajor_axis axis: item1 to item3Minor_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00

索引和选择

操作 语法 结果 选择item wp[item] DataFrame 在major_axis标签上切片 wp.major_xs(val) DataFrame 在minor_axis标签上切片 wp.minor_xs(val) DataFrame

例如,使用前面的数据,我们可以这样做:

In [164]: wp['item1']Out[164]:                    A         B         C         D2000-01-01 -1.459119 -0.167279 -0.105919 -1.5891552000-01-02 -1.224224 -0.500770 -0.169742  0.2475582000-01-03 -1.064092 -1.832947  0.094414 -0.4458642000-01-04 -0.092463 -1.629868  0.183957 -0.7023272000-01-05  1.086481 -2.833691  0.010039 -0.101303In [165]: wp.major_xs(wp.major_axis[2])Out[165]:       item1     item2     item3A -1.064092  0.813871 -1.307446B -1.832947 -2.016451  0.908996C  0.094414 -0.456631 -0.206762D -0.445864 -0.417404  1.068182In [166]: wp.minor_axisOut[166]: Index([u'A', u'B', u'C', u'D'], dtype='object')In [167]: wp.minor_xs('C')Out[167]:                item1     item2     item32000-01-01 -0.105919  1.211176 -0.0874512000-01-02 -0.169742  1.823682 -0.0930772000-01-03  0.094414 -0.456631 -0.2067622000-01-04  0.183957  0.585720  0.3140702000-01-05  0.010039  0.622204  0.016134

压缩

另一种改变对象维数的方法是squeeze 一个一维的对象,类似于wp[‘item1’]

In [168]: wp.reindex(items=['item1']).squeeze()Out[168]:                    A         B         C         D2000-01-01 -1.459119 -0.167279 -0.105919 -1.5891552000-01-02 -1.224224 -0.500770 -0.169742  0.2475582000-01-03 -1.064092 -1.832947  0.094414 -0.4458642000-01-04 -0.092463 -1.629868  0.183957 -0.7023272000-01-05  1.086481 -2.833691  0.010039 -0.101303In [169]: wp.reindex(items=['item1'], minor=['B']).squeeze()Out[169]: 2000-01-01   -0.1672792000-01-02   -0.5007702000-01-03   -1.8329472000-01-04   -1.6298682000-01-05   -2.833691Freq: D, Name: B, dtype: float64

转换为DataFrame

一个Panel可以用2D的形式表示一个分层索引的DataFrame.要将Panel对象转换为DataFrame,可以使用toframe方法:

In [171]: panel = pd.Panel(np.random.randn(3, 5, 4), items=['one', 'two', 'three'],     ...:                 major_axis=pd.date_range('1/1/2000', periods=5),     ...:                 minor_axis=['a', 'b', 'c', 'd'])In [172]: panel.to_frame()Out[172]:                        one       two     threemajor      minor                              2000-01-01 a     -0.058576 -0.026163  0.289173           b      1.333492  1.514565 -0.233190           c     -0.817197  2.144006 -0.126894           d     -1.205514 -0.572632 -0.3096792000-01-02 a      0.230310  2.712063 -0.311404           b     -0.070901 -1.373851  1.284403           c      0.928690  2.084200 -0.151439           d      1.326599 -0.571143 -0.2423542000-01-03 a     -0.684355  1.875092  0.692001           b      1.542806 -1.416353 -0.555132           c      1.048785  0.873523 -0.186362           d      1.457121 -1.266636 -0.9353502000-01-04 a     -0.821748 -0.900330 -1.458795           b      0.964931  0.119338 -0.534120           c     -0.778703  0.470976  0.913389           d     -0.078422  0.308533 -0.1280642000-01-05 a     -0.075534  0.700830  0.292943           b      0.291545  0.636898 -0.927162           c      1.103668 -0.697442 -1.354032           d     -1.209118  0.258653 -0.119056