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 -1.427215  0.193383  0.431986 -0.048781
2013-01-02 -1.327825  0.487863 -0.837461 -0.993610
2013-01-03  0.952778  0.283178  0.984822  0.828147
2013-01-04 -0.342168  1.561692 -0.680844  0.561420
2013-01-05 -0.460898 -1.907916  0.861746  0.520525
2013-01-06  0.362710 -0.406205 -0.364006 -0.335185

用传可以被转换为序列的对象的列表的方式来构建 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 -1.427215  0.193383  0.431986 -0.048781
2013-01-02 -1.327825  0.487863 -0.837461 -0.993610
2013-01-03  0.952778  0.283178  0.984822  0.828147
2013-01-04 -0.342168  1.561692 -0.680844  0.561420
2013-01-05 -0.460898 -1.907916  0.861746  0.520525

In [14]: df.tail(3)
Out[14]: 
                   A         B         C         D
2013-01-04 -0.342168  1.561692 -0.680844  0.561420
2013-01-05 -0.460898 -1.907916  0.861746  0.520525
2013-01-06  0.362710 -0.406205 -0.364006 -0.335185

展示索引与列:

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([[-1.42721477,  0.19338346,  0.43198612, -0.04878105],
       [-1.32782455,  0.48786262, -0.83746136, -0.99360986],
       [ 0.95277821,  0.28317791,  0.9848225 ,  0.82814666],
       [-0.34216824,  1.56169236, -0.6808437 ,  0.56142004],
       [-0.4608983 , -1.90791628,  0.86174632,  0.52052508],
       [ 0.36271039, -0.40620485, -0.36400636, -0.33518542]])

对于 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.373770  0.035333  0.066041  0.088753
std    0.930665  1.148228  0.796281  0.682157
min   -1.427215 -1.907916 -0.837461 -0.993610
25%   -1.111093 -0.256308 -0.601634 -0.263584
50%   -0.401533  0.238281  0.033990  0.235872
75%    0.186491  0.436691  0.754306  0.551196
max    0.952778  1.561692  0.984822  0.828147

转置你的数据:

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   -1.427215   -1.327825    0.952778   -0.342168   -0.460898    0.362710
B    0.193383    0.487863    0.283178    1.561692   -1.907916   -0.406205
C    0.431986   -0.837461    0.984822   -0.680844    0.861746   -0.364006
D   -0.048781   -0.993610    0.828147    0.561420    0.520525   -0.335185

按轴排序:

In [21]: df.sort_index(axis=1, ascending=False)
Out[21]: 
                   D         C         B         A
2013-01-01 -0.048781  0.431986  0.193383 -1.427215
2013-01-02 -0.993610 -0.837461  0.487863 -1.327825
2013-01-03  0.828147  0.984822  0.283178  0.952778
2013-01-04  0.561420 -0.680844  1.561692 -0.342168
2013-01-05  0.520525  0.861746 -1.907916 -0.460898
2013-01-06 -0.335185 -0.364006 -0.406205  0.362710

按值排序:

In [22]: df.sort_values(by='B')
Out[22]: 
                   A         B         C         D
2013-01-05 -0.460898 -1.907916  0.861746  0.520525
2013-01-06  0.362710 -0.406205 -0.364006 -0.335185
2013-01-01 -1.427215  0.193383  0.431986 -0.048781
2013-01-03  0.952778  0.283178  0.984822  0.828147
2013-01-02 -1.327825  0.487863 -0.837461 -0.993610
2013-01-04 -0.342168  1.561692 -0.680844  0.561420

选择

注解

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

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

获取

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

In [23]: df['A']
Out[23]: 
2013-01-01   -1.427215
2013-01-02   -1.327825
2013-01-03    0.952778
2013-01-04   -0.342168
2013-01-05   -0.460898
2013-01-06    0.362710
Freq: D, Name: A, dtype: float64

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

In [24]: df[0:3]
Out[24]: 
                   A         B         C         D
2013-01-01 -1.427215  0.193383  0.431986 -0.048781
2013-01-02 -1.327825  0.487863 -0.837461 -0.993610
2013-01-03  0.952778  0.283178  0.984822  0.828147

In [25]: df['20130102':'20130104']
Out[25]: 
                   A         B         C         D
2013-01-02 -1.327825  0.487863 -0.837461 -0.993610
2013-01-03  0.952778  0.283178  0.984822  0.828147
2013-01-04 -0.342168  1.561692 -0.680844  0.561420

按标签选择

详见 按标签选择

用标签获取横截面数据:

In [26]: df.loc[dates[0]]
Out[26]: 
A   -1.427215
B    0.193383
C    0.431986
D   -0.048781
Name: 2013-01-01 00:00:00, dtype: float64

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

In [27]: df.loc[:, ['A', 'B']]
Out[27]: 
                   A         B
2013-01-01 -1.427215  0.193383
2013-01-02 -1.327825  0.487863
2013-01-03  0.952778  0.283178
2013-01-04 -0.342168  1.561692
2013-01-05 -0.460898 -1.907916
2013-01-06  0.362710 -0.406205

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

In [28]: df.loc['20130102':'20130104', ['A', 'B']]
Out[28]: 
                   A         B
2013-01-02 -1.327825  0.487863
2013-01-03  0.952778  0.283178
2013-01-04 -0.342168  1.561692

降低返回对象的维度:

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

获取一个标量值:

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

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

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

按位置选择

详见 按位置选择

按传入整数的位置选择:

In [32]: df.iloc[3]
Out[32]: 
A   -0.342168
B    1.561692
C   -0.680844
D    0.561420
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.342168  1.561692
2013-01-05 -0.460898 -1.907916

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

In [34]: df.iloc[[1, 2, 4], [0, 2]]
Out[34]: 
                   A         C
2013-01-02 -1.327825 -0.837461
2013-01-03  0.952778  0.984822
2013-01-05 -0.460898  0.861746

显性地按行切片:

In [35]: df.iloc[1:3, :]
Out[35]: 
                   A         B         C         D
2013-01-02 -1.327825  0.487863 -0.837461 -0.993610
2013-01-03  0.952778  0.283178  0.984822  0.828147

显性地按列切片:

In [36]: df.iloc[:, 1:3]
Out[36]: 
                   B         C
2013-01-01  0.193383  0.431986
2013-01-02  0.487863 -0.837461
2013-01-03  0.283178  0.984822
2013-01-04  1.561692 -0.680844
2013-01-05 -1.907916  0.861746
2013-01-06 -0.406205 -0.364006

显性地获得一个值:

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

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

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

布尔值索引

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

In [39]: df[df.A > 0]
Out[39]: 
                   A         B         C         D
2013-01-03  0.952778  0.283178  0.984822  0.828147
2013-01-06  0.362710 -0.406205 -0.364006 -0.335185

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

In [40]: df[df > 0]
Out[40]: 
                   A         B         C         D
2013-01-01       NaN  0.193383  0.431986       NaN
2013-01-02       NaN  0.487863       NaN       NaN
2013-01-03  0.952778  0.283178  0.984822  0.828147
2013-01-04       NaN  1.561692       NaN  0.561420
2013-01-05       NaN       NaN  0.861746  0.520525
2013-01-06  0.362710       NaN       NaN       NaN

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 -1.427215  0.193383  0.431986 -0.048781    one
2013-01-02 -1.327825  0.487863 -0.837461 -0.993610    one
2013-01-03  0.952778  0.283178  0.984822  0.828147    two
2013-01-04 -0.342168  1.561692 -0.680844  0.561420  three
2013-01-05 -0.460898 -1.907916  0.861746  0.520525   four
2013-01-06  0.362710 -0.406205 -0.364006 -0.335185  three

In [44]: df2[df2['E'].isin(['two', 'four'])]
Out[44]: 
                   A         B         C         D     E
2013-01-03  0.952778  0.283178  0.984822  0.828147   two
2013-01-05 -0.460898 -1.907916  0.861746  0.520525  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.431986  5  NaN
2013-01-02 -1.327825  0.487863 -0.837461  5  1.0
2013-01-03  0.952778  0.283178  0.984822  5  2.0
2013-01-04 -0.342168  1.561692 -0.680844  5  3.0
2013-01-05 -0.460898 -1.907916  0.861746  5  4.0
2013-01-06  0.362710 -0.406205 -0.364006  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.431986 -5  NaN
2013-01-02 -1.327825 -0.487863 -0.837461 -5 -1.0
2013-01-03 -0.952778 -0.283178 -0.984822 -5 -2.0
2013-01-04 -0.342168 -1.561692 -0.680844 -5 -3.0
2013-01-05 -0.460898 -1.907916 -0.861746 -5 -4.0
2013-01-06 -0.362710 -0.406205 -0.364006 -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.431986  5  NaN  1.0
2013-01-02 -1.327825  0.487863 -0.837461  5  1.0  1.0
2013-01-03  0.952778  0.283178  0.984822  5  2.0  NaN
2013-01-04 -0.342168  1.561692 -0.680844  5  3.0  NaN

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

In [58]: df1.dropna(how='any')
Out[58]: 
                   A         B         C  D    F    E
2013-01-02 -1.327825  0.487863 -0.837461  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.431986  5  5.0  1.0
2013-01-02 -1.327825  0.487863 -0.837461  5  1.0  1.0
2013-01-03  0.952778  0.283178  0.984822  5  2.0  5.0
2013-01-04 -0.342168  1.561692 -0.680844  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

运算符

详见 基本二元运算符