10分钟了解pandas

这是一篇主要面向于新用户的关于pandas的简短介绍。 你可以在 Cookbook 中看到更为复杂的指导。

通常地,我们用下面这种方式导入库:

In [1]: import numpy as np

In [2]: import pandas as pd

创建对象

详见 数据结构介绍

用传一列表值的方式创建一个 Series ,使pandas构建一个默认的整数索引。

In [3]: s = pd.Series([1, 3, 5, np.nan, 6, 8])

In [4]: s
Out[4]: 
0    1.0
1    3.0
2    5.0
3    NaN
4    6.0
5    8.0
dtype: float64

用传NumPy数组的方式构建一个具有列标签与日期时间索引的 DataFrame

In [5]: dates = pd.date_range('20130101', periods=6)

In [6]: dates
Out[6]: 
DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04',
               '2013-01-05', '2013-01-06'],
              dtype='datetime64[ns]', freq='D')

In [7]: df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list('ABCD'))

In [8]: df
Out[8]: 
                   A         B         C         D
2013-01-01  0.648752  0.593078 -1.295593  0.041149
2013-01-02  1.225795  0.465408  0.600501 -0.281432
2013-01-03 -0.159979  0.749984 -1.778119  0.206457
2013-01-04  0.316474  0.932746 -0.882793  1.218417
2013-01-05  0.575033 -0.867022  0.441981 -1.177396
2013-01-06  1.154718 -2.284083  0.936261  0.438507

用传可以被转换为序列的对象的列表的方式来构建 DataFrame

In [9]: df2 = pd.DataFrame({'A': 1.,
   ...:                     'B': pd.Timestamp('20130102'),
   ...:                     'C': pd.Series(1, index=list(range(4)), dtype='float32'),
   ...:                     'D': np.array([3] * 4, dtype='int32'),
   ...:                     'E': pd.Categorical(["test", "train", "test", "train"]),
   ...:                     'F': 'foo'})
   ...: 

In [10]: df2
Out[10]: 
     A          B    C  D      E    F
0  1.0 2013-01-02  1.0  3   test  foo
1  1.0 2013-01-02  1.0  3  train  foo
2  1.0 2013-01-02  1.0  3   test  foo
3  1.0 2013-01-02  1.0  3  train  foo

得到的 DataFrame 的每一列具有不同的 dtypes

In [11]: df2.dtypes
Out[11]: 
A           float64
B    datetime64[ns]
C           float32
D             int32
E          category
F            object
dtype: object

当你在使用IPython时列名(也是对象的公有属性)的自动补全会被自动打开:

In [12]: df2.<TAB>  # noqa: E225, E999
df2.A                  df2.bool
df2.abs                df2.boxplot
df2.add                df2.C
df2.add_prefix         df2.clip
df2.add_suffix         df2.clip_lower
df2.align              df2.clip_upper
df2.all                df2.columns
df2.any                df2.combine
df2.append             df2.combine_first
df2.apply              df2.compound
df2.applymap           df2.consolidate
df2.D

如您所见,ABCD 都被收进了自动补全。 而 E 也同样在其中,简短起见我们把其他的属性截去了。

查看数据

详见 基础

这里展示如何查看一个数据框最顶端和最底端的几行数据:

In [13]: df.head()
Out[13]: 
                   A         B         C         D
2013-01-01  0.648752  0.593078 -1.295593  0.041149
2013-01-02  1.225795  0.465408  0.600501 -0.281432
2013-01-03 -0.159979  0.749984 -1.778119  0.206457
2013-01-04  0.316474  0.932746 -0.882793  1.218417
2013-01-05  0.575033 -0.867022  0.441981 -1.177396

In [14]: df.tail(3)
Out[14]: 
                   A         B         C         D
2013-01-04  0.316474  0.932746 -0.882793  1.218417
2013-01-05  0.575033 -0.867022  0.441981 -1.177396
2013-01-06  1.154718 -2.284083  0.936261  0.438507

展示索引与列:

In [15]: df.index
Out[15]: 
DatetimeIndex(['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04',
               '2013-01-05', '2013-01-06'],
              dtype='datetime64[ns]', freq='D')

In [16]: df.columns
Out[16]: Index(['A', 'B', 'C', 'D'], dtype='object')

DataFrame.to_numpy() 提供了内含数据的NumPy表示。 由于pandas和NumPy的基本区别: 每一个NumPy数组内部只具有一个针对整个数组的dtype,而pandas的DataFrame每一列只有一种dtype 。 当你调用 DataFrame.to_numpy() 时,pandas将会识别出一种NumPy的dtype来适应DataFrame中所有列。 这很有可能是 object 类型,即把所有值都转换为Python的object类型。

对于 df,一个所有值都是浮点值的 DataFrameDataFrame.to_numpy() 很快并且不需要复制数据。

In [17]: df.to_numpy()
Out[17]: 
array([[ 0.64875222,  0.59307832, -1.29559304,  0.04114874],
       [ 1.225795  ,  0.46540796,  0.60050066, -0.28143187],
       [-0.15997863,  0.74998388, -1.77811925,  0.2064572 ],
       [ 0.31647399,  0.93274638, -0.88279297,  1.21841656],
       [ 0.57503258, -0.86702186,  0.4419808 , -1.17739649],
       [ 1.15471779, -2.28408297,  0.93626149,  0.43850728]])

对于 df2,一个具有多种dtype的 DataFrame,相应地 DataFrame.to_numpy() 就具有昂贵的性能开销。

In [18]: df2.to_numpy()
Out[18]: 
array([[1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'test', 'foo'],
       [1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'train', 'foo'],
       [1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'test', 'foo'],
       [1.0, Timestamp('2013-01-02 00:00:00'), 1.0, 3, 'train', 'foo']],
      dtype=object)

注解

DataFrame.to_numpy() 在输出中 包括索引或列标签。

describe() 显示了数据的快速统计摘要:

In [19]: df.describe()
Out[19]: 
              A         B         C         D
count  6.000000  6.000000  6.000000  6.000000
mean   0.626799 -0.068315 -0.329627  0.074284
std    0.520764  1.260286  1.131389  0.794167
min   -0.159979 -2.284083 -1.778119 -1.177396
25%    0.381114 -0.533914 -1.192393 -0.200787
50%    0.611892  0.529243 -0.220406  0.123803
75%    1.028226  0.710757  0.560871  0.380495
max    1.225795  0.932746  0.936261  1.218417

转置你的数据:

In [20]: df.T
Out[20]: 
   2013-01-01  2013-01-02  2013-01-03  2013-01-04  2013-01-05  2013-01-06
A    0.648752    1.225795   -0.159979    0.316474    0.575033    1.154718
B    0.593078    0.465408    0.749984    0.932746   -0.867022   -2.284083
C   -1.295593    0.600501   -1.778119   -0.882793    0.441981    0.936261
D    0.041149   -0.281432    0.206457    1.218417   -1.177396    0.438507

按轴排序:

In [21]: df.sort_index(axis=1, ascending=False)
Out[21]: 
                   D         C         B         A
2013-01-01  0.041149 -1.295593  0.593078  0.648752
2013-01-02 -0.281432  0.600501  0.465408  1.225795
2013-01-03  0.206457 -1.778119  0.749984 -0.159979
2013-01-04  1.218417 -0.882793  0.932746  0.316474
2013-01-05 -1.177396  0.441981 -0.867022  0.575033
2013-01-06  0.438507  0.936261 -2.284083  1.154718

按值排序:

In [22]: df.sort_values(by='B')
Out[22]: 
                   A         B         C         D
2013-01-06  1.154718 -2.284083  0.936261  0.438507
2013-01-05  0.575033 -0.867022  0.441981 -1.177396
2013-01-02  1.225795  0.465408  0.600501 -0.281432
2013-01-01  0.648752  0.593078 -1.295593  0.041149
2013-01-03 -0.159979  0.749984 -1.778119  0.206457
2013-01-04  0.316474  0.932746 -0.882793  1.218417

选择

注解

虽然在交互式工作中标准Python/NumPy的选择修改表达式直观并且容易上手, 但在生产代码中,我们仍然推荐使用pandas优化过的数据获取方法, .at.iat.loc.iloc

详见关于索引的文档 索引与选择数据 and 多重/高级索引

获取

选择单一一列将会产出一个 Series ,相当于调用 df.A

In [23]: df['A']
Out[23]: 
2013-01-01    0.648752
2013-01-02    1.225795
2013-01-03   -0.159979
2013-01-04    0.316474
2013-01-05    0.575033
2013-01-06    1.154718
Freq: D, Name: A, dtype: float64

使用 [] 来选择,可以按行来对数据进行切片。

In [24]: df[0:3]
Out[24]: 
                   A         B         C         D
2013-01-01  0.648752  0.593078 -1.295593  0.041149
2013-01-02  1.225795  0.465408  0.600501 -0.281432
2013-01-03 -0.159979  0.749984 -1.778119  0.206457

In [25]: df['20130102':'20130104']
Out[25]: 
                   A         B         C         D
2013-01-02  1.225795  0.465408  0.600501 -0.281432
2013-01-03 -0.159979  0.749984 -1.778119  0.206457
2013-01-04  0.316474  0.932746 -0.882793  1.218417

按标签选择

详见 按标签选择

用标签获取横截面数据:

In [26]: df.loc[dates[0]]
Out[26]: 
A    0.648752
B    0.593078
C   -1.295593
D    0.041149
Name: 2013-01-01 00:00:00, dtype: float64

用标签获取多个轴的数据:

In [27]: df.loc[:, ['A', 'B']]
Out[27]: 
                   A         B
2013-01-01  0.648752  0.593078
2013-01-02  1.225795  0.465408
2013-01-03 -0.159979  0.749984
2013-01-04  0.316474  0.932746
2013-01-05  0.575033 -0.867022
2013-01-06  1.154718 -2.284083

使用标签切片,两端的标签 都被包含

In [28]: df.loc['20130102':'20130104', ['A', 'B']]
Out[28]: 
                   A         B
2013-01-02  1.225795  0.465408
2013-01-03 -0.159979  0.749984
2013-01-04  0.316474  0.932746

降低返回对象的维度:

In [29]: df.loc['20130102', ['A', 'B']]
Out[29]: 
A    1.225795
B    0.465408
Name: 2013-01-02 00:00:00, dtype: float64

获取一个标量值:

In [30]: df.loc[dates[0], 'A']
Out[30]: 0.6487522193702128

快速获取一个标量值(与先前方法等价):

In [31]: df.at[dates[0], 'A']
Out[31]: 0.6487522193702128

按位置选择

详见 按位置选择

按传入整数的位置选择:

In [32]: df.iloc[3]
Out[32]: 
A    0.316474
B    0.932746
C   -0.882793
D    1.218417
Name: 2013-01-04 00:00:00, dtype: float64

行为类似于NumPy/Python的按整数切片选择:

In [33]: df.iloc[3:5, 0:2]
Out[33]: 
                   A         B
2013-01-04  0.316474  0.932746
2013-01-05  0.575033 -0.867022

风格类似于NumPy/Python的按整数位置的列表选择:

In [34]: df.iloc[[1, 2, 4], [0, 2]]
Out[34]: 
                   A         C
2013-01-02  1.225795  0.600501
2013-01-03 -0.159979 -1.778119
2013-01-05  0.575033  0.441981

显性地按行切片:

In [35]: df.iloc[1:3, :]
Out[35]: 
                   A         B         C         D
2013-01-02  1.225795  0.465408  0.600501 -0.281432
2013-01-03 -0.159979  0.749984 -1.778119  0.206457

显性地按列切片:

In [36]: df.iloc[:, 1:3]
Out[36]: 
                   B         C
2013-01-01  0.593078 -1.295593
2013-01-02  0.465408  0.600501
2013-01-03  0.749984 -1.778119
2013-01-04  0.932746 -0.882793
2013-01-05 -0.867022  0.441981
2013-01-06 -2.284083  0.936261

显性地获得一个值:

In [37]: df.iloc[1, 1]
Out[37]: 0.4654079577335869

快速获得一个标量值(等价于上个方法):

In [38]: df.iat[1, 1]
Out[38]: 0.4654079577335869

布尔值索引

用单独一列的值来选择数据。

In [39]: df[df.A > 0]
Out[39]: 
                   A         B         C         D
2013-01-01  0.648752  0.593078 -1.295593  0.041149
2013-01-02  1.225795  0.465408  0.600501 -0.281432
2013-01-04  0.316474  0.932746 -0.882793  1.218417
2013-01-05  0.575033 -0.867022  0.441981 -1.177396
2013-01-06  1.154718 -2.284083  0.936261  0.438507

从一个DataFrame中选择符合布尔条件的值。

In [40]: df[df > 0]
Out[40]: 
                   A         B         C         D
2013-01-01  0.648752  0.593078       NaN  0.041149
2013-01-02  1.225795  0.465408  0.600501       NaN
2013-01-03       NaN  0.749984       NaN  0.206457
2013-01-04  0.316474  0.932746       NaN  1.218417
2013-01-05  0.575033       NaN  0.441981       NaN
2013-01-06  1.154718       NaN  0.936261  0.438507

isin() 来过滤:

In [41]: df2 = df.copy()

In [42]: df2['E'] = ['one', 'one', 'two', 'three', 'four', 'three']

In [43]: df2
Out[43]: 
                   A         B         C         D      E
2013-01-01  0.648752  0.593078 -1.295593  0.041149    one
2013-01-02  1.225795  0.465408  0.600501 -0.281432    one
2013-01-03 -0.159979  0.749984 -1.778119  0.206457    two
2013-01-04  0.316474  0.932746 -0.882793  1.218417  three
2013-01-05  0.575033 -0.867022  0.441981 -1.177396   four
2013-01-06  1.154718 -2.284083  0.936261  0.438507  three

In [44]: df2[df2['E'].isin(['two', 'four'])]
Out[44]: 
                   A         B         C         D     E
2013-01-03 -0.159979  0.749984 -1.778119  0.206457   two
2013-01-05  0.575033 -0.867022  0.441981 -1.177396  four

设定

设定自动对齐按索引对齐到数据上的新列:

In [45]: s1 = pd.Series([1, 2, 3, 4, 5, 6], index=pd.date_range('20130102', periods=6))

In [46]: s1
Out[46]: 
2013-01-02    1
2013-01-03    2
2013-01-04    3
2013-01-05    4
2013-01-06    5
2013-01-07    6
Freq: D, dtype: int64

In [47]: df['F'] = s1

按标签设定值:

In [48]: df.at[dates[0], 'A'] = 0

按位置设定值:

In [49]: df.iat[0, 1] = 0

用赋一个NumPy数组的方式设定值:

In [50]: df.loc[:, 'D'] = np.array([5] * len(df))

上一个设定操作的结果是:

In [51]: df
Out[51]: 
                   A         B         C  D    F
2013-01-01  0.000000  0.000000 -1.295593  5  NaN
2013-01-02  1.225795  0.465408  0.600501  5  1.0
2013-01-03 -0.159979  0.749984 -1.778119  5  2.0
2013-01-04  0.316474  0.932746 -0.882793  5  3.0
2013-01-05  0.575033 -0.867022  0.441981  5  4.0
2013-01-06  1.154718 -2.284083  0.936261  5  5.0

通过一个 where 操作来设定值。

In [52]: df2 = df.copy()

In [53]: df2[df2 > 0] = -df2

In [54]: df2
Out[54]: 
                   A         B         C  D    F
2013-01-01  0.000000  0.000000 -1.295593 -5  NaN
2013-01-02 -1.225795 -0.465408 -0.600501 -5 -1.0
2013-01-03 -0.159979 -0.749984 -1.778119 -5 -2.0
2013-01-04 -0.316474 -0.932746 -0.882793 -5 -3.0
2013-01-05 -0.575033 -0.867022 -0.441981 -5 -4.0
2013-01-06 -1.154718 -2.284083 -0.936261 -5 -5.0

缺失数据

pandas主要用 np.nan 值来代表缺失数据。 这在默认情况下不被包括在运算当中。 详见 缺失数据

重新索引可以允许您修改/添加/删除某个特定轴上的索引。这个操作返回源数据的一份拷贝。

In [55]: df1 = df.reindex(index=dates[0:4], columns=list(df.columns) + ['E'])

In [56]: df1.loc[dates[0]:dates[1], 'E'] = 1

In [57]: df1
Out[57]: 
                   A         B         C  D    F    E
2013-01-01  0.000000  0.000000 -1.295593  5  NaN  1.0
2013-01-02  1.225795  0.465408  0.600501  5  1.0  1.0
2013-01-03 -0.159979  0.749984 -1.778119  5  2.0  NaN
2013-01-04  0.316474  0.932746 -0.882793  5  3.0  NaN

移除任何带有缺失数据的行。

In [58]: df1.dropna(how='any')
Out[58]: 
                   A         B         C  D    F    E
2013-01-02  1.225795  0.465408  0.600501  5  1.0  1.0

填充缺失数据。

In [59]: df1.fillna(value=5)
Out[59]: 
                   A         B         C  D    F    E
2013-01-01  0.000000  0.000000 -1.295593  5  5.0  1.0
2013-01-02  1.225795  0.465408  0.600501  5  1.0  1.0
2013-01-03 -0.159979  0.749984 -1.778119  5  2.0  5.0
2013-01-04  0.316474  0.932746 -0.882793  5  3.0  5.0

得到值为 nan 的值的布尔值掩码。

In [60]: pd.isna(df1)
Out[60]: 
                A      B      C      D      F      E
2013-01-01  False  False  False  False   True  False
2013-01-02  False  False  False  False  False  False
2013-01-03  False  False  False  False  False   True
2013-01-04  False  False  False  False  False   True

运算符

详见 基本二元运算符