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

数据结构介绍

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 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]: s
Out[59]: 
a    1
b    2
c    3
Name: first, dtype: int64

In [60]: pd.DataFrame(s)
Out[60]: 
   first
a      1
b      2
c      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]: data
Out[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]: data
Out[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  B
C          
Hello  1  2
World  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  B
0  1  4
1  2  5
2  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  three
A    1    2      3
B    4    5      6

列的选择、添加和删除

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

In [74]: df['one']
Out[74]: 
a     1
b     2
c     3
d   NaN
Name: one, dtype: float64

In [75]: df['three'] = df['one'] * df['two']

In [76]: df['flag'] = df['one'] > 2

In [77]: df
Out[77]: 
   one  two  three   flag
a    1    1      1  False
b    2    2      4  False
c    3    3      9   True
d  NaN    4    NaN  False

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

In [78]: del df['two']

In [79]: three = df.pop('three')

In [80]: df
Out[80]: 
   one   flag
a    1  False
b    2  False
c    3   True
d  NaN  False

In [81]: three
Out[81]: 
a     1
b     4
c     9
d   NaN
Name: three, dtype: float64

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

In [82]: df['foo'] = 'bar'

In [83]: df
Out[83]: 
   one   flag  foo
a    1  False  bar
b    2  False  bar
c    3   True  bar
d  NaN  False  bar

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

In [84]: df['one_trunc'] = df['one'][:2]

In [85]: df
Out[85]: 
   one   flag  foo  one_trunc
a    1  False  bar          1
b    2  False  bar          2
c    3   True  bar        NaN
d  NaN  False  bar        NaN

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

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

In [87]: df
Out[87]: 
   one  bar   flag  foo  one_trunc
a    1    1  False  bar          1
b    2    2  False  bar          2
c    3    3   True  bar        NaN
d  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         Name
0          5.1         3.5          1.4         0.2  Iris-setosa
1          4.9         3.0          1.4         0.2  Iris-setosa
2          4.7         3.2          1.3         0.2  Iris-setosa
3          4.6         3.1          1.5         0.2  Iris-setosa
4          5.0         3.6          1.4         0.2  Iris-setosa

In [49]: (iris.assign(sepal_ratio = iris['SepalWidth'] / iris['SepalLength']).head())
Out[49]: 
   SepalLength  SepalWidth  PetalLength  PetalWidth         Name  sepal_ratio
0          5.1         3.5          1.4         0.2  Iris-setosa     0.686275
1          4.9         3.0          1.4         0.2  Iris-setosa     0.612245
2          4.7         3.2          1.3         0.2  Iris-setosa     0.680851
3          4.6         3.1          1.5         0.2  Iris-setosa     0.673913
4          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_ratio
0          5.1         3.5          1.4         0.2  Iris-setosa     0.686275
1          4.9         3.0          1.4         0.2  Iris-setosa     0.612245
2          4.7         3.2          1.3         0.2  Iris-setosa     0.680851
3          4.6         3.1          1.5         0.2  Iris-setosa     0.673913
4          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]: df
Out[63]: 
   one  bar   flag  foo  one_trunc
a    1    1  False  bar          1
b    2    2  False  bar          2
c    3    3   True  bar        NaN
d  NaN  NaN  False  bar        NaN

#根据索引标签选择
In [64]: df.loc['b']
Out[64]: 
one              2
bar              2
flag         False
foo            bar
one_trunc        2
Name: b, dtype: object

#根据位置选择
In [65]: df.iloc[2]
Out[65]: 
one             3
bar             3
flag         True
foo           bar
one_trunc     NaN
Name: c, dtype: object

数据对齐和运算

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

In [69]: df = pd.DataFrame(np.random.randn(10, 4), columns=['A', 'B', 'C', 'D'])

In [70]: df
Out[70]: 
          A         B         C         D
0 -1.081213  0.964799 -1.526936  0.857095
1  0.786559 -0.824999  0.373886  0.383198
2 -0.026515 -0.539306  0.987269  0.045101
3 -0.726887 -1.176843 -0.799625 -0.192155
4 -1.180493  2.145532  0.682645  0.317200
5  1.041298 -1.334093  0.346744 -0.222402
6 -0.553535 -1.031090 -1.738747 -0.404298
7  0.367074 -1.312607  0.811453 -0.829041
8  1.150281 -0.435246  0.686140  1.672713
9 -2.811454 -0.064040 -0.173748  0.156016

In [71]: df2 = pd.DataFrame(np.random.randn(7, 3), columns=['A', 'B', 'C'])

In [72]: df2
Out[72]: 
          A         B         C
0 -0.116847  2.508202 -0.206053
1 -0.264634 -0.440654  0.355929
2 -0.805070  1.162288  0.637293
3 -0.423643  0.854117 -0.385428
4  0.790752  0.084708 -0.699494
5  2.139285 -0.546327  0.381495
6 -0.086828  1.019701  0.448619

In [73]: df + df2
Out[73]: 
          A         B         C   D
0 -1.198059  3.473001 -1.732989 NaN
1  0.521925 -1.265653  0.729814 NaN
2 -0.831585  0.622982  1.624562 NaN
3 -1.150530 -0.322726 -1.185053 NaN
4 -0.389741  2.230240 -0.016849 NaN
5  3.180583 -1.880420  0.728239 NaN
6 -0.640363 -0.011389 -1.290128 NaN
7       NaN       NaN       NaN NaN
8       NaN       NaN       NaN NaN
9       NaN       NaN       NaN NaN

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

In [74]: df.iloc[0]
Out[74]: 
A   -1.081213
B    0.964799
C   -1.526936
D    0.857095
Name: 0, dtype: float64

In [75]: df - df.iloc[0]
Out[75]: 
          A         B         C         D
0  0.000000  0.000000  0.000000  0.000000
1  1.867771 -1.789798  1.900821 -0.473897
2  1.054698 -1.504105  2.514205 -0.811994
3  0.354326 -2.141642  0.727311 -1.049250
4 -0.099280  1.180733  2.209580 -0.539896
5  2.122511 -2.298892  1.873680 -1.079498
6  0.527677 -1.995888 -0.211811 -1.261393
7  1.448286 -2.277405  2.338389 -1.686136
8  2.231494 -1.400045  2.213076  0.815618
9 -1.730241 -1.028839  1.353188 -0.701080

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

In [76]: index = pd.date_range('1/1/2000', periods=8)

In [77]: index
Out[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]: df
Out[79]: 
                   A         B         C
2000-01-01  1.658336  0.312690  0.434380
2000-01-02  1.588613  1.044227 -0.548043
2000-01-03  1.453697  0.634530 -1.125464
2000-01-04  1.799968 -0.579391  0.047857
2000-01-05 -0.053769  0.067639  0.195662
2000-01-06 -1.863360  0.772522  0.690778
2000-01-07 -0.157916 -0.605435  0.324758
2000-01-08 -1.265800  0.157990  0.022863

In [80]: type(df['A'])
Out[80]: pandas.core.series.Series

In [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 + 2
Out[85]: 
                    A         B         C
2000-01-01  10.291678  3.563450  4.171900
2000-01-02   9.943063  7.221136 -0.740213
2000-01-03   9.268486  5.172651 -3.627319
2000-01-04  10.999838 -0.896953  2.239286
2000-01-05   1.731153  2.338194  2.978308
2000-01-06  -7.316800  5.862611  5.453892
2000-01-07   1.210420 -1.027175  3.623791
2000-01-08  -4.329001  2.789950  2.114315

In [86]: 1 / df
Out[86]: 
                    A          B          C
2000-01-01   0.603014   3.198056   2.302132
2000-01-02   0.629480   0.957646  -1.824675
2000-01-03   0.687901   1.575969  -0.888523
2000-01-04   0.555566  -1.725951  20.895489
2000-01-05 -18.597913  14.784416   5.110867
2000-01-06  -0.536665   1.294461   1.447642
2000-01-07  -6.332484  -1.651705   3.079215
2000-01-08  -0.790014   6.329511  43.738650

In [87]: df ** 4
Out[87]: 
                    A         B             C
2000-01-01   7.562925  0.009560  3.560239e-02
2000-01-02   6.369012  1.188995  9.021058e-02
2000-01-03   4.465763  0.162110  1.604450e+00
2000-01-04  10.496843  0.112690  5.245535e-06
2000-01-05   0.000008  0.000021  1.465621e-03
2000-01-06  12.055550  0.356159  2.276957e-01
2000-01-07   0.000622  0.134360  1.112346e-02
2000-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 & df2
Out[90]: 
       a      b
0  False  False
1  False   True
2   True  False

In [91]: df1 | df2
Out[91]: 
      a     b
0  True  True
1  True  True
2  True  True

In [92]: df1 ^ df2
Out[92]: 
       a      b
0   True   True
1   True  False
2  False   True

In [93]: -df1
Out[93]: 
       a      b
0  False   True
1   True  False
2  False  False

行列转换

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

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

In [96]: df[:5].T
Out[96]: 
   2000-01-01  2000-01-02  2000-01-03  2000-01-04  2000-01-05
A    1.658336    1.588613    1.453697    1.799968   -0.053769
B    0.312690    1.044227    0.634530   -0.579391    0.067639
C    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         C
2000-01-01  5.250565  1.367098  1.544005
2000-01-02  4.896950  2.841202  0.578080
2000-01-03  4.278905  1.886136  0.324502
2000-01-04  6.049451  0.560240  1.049021
2000-01-05  0.947651  1.069979  1.216115
2000-01-06  0.155150  2.165220  1.995268
2000-01-07  0.853922  0.545837  1.383696
2000-01-08  0.282014  1.171155  1.023126

In [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         C
A  15.729075  0.509448 -3.078136
B   0.509448  2.919385 -0.824455
C  -3.078136 -0.824455  2.379445

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

In [101]: s1 = pd.Series(np.arange(5, 10))

In [102]: s1
Out[102]: 
0    5
1    6
2    7
3    8
4    9
dtype: int32

In [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         Name
0            5.1         3.5          1.4         0.2  Iris-setosa
1            4.9         3.0          1.4         0.2  Iris-setosa
2            4.7         3.2          1.3         0.2  Iris-setosa
3            4.6         3.1          1.5         0.2  Iris-setosa
4            5.0         3.6          1.4         0.2  Iris-setosa
5            5.2         3.5          1.4         0.2  Iris-setosa
6            4.9         3.0          1.7         0.2  Iris-setosa
7            5.4         3.2          1.5         0.3  Iris-setosa
8            4.6         3.1          1.4         0.2  Iris-setosa
9            5.3         3.6          1.4         0.2  Iris-setosa
10           5.1         3.5          1.4         0.2  Iris-setosa
11           4.9         3.0          1.4         0.3  Iris-setosa
12           4.7         3.6          1.3         0.2  Iris-setosa
13           4.6         3.1          1.5         0.2  Iris-setosa
14           5.0         3.6          1.4         0.2  Iris-setosa
15           5.2         3.5          1.4         0.2  Iris-setosa
16           4.9         3.0          1.6         0.2  Iris-setosa
17           5.4         3.2          1.7         0.3  Iris-setosa
18           4.6         3.2          1.5         0.2  Iris-setosa
19           5.3         3.1          1.4         0.4  Iris-setosa
20           5.3         3.6          1.4         0.2  Iris-setosa
21           5.1         3.0          1.4         0.2  Iris-setosa
22           4.9         3.2          1.4         0.2  Iris-setosa
23           4.7         3.1          1.4         0.5  Iris-setosa
24           4.9         3.6          1.3         0.2  Iris-setosa
25           4.7         3.5          1.5         0.3  Iris-setosa
26           4.6         3.0          1.4         0.2  Iris-setosa
27           5.3         3.6          1.3         0.2  Iris-setosa
28           5.3         3.1          1.8         0.2  Iris-setosa
29           5.3         3.0          1.4         0.7  Iris-setosa
..           ...         ...          ...         ...          ...
573          5.1         3.5          1.4         0.2  Iris-setosa
574          4.9         3.0          1.4         0.3  Iris-setosa
575          4.7         3.6          1.3         0.2  Iris-setosa
576          4.6         3.1          1.5         0.2  Iris-setosa
577          5.0         3.6          1.4         0.2  Iris-setosa
578          5.2         3.5          1.4         0.2  Iris-setosa
579          4.9         3.0          1.6         0.2  Iris-setosa
580          5.4         3.2          1.7         0.3  Iris-setosa
581          4.6         3.2          1.5         0.2  Iris-setosa
582          5.3         3.1          1.4         0.4  Iris-setosa
583          5.3         3.6          1.4         0.2  Iris-setosa
584          5.1         3.0          1.4         0.2  Iris-setosa
585          4.9         3.2          1.4         0.2  Iris-setosa
586          4.7         3.1          1.4         0.5  Iris-setosa
587          4.9         3.6          1.3         0.2  Iris-setosa
588          4.7         3.5          1.5         0.3  Iris-setosa
589          4.6         3.0          1.4         0.2  Iris-setosa
590          5.3         3.6          1.3         0.2  Iris-setosa
591          5.3         3.1          1.8         0.2  Iris-setosa
592          5.3         3.0          1.4         0.7  Iris-setosa
593          5.1         3.2          1.4         0.2  Iris-setosa
594          4.9         3.1          1.4         0.2  Iris-setosa
595          4.7         3.6          1.3         0.2  Iris-setosa
596          5.1         3.1          1.5         0.2  Iris-setosa
597          4.9         3.6          1.4         0.3  Iris-setosa
598          5.2         3.5          1.4         0.2  Iris-setosa
599          4.9         3.0          1.6         0.2  Iris-setosa
600          5.4         3.2          1.4         0.2  Iris-setosa
601          4.6         3.1          1.3         0.7  Iris-setosa
602          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 602
Data columns (total 5 columns):
SepalLength    603 non-null float64
SepalWidth     603 non-null float64
PetalLength    603 non-null float64
PetalWidth     603 non-null float64
Name           603 non-null object
dtypes: float64(4), object(1)
memory usage: 25.9+ KB

In [111]: iris = pd.read_csv(u'data/iris.csv')

In [112]: print(iris)
     SepalLength  SepalWidth  PetalLength  PetalWidth         Name
0            5.1         3.5          1.4         0.2  Iris-setosa
1            4.9         3.0          1.4         0.2  Iris-setosa
2            4.7         3.2          1.3         0.2  Iris-setosa
3            4.6         3.1          1.5         0.2  Iris-setosa
..           ...         ...          ...         ................
600          5.4         3.2          1.4         0.2  Iris-setosa
601          4.6         3.1          1.3         0.7  Iris-setosa
602          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 602
Data columns (total 5 columns):
SepalLength    603 non-null float64
SepalWidth     603 non-null float64
PetalLength    603 non-null float64
PetalWidth     603 non-null float64
Name           603 non-null object
dtypes: float64(4), object(1)
memory usage: 25.9+ KB

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

In [116]: print(iris.iloc[-20:, ].to_string())
     SepalLength  SepalWidth  PetalLength  PetalWidth         Name
583          5.3         3.6          1.4         0.2  Iris-setosa
584          5.1         3.0          1.4         0.2  Iris-setosa
585          4.9         3.2          1.4         0.2  Iris-setosa
586          4.7         3.1          1.4         0.5  Iris-setosa
587          4.9         3.6          1.3         0.2  Iris-setosa
588          4.7         3.5          1.5         0.3  Iris-setosa
589          4.6         3.0          1.4         0.2  Iris-setosa
590          5.3         3.6          1.3         0.2  Iris-setosa
591          5.3         3.1          1.8         0.2  Iris-setosa
592          5.3         3.0          1.4         0.7  Iris-setosa
593          5.1         3.2          1.4         0.2  Iris-setosa
594          4.9         3.1          1.4         0.2  Iris-setosa
595          4.7         3.6          1.3         0.2  Iris-setosa
596          5.1         3.1          1.5         0.2  Iris-setosa
597          4.9         3.6          1.4         0.3  Iris-setosa
598          5.2         3.5          1.4         0.2  Iris-setosa
599          4.9         3.0          1.6         0.2  Iris-setosa
600          5.4         3.2          1.4         0.2  Iris-setosa
601          4.6         3.1          1.3         0.7  Iris-setosa
602          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) #默认为80

In [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]: df
Out[126]: 
       foo1      foo2
0  1.095587 -0.135147
1  1.049579 -0.117808
2  1.029435  1.438757
3  0.177883  0.123195
4 -0.964396 -2.319625

In [127]: df.foo1
Out[127]: 
0    1.095587
1    1.049579
2    1.029435
3    0.177883
4   -0.964396
Name: 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]: wp
Out[136]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 5 (major_axis) x 4 (minor_axis)
Items axis: item1 to item2
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00
Minor_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 Item2
Major_axis axis: 0 to 3
Minor_axis axis: 0 to 2

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

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

参数名默认值描述
intersectFalse删除索引没有对其的元素
orientitems使用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 2
Major_axis axis: 0 to 3
Minor_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]: df
Out[141]: 
     a         b
0  foo  0.075889
1  bar -0.450220
2  baz  1.570256

In [142]: data = {'item1': df, 'item2': df}

In [143]: panel = pd.Panel.from_dict(data, orient='minor')

In [144]: panel['a']
Out[144]: 
  item1 item2
0   foo   foo
1   bar   bar
2   baz   baz

In [145]: panel['b']
Out[145]: 
      item1     item2
0  0.075889  0.075889
1 -0.450220 -0.450220
2  1.570256  1.570256

In [146]: panel['b'].dtypes
Out[146]: 
item1    float64
item2    float64
dtype: 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]: df
Out[151]: 
       A  B
two y  1  5
    x  2  6
one y  3  7
    x  4  8

In [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 B
Major_axis axis: one to two
Minor_axis axis: x to y

Item的选择/添加/删除

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

In [156]: wp['item1']
Out[156]: 
                   A         B         C         D
2000-01-01 -1.459119 -0.167279 -0.105919 -1.589155
2000-01-02 -1.224224 -0.500770 -0.169742  0.247558
2000-01-03 -1.064092 -1.832947  0.094414 -0.445864
2000-01-04 -0.092463 -1.629868  0.183957 -0.702327
2000-01-05  1.086481 -2.833691  0.010039 -0.101303

In [157]: wp['item3'] = wp['item1'] / wp['item2']

In [158]: wp
Out[158]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 3 (items) x 5 (major_axis) x 4 (minor_axis)
Items axis: item1 to item3
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00
Minor_axis axis: A to D

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

转换

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

In [160]: wp
Out[160]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 3 (items) x 5 (major_axis) x 4 (minor_axis)
Items axis: item1 to item3
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00
Minor_axis axis: A to D

In [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 D
Major_axis axis: item1 to item3
Minor_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00

索引和选择

操作语法结果
选择itemwp[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         D
2000-01-01 -1.459119 -0.167279 -0.105919 -1.589155
2000-01-02 -1.224224 -0.500770 -0.169742  0.247558
2000-01-03 -1.064092 -1.832947  0.094414 -0.445864
2000-01-04 -0.092463 -1.629868  0.183957 -0.702327
2000-01-05  1.086481 -2.833691  0.010039 -0.101303

In [165]: wp.major_xs(wp.major_axis[2])
Out[165]: 
      item1     item2     item3
A -1.064092  0.813871 -1.307446
B -1.832947 -2.016451  0.908996
C  0.094414 -0.456631 -0.206762
D -0.445864 -0.417404  1.068182

In [166]: wp.minor_axis
Out[166]: Index([u'A', u'B', u'C', u'D'], dtype='object')

In [167]: wp.minor_xs('C')
Out[167]: 
               item1     item2     item3
2000-01-01 -0.105919  1.211176 -0.087451
2000-01-02 -0.169742  1.823682 -0.093077
2000-01-03  0.094414 -0.456631 -0.206762
2000-01-04  0.183957  0.585720  0.314070
2000-01-05  0.010039  0.622204  0.016134

压缩

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

In [168]: wp.reindex(items=['item1']).squeeze()
Out[168]: 
                   A         B         C         D
2000-01-01 -1.459119 -0.167279 -0.105919 -1.589155
2000-01-02 -1.224224 -0.500770 -0.169742  0.247558
2000-01-03 -1.064092 -1.832947  0.094414 -0.445864
2000-01-04 -0.092463 -1.629868  0.183957 -0.702327
2000-01-05  1.086481 -2.833691  0.010039 -0.101303

In [169]: wp.reindex(items=['item1'], minor=['B']).squeeze()
Out[169]: 
2000-01-01   -0.167279
2000-01-02   -0.500770
2000-01-03   -1.832947
2000-01-04   -1.629868
2000-01-05   -2.833691
Freq: 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     three
major      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.309679
2000-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.242354
2000-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.935350
2000-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.128064
2000-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
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值