pandas0.24.x文档3.4 数据结构

作者: Lykit01 | 来源:发表于2019-04-24 21:38 被阅读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包的文档.

    相关文章

      网友评论

        本文标题:pandas0.24.x文档3.4 数据结构

        本文链接:https://www.haomeiwen.com/subject/mkgngqtx.html