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.513811 -0.682048  1.026528  0.613557
2013-01-02  0.258981  1.925866  1.287821  0.110656
2013-01-03 -0.007805  1.016452 -1.743360  0.281440
2013-01-04 -0.266718  0.278100  0.563045 -1.316449
2013-01-05  0.055023 -1.408064  0.676574 -1.179435
2013-01-06  1.835612  1.262198  1.228904  1.685941

用传可以被转换为序列的对象的列表的方式来构建 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.513811 -0.682048  1.026528  0.613557
2013-01-02  0.258981  1.925866  1.287821  0.110656
2013-01-03 -0.007805  1.016452 -1.743360  0.281440
2013-01-04 -0.266718  0.278100  0.563045 -1.316449
2013-01-05  0.055023 -1.408064  0.676574 -1.179435

In [14]: df.tail(3)
Out[14]: 
                   A         B         C         D
2013-01-04 -0.266718  0.278100  0.563045 -1.316449
2013-01-05  0.055023 -1.408064  0.676574 -1.179435
2013-01-06  1.835612  1.262198  1.228904  1.685941

展示索引与列:

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.51381119, -0.68204775,  1.02652782,  0.61355664],
       [ 0.25898128,  1.925866  ,  1.28782052,  0.11065597],
       [-0.00780526,  1.01645185, -1.74335968,  0.28144037],
       [-0.26671773,  0.27810008,  0.56304502, -1.31644916],
       [ 0.05502254, -1.40806401,  0.67657411, -1.17943534],
       [ 1.83561196,  1.26219848,  1.22890403,  1.68594115]])

对于 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.226880  0.398751  0.506585  0.032618
std    0.832577  1.257493  1.139890  1.133845
min   -0.513811 -1.408064 -1.743360 -1.316449
25%   -0.201990 -0.442011  0.591427 -0.856913
50%    0.023609  0.647276  0.851551  0.196048
75%    0.207992  1.200762  1.178310  0.530528
max    1.835612  1.925866  1.287821  1.685941

转置你的数据:

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.513811    0.258981   -0.007805   -0.266718    0.055023    1.835612
B   -0.682048    1.925866    1.016452    0.278100   -1.408064    1.262198
C    1.026528    1.287821   -1.743360    0.563045    0.676574    1.228904
D    0.613557    0.110656    0.281440   -1.316449   -1.179435    1.685941

按轴排序:

In [21]: df.sort_index(axis=1, ascending=False)
Out[21]: 
                   D         C         B         A
2013-01-01  0.613557  1.026528 -0.682048 -0.513811
2013-01-02  0.110656  1.287821  1.925866  0.258981
2013-01-03  0.281440 -1.743360  1.016452 -0.007805
2013-01-04 -1.316449  0.563045  0.278100 -0.266718
2013-01-05 -1.179435  0.676574 -1.408064  0.055023
2013-01-06  1.685941  1.228904  1.262198  1.835612

按值排序:

In [22]: df.sort_values(by='B')
Out[22]: 
                   A         B         C         D
2013-01-05  0.055023 -1.408064  0.676574 -1.179435
2013-01-01 -0.513811 -0.682048  1.026528  0.613557
2013-01-04 -0.266718  0.278100  0.563045 -1.316449
2013-01-03 -0.007805  1.016452 -1.743360  0.281440
2013-01-06  1.835612  1.262198  1.228904  1.685941
2013-01-02  0.258981  1.925866  1.287821  0.110656

选择

注解

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

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

获取

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

In [23]: df['A']
Out[23]: 
2013-01-01   -0.513811
2013-01-02    0.258981
2013-01-03   -0.007805
2013-01-04   -0.266718
2013-01-05    0.055023
2013-01-06    1.835612
Freq: D, Name: A, dtype: float64

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

In [24]: df[0:3]
Out[24]: 
                   A         B         C         D
2013-01-01 -0.513811 -0.682048  1.026528  0.613557
2013-01-02  0.258981  1.925866  1.287821  0.110656
2013-01-03 -0.007805  1.016452 -1.743360  0.281440

In [25]: df['20130102':'20130104']
Out[25]: 
                   A         B         C         D
2013-01-02  0.258981  1.925866  1.287821  0.110656
2013-01-03 -0.007805  1.016452 -1.743360  0.281440
2013-01-04 -0.266718  0.278100  0.563045 -1.316449

按标签选择

详见 按标签选择

用标签获取横截面数据:

In [26]: df.loc[dates[0]]
Out[26]: 
A   -0.513811
B   -0.682048
C    1.026528
D    0.613557
Name: 2013-01-01 00:00:00, dtype: float64

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

In [27]: df.loc[:, ['A', 'B']]
Out[27]: 
                   A         B
2013-01-01 -0.513811 -0.682048
2013-01-02  0.258981  1.925866
2013-01-03 -0.007805  1.016452
2013-01-04 -0.266718  0.278100
2013-01-05  0.055023 -1.408064
2013-01-06  1.835612  1.262198

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

In [28]: df.loc['20130102':'20130104', ['A', 'B']]
Out[28]: 
                   A         B
2013-01-02  0.258981  1.925866
2013-01-03 -0.007805  1.016452
2013-01-04 -0.266718  0.278100

降低返回对象的维度:

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

获取一个标量值:

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

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

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

按位置选择

详见 按位置选择

按传入整数的位置选择:

In [32]: df.iloc[3]
Out[32]: 
A   -0.266718
B    0.278100
C    0.563045
D   -1.316449
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.266718  0.278100
2013-01-05  0.055023 -1.408064

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

In [34]: df.iloc[[1, 2, 4], [0, 2]]
Out[34]: 
                   A         C
2013-01-02  0.258981  1.287821
2013-01-03 -0.007805 -1.743360
2013-01-05  0.055023  0.676574

显性地按行切片:

In [35]: df.iloc[1:3, :]
Out[35]: 
                   A         B         C         D
2013-01-02  0.258981  1.925866  1.287821  0.110656
2013-01-03 -0.007805  1.016452 -1.743360  0.281440

显性地按列切片:

In [36]: df.iloc[:, 1:3]
Out[36]: 
                   B         C
2013-01-01 -0.682048  1.026528
2013-01-02  1.925866  1.287821
2013-01-03  1.016452 -1.743360
2013-01-04  0.278100  0.563045
2013-01-05 -1.408064  0.676574
2013-01-06  1.262198  1.228904

显性地获得一个值:

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

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

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

布尔值索引

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

In [39]: df[df.A > 0]
Out[39]: 
                   A         B         C         D
2013-01-02  0.258981  1.925866  1.287821  0.110656
2013-01-05  0.055023 -1.408064  0.676574 -1.179435
2013-01-06  1.835612  1.262198  1.228904  1.685941

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

In [40]: df[df > 0]
Out[40]: 
                   A         B         C         D
2013-01-01       NaN       NaN  1.026528  0.613557
2013-01-02  0.258981  1.925866  1.287821  0.110656
2013-01-03       NaN  1.016452       NaN  0.281440
2013-01-04       NaN  0.278100  0.563045       NaN
2013-01-05  0.055023       NaN  0.676574       NaN
2013-01-06  1.835612  1.262198  1.228904  1.685941

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.513811 -0.682048  1.026528  0.613557    one
2013-01-02  0.258981  1.925866  1.287821  0.110656    one
2013-01-03 -0.007805  1.016452 -1.743360  0.281440    two
2013-01-04 -0.266718  0.278100  0.563045 -1.316449  three
2013-01-05  0.055023 -1.408064  0.676574 -1.179435   four
2013-01-06  1.835612  1.262198  1.228904  1.685941  three

In [44]: df2[df2['E'].isin(['two', 'four'])]
Out[44]: 
                   A         B         C         D     E
2013-01-03 -0.007805  1.016452 -1.743360  0.281440   two
2013-01-05  0.055023 -1.408064  0.676574 -1.179435  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.026528  5  NaN
2013-01-02  0.258981  1.925866  1.287821  5  1.0
2013-01-03 -0.007805  1.016452 -1.743360  5  2.0
2013-01-04 -0.266718  0.278100  0.563045  5  3.0
2013-01-05  0.055023 -1.408064  0.676574  5  4.0
2013-01-06  1.835612  1.262198  1.228904  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.026528 -5  NaN
2013-01-02 -0.258981 -1.925866 -1.287821 -5 -1.0
2013-01-03 -0.007805 -1.016452 -1.743360 -5 -2.0
2013-01-04 -0.266718 -0.278100 -0.563045 -5 -3.0
2013-01-05 -0.055023 -1.408064 -0.676574 -5 -4.0
2013-01-06 -1.835612 -1.262198 -1.228904 -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.026528  5  NaN  1.0
2013-01-02  0.258981  1.925866  1.287821  5  1.0  1.0
2013-01-03 -0.007805  1.016452 -1.743360  5  2.0  NaN
2013-01-04 -0.266718  0.278100  0.563045  5  3.0  NaN

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

In [58]: df1.dropna(how='any')
Out[58]: 
                   A         B         C  D    F    E
2013-01-02  0.258981  1.925866  1.287821  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.026528  5  5.0  1.0
2013-01-02  0.258981  1.925866  1.287821  5  1.0  1.0
2013-01-03 -0.007805  1.016452 -1.743360  5  2.0  5.0
2013-01-04 -0.266718  0.278100  0.563045  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

运算符

详见 基本二元运算符