pandas0.24.x文档3.4 数据结构
目录:
1 0.24.1版本新特性
2 安装
3马上开始
3.1 pandas概况
3.2 十分钟上手pandas
3.3 基础功能(一)
3.3 基础功能(二)
3.3基础功能(三)
3.4 数据结构
3.4 数据结构简介
我们先对pandas的基本数据结构进行一个简单快速的概览。数据类型、索引和轴标签/对齐等操作能对所有对象应用。首先,将NumPy和pandas引入你的命名空间。
In [1]: import numpy as np
In [2]: import pandas as pd
我们有个基本的信条:数据默认对齐。标签和数据间的联系不会被打破,除非你强制打破。
我们先简短地看看数据结构,然后考虑不同部分的函数和方法。
3.4.1 一维数据结构(Series)
Series是能处理任何数据类型(包括整数、字符串、浮点数和Python对象等等)的一维标签化数组。轴标签统称为索引。创建Series的基本方法是创建:
>>> s = pd.Series(data, index=index)
这里,传入的数据可以来自不同的类型:
- Python对象
- ndarray对象
- 标量值(比如5)
传入的index是轴标签的列表。因此,感觉数据的不同,这可以分为以下几种情况。
从ndarray对象创建
如果原数据是ndarray,那么index必须和data的长度一样。如果没有传入索引值,将会创建一个包含[0,1,2,...,len(data)-1]的index。
In [3]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
In [4]: s
Out[4]:
a 0.469112
b -0.282863
c -1.509059
d -1.135632
e 1.212112
dtype: float64
In [5]: s.index
Out[5]: Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
In [6]: pd.Series(np.random.randn(5))
Out[6]:
0 -0.173215
1 0.119209
2 -1.044236
3 -0.861849
4 -2.104569
dtype: float64
注意: pandas支持非唯一索引值。如果试图执行不支持重复索引值的操作,则此时将引发异常。懒惰的原因几乎都是基于性能的(在计算中有许多实例,比如GroupBy中不使用索引的部分)。
从dict对象创建
Series可以从dict实例化。
In [7]: d = {'b': 1, 'a': 0, 'c': 2}
In [8]: pd.Series(d)
Out[8]:
b 1
a 0
c 2
dtype: int64
注意: 如果原数据是字典并且没有传入index,当你使用的Python版本大于等于3.6pandas版本大于等于0.23时,Series的索引将按照字典的插入顺序。
当你使用的Python版本小于3.6或者pandas版本小于0.23时,Series的索引将会是字典的键按照词序形成的列表。
在上面的例子中,如果你使用的Python版本比3.6低或者pandas版本比0.23低,Series,生成的Series是按照键的词序来排序的,即['a', 'b', 'c'],而不是['b', 'a', 'c']。如果传递了索引,则会匹配出与索引中的标签对应的数据中的值。
In [9]: d = {'a': 0., 'b': 1., 'c': 2.}
In [10]: pd.Series(d)
Out[10]:
a 0.0
b 1.0
c 2.0
dtype: float64
In [11]: pd.Series(d, index=['b', 'c', 'd', 'a'])
Out[11]:
b 1.0
c 2.0
d NaN
a 0.0
dtype: float64
注意: NaN(not a number)是pandas使用的标准的缺失值处理器。
从标量值创建
如果原数据是标量值,必须提供一个索引。这个标量值会被重复来匹配index的长度。
In [12]: pd.Series(5., index=['a', 'b', 'c', 'd', 'e'])
Out[12]:
a 5.0
b 5.0
c 5.0
d 5.0
e 5.0
dtype: float64
3.4.1.1 Series类似ndarray
Series表现地和ndarray非常像,并且是大多数NumPy函数的合法参数。然而,像切片这样的操作也会对索引进行切片。
In [13]: s[0]
Out[13]: 0.46911229990718628
In [14]: s[:3]
Out[14]:
a 0.469112
b -0.282863
c -1.509059
dtype: float64
In [15]: s[s > s.median()]
Out[15]:
a 0.469112
e 1.212112
dtype: float64
In [16]: s[[4, 3, 1]]
Out[16]:
e 1.212112
d -1.135632
b -0.282863
dtype: float64
In [17]: np.exp(s)
Out[17]:
a 1.598575
b 0.753623
c 0.221118
d 0.321219
e 3.360575
dtype: float64
注意: 在section部分,我们将要介绍基于数组的索引,比如s[[4,3,1]]。
和NumPy数组一样,一个Series也有dtype。
In [18]: s.dtype
Out[18]: dtype('float64')
float64是最常见的NumPy数据类型。不过,pandas和其他第三方库在一些地方扩展了NumPy的类型系统,在这些地方,dtype就是ExtensionDtype.在pandas一些例子中,数据类型是Categorical和可为空的整数类型。详情请看dtypes.
如果你需要一个支持Series的数组,请使用Series.array.
In [19]: s.array
Out[19]:
<PandasArray>
[ 0.46911229990718628, -0.28286334432866328, -1.5090585031735124,
-1.1356323710171934, 1.2121120250208506]
Length: 5, dtype: float64
如果你要做一些不需要索引的操作,直接访问数组更有用。(比如,禁用自动对齐)
Series.array是扩展数组。简单来说,一个扩展数组只是包裹一个或多个具体的numpy.ndarray的容器。pandas知道怎样运用ExtensionArray并且将其储存在Series或DataFrame中的一列中。详情请看dtypes.Series只是类似ndarray,如果需要真正的ndarray,请使用Series.to_numpy().
In [20]: s.to_numpy()
Out[20]: array([ 0.4691, -0.2829, -1.5091, -1.1356, 1.2121])
即使Series由扩展数组支持,series.to_numpy()也将返回numpy ndarray。
3.4.1.2 Series类似字典
Series就像是一个大小灵活的字典,可以通过index标签取值和赋值:
In [21]: s['a']
Out[21]: 0.46911229990718628
In [22]: s['e'] = 12.
In [23]: s
Out[23]:
a 0.469112
b -0.282863
c -1.509059
d -1.135632
e 12.000000
dtype: float64
In [24]: 'e' in s
Out[24]: True
In [25]: 'f' in s
Out[25]: False
如果一个标签不存在,会抛出异常:
>>> s['f']
KeyError: 'f'
使用get方法,不存在的标签会返回None或者指定的默认值:
In [26]: s.get('f')
In [27]: s.get('f', np.nan)
Out[27]: nan
也可以参看属性访问部分.
3.4.1.3 矢量操作和Series的标签对齐
使用原始numpy数组时,通常不需要逐值循环。在pandas中对Series做同样的操作也是可行的。Series能够应用ndarray的大多数NumPy方法。
In [28]: s + s
Out[28]:
a 0.938225
b -0.565727
c -3.018117
d -2.271265
e 24.000000
dtype: float64
In [29]: s * 2
Out[29]:
a 0.938225
b -0.565727
c -3.018117
d -2.271265
e 24.000000
dtype: float64
In [30]: np.exp(s)
Out[30]:
a 1.598575
b 0.753623
c 0.221118
d 0.321219
e 162754.791419
dtype: float64
np.exp()返回e的幂次方
Series和ndarray的关键不同点在于Series会根据标签自动对齐数据。因此,在写计算公式时不必考虑Series是否包含同样的标签。
In [31]: s[1:] + s[:-1]
Out[31]:
a NaN
b -0.565727
c -3.018117
d -2.271265
e NaN
dtype: float64
上面这个对于两个没有对齐的Series的操作的结果会产生一个对两者索引取并集的结果。如果一个标签在其中一个中找不到的话会被标注为NaN值。这样能够在不明确指定数据对齐的情况下,保证交互式的数据分析和研究更加自由灵活。pandas数据结构的集成的数据对齐特征使得pandas不同于大多数处理标签化数据的大多数相关工具。
注意: 通常,为了避免损失信息,我们选择让不同索引的对象之间的操作结果默认取并集。即使没有数据,索引标签也是计算中非常重要的信息。当然,你也可以通过dropna函数来把那些缺失值的标签也去掉。
3.4.1.4 name属性
Series有一个name属性。
In [32]: s = pd.Series(np.random.randn(5), name='something')
In [33]: s
Out[33]:
0 -0.494929
1 1.071804
2 0.721555
3 -0.706771
4 -1.039575
Name: something, dtype: float64
In [34]: s.name
Out[34]: 'something'
在很多情况下,Series的name会自动指定,尤其是当你对DataFrame做1维切片时,下面你将会看到。
0.18.0版本的新特性
你能用pandas.Series.rename()方法对Series进行重命名。
In [35]: s2 = s.rename("different")
In [36]: s2.name
Out[36]: 'different'
注意这里的s和s2是不同的对象。
3.4.2 二维数据结构(DataFrame)
DataFrame 是2维的带标签的数据结构,它的列的数据类型可以不一样。你可以把它想象成一个电子表格、SQL表格或者由Series对象构成的字典。在pandas的对象当中,DataFrame是最常用的数据结构。和Series一样,DataFrame支持多种创建方式:
- 1维ndarray、列表、字典或Series构成的字典
- 2维的numpy.ndarray
- 结构化的或者record ndarray
- Series
- 其他DataFrame
对于数据,你可以选择是否传入index(行标签)或者columns(列标签)参数。如果你传入了index或者columns参数,那么生成的DataFrame的index和columns也就指定了。因此如果传入由Series组成的字典和指定的index,和传入的index不匹配的数据将会被丢弃。
如果轴标签没有传递,则将根据一般规则从输入数据构建轴标签。
注意: 当你从字典创建DataFrame,并且没有指定columns的话,如果使用的Python版本大于等于3.6并且pandas版本大于等于0.23,生成的DataFrame的列将根据字典的插入顺序排序。
如果使用的Python版本小于3.6或者pandas版本小于0.23,生成的DataFrame的列将根据字典的key的词序排序。
3.4.2.1 从Series或字典构成的字典创建
生成的index将是所有Series的index的并集。如果有任何嵌套的dict,这些dict将首先转换为Series。如果没有传入columns参数,列名将是排好序的字典key列表。
In [37]: d = {'one': pd.Series([1., 2., 3.], index=['a', 'b', 'c']),
....: 'two': pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
....:
In [38]: df = pd.DataFrame(d)
In [39]: df
Out[39]:
one two
a 1.0 1.0
b 2.0 2.0
c 3.0 3.0
d NaN 4.0
In [40]: pd.DataFrame(d, index=['d', 'b', 'a'])
Out[40]:
one two
d NaN 4.0
b 2.0 2.0
a 1.0 1.0
In [41]: pd.DataFrame(d, index=['d', 'b', 'a'], columns=['two', 'three'])
Out[41]:
two three
d 4.0 NaN
b 2.0 NaN
a 1.0 NaN
通过访问index和columns属性可以分别得到行和列标签。
注意: 从传入的字典创建DataFrame时,如果传入了columns参数,传入的columns参数将会覆盖掉字典本身的keys。
In [42]: df.index
Out[42]: Index(['a', 'b', 'c', 'd'], dtype='object')
In [43]: df.columns
Out[43]: Index(['one', 'two'], dtype='object')
3.4.2.2 从ndarray/列表构成的字典创建
一起传入的ndarray必须是同样长度的。如果要传入index参数,也必须和这些数组一样长。如果没有传入index参数,生成的index会是range(n),其中n是数组长度。
In [44]: d = {'one': [1., 2., 3., 4.],
....: 'two': [4., 3., 2., 1.]}
....:
In [45]: pd.DataFrame(d)
Out[45]:
one two
0 1.0 4.0
1 2.0 3.0
2 3.0 2.0
3 4.0 1.0
In [46]: pd.DataFrame(d, index=['a', 'b', 'c', 'd'])
Out[46]:
one two
a 1.0 4.0
b 2.0 3.0
c 3.0 2.0
d 4.0 1.0
3.4.2.3 从结构化的或者record ndarray创建
这种情况的处理和上文对数组组成的字典的处理相同。
In [47]: data = np.zeros((2, ), dtype=[('A', 'i4'), ('B', 'f4'), ('C', 'a10')])
In [48]: data[:] = [(1, 2., 'Hello'), (2, 3., "World")]
In [49]: pd.DataFrame(data)
Out[49]:
A B C
0 1 2.0 b'Hello'
1 2 3.0 b'World'
In [50]: pd.DataFrame(data, index=['first', 'second'])
Out[50]:
A B C
first 1 2.0 b'Hello'
second 2 3.0 b'World'
In [51]: pd.DataFrame(data, columns=['C', 'A', 'B'])
Out[51]:
C A B
0 b'Hello' 1 2.0
1 b'World' 2 3.0
注意: DataFrame并不是完全像2维的NumPy ndarray那样工作的。
3.4.2.4 从字典构成的列表创建
In [52]: data2 = [{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]
In [53]: pd.DataFrame(data2)
Out[53]:
a b c
0 1 2 NaN
1 5 10 20.0
In [54]: pd.DataFrame(data2, index=['first', 'second'])
Out[54]:
a b c
first 1 2 NaN
second 5 10 20.0
In [55]: pd.DataFrame(data2, columns=['a', 'b'])
Out[55]:
a b
0 1 2
1 5 10
3.4.2.5 从元组构成的字典创建
通过传入元组字典,你能自动创建一个多重索引的DataFrame。
In [56]: 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[56]:
a b
b a c a b
A B 1.0 4.0 5.0 8.0 10.0
C 2.0 3.0 6.0 7.0 NaN
D NaN NaN NaN NaN 9.0
3.4.2.6 来自Series
从Series创建DataFrame和Series有同样的index,列名也是来自Series,除非提供了其他列名。
缺失数据
详情请看缺失数据。在从含有缺失值的数据构建DataFrame时,我们用np.nan来代替那些缺失的数据。另外,你也可以传递一个numpy.MaskedArray参数给DataFrame构造器,其他覆盖的输入将会被认为是缺失值。
3.4.2.7 备选构造器
DataFrame.from_dict
DataFrame.from_dict接受字典或数组型的序列构成的字典,并且返回一个DataFrame。这个方法和DataFrame构造器很像,除了orient参数不一样,orient默认是'columns',但是也可以设置成'index',这样可以使用字典的keys作为行标签。
In [57]: pd.DataFrame.from_dict(dict([('A', [1, 2, 3]), ('B', [4, 5, 6])]))
Out[57]:
A B
0 1 4
1 2 5
2 3 6
如果你传入orient='index',keys将会是行标签。在这种情况下,你可以传入想要的列名:
In [58]: pd.DataFrame.from_dict(dict([('A', [1, 2, 3]), ('B', [4, 5, 6])]),
....: orient='index', columns=['one', 'two', 'three'])
....:
Out[58]:
one two three
A 1 2 3
B 4 5 6
DataFrame.from_records
DataFrame.from_records接受元组组成的列表或者结构化数据类型的ndarra.它和常规的DataFrame构造器类似,除了生成的DataFrame的索引可能是指定结构化数据类型的特定字段。比如:
In [59]: data
Out[59]:
array([(1, 2., b'Hello'), (2, 3., b'World')],
dtype=[('A', '<i4'), ('B', '<f4'), ('C', 'S10')])
In [60]: pd.DataFrame.from_records(data, index='C')
Out[60]:
A B
C
b'Hello' 1 2.0
b'World' 2 3.0
3.4.2.8 列选择、添加、删除
你可以从字面意思上把DataFrame看作是由类似索引的Series构成的字典。取值、赋值以及删除列都和对应的字典操作有相同的语法。
In [61]: df['one']
Out[61]:
a 1.0
b 2.0
c 3.0
d NaN
Name: one, dtype: float64
In [62]: df['three'] = df['one'] * df['two']
In [63]: df['flag'] = df['one'] > 2
In [64]: df
Out[64]:
one two three flag
a 1.0 1.0 1.0 False
b 2.0 2.0 4.0 False
c 3.0 3.0 9.0 True
d NaN 4.0 NaN False
删除列也和字典相似。
In [65]: del df['two']
In [66]: three = df.pop('three')
In [67]: df
Out[67]:
one flag
a 1.0 False
b 2.0 False
c 3.0 True
d NaN False
当插入一个标量值时,会自动推广到整个列。
In [68]: df['foo'] = 'bar'
In [69]: df
Out[69]:
one flag foo
a 1.0 False bar
b 2.0 False bar
c 3.0 True bar
d NaN False bar
当插入的Series和DataFrame的索引不同时,Series的索引将会被改造成DataFrame的索引。
In [70]: df['one_trunc'] = df['one'][:2]
In [71]: df
Out[71]:
one flag foo one_trunc
a 1.0 False bar 1.0
b 2.0 False bar 2.0
c 3.0 True bar NaN
d NaN False bar NaN
你也可以插入原生的ndarray,但是长度必须和DataFrame的索引的长度相同。
默认情况下,插入的列会被放到最后面。但insert函数也支持在特定位置上进行插入。
In [72]: df.insert(1, 'bar', df['one'])
In [73]: df
Out[73]:
one bar flag foo one_trunc
a 1.0 1.0 False bar 1.0
b 2.0 2.0 False bar 2.0
c 3.0 3.0 True bar NaN
d NaN NaN False bar NaN
3.4.2.9 在方法链中分配新列
受dplyr的转换动词启发,DataFrame有一个assign()方法,允许用户创建可能来自已有的列的新列。
In [74]: iris = pd.read_csv('data/iris.data')
In [75]: iris.head()
Out[75]:
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 [76]: (iris.assign(sepal_ratio=iris['SepalWidth'] / iris['SepalLength'])
....: .head())
....:
Out[76]:
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
在上面的例子中,我们插入了一个预先计算的值。我们还可以传入一个参数的函数,它将在分配给的DataFrame上进行计算。
In [77]: iris.assign(sepal_ratio=lambda x: (x['SepalWidth'] / x['SepalLength'])).head()
Out[77]:
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中筛选出'SepalLength'列大于5的数据,计数比率,并作图。
In [78]: (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[78]: <matplotlib.axes._subplots.AxesSubplot at 0x7f2b527b1a58>
[图片上传失败...(image-b7a179-1556113063245)]
这里传递了一个函数,函数会在指派的DataFrame上计算。而且,DataFrame过滤出了'SepalLength'列大于5的行。先做了过滤,然后做了计算。这个例子中我们没有可用的过滤了的DataFrame可用。用于赋值的函数签名只是**Kwargs.键是新字段的列名,这些值要么是要插入的值(例如,一个序列或numpy数组),要么是要在DataFrame上调用的一个参数的函数。 函数会返回原数据的副本,同时插入了新值。
0.23.0版本新变化
使用Python3.6时,**kwargs的顺序会保留。这就支持了依赖赋值,即assign方法中的表达式的后面部分能引用前面部分新生成的参数。
In [79]: dfa = pd.DataFrame({"A": [1, 2, 3],
....: "B": [4, 5, 6]})
....:
In [80]: dfa.assign(C=lambda x: x['A'] + x['B'],
....: D=lambda x: x['A'] + x['C'])
....:
Out[80]:
A B C D
0 1 4 5 6
1 2 5 7 9
2 3 6 9 12
在同一个表达式中,x['C']代表了新生成的列,这等价于dfa['A']+dfa['B'].
为了使代码兼容所有版本的python,请把赋值表达式分成两部分:
In [81]: dependent = pd.DataFrame({"A": [1, 1, 1]})
In [82]: (dependent.assign(A=lambda x: x['A'] + 1)
....: .assign(B=lambda x: x['A'] + 2))
....:
Out[82]:
A B
0 2 4
1 2 4
2 2 4
警告: 依赖赋值可能会在python 3.6和旧版本的python之间微妙地改变代码的行为。
如果你需要写同时支持3.6版本之前或之后的Python,在传入赋值表达式时请小心:
- 更新已有的列
- 在同一个assign中引用新更新的列
比如,下面我们将更新A列,然后在创建B列时引用A列。
>>> dependent = pd.DataFrame({"A": [1, 1, 1]})
>>> dependent.assign(A=lambda x: x["A"] + 1, B=lambda x: x["A"] + 2)
对于Python3.5或者更早的版本,创建B列的表达式会引用到A列的“旧”值,结果是这样的:
A B
0 2 3
1 2 3
2 2 3
而对于Python3.6版本或之后的版本,创建B列的表达式会引用到A列的“新”值,结果是这样的:
A B
0 2 4
1 2 4
2 2 4
3.4.2.10 索引/选择
基本的索引方法如下:
操作 | 语法 | 结果 |
---|---|---|
选择列 | df[col] | Series |
通过标签选择行 | df.loc[label] | Series |
通过整数位置来选取行 | df.iloc[loc] | Series |
行切片 | df[5:10] | DataFrame |
通过布尔向量选择行 | df[bool_vec] | DataFrame |
举个例子,选取一行时,返回一个Series,其索引是DataFrame的列。
In [83]: df.loc['b']
Out[83]:
one 2
bar 2
flag False
foo bar
one_trunc 2
Name: b, dtype: object
In [84]: df.iloc[2]
Out[84]:
one 3
bar 3
flag True
foo bar
one_trunc NaN
Name: c, dtype: object
有关复杂的基于标签的索引和切片的更详尽的处理,请参阅索引部分。在重新索引部分 ,我们会强调重新索引和转换到新标签集的基础。
3.4.2.11 数据对齐和运算
DataFrame之间的运算会自动对齐列和索引(行标签)。另外,生成的对象将会有所有DataFrame列和行标签的合集。
In [85]: df = pd.DataFrame(np.random.randn(10, 4), columns=['A', 'B', 'C', 'D'])
In [86]: df2 = pd.DataFrame(np.random.randn(7, 3), columns=['A', 'B', 'C'])
In [87]: df + df2
Out[87]:
A B C D
0 0.045691 -0.014138 1.380871 NaN
1 -0.955398 -1.501007 0.037181 NaN
2 -0.662690 1.534833 -0.859691 NaN
3 -2.452949 1.237274 -0.133712 NaN
4 1.414490 1.951676 -2.320422 NaN
5 -0.494922 -1.649727 -1.084601 NaN
6 -1.047551 -0.748572 -0.805479 NaN
7 NaN NaN NaN NaN
8 NaN NaN NaN NaN
9 NaN NaN NaN NaN
对DataFrame和Series进行操作时,默认的操作是将Series的索引和DataFrame的列对齐,然后逐行推广。比如:
In [88]: df - df.iloc[0]
Out[88]:
A B C D
0 0.000000 0.000000 0.000000 0.000000
1 -1.359261 -0.248717 -0.453372 -1.754659
2 0.253128 0.829678 0.010026 -1.991234
3 -1.311128 0.054325 -1.724913 -1.620544
4 0.573025 1.500742 -0.676070 1.367331
5 -1.741248 0.781993 -1.241620 -2.053136
6 -1.240774 -0.869551 -0.153282 0.000430
7 -0.743894 0.411013 -0.929563 -0.282386
8 -1.194921 1.320690 0.238224 -1.482644
9 2.293786 1.856228 0.773289 -1.446531
这里df.iloc[0]取的是第0行,上面的运算是逐行减去第0行
在处理时间序列的特殊情况下,并且DataFrame也包含日期,推广方向将是列维度的。
In [89]: index = pd.date_range('1/1/2000', periods=8)
In [90]: df = pd.DataFrame(np.random.randn(8, 3), index=index, columns=list('ABC'))
In [91]: df
Out[91]:
A B C
2000-01-01 -1.226825 0.769804 -1.281247
2000-01-02 -0.727707 -0.121306 -0.097883
2000-01-03 0.695775 0.341734 0.959726
2000-01-04 -1.110336 -0.619976 0.149748
2000-01-05 -0.732339 0.687738 0.176444
2000-01-06 0.403310 -0.154951 0.301624
2000-01-07 -2.179861 -1.369849 -0.954208
2000-01-08 1.462696 -1.743161 -0.826591
In [92]: type(df['A'])
Out[92]: pandas.core.series.Series
In [93]: df - df['A']
Out[93]:
2000-01-01 00:00:00 2000-01-02 00:00:00 2000-01-03 00:00:00 2000-01-04 00:00:00 2000-01-05 00:00:00 ... 2000-01-07 00:00:00 2000-01-08 00:00:00 A B C
2000-01-01 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN
2000-01-02 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN
2000-01-03 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN
2000-01-04 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN
2000-01-05 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN
2000-01-06 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN
2000-01-07 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN
2000-01-08 NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN
[8 rows x 11 columns]
警告:
df-df['A']
已经弃用了,并且在未来的发行版中将被移除。完成这项操作更好的方式是:
df.sub(df['A'],axis=0)
如果想对匹配和推广有更精确的控制,请看二元操作部分.
对标量的操作和期望的一样:
In [94]: df * 5 + 2
Out[94]:
A B C
2000-01-01 -4.134126 5.849018 -4.406237
2000-01-02 -1.638535 1.393469 1.510587
2000-01-03 5.478873 3.708672 6.798628
2000-01-04 -3.551681 -1.099880 2.748742
2000-01-05 -1.661697 5.438692 2.882222
2000-01-06 4.016548 1.225246 3.508122
2000-01-07 -8.899303 -4.849247 -2.771039
2000-01-08 9.313480 -6.715805 -2.132955
In [95]: 1 / df
Out[95]:
A B C
2000-01-01 -0.815112 1.299033 -0.780489
2000-01-02 -1.374179 -8.243600 -10.216313
2000-01-03 1.437247 2.926250 1.041965
2000-01-04 -0.900628 -1.612966 6.677871
2000-01-05 -1.365487 1.454041 5.667510
2000-01-06 2.479485 -6.453662 3.315381
2000-01-07 -0.458745 -0.730007 -1.047990
2000-01-08 0.683669 -0.573671 -1.209788
In [96]: df ** 4
Out[96]:
A B C
2000-01-01 2.265327 0.351172 2.694833
2000-01-02 0.280431 0.000217 0.000092
2000-01-03 0.234355 0.013638 0.848376
2000-01-04 1.519910 0.147740 0.000503
2000-01-05 0.287640 0.223714 0.000969
2000-01-06 0.026458 0.000576 0.008277
2000-01-07 22.579530 3.521204 0.829033
2000-01-08 4.577374 9.233151 0.466834
这也同样适用于布尔操作。
In [97]: df1 = pd.DataFrame({'a': [1, 0, 1], 'b': [0, 1, 1]}, dtype=bool)
In [98]: df2 = pd.DataFrame({'a': [0, 1, 1], 'b': [1, 1, 0]}, dtype=bool)
In [99]: df1 & df2
Out[99]:
a b
0 False False
1 False True
2 True False
In [100]: df1 | df2
Out[100]:
a b
0 True True
1 True True
2 True True
In [101]: df1 ^ df2
Out[101]:
a b
0 True True
1 True False
2 False True
In [102]: -df1
Out[102]:
a b
0 False True
1 True False
2 False False
3.4.2.12 转置
和ndarray类似,转置需要通过T属性。
# only show the first 5 rows
In [103]: df[:5].T
Out[103]:
2000-01-01 2000-01-02 2000-01-03 2000-01-04 2000-01-05
A -1.226825 -0.727707 0.695775 -1.110336 -0.732339
B 0.769804 -0.121306 0.341734 -0.619976 0.687738
C -1.281247 -0.097883 0.959726 0.149748 0.176444
3.4.2.13 DataFrame与NumPy函数的互操作性
假定DataFrame的数据是数值型的话,元素级别的NumPy函数(比如log,exp,sqrt等等)和其他的NumPy函数都可以没有问题地运行在DataFrame上。
In [104]: np.exp(df)
Out[104]:
A B C
2000-01-01 0.293222 2.159342 0.277691
2000-01-02 0.483015 0.885763 0.906755
2000-01-03 2.005262 1.407386 2.610980
2000-01-04 0.329448 0.537957 1.161542
2000-01-05 0.480783 1.989212 1.192968
2000-01-06 1.496770 0.856457 1.352053
2000-01-07 0.113057 0.254145 0.385117
2000-01-08 4.317584 0.174966 0.437538
In [105]: np.asarray(df)
Out[105]:
array([[-1.2268, 0.7698, -1.2812],
[-0.7277, -0.1213, -0.0979],
[ 0.6958, 0.3417, 0.9597],
[-1.1103, -0.62 , 0.1497],
[-0.7323, 0.6877, 0.1764],
[ 0.4033, -0.155 , 0.3016],
[-2.1799, -1.3698, -0.9542],
[ 1.4627, -1.7432, -0.8266]])
DataFrame的dot方法可以进行矩阵乘法:
In [106]: df.T.dot(df)
Out[106]:
A B C
A 11.341858 -0.059772 3.007998
B -0.059772 6.520556 2.083308
C 3.007998 2.083308 4.310549
类似的,Series的dot方法可以进行点积运算:
In [107]: s1 = pd.Series(np.arange(5, 10))
In [108]: s1.dot(s1)
Out[108]: 255
DataFrame并不是用来代替ndarray的,因为它的索引语义在某些地方与矩阵有很大的不同。
3.4.2.14 控制台展示
非常大的DataFrame会被截断成几部分,以便于在控制台中展示。运用info()方法可以得知其概况。(这里我从plyr R包读取了csv版本的baseball数据集。)
In [109]: baseball = pd.read_csv('data/baseball.csv')
In [110]: print(baseball)
id player year stint team lg g ab r h X2b X3b hr rbi sb cs bb so ibb hbp sh sf gidp
0 88641 womacto01 2006 2 CHN NL 19 50 6 14 1 0 1 2.0 1.0 1.0 4 4.0 0.0 0.0 3.0 0.0 0.0
1 88643 schilcu01 2006 1 BOS AL 31 2 0 1 0 0 0 0.0 0.0 0.0 0 1.0 0.0 0.0 0.0 0.0 0.0
.. ... ... ... ... ... .. .. ... .. ... ... ... .. ... ... ... .. ... ... ... ... ... ...
98 89533 aloumo01 2007 1 NYN NL 87 328 51 112 19 1 13 49.0 3.0 0.0 27 30.0 5.0 2.0 0.0 3.0 13.0
99 89534 alomasa02 2007 1 NYN NL 8 22 1 3 1 0 0 0.0 0.0 0.0 0 3.0 0.0 0.0 0.0 0.0 0.0
[100 rows x 23 columns]
In [111]: baseball.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100 entries, 0 to 99
Data columns (total 23 columns):
id 100 non-null int64
player 100 non-null object
year 100 non-null int64
stint 100 non-null int64
team 100 non-null object
lg 100 non-null object
g 100 non-null int64
ab 100 non-null int64
r 100 non-null int64
h 100 non-null int64
X2b 100 non-null int64
X3b 100 non-null int64
hr 100 non-null int64
rbi 100 non-null float64
sb 100 non-null float64
cs 100 non-null float64
bb 100 non-null int64
so 100 non-null float64
ibb 100 non-null float64
hbp 100 non-null float64
sh 100 non-null float64
sf 100 non-null float64
gidp 100 non-null float64
dtypes: float64(9), int64(11), object(3)
memory usage: 18.0+ KB
不过,使用to_string()方法会用表格的方式呈现DataFrame,虽然有时不能很好地适应控制台:
In [112]: print(baseball.iloc[-20:, :12].to_string())
id player year stint team lg g ab r h X2b X3b
80 89474 finlest01 2007 1 COL NL 43 94 9 17 3 0
81 89480 embreal01 2007 1 OAK AL 4 0 0 0 0 0
82 89481 edmonji01 2007 1 SLN NL 117 365 39 92 15 2
83 89482 easleda01 2007 1 NYN NL 76 193 24 54 6 0
84 89489 delgaca01 2007 1 NYN NL 139 538 71 139 30 0
85 89493 cormirh01 2007 1 CIN NL 6 0 0 0 0 0
86 89494 coninje01 2007 2 NYN NL 21 41 2 8 2 0
87 89495 coninje01 2007 1 CIN NL 80 215 23 57 11 1
88 89497 clemero02 2007 1 NYA AL 2 2 0 1 0 0
89 89498 claytro01 2007 2 BOS AL 8 6 1 0 0 0
90 89499 claytro01 2007 1 TOR AL 69 189 23 48 14 0
91 89501 cirilje01 2007 2 ARI NL 28 40 6 8 4 0
92 89502 cirilje01 2007 1 MIN AL 50 153 18 40 9 2
93 89521 bondsba01 2007 1 SFN NL 126 340 75 94 14 0
94 89523 biggicr01 2007 1 HOU NL 141 517 68 130 31 3
95 89525 benitar01 2007 2 FLO NL 34 0 0 0 0 0
96 89526 benitar01 2007 1 SFN NL 19 0 0 0 0 0
97 89530 ausmubr01 2007 1 HOU NL 117 349 38 82 16 3
98 89533 aloumo01 2007 1 NYN NL 87 328 51 112 19 1
99 89534 alomasa02 2007 1 NYN NL 8 22 1 3 1 0
默认情况下,宽的DataFrame会跨多行打印:
In [113]: pd.DataFrame(np.random.randn(3, 12))
Out[113]:
0 1 2 3 4 5 6 7 8 9 10 11
0 -0.345352 1.314232 0.690579 0.995761 2.396780 0.014871 3.357427 -0.317441 -1.236269 0.896171 -0.487602 -0.082240
1 -2.182937 0.380396 0.084844 0.432390 1.519970 -0.493662 0.600178 0.274230 0.132885 -0.023688 2.410179 1.450520
2 0.206053 -0.251905 -2.213588 1.063327 1.266143 0.299368 -0.863838 0.408204 -1.048089 -0.025747 -0.988387 0.094055
通过设置display.width参数可以改变每行的打印量:
In [114]: pd.set_option('display.width', 40) # default is 80
In [115]: pd.DataFrame(np.random.randn(3, 12))
Out[115]:
0 1 2 3 4 5 6 7 8 9 10 11
0 1.262731 1.289997 0.082423 -0.055758 0.536580 -0.489682 0.369374 -0.034571 -2.484478 -0.281461 0.030711 0.109121
1 1.126203 -0.977349 1.474071 -0.064034 -1.282782 0.781836 -1.071357 0.441153 2.353925 0.583787 0.221471 -0.744471
2 0.758527 1.729689 -0.964980 -0.845696 -1.340896 1.846883 -1.328865 1.682706 -1.717693 0.888782 0.228440 0.901805
官网的展示是用拖动条的,因此一行可以展示完。现在的jupyternotebook也支持一行展示。
你也可以通过设置display.max_colwidth参数来调节单列的最大宽度。
In [116]: datafile = {'filename': ['filename_01', 'filename_02'],
.....: 'path': ["media/user_name/storage/folder_01/filename_01",
.....: "media/user_name/storage/folder_02/filename_02"]}
.....:
In [117]: pd.set_option('display.max_colwidth', 30)
In [118]: pd.DataFrame(datafile)
Out[118]:
filename path
0 filename_01 media/user_name/storage/fo...
1 filename_02 media/user_name/storage/fo...
In [119]: pd.set_option('display.max_colwidth', 100)
In [120]: pd.DataFrame(datafile)
Out[120]:
filename path
0 filename_01 media/user_name/storage/folder_01/filename_01
1 filename_02 media/user_name/storage/folder_02/filename_02
你也可以通过expand_frame_repr可选项来关掉这个特性。这会在一格中打印整张表格。
3.4.2.15 DataFrame列属性访问和IPython自动补全
如果DataFrame的列标签是合法的Python变量名,这列可以通过属性的访问方法访问到。
In [121]: df = pd.DataFrame({'foo1': np.random.randn(5),
.....: 'foo2': np.random.randn(5)})
.....:
In [122]: df
Out[122]:
foo1 foo2
0 1.171216 -0.858447
1 0.520260 0.306996
2 -1.197071 -0.028665
3 -1.066969 0.384316
4 -0.303421 1.574159
In [123]: df.foo1
Out[123]:
0 1.171216
1 0.520260
2 -1.197071
3 -1.066969
4 -0.303421
Name: foo1, dtype: float64
各列都和IPython的补全机制做了关联,因此可以通过tab键补全:
In [5]: df.fo<TAB> # noqa: E225, E999
df.foo1 df.foo2
3.4.3 三维数据结构/面板(Panel)
警告: 在0.20.0版本,Panel被弃用了,并且在未来的版本中将被起用。请看弃用Panel部分.
Panel虽然使用地较少,但也是很重要的3维数据容器。“Panel data”这个术语来源于计量经济学,部分原因也是来自pandas这个名字:pan(el)-da(ta)-s. Panel3个轴的名字是为了在语义上更好地描述panel数据,尤其是其计量分析。不过,为了严格地对DataFrame对象进行切片和切分,你可能会发现轴名称有点随意。
- items:第0轴,每个元素都对应于一个DataFrame
- major_axis:第1轴,每个DataFrame的index(行)
- minor_axis:第2轴,每个DataFrame的列
panel的构造工作起来就像你预期的一样。
3.4.3.1 从3维ndarray创建,可选轴标签参数
In [124]: 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 [125]: wp
Out[125]:
<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
3.4.3.2 从DataFrame构成的字典创建
In [126]: data = {'Item1': pd.DataFrame(np.random.randn(4, 3)),
.....: 'Item2': pd.DataFrame(np.random.randn(4, 2))}
.....:
In [127]: pd.Panel(data)
Out[127]:
<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
请注意字典中的values只需要能转换成DataFrame就行。因此,上面的DataFrame的构造方法都适用。
一个有用的工厂函数是Panel.from_dict,需要传入上文所说的DataFrame构成的字典,以及下面几个参数:
参数 | 默认 | 描述 |
---|---|---|
intersect | False | 删除索引不对齐的元素 |
orient | items | 使用minor来把DataFrame的列作为panel的items |
比如,我们和上面的构造做一下对比:
In [128]: pd.Panel.from_dict(data, orient='minor')
Out[128]:
<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
对于混合类型的DataFrame,orient参数尤其有用。如果你传入的字典中的DataFrame的列是混合类型的,所有的数据的类型都会升级到object类型,除非你传入参数orient='minor'.
In [129]: df = pd.DataFrame({'a': ['foo', 'bar', 'baz'],
.....: 'b': np.random.randn(3)})
.....:
In [130]: df
Out[130]:
a b
0 foo -0.308853
1 bar -0.681087
2 baz 0.377953
In [131]: data = {'item1': df, 'item2': df}
In [132]: panel = pd.Panel.from_dict(data, orient='minor')
In [133]: panel['a']
Out[133]:
item1 item2
0 foo foo
1 bar bar
2 baz baz
In [134]: panel['b']
Out[134]:
item1 item2
0 -0.308853 -0.308853
1 -0.681087 -0.681087
2 0.377953 0.377953
In [135]: panel['b'].dtypes
Out[135]:
item1 float64
item2 float64
dtype: object
注意: Panel,通常比Series和DataFrame使用地要少,在未来也将被轻微地忽视。很多DataFrame中能用的方法和可选项在Panel中都用不了。
3.4.3.3 从DataFrame创建,使用to_panel方法
to_panel方法能把有两层索引的DataFrame转换为Panel。
In [136]: midx = pd.MultiIndex(levels=[['one', 'two'], ['x', 'y']],
.....: codes=[[1, 1, 0, 0], [1, 0, 1, 0]])
.....:
In [137]: df = pd.DataFrame({'A': [1, 2, 3, 4], 'B': [5, 6, 7, 8]}, index=midx)
In [138]: df.to_panel()
Out[138]:
<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
3.4.3.4 元素选择/添加/删除
就像DataFrame是由Series构成的字典一样,Panel是由DataFrame构成的字典。
In [139]: wp['Item1']
Out[139]:
A B C D
2000-01-01 1.588931 0.476720 0.473424 -0.242861
2000-01-02 -0.014805 -0.284319 0.650776 -1.461665
2000-01-03 -1.137707 -0.891060 -0.693921 1.613616
2000-01-04 0.464000 0.227371 -0.496922 0.306389
2000-01-05 -2.290613 -1.134623 -1.561819 -0.260838
In [140]: wp['Item3'] = wp['Item1'] / wp['Item2']
插入和删除的api和DataFrame相同。和DataFrame一样,如果item是有效的python标识符,你也可以将它作为属性来访问,并且在IPython中用tab键补全。
3.4.3.5 转置
运用transpose方法能将Panel重组。(默认不会返回一个副本,除非原数据是异质的。)
In [141]: wp.transpose(2, 0, 1)
Out[141]:
<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
3.4.3.6 索引/选择
操作 | 语法 | 结果 |
---|---|---|
选取项 | wp[item] | DataFrame |
在major_axis轴上切片 | wp.major_xs(val) | DataFrame |
在wp.minor_axis轴上切片 | wp.minor_xs(val) | DataFrame |
比如,使用早一些的例子,我们可以这样做:
In [142]: wp['Item1']
Out[142]:
A B C D
2000-01-01 1.588931 0.476720 0.473424 -0.242861
2000-01-02 -0.014805 -0.284319 0.650776 -1.461665
2000-01-03 -1.137707 -0.891060 -0.693921 1.613616
2000-01-04 0.464000 0.227371 -0.496922 0.306389
2000-01-05 -2.290613 -1.134623 -1.561819 -0.260838
In [143]: wp.major_xs(wp.major_axis[2])
Out[143]:
Item1 Item2 Item3
A -1.137707 0.800193 -1.421791
B -0.891060 0.782098 -1.139320
C -0.693921 -1.069094 0.649074
D 1.613616 -1.099248 -1.467927
In [144]: wp.minor_axis
Out[144]: Index(['A', 'B', 'C', 'D'], dtype='object')
In [145]: wp.minor_xs('C')
Out[145]:
Item1 Item2 Item3
2000-01-01 0.473424 -0.902937 -0.524316
2000-01-02 0.650776 -1.144073 -0.568824
2000-01-03 -0.693921 -1.069094 0.649074
2000-01-04 -0.496922 0.661084 -0.751678
2000-01-05 -1.561819 -1.056652 1.478083
3.4.3.7 压缩
改变维度的另一种方法是压缩一个一维的对象,比如wp['Item1']这样的。
In [146]: wp.reindex(items=['Item1']).squeeze()
Out[146]:
A B C D
2000-01-01 1.588931 0.476720 0.473424 -0.242861
2000-01-02 -0.014805 -0.284319 0.650776 -1.461665
2000-01-03 -1.137707 -0.891060 -0.693921 1.613616
2000-01-04 0.464000 0.227371 -0.496922 0.306389
2000-01-05 -2.290613 -1.134623 -1.561819 -0.260838
In [147]: wp.reindex(items=['Item1'], minor=['B']).squeeze()
Out[147]:
2000-01-01 0.476720
2000-01-02 -0.284319
2000-01-03 -0.891060
2000-01-04 0.227371
2000-01-05 -1.134623
Freq: D, Name: B, dtype: float64
3.4.3.8 转换为DataFrame
Panel能装换为一个多层次的DataFrame,以2维的表格形式呈现。详情请看多重索引部分.把Panel转换为DataFrame需用到to_frame方法:
In [148]: 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 [149]: panel.to_frame()
Out[149]:
one two three
major minor
2000-01-01 a 0.493672 1.219492 -1.290493
b -2.461467 0.062297 0.787872
c -1.553902 -0.110388 1.515707
d 2.015523 -1.184357 -0.276487
2000-01-02 a -1.833722 -0.558081 -0.223762
b 1.771740 0.077849 1.397431
c -0.670027 0.629498 1.503874
d 0.049307 -1.035260 -0.478905
2000-01-03 a -0.521493 -0.438229 -0.135950
b -3.201750 0.503703 -0.730327
c 0.792716 0.413086 -0.033277
d 0.146111 -1.139050 0.281151
2000-01-04 a 1.903247 0.660342 -1.298915
b -0.747169 0.464794 -2.819487
c -0.309038 -0.309337 -0.851985
d 0.393876 -0.649593 -1.106952
2000-01-05 a 1.861468 0.683758 -0.937731
b 0.936527 -0.643834 -1.537770
c 1.255746 0.421287 0.555759
d -2.655452 1.032814 -2.277282
3.4.4 弃用面板(Deprecate Panel)
在过去的一些年里,pandas在深度和广度上都取得了发展,带来了新的特性、数据类型以及操作程序。因此,为了支持Series、DataFrame和Panel的高效索引和函数程序,我们不得不面对逐渐增加的碎片化和难以理解的代码基。
3维的Panel结构,相比于1维的Series和2维的DataFrame,对于许多数据分析来说不那么常见。因此在未来pandas将专注于1维和2维的数据结构。
通常情况下,用户能够使用多重索引的DataFrame来轻松处理高纬度的数据。
此外,xarray包从一开始就是为支持多维数据的分析而构建的,已经涵盖了Panel的主要用途。这里是xarray的panel转换文档.
In [150]: import pandas.util.testing as tm
In [151]: p = tm.makePanel()
In [152]: p
Out[152]:
<class 'pandas.core.panel.Panel'>
Dimensions: 3 (items) x 30 (major_axis) x 4 (minor_axis)
Items axis: ItemA to ItemC
Major_axis axis: 2000-01-03 00:00:00 to 2000-02-11 00:00:00
Minor_axis axis: A to D
转换为多重索引的DataFrame。
In [153]: p.to_frame()
Out[153]:
ItemA ItemB ItemC
major minor
2000-01-03 A -0.390201 -1.624062 -0.605044
B 1.562443 0.483103 0.583129
C -1.085663 0.768159 -0.273458
D 0.136235 -0.021763 -0.700648
2000-01-04 A 1.207122 -0.758514 0.878404
B 0.763264 0.061495 -0.876690
C -1.114738 0.225441 -0.335117
D 0.886313 -0.047152 -1.166607
2000-01-05 A 0.178690 -0.560859 -0.921485
B 0.162027 0.240767 -1.919354
C -0.058216 0.543294 -0.476268
D -1.350722 0.088472 -0.367236
2000-01-06 A -1.004168 -0.589005 -0.200312
B -0.902704 0.782413 -0.572707
C -0.486768 0.771931 -1.765602
D -0.886348 -0.857435 1.296674
2000-01-07 A -1.377627 -1.070678 0.522423
B 1.106010 0.628462 -1.736484
C 1.685148 -0.968145 0.578223
D -1.013316 -2.503786 0.641385
2000-01-10 A 0.499281 -1.681101 0.722511
B -0.199234 -0.880627 -1.335113
C 0.112572 -1.176383 0.242697
D 1.920906 -1.058041 -0.779432
2000-01-11 A -1.405256 0.403776 -1.702486
B 0.458265 0.777575 -1.244471
C -1.495309 -3.192716 0.208129
D -0.388231 -0.657981 0.602456
2000-01-12 A 0.162565 0.609862 -0.709535
B 0.491048 -0.779367 0.347339
... ... ... ...
2000-02-02 C -0.303961 -0.463752 -0.288962
D 0.104050 1.116086 0.506445
2000-02-03 A -2.338595 -0.581967 -0.801820
B -0.557697 -0.033731 -0.176382
C 0.625555 -0.055289 0.875359
D 0.174068 -0.443915 1.626369
2000-02-04 A -0.374279 -1.233862 -0.915751
B 0.381353 -1.108761 -1.970108
C -0.059268 -0.360853 -0.614618
D -0.439461 -0.200491 0.429518
2000-02-07 A -2.359958 -3.520876 -0.288156
B 1.337122 -0.314399 -1.044208
C 0.249698 0.728197 0.565375
D -0.741343 1.092633 0.013910
2000-02-08 A -1.157886 0.516870 -1.199945
B -1.531095 -0.860626 -0.821179
C 1.103949 1.326768 0.068184
D -0.079673 -1.675194 -0.458272
2000-02-09 A -0.551865 0.343125 -0.072869
B 1.331458 0.370397 -1.914267
C -1.087532 0.208927 0.788871
D -0.922875 0.437234 -1.531004
2000-02-10 A 1.592673 2.137827 -1.828740
B -0.571329 -1.761442 -0.826439
C 1.998044 0.292058 -0.280343
D 0.303638 0.388254 -0.500569
2000-02-11 A 1.559318 0.452429 -1.716981
B -0.026671 -0.899454 0.124808
C -0.244548 -2.019610 0.931536
D -0.917368 0.479630 0.870690
[120 rows x 3 columns]
或者,你也可以将Panel转换为xarray的DataArray。
In [154]: p.to_xarray()
Out[154]:
<xarray.DataArray (items: 3, major_axis: 30, minor_axis: 4)>
array([[[-0.390201, 1.562443, -1.085663, 0.136235],
[ 1.207122, 0.763264, -1.114738, 0.886313],
...,
[ 1.592673, -0.571329, 1.998044, 0.303638],
[ 1.559318, -0.026671, -0.244548, -0.917368]],
[[-1.624062, 0.483103, 0.768159, -0.021763],
[-0.758514, 0.061495, 0.225441, -0.047152],
...,
[ 2.137827, -1.761442, 0.292058, 0.388254],
[ 0.452429, -0.899454, -2.01961 , 0.47963 ]],
[[-0.605044, 0.583129, -0.273458, -0.700648],
[ 0.878404, -0.87669 , -0.335117, -1.166607],
...,
[-1.82874 , -0.826439, -0.280343, -0.500569],
[-1.716981, 0.124808, 0.931536, 0.87069 ]]])
Coordinates:
* items (items) object 'ItemA' 'ItemB' 'ItemC'
* major_axis (major_axis) datetime64[ns] 2000-01-03 2000-01-04 ... 2000-02-11
* minor_axis (minor_axis) object 'A' 'B' 'C' 'D'
详情请看xarray包的文档.