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.225228 -2.401909  0.517596 -0.872217
2013-01-02  0.156417 -1.324609 -1.361773 -0.125418
2013-01-03  2.147777 -0.526022  0.002507  1.915504
2013-01-04  0.518793  1.182279  0.324116  0.565866
2013-01-05  0.023567 -1.379935  0.386087 -0.328761
2013-01-06  0.989807 -0.527137 -0.063642  1.157528

用传可以被转换为序列的对象的列表的方式来构建 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.225228 -2.401909  0.517596 -0.872217
2013-01-02  0.156417 -1.324609 -1.361773 -0.125418
2013-01-03  2.147777 -0.526022  0.002507  1.915504
2013-01-04  0.518793  1.182279  0.324116  0.565866
2013-01-05  0.023567 -1.379935  0.386087 -0.328761

In [14]: df.tail(3)
Out[14]: 
                   A         B         C         D
2013-01-04  0.518793  1.182279  0.324116  0.565866
2013-01-05  0.023567 -1.379935  0.386087 -0.328761
2013-01-06  0.989807 -0.527137 -0.063642  1.157528

展示索引与列:

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.22522811, -2.40190946,  0.51759553, -0.87221691],
       [ 0.15641703, -1.32460855, -1.36177291, -0.12541838],
       [ 2.1477766 , -0.52602244,  0.00250744,  1.91550365],
       [ 0.51879326,  1.18227874,  0.32411579,  0.56586645],
       [ 0.02356705, -1.37993469,  0.38608749, -0.32876134],
       [ 0.98980727, -0.52713679, -0.06364223,  1.15752832]])

对于 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.601856 -0.829556 -0.032518  0.385417
std    0.867661  1.204272  0.689080  1.031749
min   -0.225228 -2.401909 -1.361773 -0.872217
25%    0.056780 -1.366103 -0.047105 -0.277926
50%    0.337605 -0.925873  0.163312  0.220224
75%    0.872054 -0.526301  0.370595  1.009613
max    2.147777  1.182279  0.517596  1.915504

转置你的数据:

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.225228    0.156417    2.147777    0.518793    0.023567    0.989807
B   -2.401909   -1.324609   -0.526022    1.182279   -1.379935   -0.527137
C    0.517596   -1.361773    0.002507    0.324116    0.386087   -0.063642
D   -0.872217   -0.125418    1.915504    0.565866   -0.328761    1.157528

按轴排序:

In [21]: df.sort_index(axis=1, ascending=False)
Out[21]: 
                   D         C         B         A
2013-01-01 -0.872217  0.517596 -2.401909 -0.225228
2013-01-02 -0.125418 -1.361773 -1.324609  0.156417
2013-01-03  1.915504  0.002507 -0.526022  2.147777
2013-01-04  0.565866  0.324116  1.182279  0.518793
2013-01-05 -0.328761  0.386087 -1.379935  0.023567
2013-01-06  1.157528 -0.063642 -0.527137  0.989807

按值排序:

In [22]: df.sort_values(by='B')
Out[22]: 
                   A         B         C         D
2013-01-01 -0.225228 -2.401909  0.517596 -0.872217
2013-01-05  0.023567 -1.379935  0.386087 -0.328761
2013-01-02  0.156417 -1.324609 -1.361773 -0.125418
2013-01-06  0.989807 -0.527137 -0.063642  1.157528
2013-01-03  2.147777 -0.526022  0.002507  1.915504
2013-01-04  0.518793  1.182279  0.324116  0.565866

选择

注解

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

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

获取

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

In [23]: df['A']
Out[23]: 
2013-01-01   -0.225228
2013-01-02    0.156417
2013-01-03    2.147777
2013-01-04    0.518793
2013-01-05    0.023567
2013-01-06    0.989807
Freq: D, Name: A, dtype: float64

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

In [24]: df[0:3]
Out[24]: 
                   A         B         C         D
2013-01-01 -0.225228 -2.401909  0.517596 -0.872217
2013-01-02  0.156417 -1.324609 -1.361773 -0.125418
2013-01-03  2.147777 -0.526022  0.002507  1.915504

In [25]: df['20130102':'20130104']
Out[25]: 
                   A         B         C         D
2013-01-02  0.156417 -1.324609 -1.361773 -0.125418
2013-01-03  2.147777 -0.526022  0.002507  1.915504
2013-01-04  0.518793  1.182279  0.324116  0.565866

按标签选择

详见 按标签选择

用标签获取横截面数据:

In [26]: df.loc[dates[0]]
Out[26]: 
A   -0.225228
B   -2.401909
C    0.517596
D   -0.872217
Name: 2013-01-01 00:00:00, dtype: float64

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

In [27]: df.loc[:, ['A', 'B']]
Out[27]: 
                   A         B
2013-01-01 -0.225228 -2.401909
2013-01-02  0.156417 -1.324609
2013-01-03  2.147777 -0.526022
2013-01-04  0.518793  1.182279
2013-01-05  0.023567 -1.379935
2013-01-06  0.989807 -0.527137

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

In [28]: df.loc['20130102':'20130104', ['A', 'B']]
Out[28]: 
                   A         B
2013-01-02  0.156417 -1.324609
2013-01-03  2.147777 -0.526022
2013-01-04  0.518793  1.182279

降低返回对象的维度:

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

获取一个标量值:

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

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

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

按位置选择

详见 按位置选择

按传入整数的位置选择:

In [32]: df.iloc[3]
Out[32]: 
A    0.518793
B    1.182279
C    0.324116
D    0.565866
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.518793  1.182279
2013-01-05  0.023567 -1.379935

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

In [34]: df.iloc[[1, 2, 4], [0, 2]]
Out[34]: 
                   A         C
2013-01-02  0.156417 -1.361773
2013-01-03  2.147777  0.002507
2013-01-05  0.023567  0.386087

显性地按行切片:

In [35]: df.iloc[1:3, :]
Out[35]: 
                   A         B         C         D
2013-01-02  0.156417 -1.324609 -1.361773 -0.125418
2013-01-03  2.147777 -0.526022  0.002507  1.915504

显性地按列切片:

In [36]: df.iloc[:, 1:3]
Out[36]: 
                   B         C
2013-01-01 -2.401909  0.517596
2013-01-02 -1.324609 -1.361773
2013-01-03 -0.526022  0.002507
2013-01-04  1.182279  0.324116
2013-01-05 -1.379935  0.386087
2013-01-06 -0.527137 -0.063642

显性地获得一个值:

In [37]: df.iloc[1, 1]
Out[37]: -1.324608554870402

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

In [38]: df.iat[1, 1]
Out[38]: -1.324608554870402

布尔值索引

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

In [39]: df[df.A > 0]
Out[39]: 
                   A         B         C         D
2013-01-02  0.156417 -1.324609 -1.361773 -0.125418
2013-01-03  2.147777 -0.526022  0.002507  1.915504
2013-01-04  0.518793  1.182279  0.324116  0.565866
2013-01-05  0.023567 -1.379935  0.386087 -0.328761
2013-01-06  0.989807 -0.527137 -0.063642  1.157528

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

In [40]: df[df > 0]
Out[40]: 
                   A         B         C         D
2013-01-01       NaN       NaN  0.517596       NaN
2013-01-02  0.156417       NaN       NaN       NaN
2013-01-03  2.147777       NaN  0.002507  1.915504
2013-01-04  0.518793  1.182279  0.324116  0.565866
2013-01-05  0.023567       NaN  0.386087       NaN
2013-01-06  0.989807       NaN       NaN  1.157528

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.225228 -2.401909  0.517596 -0.872217    one
2013-01-02  0.156417 -1.324609 -1.361773 -0.125418    one
2013-01-03  2.147777 -0.526022  0.002507  1.915504    two
2013-01-04  0.518793  1.182279  0.324116  0.565866  three
2013-01-05  0.023567 -1.379935  0.386087 -0.328761   four
2013-01-06  0.989807 -0.527137 -0.063642  1.157528  three

In [44]: df2[df2['E'].isin(['two', 'four'])]
Out[44]: 
                   A         B         C         D     E
2013-01-03  2.147777 -0.526022  0.002507  1.915504   two
2013-01-05  0.023567 -1.379935  0.386087 -0.328761  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  0.517596  5  NaN
2013-01-02  0.156417 -1.324609 -1.361773  5  1.0
2013-01-03  2.147777 -0.526022  0.002507  5  2.0
2013-01-04  0.518793  1.182279  0.324116  5  3.0
2013-01-05  0.023567 -1.379935  0.386087  5  4.0
2013-01-06  0.989807 -0.527137 -0.063642  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 -0.517596 -5  NaN
2013-01-02 -0.156417 -1.324609 -1.361773 -5 -1.0
2013-01-03 -2.147777 -0.526022 -0.002507 -5 -2.0
2013-01-04 -0.518793 -1.182279 -0.324116 -5 -3.0
2013-01-05 -0.023567 -1.379935 -0.386087 -5 -4.0
2013-01-06 -0.989807 -0.527137 -0.063642 -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  0.517596  5  NaN  1.0
2013-01-02  0.156417 -1.324609 -1.361773  5  1.0  1.0
2013-01-03  2.147777 -0.526022  0.002507  5  2.0  NaN
2013-01-04  0.518793  1.182279  0.324116  5  3.0  NaN

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

In [58]: df1.dropna(how='any')
Out[58]: 
                   A         B         C  D    F    E
2013-01-02  0.156417 -1.324609 -1.361773  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  0.517596  5  5.0  1.0
2013-01-02  0.156417 -1.324609 -1.361773  5  1.0  1.0
2013-01-03  2.147777 -0.526022  0.002507  5  2.0  5.0
2013-01-04  0.518793  1.182279  0.324116  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

运算符

详见 基本二元运算符