2. Pandas 基础用法

本节介绍 Pandas 数据结构的基础用法。下列代码创建上一节用过的示例数据对象:

  1. In [1]: index = pd.date_range('1/1/2000', periods=8)
  2. In [2]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
  3. In [3]: df = pd.DataFrame(np.random.randn(8, 3), index=index,
  4. ...: columns=['A', 'B', 'C'])
  5. ...:

2.1. Head 与 Tail

head()tail() 用于快速预览 Series 与 DataFrame,默认显示 5 条数据,也可以指定显示数据的数量。

  1. In [4]: long_series = pd.Series(np.random.randn(1000))
  2. In [5]: long_series.head()
  3. Out[5]:
  4. 0 -1.157892
  5. 1 -1.344312
  6. 2 0.844885
  7. 3 1.075770
  8. 4 -0.109050
  9. dtype: float64
  10. In [6]: long_series.tail(3)
  11. Out[6]:
  12. 997 -0.289388
  13. 998 -1.020544
  14. 999 0.589993
  15. dtype: float64

2.2. 属性与底层数据

Pandas 可以通过多个属性访问元数据:

  • shape:
    • 输出对象的轴维度,与 ndarray 一致
  • 轴标签
    • Series: Index (仅有此轴)
    • DataFrame: Index (行) 与

注意: 为属性赋值是安全的

  1. In [7]: df[:2]
  2. Out[7]:
  3. A B C
  4. 2000-01-01 -0.173215 0.119209 -1.044236
  5. 2000-01-02 -0.861849 -2.104569 -0.494929
  6. In [8]: df.columns = [x.lower() for x in df.columns]
  7. In [9]: df
  8. Out[9]:
  9. a b c
  10. 2000-01-01 -0.173215 0.119209 -1.044236
  11. 2000-01-02 -0.861849 -2.104569 -0.494929
  12. 2000-01-03 1.071804 0.721555 -0.706771
  13. 2000-01-04 -1.039575 0.271860 -0.424972
  14. 2000-01-05 0.567020 0.276232 -1.087401
  15. 2000-01-06 -0.673690 0.113648 -1.478427
  16. 2000-01-07 0.524988 0.404705 0.577046
  17. 2000-01-08 -1.715002 -1.039268 -0.370647

Pandas 对象(IndexSeriesDataFrame)相当于数组的容器,用于存储数据、执行计算。大部分类型的底层数组都是 numpy.ndarray。不过,Pandas 与第三方支持库一般都会扩展 NumPy 类型系统,添加自定义数组(见数据类型)。

.array 属性用于提取 IndexSeries 里的数据。

  1. In [10]: s.array
  2. Out[10]:
  3. <PandasArray>
  4. [ 0.4691122999071863, -0.2828633443286633, -1.5090585031735124,
  5. -1.1356323710171934, 1.2121120250208506]
  6. Length: 5, dtype: float64
  7. In [11]: s.index.array
  8. Out[11]:
  9. <PandasArray>
  10. ['a', 'b', 'c', 'd', 'e']
  11. Length: 5, dtype: object

array 一般指 ExtensionArray。至于什么是 ExtensionArray 及 Pandas 为什么要用 ExtensionArray 不是本节要说明的内容。更多信息请参阅数据类型

提取 NumPy 数组,用 to_numpy()numpy.asarray()

  1. In [12]: s.to_numpy()
  2. Out[12]: array([ 0.4691, -0.2829, -1.5091, -1.1356, 1.2121])
  3. In [13]: np.asarray(s)
  4. Out[13]: array([ 0.4691, -0.2829, -1.5091, -1.1356, 1.2121])

SeriesIndex 的类型是 ExtensionArray 时, to_numpy() 会复制数据,并强制转换值。详情见数据类型

to_numpy() 可以控制 numpy.ndarray 生成的数据类型。以带时区的 datetime 为例,NumPy 未提供时区信息的 datetime 数据类型,Pandas 则提供了两种表现形式:

  1. 一种是带 Timestampnumpy.ndarray,提供了正确的 tz 信息。
  2. 另一种是 datetime64[ns],这也是一种 numpy.ndarray,值被转换为 UTC,但去掉了时区信息。

时区信息可以用 dtype=object 保存。

  1. In [14]: ser = pd.Series(pd.date_range('2000', periods=2, tz="CET"))
  2. In [15]: ser.to_numpy(dtype=object)
  3. Out[15]:
  4. array([Timestamp('2000-01-01 00:00:00+0100', tz='CET', freq='D'),
  5. Timestamp('2000-01-02 00:00:00+0100', tz='CET', freq='D')],
  6. dtype=object)

或用 dtype='datetime64[ns]' 去除。

  1. In [16]: ser.to_numpy(dtype="datetime64[ns]")
  2. Out[16]:
  3. array(['1999-12-31T23:00:00.000000000', '2000-01-01T23:00:00.000000000'],
  4. dtype='datetime64[ns]')

提取 DataFrame 里的原数据稍微有点复杂。DataFrame 里所有列的数据类型都一样时,DataFrame.to_numpy() 返回底层数据:

  1. In [17]: df.to_numpy()
  2. Out[17]:
  3. array([[-0.1732, 0.1192, -1.0442],
  4. [-0.8618, -2.1046, -0.4949],
  5. [ 1.0718, 0.7216, -0.7068],
  6. [-1.0396, 0.2719, -0.425 ],
  7. [ 0.567 , 0.2762, -1.0874],
  8. [-0.6737, 0.1136, -1.4784],
  9. [ 0.525 , 0.4047, 0.577 ],
  10. [-1.715 , -1.0393, -0.3706]])

DataFrame 为同构型数据时,Pandas 直接修改原始 ndarray,所做修改会直接反应在数据结构里。对于异质型数据,即 DataFrame 列的数据类型不一样时,就不是这种操作模式了。与轴标签不同,不能为值的属性赋值。

::: tip 注意

处理异质型数据时,输出结果 ndarray 的数据类型适用于涉及的各类数据。若 DataFrame 里包含字符串,输出结果的数据类型就是 object。要是只有浮点数或整数,则输出结果的数据类型是浮点数。

:::

以前,Pandas 推荐用 Series.valuesDataFrame.values 从 Series 或 DataFrame 里提取数据。旧有代码库或在线教程里仍在用这种操作,但 Pandas 已改进了此功能,现在,推荐用 .arrayto_numpy 提取数据,别再用 .values 了。.values 有以下几个缺点:

  1. Series 含扩展类型时,Series.values 无法判断到底是该返回 NumPy array,还是返回 ExtensionArray。而 Series.array 则只返回 ExtensionArray,且不会复制数据。Series.to_numpy() 则返回 NumPy 数组,其代价是需要复制、并强制转换数据的值。
  2. DataFrame 含多种数据类型时,DataFrame.values 会复制数据,并将数据的值强制转换同一种数据类型,这是一种代价较高的操作。DataFrame.to_numpy() 则返回 NumPy 数组,这种方式更清晰,也不会把 DataFrame 里的数据都当作一种类型。

2.3. 加速操作

借助 numexprbottleneck 支持库,Pandas 可以加速特定类型的二进制数值与布尔操作。

处理大型数据集时,这两个支持库特别有用,加速效果也非常明显。 numexpr 使用智能分块、缓存与多核技术。bottleneck 是一组专属 cython 例程,处理含 nans 值的数组时,特别快。

请看下面这个例子(DataFrame 包含 100 列 X 10 万行数据):

操作0.11.0版 (ms)旧版 (ms)提升比率
df1 > df213.32125.350.1063
df1 * df221.7136.630.5928
df1 + df222.0436.500.6039

强烈建议安装这两个支持库,更多信息,请参阅推荐支持库

这两个支持库默认为启用状态,可用以下选项设置:

0.20.0 版新增。

  1. pd.set_option('compute.use_bottleneck', False)
  2. pd.set_option('compute.use_numexpr', False)

2.4. 二进制操作

Pandas 数据结构之间执行二进制操作,要注意下列两个关键点:

  • 多维(DataFrame)与低维(Series)对象之间的广播机制;
  • 计算中的缺失值处理。

这两个问题可以同时处理,但下面先介绍怎么分开处理。

匹配/广播机制

DataFrame 支持 add()sub()mul()div()radd()rsub() 等方法执行二进制操作。广播机制重点关注输入的 Series。通过 axis 关键字,匹配 indexcolumns 即可调用这些函数。

  1. In [18]: df = pd.DataFrame({
  2. ....: 'one': pd.Series(np.random.randn(3), index=['a', 'b', 'c']),
  3. ....: 'two': pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd']),
  4. ....: 'three': pd.Series(np.random.randn(3), index=['b', 'c', 'd'])})
  5. ....:
  6. In [19]: df
  7. Out[19]:
  8. one two three
  9. a 1.394981 1.772517 NaN
  10. b 0.343054 1.912123 -0.050390
  11. c 0.695246 1.478369 1.227435
  12. d NaN 0.279344 -0.613172
  13. In [20]: row = df.iloc[1]
  14. In [21]: column = df['two']
  15. In [22]: df.sub(row, axis='columns')
  16. Out[22]:
  17. one two three
  18. a 1.051928 -0.139606 NaN
  19. b 0.000000 0.000000 0.000000
  20. c 0.352192 -0.433754 1.277825
  21. d NaN -1.632779 -0.562782
  22. In [23]: df.sub(row, axis=1)
  23. Out[23]:
  24. one two three
  25. a 1.051928 -0.139606 NaN
  26. b 0.000000 0.000000 0.000000
  27. c 0.352192 -0.433754 1.277825
  28. d NaN -1.632779 -0.562782
  29. In [24]: df.sub(column, axis='index')
  30. Out[24]:
  31. one two three
  32. a -0.377535 0.0 NaN
  33. b -1.569069 0.0 -1.962513
  34. c -0.783123 0.0 -0.250933
  35. d NaN 0.0 -0.892516
  36. In [25]: df.sub(column, axis=0)
  37. Out[25]:
  38. one two three
  39. a -0.377535 0.0 NaN
  40. b -1.569069 0.0 -1.962513
  41. c -0.783123 0.0 -0.250933
  42. d NaN 0.0 -0.892516

还可以用 Series 对齐多层索引 DataFrame 的某一层级。

  1. In [26]: dfmi = df.copy()
  2. In [27]: dfmi.index = pd.MultiIndex.from_tuples([(1, 'a'), (1, 'b'),
  3. ....: (1, 'c'), (2, 'a')],
  4. ....: names=['first', 'second'])
  5. ....:
  6. In [28]: dfmi.sub(column, axis=0, level='second')
  7. Out[28]:
  8. one two three
  9. first second
  10. 1 a -0.377535 0.000000 NaN
  11. b -1.569069 0.000000 -1.962513
  12. c -0.783123 0.000000 -0.250933
  13. 2 a NaN -1.493173 -2.385688

Series 与 Index 还支持 divmod() 内置函数,该函数同时执行向下取整除与模运算,返回两个与左侧类型相同的元组。示例如下:

  1. In [29]: s = pd.Series(np.arange(10))
  2. In [30]: s
  3. Out[30]:
  4. 0 0
  5. 1 1
  6. 2 2
  7. 3 3
  8. 4 4
  9. 5 5
  10. 6 6
  11. 7 7
  12. 8 8
  13. 9 9
  14. dtype: int64
  15. In [31]: div, rem = divmod(s, 3)
  16. In [32]: div
  17. Out[32]:
  18. 0 0
  19. 1 0
  20. 2 0
  21. 3 1
  22. 4 1
  23. 5 1
  24. 6 2
  25. 7 2
  26. 8 2
  27. 9 3
  28. dtype: int64
  29. In [33]: rem
  30. Out[33]:
  31. 0 0
  32. 1 1
  33. 2 2
  34. 3 0
  35. 4 1
  36. 5 2
  37. 6 0
  38. 7 1
  39. 8 2
  40. 9 0
  41. dtype: int64
  42. In [34]: idx = pd.Index(np.arange(10))
  43. In [35]: idx
  44. Out[35]: Int64Index([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='int64')
  45. In [36]: div, rem = divmod(idx, 3)
  46. In [37]: div
  47. Out[37]: Int64Index([0, 0, 0, 1, 1, 1, 2, 2, 2, 3], dtype='int64')
  48. In [38]: rem
  49. Out[38]: Int64Index([0, 1, 2, 0, 1, 2, 0, 1, 2, 0], dtype='int64')

divmod() 还支持元素级运算:

  1. In [39]: div, rem = divmod(s, [2, 2, 3, 3, 4, 4, 5, 5, 6, 6])
  2. In [40]: div
  3. Out[40]:
  4. 0 0
  5. 1 0
  6. 2 0
  7. 3 1
  8. 4 1
  9. 5 1
  10. 6 1
  11. 7 1
  12. 8 1
  13. 9 1
  14. dtype: int64
  15. In [41]: rem
  16. Out[41]:
  17. 0 0
  18. 1 1
  19. 2 2
  20. 3 0
  21. 4 0
  22. 5 1
  23. 6 1
  24. 7 2
  25. 8 2
  26. 9 3
  27. dtype: int64

缺失值与填充缺失值操作

Series 与 DataFrame 的算数函数支持 fill_value 选项,即用指定值替换某个位置的缺失值。比如,两个 DataFrame 相加,除非两个 DataFrame 里同一个位置都有缺失值,其相加的和仍为 NaN,如果只有一个 DataFrame 里存在缺失值,则可以用 fill_value 指定一个值来替代 NaN,当然,也可以用 fillnaNaN 替换为想要的值。

::: tip 注意

下面第 43 条代码里,Pandas 官档没有写 df2 是哪里来的,这里补上,与 df 类似。 ``` df2 = pd.DataFrame({ ….: ‘one’: pd.Series(np.random.randn(3), index=[‘a’, ‘b’, ‘c’]), ….: ‘two’: pd.Series(np.random.randn(4), index=[‘a’, ‘b’, ‘c’, ‘d’]), ….: ‘three’: pd.Series(np.random.randn(3), index=[‘a’, ‘b’, ‘c’, ‘d’])}) ….:

  1. :::

In [42]: df Out[42]: one two three a 1.394981 1.772517 NaN b 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435 d NaN 0.279344 -0.613172

In [43]: df2 Out[43]: one two three a 1.394981 1.772517 1.000000 b 0.343054 1.912123 -0.050390 c 0.695246 1.478369 1.227435 d NaN 0.279344 -0.613172

In [44]: df + df2 Out[44]: one two three a 2.789963 3.545034 NaN b 0.686107 3.824246 -0.100780 c 1.390491 2.956737 2.454870 d NaN 0.558688 -1.226343

In [45]: df.add(df2, fill_value=0) Out[45]: one two three a 2.789963 3.545034 1.000000 b 0.686107 3.824246 -0.100780 c 1.390491 2.956737 2.454870 d NaN 0.558688 -1.226343

  1. ### 比较操作
  2. 与上一小节的算数运算类似,Series DataFrame 还支持 `eq``ne``lt``gt``le``ge` 等二进制比较操作的方法:
  3. <table><thead><tr><th>序号</th><th>缩写</th><th>英文</th><th>中文</th></tr></thead><tbody><tr><td>1</td><td>eq</td><td>equal to</td><td>等于</td></tr><tr><td>2</td><td>ne</td><td>not equal to</td><td>不等于</td></tr><tr><td>3</td><td>lt</td><td>less than</td><td>小于</td></tr><tr><td>4</td><td>gt</td><td>greater than</td><td>大于</td></tr><tr><td>5</td><td>le</td><td>less than or equal to</td><td>小于等于</td></tr><tr><td>6</td><td>ge</td><td>greater than or equal to</td><td>大于等于</td></tr></tbody></table>

In [46]: df.gt(df2) Out[46]: one two three a False False False b False False False c False False False d False False False

In [47]: df2.ne(df) Out[47]: one two three a False False True b False False False c False False False d True False False

  1. 这些操作生成一个与左侧输入对象类型相同的 Pandas 对象,即,dtype `bool``boolean` 对象可用于索引操作,参阅[布尔索引](https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#indexing-boolean)。
  2. ### 布尔简化
  3. [`empty`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.empty.html#pandas.DataFrame.empty)、[`any()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.any.html#pandas.DataFrame.any)、[`all()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.all.html#pandas.DataFrame.all)、[`bool()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.bool.html#pandas.DataFrame.bool) 可以把数据汇总简化至单个布尔值。

In [48]: (df > 0).all() Out[48]: one False two True three False dtype: bool

In [49]: (df > 0).any() Out[49]: one True two True three True dtype: bool

  1. 还可以进一步把上面的结果简化为单个布尔值。

In [50]: (df > 0).any().any() Out[50]: True

  1. 通过 [`empty`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.empty.html#pandas.DataFrame.empty) 属性,可以验证 Pandas 对象是否为**空**。

In [51]: df.empty Out[51]: False

In [52]: pd.DataFrame(columns=list(‘ABC’)).empty Out[52]: True

  1. [`bool()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.bool.html#pandas.DataFrame.bool) 方法验证单元素 pandas 对象的布尔值。

In [53]: pd.Series([True]).bool() Out[53]: True

In [54]: pd.Series([False]).bool() Out[54]: False

In [55]: pd.DataFrame([[True]]).bool() Out[55]: True

In [56]: pd.DataFrame([[False]]).bool() Out[56]: False

  1. ::: danger 警告
  2. 以下代码:

if df: … pass ```

  1. >>> df and df2

上述代码试图比对多个值,因此,这两种操作都会触发错误:

  1. ValueError: The truth value of an array is ambiguous. Use a.empty, a.any() or a.all().

:::

了解详情,请参阅各种坑小节的内容。

比较对象是否等效

一般情况下,多种方式都能得出相同的结果。以 df + dfdf * 2 为例。应用上一小节学到的知识,测试这两种计算方式的结果是否一致,一般人都会用 (df + df == df * 2).all(),不过,这个表达式的结果是 False

  1. In [57]: df + df == df * 2
  2. Out[57]:
  3. one two three
  4. a True True False
  5. b True True True
  6. c True True True
  7. d False True True
  8. In [58]: (df + df == df * 2).all()
  9. Out[58]:
  10. one False
  11. two True
  12. three False
  13. dtype: bool

注意:布尔型 DataFrame df + df == df * 2 中有 False 值!这是因为两个 NaN 值的比较结果为不等

  1. In [59]: np.nan == np.nan
  2. Out[59]: False

为了验证数据是否等效,Series 与 DataFrame 等 N 维框架提供了 equals() 方法,用这个方法验证 NaN 值的结果为相等

  1. In [60]: (df + df).equals(df * 2)
  2. Out[60]: True

注意:Series 与 DataFrame 索引的顺序必须一致,验证结果才能为 True

  1. In [61]: df1 = pd.DataFrame({'col': ['foo', 0, np.nan]})
  2. In [62]: df2 = pd.DataFrame({'col': [np.nan, 0, 'foo']}, index=[2, 1, 0])
  3. In [63]: df1.equals(df2)
  4. Out[63]: False
  5. In [64]: df1.equals(df2.sort_index())
  6. Out[64]: True

比较 array 型对象

用标量值与 Pandas 数据结构对比数据元素非常简单:

  1. In [65]: pd.Series(['foo', 'bar', 'baz']) == 'foo'
  2. Out[65]:
  3. 0 True
  4. 1 False
  5. 2 False
  6. dtype: bool
  7. In [66]: pd.Index(['foo', 'bar', 'baz']) == 'foo'
  8. Out[66]: array([ True, False, False])

Pandas 还能对比两个等长 array 对象里的数据元素:

  1. In [67]: pd.Series(['foo', 'bar', 'baz']) == pd.Index(['foo', 'bar', 'qux'])
  2. Out[67]:
  3. 0 True
  4. 1 True
  5. 2 False
  6. dtype: bool
  7. In [68]: pd.Series(['foo', 'bar', 'baz']) == np.array(['foo', 'bar', 'qux'])
  8. Out[68]:
  9. 0 True
  10. 1 True
  11. 2 False
  12. dtype: bool

对比不等长的 IndexSeries 对象会触发 ValueError

  1. In [55]: pd.Series(['foo', 'bar', 'baz']) == pd.Series(['foo', 'bar'])
  2. ValueError: Series lengths must match to compare
  3. In [56]: pd.Series(['foo', 'bar', 'baz']) == pd.Series(['foo'])
  4. ValueError: Series lengths must match to compare

注意: 这里的操作与 NumPy 的广播机制不同:

  1. In [69]: np.array([1, 2, 3]) == np.array([2])
  2. Out[69]: array([False, True, False])

NumPy 无法执行广播操作时,返回 False:

  1. In [70]: np.array([1, 2, 3]) == np.array([1, 2])
  2. Out[70]: False

合并重叠数据集

有时,要合并两个相似的数据集,两个数据集里的其中一个的数据比另一个多。比如,展示特定经济指标的两个数据序列,其中一个是“高质量”指标,另一个是“低质量”指标。一般来说,低质量序列可能包含更多的历史数据,或覆盖更广的数据。因此,要合并这两个 DataFrame 对象,其中一个 DataFrame 中的缺失值将按指定条件用另一个 DataFrame 里类似标签中的数据进行填充。要实现这一操作,请用下列代码中的 combine_first() 函数。

  1. In [71]: df1 = pd.DataFrame({'A': [1., np.nan, 3., 5., np.nan],
  2. ....: 'B': [np.nan, 2., 3., np.nan, 6.]})
  3. ....:
  4. In [72]: df2 = pd.DataFrame({'A': [5., 2., 4., np.nan, 3., 7.],
  5. ....: 'B': [np.nan, np.nan, 3., 4., 6., 8.]})
  6. ....:
  7. In [73]: df1
  8. Out[73]:
  9. A B
  10. 0 1.0 NaN
  11. 1 NaN 2.0
  12. 2 3.0 3.0
  13. 3 5.0 NaN
  14. 4 NaN 6.0
  15. In [74]: df2
  16. Out[74]:
  17. A B
  18. 0 5.0 NaN
  19. 1 2.0 NaN
  20. 2 4.0 3.0
  21. 3 NaN 4.0
  22. 4 3.0 6.0
  23. 5 7.0 8.0
  24. In [75]: df1.combine_first(df2)
  25. Out[75]:
  26. A B
  27. 0 1.0 NaN
  28. 1 2.0 2.0
  29. 2 3.0 3.0
  30. 3 5.0 4.0
  31. 4 3.0 6.0
  32. 5 7.0 8.0

DataFrame 通用合并方法

上述 combine_first() 方法调用了更普适的 DataFrame.combine() 方法。该方法提取另一个 DataFrame 及合并器函数,并将之与输入的 DataFrame 对齐,再传递与 Series 配对的合并器函数(比如,名称相同的列)。

下面的代码复现了上述的 combine_first() 函数:

  1. In [76]: def combiner(x, y):
  2. ....: return np.where(pd.isna(x), y, x)
  3. ....:

2.5. 描述性统计

SeriesDataFrame 支持大量计算描述性统计的方法与操作。这些方法大部分都是 sum()mean()quantile() 等聚合函数,其输出结果比原始数据集小;此外,还有输出结果与原始数据集同样大小的 cumsum()cumprod() 等函数。这些方法都基本上都接受 axis 参数,如, ndarray.{sum,std,…},但这里的 axis 可以用名称或整数指定:

  • Series:无需 axis 参数
  • DataFrame
    • index,即 axis=0,默认值
    • columns, 即 axis=1

示例如下:

  1. In [77]: df
  2. Out[77]:
  3. one two three
  4. a 1.394981 1.772517 NaN
  5. b 0.343054 1.912123 -0.050390
  6. c 0.695246 1.478369 1.227435
  7. d NaN 0.279344 -0.613172
  8. In [78]: df.mean(0)
  9. Out[78]:
  10. one 0.811094
  11. two 1.360588
  12. three 0.187958
  13. dtype: float64
  14. In [79]: df.mean(1)
  15. Out[79]:
  16. a 1.583749
  17. b 0.734929
  18. c 1.133683
  19. d -0.166914
  20. dtype: float64

上述方法都支持 skipna 关键字,指定是否要排除缺失数据,默认值为 True

  1. In [80]: df.sum(0, skipna=False)
  2. Out[80]:
  3. one NaN
  4. two 5.442353
  5. three NaN
  6. dtype: float64
  7. In [81]: df.sum(axis=1, skipna=True)
  8. Out[81]:
  9. a 3.167498
  10. b 2.204786
  11. c 3.401050
  12. d -0.333828
  13. dtype: float64

结合广播机制或算数操作,可以描述不同统计过程,比如标准化,即渲染数据零均值与标准差 1,这种操作非常简单:

  1. In [82]: ts_stand = (df - df.mean()) / df.std()
  2. In [83]: ts_stand.std()
  3. Out[83]:
  4. one 1.0
  5. two 1.0
  6. three 1.0
  7. dtype: float64
  8. In [84]: xs_stand = df.sub(df.mean(1), axis=0).div(df.std(1), axis=0)
  9. In [85]: xs_stand.std(1)
  10. Out[85]:
  11. a 1.0
  12. b 1.0
  13. c 1.0
  14. d 1.0
  15. dtype: float64

注 : cumsum()cumprod() 等方法保留 NaN 值的位置。这与 expanding()rolling() 略显不同,详情请参阅本文

  1. In [86]: df.cumsum()
  2. Out[86]:
  3. one two three
  4. a 1.394981 1.772517 NaN
  5. b 1.738035 3.684640 -0.050390
  6. c 2.433281 5.163008 1.177045
  7. d NaN 5.442353 0.563873

下表为常用函数汇总表。每个函数都支持 level 参数,仅在数据对象为结构化 Index 时使用。

函数描述
count统计非空值数量
sum汇总值
mean平均值
mad平均绝对偏差
median算数中位数
min最小值
max最大值
mode众数
abs绝对值
prod乘积
std贝塞尔校正的样本标准偏差
var无偏方差
sem平均值的标准误差
skew样本偏度 (第三阶)
kurt样本峰度 (第四阶)
quantile样本分位数 (不同 % 的值)
cumsum累加
cumprod累乘
cummax累积最大值
cummin累积最小值

注意:NumPy 的 meanstdsum 等方法默认不统计 Series 里的空值。

  1. In [87]: np.mean(df['one'])
  2. Out[87]: 0.8110935116651192
  3. In [88]: np.mean(df['one'].to_numpy())
  4. Out[88]: nan

Series.nunique() 返回 Series 里所有非空值的唯一值。

  1. In [89]: series = pd.Series(np.random.randn(500))
  2. In [90]: series[20:500] = np.nan
  3. In [91]: series[10:20] = 5
  4. In [92]: series.nunique()
  5. Out[92]: 11

数据总结:describe

describe() 函数计算 Series 与 DataFrame 数据列的各种数据统计量,注意,这里排除了空值

  1. In [93]: series = pd.Series(np.random.randn(1000))
  2. In [94]: series[::2] = np.nan
  3. In [95]: series.describe()
  4. Out[95]:
  5. count 500.000000
  6. mean -0.021292
  7. std 1.015906
  8. min -2.683763
  9. 25% -0.699070
  10. 50% -0.069718
  11. 75% 0.714483
  12. max 3.160915
  13. dtype: float64
  14. In [96]: frame = pd.DataFrame(np.random.randn(1000, 5),
  15. ....: columns=['a', 'b', 'c', 'd', 'e'])
  16. ....:
  17. In [97]: frame.iloc[::2] = np.nan
  18. In [98]: frame.describe()
  19. Out[98]:
  20. a b c d e
  21. count 500.000000 500.000000 500.000000 500.000000 500.000000
  22. mean 0.033387 0.030045 -0.043719 -0.051686 0.005979
  23. std 1.017152 0.978743 1.025270 1.015988 1.006695
  24. min -3.000951 -2.637901 -3.303099 -3.159200 -3.188821
  25. 25% -0.647623 -0.576449 -0.712369 -0.691338 -0.691115
  26. 50% 0.047578 -0.021499 -0.023888 -0.032652 -0.025363
  27. 75% 0.729907 0.775880 0.618896 0.670047 0.649748
  28. max 2.740139 2.752332 3.004229 2.728702 3.240991

此外,还可以指定输出结果包含的分位数:

  1. In [99]: series.describe(percentiles=[.05, .25, .75, .95])
  2. Out[99]:
  3. count 500.000000
  4. mean -0.021292
  5. std 1.015906
  6. min -2.683763
  7. 5% -1.645423
  8. 25% -0.699070
  9. 50% -0.069718
  10. 75% 0.714483
  11. 95% 1.711409
  12. max 3.160915
  13. dtype: float64

一般情况下,默认值包含中位数

对于非数值型 Series 对象, describe() 返回值的总数、唯一值数量、出现次数最多的值及出现的次数。

  1. In [100]: s = pd.Series(['a', 'a', 'b', 'b', 'a', 'a', np.nan, 'c', 'd', 'a'])
  2. In [101]: s.describe()
  3. Out[101]:
  4. count 9
  5. unique 4
  6. top a
  7. freq 5
  8. dtype: object

注意:对于混合型的 DataFrame 对象, describe() 只返回数值列的汇总统计量,如果没有数值列,则只显示类别型的列。

  1. In [102]: frame = pd.DataFrame({'a': ['Yes', 'Yes', 'No', 'No'], 'b': range(4)})
  2. In [103]: frame.describe()
  3. Out[103]:
  4. b
  5. count 4.000000
  6. mean 1.500000
  7. std 1.290994
  8. min 0.000000
  9. 25% 0.750000
  10. 50% 1.500000
  11. 75% 2.250000
  12. max 3.000000

include/exclude 参数的值为列表,用该参数可以控制包含或排除的数据类型。这里还有一个特殊值,all

  1. In [104]: frame.describe(include=['object'])
  2. Out[104]:
  3. a
  4. count 4
  5. unique 2
  6. top Yes
  7. freq 2
  8. In [105]: frame.describe(include=['number'])
  9. Out[105]:
  10. b
  11. count 4.000000
  12. mean 1.500000
  13. std 1.290994
  14. min 0.000000
  15. 25% 0.750000
  16. 50% 1.500000
  17. 75% 2.250000
  18. max 3.000000
  19. In [106]: frame.describe(include='all')
  20. Out[106]:
  21. a b
  22. count 4 4.000000
  23. unique 2 NaN
  24. top Yes NaN
  25. freq 2 NaN
  26. mean NaN 1.500000
  27. std NaN 1.290994
  28. min NaN 0.000000
  29. 25% NaN 0.750000
  30. 50% NaN 1.500000
  31. 75% NaN 2.250000
  32. max NaN 3.000000

本功能依托于 select_dtypes,要了解该参数接受哪些输入内容请参阅本文

最大值与最小值对应的索引

Series 与 DataFrame 的 idxmax()idxmin() 函数计算最大值与最小值对应的索引。

  1. In [107]: s1 = pd.Series(np.random.randn(5))
  2. In [108]: s1
  3. Out[108]:
  4. 0 1.118076
  5. 1 -0.352051
  6. 2 -1.242883
  7. 3 -1.277155
  8. 4 -0.641184
  9. dtype: float64
  10. In [109]: s1.idxmin(), s1.idxmax()
  11. Out[109]: (3, 0)
  12. In [110]: df1 = pd.DataFrame(np.random.randn(5, 3), columns=['A', 'B', 'C'])
  13. In [111]: df1
  14. Out[111]:
  15. A B C
  16. 0 -0.327863 -0.946180 -0.137570
  17. 1 -0.186235 -0.257213 -0.486567
  18. 2 -0.507027 -0.871259 -0.111110
  19. 3 2.000339 -2.430505 0.089759
  20. 4 -0.321434 -0.033695 0.096271
  21. In [112]: df1.idxmin(axis=0)
  22. Out[112]:
  23. A 2
  24. B 3
  25. C 1
  26. dtype: int64
  27. In [113]: df1.idxmax(axis=1)
  28. Out[113]:
  29. 0 C
  30. 1 A
  31. 2 C
  32. 3 A
  33. 4 C
  34. dtype: object

多行或多列中存在多个最大值或最小值时,idxmax()idxmin() 只返回匹配到的第一个值的 Index

  1. In [114]: df3 = pd.DataFrame([2, 1, 1, 3, np.nan], columns=['A'], index=list('edcba'))
  2. In [115]: df3
  3. Out[115]:
  4. A
  5. e 2.0
  6. d 1.0
  7. c 1.0
  8. b 3.0
  9. a NaN
  10. In [116]: df3['A'].idxmin()
  11. Out[116]: 'd'

::: tip 注意

idxminidxmax 对应 NumPy 里的 argminargmax

:::

值计数(直方图)与众数

Series 的 value_counts() 方法及顶级函数计算一维数组中数据值的直方图,还可以用作常规数组的函数:

  1. In [117]: data = np.random.randint(0, 7, size=50)
  2. In [118]: data
  3. Out[118]:
  4. array([6, 6, 2, 3, 5, 3, 2, 5, 4, 5, 4, 3, 4, 5, 0, 2, 0, 4, 2, 0, 3, 2,
  5. 2, 5, 6, 5, 3, 4, 6, 4, 3, 5, 6, 4, 3, 6, 2, 6, 6, 2, 3, 4, 2, 1,
  6. 6, 2, 6, 1, 5, 4])
  7. In [119]: s = pd.Series(data)
  8. In [120]: s.value_counts()
  9. Out[120]:
  10. 6 10
  11. 2 10
  12. 4 9
  13. 5 8
  14. 3 8
  15. 0 3
  16. 1 2
  17. dtype: int64
  18. In [121]: pd.value_counts(data)
  19. Out[121]:
  20. 6 10
  21. 2 10
  22. 4 9
  23. 5 8
  24. 3 8
  25. 0 3
  26. 1 2
  27. dtype: int64

与上述操作类似,还可以统计 Series 或 DataFrame 的众数,即出现频率最高的值:

  1. In [122]: s5 = pd.Series([1, 1, 3, 3, 3, 5, 5, 7, 7, 7])
  2. In [123]: s5.mode()
  3. Out[123]:
  4. 0 3
  5. 1 7
  6. dtype: int64
  7. In [124]: df5 = pd.DataFrame({"A": np.random.randint(0, 7, size=50),
  8. .....: "B": np.random.randint(-10, 15, size=50)})
  9. .....:
  10. In [125]: df5.mode()
  11. Out[125]:
  12. A B
  13. 0 1.0 -9
  14. 1 NaN 10
  15. 2 NaN 13

离散化与分位数

cut() 函数(以值为依据实现分箱)及 qcut() 函数(以样本分位数为依据实现分箱)用于连续值的离散化:

  1. In [126]: arr = np.random.randn(20)
  2. In [127]: factor = pd.cut(arr, 4)
  3. In [128]: factor
  4. Out[128]:
  5. [(-0.251, 0.464], (-0.968, -0.251], (0.464, 1.179], (-0.251, 0.464], (-0.968, -0.251], ..., (-0.251, 0.464], (-0.968, -0.251], (-0.968, -0.251], (-0.968, -0.251], (-0.968, -0.251]]
  6. Length: 20
  7. Categories (4, interval[float64]): [(-0.968, -0.251] < (-0.251, 0.464] < (0.464, 1.179] <
  8. (1.179, 1.893]]
  9. In [129]: factor = pd.cut(arr, [-5, -1, 0, 1, 5])
  10. In [130]: factor
  11. Out[130]:
  12. [(0, 1], (-1, 0], (0, 1], (0, 1], (-1, 0], ..., (-1, 0], (-1, 0], (-1, 0], (-1, 0], (-1, 0]]
  13. Length: 20
  14. Categories (4, interval[int64]): [(-5, -1] < (-1, 0] < (0, 1] < (1, 5]]

qcut() 计算样本分位数。比如,下列代码按等距分位数分割正态分布的数据:

  1. In [131]: arr = np.random.randn(30)
  2. In [132]: factor = pd.qcut(arr, [0, .25, .5, .75, 1])
  3. In [133]: factor
  4. Out[133]:
  5. [(0.569, 1.184], (-2.278, -0.301], (-2.278, -0.301], (0.569, 1.184], (0.569, 1.184], ..., (-0.301, 0.569], (1.184, 2.346], (1.184, 2.346], (-0.301, 0.569], (-2.278, -0.301]]
  6. Length: 30
  7. Categories (4, interval[float64]): [(-2.278, -0.301] < (-0.301, 0.569] < (0.569, 1.184] <
  8. (1.184, 2.346]]
  9. In [134]: pd.value_counts(factor)
  10. Out[134]:
  11. (1.184, 2.346] 8
  12. (-2.278, -0.301] 8
  13. (0.569, 1.184] 7
  14. (-0.301, 0.569] 7
  15. dtype: int64

定义分箱时,还可以传递无穷值:

  1. In [135]: arr = np.random.randn(20)
  2. In [136]: factor = pd.cut(arr, [-np.inf, 0, np.inf])
  3. In [137]: factor
  4. Out[137]:
  5. [(-inf, 0.0], (0.0, inf], (0.0, inf], (-inf, 0.0], (-inf, 0.0], ..., (-inf, 0.0], (-inf, 0.0], (-inf, 0.0], (0.0, inf], (0.0, inf]]
  6. Length: 20
  7. Categories (2, interval[float64]): [(-inf, 0.0] < (0.0, inf]]

2.6. 函数应用

不管是为 Pandas 对象应用自定义函数,还是应用第三方函数,都离不开以下三种方法。用哪种方法取决于操作的对象是 DataFrame,还是 Series ;是行、列,还是元素。

  1. 表级函数应用:pipe()
  2. 行列级函数应用: apply()
  3. 聚合 API: agg()transform()
  4. 元素级函数应用:applymap()

表级函数应用

虽然可以把 DataFrame 与 Series 传递给函数,不过链式调用函数时,最好使用 pipe() 方法。对比以下两种方式:

  1. # f、g、h 是提取、返回 `DataFrames` 的函数
  2. >>> f(g(h(df), arg1=1), arg2=2, arg3=3)

下列代码与上述代码等效:

  1. >>> (df.pipe(h)
  2. ... .pipe(g, arg1=1)
  3. ... .pipe(f, arg2=2, arg3=3))

Pandas 鼓励使用第二种方式,即链式方法。在链式方法中调用自定义函数或第三方支持库函数时,用 pipe 更容易,与用 Pandas 自身方法一样。

上例中,fgh 这几个函数都把 DataFrame 当作首位参数。要是想把数据作为第二个参数,该怎么办?本例中,pipe 为元组 (callable,data_keyword)形式。.pipeDataFrame 作为元组里指定的参数。

下例用 statsmodels 拟合回归。该 API 先接收一个公式,DataFrame 是第二个参数,data。要传递函数,则要用pipe 接收关键词对 (sm.ols,'data')。

  1. In [138]: import statsmodels.formula.api as sm
  2. In [139]: bb = pd.read_csv('data/baseball.csv', index_col='id')
  3. In [140]: (bb.query('h > 0')
  4. .....: .assign(ln_h=lambda df: np.log(df.h))
  5. .....: .pipe((sm.ols, 'data'), 'hr ~ ln_h + year + g + C(lg)')
  6. .....: .fit()
  7. .....: .summary()
  8. .....: )
  9. .....:
  10. Out[140]:
  11. <class 'statsmodels.iolib.summary.Summary'>
  12. """
  13. OLS Regression Results
  14. ==============================================================================
  15. Dep. Variable: hr R-squared: 0.685
  16. Model: OLS Adj. R-squared: 0.665
  17. Method: Least Squares F-statistic: 34.28
  18. Date: Thu, 22 Aug 2019 Prob (F-statistic): 3.48e-15
  19. Time: 15:48:59 Log-Likelihood: -205.92
  20. No. Observations: 68 AIC: 421.8
  21. Df Residuals: 63 BIC: 432.9
  22. Df Model: 4
  23. Covariance Type: nonrobust
  24. ===============================================================================
  25. coef std err t P>|t| [0.025 0.975]
  26. -------------------------------------------------------------------------------
  27. Intercept -8484.7720 4664.146 -1.819 0.074 -1.78e+04 835.780
  28. C(lg)[T.NL] -2.2736 1.325 -1.716 0.091 -4.922 0.375
  29. ln_h -1.3542 0.875 -1.547 0.127 -3.103 0.395
  30. year 4.2277 2.324 1.819 0.074 -0.417 8.872
  31. g 0.1841 0.029 6.258 0.000 0.125 0.243
  32. ==============================================================================
  33. Omnibus: 10.875 Durbin-Watson: 1.999
  34. Prob(Omnibus): 0.004 Jarque-Bera (JB): 17.298
  35. Skew: 0.537 Prob(JB): 0.000175
  36. Kurtosis: 5.225 Cond. No. 1.49e+07
  37. ==============================================================================
  38. Warnings:
  39. [1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
  40. [2] The condition number is large, 1.49e+07. This might indicate that there are
  41. strong multicollinearity or other numerical problems.
  42. """

unix 的 pipe 与后来出现的 dplyrmagrittr 启发了pipe 方法,在此,引入了 R 语言里用于读取 pipe 的操作符 (%>%)。pipe 的实现思路非常清晰,仿佛 Python 源生的一样。强烈建议大家阅读 pipe() 的源代码。

行列级函数应用

apply() 方法沿着 DataFrame 的轴应用函数,比如,描述性统计方法,该方法支持 axis 参数。

  1. In [141]: df.apply(np.mean)
  2. Out[141]:
  3. one 0.811094
  4. two 1.360588
  5. three 0.187958
  6. dtype: float64
  7. In [142]: df.apply(np.mean, axis=1)
  8. Out[142]:
  9. a 1.583749
  10. b 0.734929
  11. c 1.133683
  12. d -0.166914
  13. dtype: float64
  14. In [143]: df.apply(lambda x: x.max() - x.min())
  15. Out[143]:
  16. one 1.051928
  17. two 1.632779
  18. three 1.840607
  19. dtype: float64
  20. In [144]: df.apply(np.cumsum)
  21. Out[144]:
  22. one two three
  23. a 1.394981 1.772517 NaN
  24. b 1.738035 3.684640 -0.050390
  25. c 2.433281 5.163008 1.177045
  26. d NaN 5.442353 0.563873
  27. In [145]: df.apply(np.exp)
  28. Out[145]:
  29. one two three
  30. a 4.034899 5.885648 NaN
  31. b 1.409244 6.767440 0.950858
  32. c 2.004201 4.385785 3.412466
  33. d NaN 1.322262 0.541630

apply() 方法还支持通过函数名字符串调用函数。

  1. In [146]: df.apply('mean')
  2. Out[146]:
  3. one 0.811094
  4. two 1.360588
  5. three 0.187958
  6. dtype: float64
  7. In [147]: df.apply('mean', axis=1)
  8. Out[147]:
  9. a 1.583749
  10. b 0.734929
  11. c 1.133683
  12. d -0.166914
  13. dtype: float64

默认情况下,apply() 调用的函数返回的类型会影响 DataFrame.apply 输出结果的类型。

  • 函数返回的是 Series 时,最终输出结果是 DataFrame。输出的列与函数返回的 Series 索引相匹配。
  • 函数返回其它任意类型时,输出结果是 Series

result_type 会覆盖默认行为,该参数有三个选项:reducebroadcastexpand。这些选项决定了列表型返回值是否扩展为 DataFrame

用好 apply() 可以了解数据集的很多信息。比如可以提取每列的最大值对应的日期:

  1. In [148]: tsdf = pd.DataFrame(np.random.randn(1000, 3), columns=['A', 'B', 'C'],
  2. .....: index=pd.date_range('1/1/2000', periods=1000))
  3. .....:
  4. In [149]: tsdf.apply(lambda x: x.idxmax())
  5. Out[149]:
  6. A 2000-08-06
  7. B 2001-01-18
  8. C 2001-07-18
  9. dtype: datetime64[ns]

还可以向 apply() 方法传递额外的参数与关键字参数。比如下例中要应用的这个函数:

  1. def subtract_and_divide(x, sub, divide=1):
  2. return (x - sub) / divide

可以用下列方式应用该函数:

  1. df.apply(subtract_and_divide, args=(5,), divide=3)

为每行或每列执行 Series 方法的功能也很实用:

  1. In [150]: tsdf
  2. Out[150]:
  3. A B C
  4. 2000-01-01 -0.158131 -0.232466 0.321604
  5. 2000-01-02 -1.810340 -3.105758 0.433834
  6. 2000-01-03 -1.209847 -1.156793 -0.136794
  7. 2000-01-04 NaN NaN NaN
  8. 2000-01-05 NaN NaN NaN
  9. 2000-01-06 NaN NaN NaN
  10. 2000-01-07 NaN NaN NaN
  11. 2000-01-08 -0.653602 0.178875 1.008298
  12. 2000-01-09 1.007996 0.462824 0.254472
  13. 2000-01-10 0.307473 0.600337 1.643950
  14. In [151]: tsdf.apply(pd.Series.interpolate)
  15. Out[151]:
  16. A B C
  17. 2000-01-01 -0.158131 -0.232466 0.321604
  18. 2000-01-02 -1.810340 -3.105758 0.433834
  19. 2000-01-03 -1.209847 -1.156793 -0.136794
  20. 2000-01-04 -1.098598 -0.889659 0.092225
  21. 2000-01-05 -0.987349 -0.622526 0.321243
  22. 2000-01-06 -0.876100 -0.355392 0.550262
  23. 2000-01-07 -0.764851 -0.088259 0.779280
  24. 2000-01-08 -0.653602 0.178875 1.008298
  25. 2000-01-09 1.007996 0.462824 0.254472
  26. 2000-01-10 0.307473 0.600337 1.643950

apply() 有一个参数 raw,默认值为 False,在应用函数前,使用该参数可以将每行或列转换为 Series。该参数为 True 时,传递的函数接收 ndarray 对象,若不需要索引功能,这种操作能显著提高性能。

聚合 API

0.20.0 版新增

聚合 API 可以快速、简洁地执行多个聚合操作。Pandas 对象支持多个类似的 API,如 groupby APIwindow functions APIresample API。聚合函数为DataFrame.aggregate(),它的别名是 DataFrame.agg()

此处用与上例类似的 DataFrame

  1. In [152]: tsdf = pd.DataFrame(np.random.randn(10, 3), columns=['A', 'B', 'C'],
  2. .....: index=pd.date_range('1/1/2000', periods=10))
  3. .....:
  4. In [153]: tsdf.iloc[3:7] = np.nan
  5. In [154]: tsdf
  6. Out[154]:
  7. A B C
  8. 2000-01-01 1.257606 1.004194 0.167574
  9. 2000-01-02 -0.749892 0.288112 -0.757304
  10. 2000-01-03 -0.207550 -0.298599 0.116018
  11. 2000-01-04 NaN NaN NaN
  12. 2000-01-05 NaN NaN NaN
  13. 2000-01-06 NaN NaN NaN
  14. 2000-01-07 NaN NaN NaN
  15. 2000-01-08 0.814347 -0.257623 0.869226
  16. 2000-01-09 -0.250663 -1.206601 0.896839
  17. 2000-01-10 2.169758 -1.333363 0.283157

应用单个函数时,该操作与 apply() 等效,这里也可以用字符串表示聚合函数名。下面的聚合函数输出的结果为 Series

  1. In [155]: tsdf.agg(np.sum)
  2. Out[155]:
  3. A 3.033606
  4. B -1.803879
  5. C 1.575510
  6. dtype: float64
  7. In [156]: tsdf.agg('sum')
  8. Out[156]:
  9. A 3.033606
  10. B -1.803879
  11. C 1.575510
  12. dtype: float64
  13. # 因为应用的是单个函数,该操作与`.sum()` 是等效的
  14. In [157]: tsdf.sum()
  15. Out[157]:
  16. A 3.033606
  17. B -1.803879
  18. C 1.575510
  19. dtype: float64

Series 单个聚合操作返回标量值:

  1. In [158]: tsdf.A.agg('sum')
  2. Out[158]: 3.033606102414146

多函数聚合

还可以用列表形式传递多个聚合函数。每个函数在输出结果 DataFrame 里以行的形式显示,行名是每个聚合函数的函数名。

  1. In [159]: tsdf.agg(['sum'])
  2. Out[159]:
  3. A B C
  4. sum 3.033606 -1.803879 1.57551

多个函数输出多行:

  1. In [160]: tsdf.agg(['sum', 'mean'])
  2. Out[160]:
  3. A B C
  4. sum 3.033606 -1.803879 1.575510
  5. mean 0.505601 -0.300647 0.262585

Series 聚合多函数返回结果还是 Series,索引为函数名:

  1. In [161]: tsdf.A.agg(['sum', 'mean'])
  2. Out[161]:
  3. sum 3.033606
  4. mean 0.505601
  5. Name: A, dtype: float64

传递 lambda 函数时,输出名为 <lambda> 的行:

  1. In [162]: tsdf.A.agg(['sum', lambda x: x.mean()])
  2. Out[162]:
  3. sum 3.033606
  4. <lambda> 0.505601
  5. Name: A, dtype: float64

应用自定义函数时,该函数名为输出结果的行名:

  1. In [163]: def mymean(x):
  2. .....: return x.mean()
  3. .....:
  4. In [164]: tsdf.A.agg(['sum', mymean])
  5. Out[164]:
  6. sum 3.033606
  7. mymean 0.505601
  8. Name: A, dtype: float64

用字典实现聚合

指定为哪些列应用哪些聚合函数时,需要把包含列名与标量(或标量列表)的字典传递给 DataFrame.agg

注意:这里输出结果的顺序不是固定的,要想让输出顺序与输入顺序一致,请使用 OrderedDict

  1. In [165]: tsdf.agg({'A': 'mean', 'B': 'sum'})
  2. Out[165]:
  3. A 0.505601
  4. B -1.803879
  5. dtype: float64

输入的参数是列表时,输出结果为 DataFrame,并以矩阵形式显示所有聚合函数的计算结果,且输出结果由所有唯一函数组成。未执行聚合操作的列输出结果为 NaN 值:

  1. In [166]: tsdf.agg({'A': ['mean', 'min'], 'B': 'sum'})
  2. Out[166]:
  3. A B
  4. mean 0.505601 NaN
  5. min -0.749892 NaN
  6. sum NaN -1.803879

多种数据类型(Dtype)

groupby.agg 操作类似,DataFrame 含不能执行聚合的数据类型时,.agg 只计算可聚合的列:

  1. In [167]: mdf = pd.DataFrame({'A': [1, 2, 3],
  2. .....: 'B': [1., 2., 3.],
  3. .....: 'C': ['foo', 'bar', 'baz'],
  4. .....: 'D': pd.date_range('20130101', periods=3)})
  5. .....:
  6. In [168]: mdf.dtypes
  7. Out[168]:
  8. A int64
  9. B float64
  10. C object
  11. D datetime64[ns]
  12. dtype: object
  1. In [169]: mdf.agg(['min', 'sum'])
  2. Out[169]:
  3. A B C D
  4. min 1 1.0 bar 2013-01-01
  5. sum 6 6.0 foobarbaz NaT

自定义 Describe

.agg() 可以创建类似于内置 describe 函数 的自定义 describe 函数。

  1. In [170]: from functools import partial
  2. In [171]: q_25 = partial(pd.Series.quantile, q=0.25)
  3. In [172]: q_25.__name__ = '25%'
  4. In [173]: q_75 = partial(pd.Series.quantile, q=0.75)
  5. In [174]: q_75.__name__ = '75%'
  6. In [175]: tsdf.agg(['count', 'mean', 'std', 'min', q_25, 'median', q_75, 'max'])
  7. Out[175]:
  8. A B C
  9. count 6.000000 6.000000 6.000000
  10. mean 0.505601 -0.300647 0.262585
  11. std 1.103362 0.887508 0.606860
  12. min -0.749892 -1.333363 -0.757304
  13. 25% -0.239885 -0.979600 0.128907
  14. median 0.303398 -0.278111 0.225365
  15. 75% 1.146791 0.151678 0.722709
  16. max 2.169758 1.004194 0.896839

Transform API

0.20.0 版新增

transform() 方法的返回结果与原始数据的索引相同,大小相同。与 .agg API 类似,该 API 支持同时处理多种操作,不用一个一个操作。

下面,先创建一个 DataFrame:

  1. In [176]: tsdf = pd.DataFrame(np.random.randn(10, 3), columns=['A', 'B', 'C'],
  2. .....: index=pd.date_range('1/1/2000', periods=10))
  3. .....:
  4. In [177]: tsdf.iloc[3:7] = np.nan
  5. In [178]: tsdf
  6. Out[178]:
  7. A B C
  8. 2000-01-01 -0.428759 -0.864890 -0.675341
  9. 2000-01-02 -0.168731 1.338144 -1.279321
  10. 2000-01-03 -1.621034 0.438107 0.903794
  11. 2000-01-04 NaN NaN NaN
  12. 2000-01-05 NaN NaN NaN
  13. 2000-01-06 NaN NaN NaN
  14. 2000-01-07 NaN NaN NaN
  15. 2000-01-08 0.254374 -1.240447 -0.201052
  16. 2000-01-09 -0.157795 0.791197 -1.144209
  17. 2000-01-10 -0.030876 0.371900 0.061932

这里转换的是整个 DataFrame。.transform() 支持 NumPy 函数、字符串函数及自定义函数。

  1. In [179]: tsdf.transform(np.abs)
  2. Out[179]:
  3. A B C
  4. 2000-01-01 0.428759 0.864890 0.675341
  5. 2000-01-02 0.168731 1.338144 1.279321
  6. 2000-01-03 1.621034 0.438107 0.903794
  7. 2000-01-04 NaN NaN NaN
  8. 2000-01-05 NaN NaN NaN
  9. 2000-01-06 NaN NaN NaN
  10. 2000-01-07 NaN NaN NaN
  11. 2000-01-08 0.254374 1.240447 0.201052
  12. 2000-01-09 0.157795 0.791197 1.144209
  13. 2000-01-10 0.030876 0.371900 0.061932
  14. In [180]: tsdf.transform('abs')
  15. Out[180]:
  16. A B C
  17. 2000-01-01 0.428759 0.864890 0.675341
  18. 2000-01-02 0.168731 1.338144 1.279321
  19. 2000-01-03 1.621034 0.438107 0.903794
  20. 2000-01-04 NaN NaN NaN
  21. 2000-01-05 NaN NaN NaN
  22. 2000-01-06 NaN NaN NaN
  23. 2000-01-07 NaN NaN NaN
  24. 2000-01-08 0.254374 1.240447 0.201052
  25. 2000-01-09 0.157795 0.791197 1.144209
  26. 2000-01-10 0.030876 0.371900 0.061932
  27. In [181]: tsdf.transform(lambda x: x.abs())
  28. Out[181]:
  29. A B C
  30. 2000-01-01 0.428759 0.864890 0.675341
  31. 2000-01-02 0.168731 1.338144 1.279321
  32. 2000-01-03 1.621034 0.438107 0.903794
  33. 2000-01-04 NaN NaN NaN
  34. 2000-01-05 NaN NaN NaN
  35. 2000-01-06 NaN NaN NaN
  36. 2000-01-07 NaN NaN NaN
  37. 2000-01-08 0.254374 1.240447 0.201052
  38. 2000-01-09 0.157795 0.791197 1.144209
  39. 2000-01-10 0.030876 0.371900 0.061932

这里的 transform() 接受单个函数;与 ufunc 等效。

  1. In [182]: np.abs(tsdf)
  2. Out[182]:
  3. A B C
  4. 2000-01-01 0.428759 0.864890 0.675341
  5. 2000-01-02 0.168731 1.338144 1.279321
  6. 2000-01-03 1.621034 0.438107 0.903794
  7. 2000-01-04 NaN NaN NaN
  8. 2000-01-05 NaN NaN NaN
  9. 2000-01-06 NaN NaN NaN
  10. 2000-01-07 NaN NaN NaN
  11. 2000-01-08 0.254374 1.240447 0.201052
  12. 2000-01-09 0.157795 0.791197 1.144209
  13. 2000-01-10 0.030876 0.371900 0.061932

.transform()Series 传递单个函数时,返回的结果也是单个 Series

  1. In [183]: tsdf.A.transform(np.abs)
  2. Out[183]:
  3. 2000-01-01 0.428759
  4. 2000-01-02 0.168731
  5. 2000-01-03 1.621034
  6. 2000-01-04 NaN
  7. 2000-01-05 NaN
  8. 2000-01-06 NaN
  9. 2000-01-07 NaN
  10. 2000-01-08 0.254374
  11. 2000-01-09 0.157795
  12. 2000-01-10 0.030876
  13. Freq: D, Name: A, dtype: float64

多函数 Transform

transform() 调用多个函数时,生成多层索引 DataFrame。第一层是原始数据集的列名;第二层是 transform() 调用的函数名。

  1. In [184]: tsdf.transform([np.abs, lambda x: x + 1])
  2. Out[184]:
  3. A B C
  4. absolute <lambda> absolute <lambda> absolute <lambda>
  5. 2000-01-01 0.428759 0.571241 0.864890 0.135110 0.675341 0.324659
  6. 2000-01-02 0.168731 0.831269 1.338144 2.338144 1.279321 -0.279321
  7. 2000-01-03 1.621034 -0.621034 0.438107 1.438107 0.903794 1.903794
  8. 2000-01-04 NaN NaN NaN NaN NaN NaN
  9. 2000-01-05 NaN NaN NaN NaN NaN NaN
  10. 2000-01-06 NaN NaN NaN NaN NaN NaN
  11. 2000-01-07 NaN NaN NaN NaN NaN NaN
  12. 2000-01-08 0.254374 1.254374 1.240447 -0.240447 0.201052 0.798948
  13. 2000-01-09 0.157795 0.842205 0.791197 1.791197 1.144209 -0.144209
  14. 2000-01-10 0.030876 0.969124 0.371900 1.371900 0.061932 1.061932

为 Series 应用多个函数时,输出结果是 DataFrame,列名是 transform() 调用的函数名。

  1. In [185]: tsdf.A.transform([np.abs, lambda x: x + 1])
  2. Out[185]:
  3. absolute <lambda>
  4. 2000-01-01 0.428759 0.571241
  5. 2000-01-02 0.168731 0.831269
  6. 2000-01-03 1.621034 -0.621034
  7. 2000-01-04 NaN NaN
  8. 2000-01-05 NaN NaN
  9. 2000-01-06 NaN NaN
  10. 2000-01-07 NaN NaN
  11. 2000-01-08 0.254374 1.254374
  12. 2000-01-09 0.157795 0.842205
  13. 2000-01-10 0.030876 0.969124

用字典执行 transform 操作

函数字典可以为每列执行指定 transform() 操作。

  1. In [186]: tsdf.transform({'A': np.abs, 'B': lambda x: x + 1})
  2. Out[186]:
  3. A B
  4. 2000-01-01 0.428759 0.135110
  5. 2000-01-02 0.168731 2.338144
  6. 2000-01-03 1.621034 1.438107
  7. 2000-01-04 NaN NaN
  8. 2000-01-05 NaN NaN
  9. 2000-01-06 NaN NaN
  10. 2000-01-07 NaN NaN
  11. 2000-01-08 0.254374 -0.240447
  12. 2000-01-09 0.157795 1.791197
  13. 2000-01-10 0.030876 1.371900

transform() 的参数是列表字典时,生成的是以 transform() 调用的函数为名的多层索引 DataFrame。

  1. In [187]: tsdf.transform({'A': np.abs, 'B': [lambda x: x + 1, 'sqrt']})
  2. Out[187]:
  3. A B
  4. absolute <lambda> sqrt
  5. 2000-01-01 0.428759 0.135110 NaN
  6. 2000-01-02 0.168731 2.338144 1.156782
  7. 2000-01-03 1.621034 1.438107 0.661897
  8. 2000-01-04 NaN NaN NaN
  9. 2000-01-05 NaN NaN NaN
  10. 2000-01-06 NaN NaN NaN
  11. 2000-01-07 NaN NaN NaN
  12. 2000-01-08 0.254374 -0.240447 NaN
  13. 2000-01-09 0.157795 1.791197 0.889493
  14. 2000-01-10 0.030876 1.371900 0.609836

元素级函数应用

并非所有函数都能矢量化,即接受 NumPy 数组,返回另一个数组或值,DataFrame 的 applymap() 及 Series 的 map() ,支持任何接收单个值并返回单个值的 Python 函数。

示例如下:

  1. In [188]: df4
  2. Out[188]:
  3. one two three
  4. a 1.394981 1.772517 NaN
  5. b 0.343054 1.912123 -0.050390
  6. c 0.695246 1.478369 1.227435
  7. d NaN 0.279344 -0.613172
  8. In [189]: def f(x):
  9. .....: return len(str(x))
  10. .....:
  11. In [190]: df4['one'].map(f)
  12. Out[190]:
  13. a 18
  14. b 19
  15. c 18
  16. d 3
  17. Name: one, dtype: int64
  18. In [191]: df4.applymap(f)
  19. Out[191]:
  20. one two three
  21. a 18 17 3
  22. b 19 18 20
  23. c 18 18 16
  24. d 3 19 19

Series.map() 还有个功能,可以“连接”或“映射”第二个 Series 定义的值。这与 merging / joining 功能联系非常紧密:

  1. In [192]: s = pd.Series(['six', 'seven', 'six', 'seven', 'six'],
  2. .....: index=['a', 'b', 'c', 'd', 'e'])
  3. .....:
  4. In [193]: t = pd.Series({'six': 6., 'seven': 7.})
  5. In [194]: s
  6. Out[194]:
  7. a six
  8. b seven
  9. c six
  10. d seven
  11. e six
  12. dtype: object
  13. In [195]: s.map(t)
  14. Out[195]:
  15. a 6.0
  16. b 7.0
  17. c 6.0
  18. d 7.0
  19. e 6.0
  20. dtype: float64

2.7. 重置索引与更换标签

reindex() 是 Pandas 里实现数据对齐的基本方法,该方法执行几乎所有功能都要用到的标签对齐功能。 reindex 指的是沿着指定轴,让数据与给定的一组标签进行匹配。该功能完成以下几项操作:

  • 让现有数据匹配一组新标签,并重新排序;
  • 在无数据但有标签的位置插入缺失值(NA)标记;
  • 如果指定,则按逻辑填充无标签的数据,该操作多见于时间序列数据。

示例如下:

  1. In [196]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
  2. In [197]: s
  3. Out[197]:
  4. a 1.695148
  5. b 1.328614
  6. c 1.234686
  7. d -0.385845
  8. e -1.326508
  9. dtype: float64
  10. In [198]: s.reindex(['e', 'b', 'f', 'd'])
  11. Out[198]:
  12. e -1.326508
  13. b 1.328614
  14. f NaN
  15. d -0.385845
  16. dtype: float64

本例中,原 Series 里没有标签 f ,因此,输出结果里 f 对应的值为 NaN

DataFrame 支持同时 reindex 索引与列:

  1. In [199]: df
  2. Out[199]:
  3. one two three
  4. a 1.394981 1.772517 NaN
  5. b 0.343054 1.912123 -0.050390
  6. c 0.695246 1.478369 1.227435
  7. d NaN 0.279344 -0.613172
  8. In [200]: df.reindex(index=['c', 'f', 'b'], columns=['three', 'two', 'one'])
  9. Out[200]:
  10. three two one
  11. c 1.227435 1.478369 0.695246
  12. f NaN NaN NaN
  13. b -0.050390 1.912123 0.343054

reindex 还支持 axis 关键字:

  1. In [201]: df.reindex(['c', 'f', 'b'], axis='index')
  2. Out[201]:
  3. one two three
  4. c 0.695246 1.478369 1.227435
  5. f NaN NaN NaN
  6. b 0.343054 1.912123 -0.050390

注意:不同对象可以共享 Index 包含的轴标签。比如,有一个 Series,还有一个 DataFrame,可以执行下列操作:

  1. In [202]: rs = s.reindex(df.index)
  2. In [203]: rs
  3. Out[203]:
  4. a 1.695148
  5. b 1.328614
  6. c 1.234686
  7. d -0.385845
  8. dtype: float64
  9. In [204]: rs.index is df.index
  10. Out[204]: True

这里指的是,重置后,Series 的索引与 DataFrame 的索引是同一个 Python 对象。

0.21.0 版新增

DataFrame.reindex() 还支持 “轴样式”调用习语,可以指定单个 labels 参数,并指定应用于哪个 axis

  1. In [205]: df.reindex(['c', 'f', 'b'], axis='index')
  2. Out[205]:
  3. one two three
  4. c 0.695246 1.478369 1.227435
  5. f NaN NaN NaN
  6. b 0.343054 1.912123 -0.050390
  7. In [206]: df.reindex(['three', 'two', 'one'], axis='columns')
  8. Out[206]:
  9. three two one
  10. a NaN 1.772517 1.394981
  11. b -0.050390 1.912123 0.343054
  12. c 1.227435 1.478369 0.695246
  13. d -0.613172 0.279344 NaN

::: tip 注意

多层索引与高级索引介绍了怎样用更简洁的方式重置索引。

:::

::: tip 注意

编写注重性能的代码时,最好花些时间深入理解 reindex预对齐数据后,操作会更快。两个未对齐的 DataFrame 相加,后台操作会执行 reindex。探索性分析时很难注意到这点有什么不同,这是因为 reindex 已经进行了高度优化,但需要注重 CPU 周期时,显式调用 reindex 还是有一些影响的。

:::

重置索引,并与其它对象对齐

提取一个对象,并用另一个具有相同标签的对象 reindex 该对象的轴。这种操作的语法虽然简单,但未免有些啰嗦。这时,最好用 reindex_like() 方法,这是一种既有效,又简单的方式:

  1. In [207]: df2
  2. Out[207]:
  3. one two
  4. a 1.394981 1.772517
  5. b 0.343054 1.912123
  6. c 0.695246 1.478369
  7. In [208]: df3
  8. Out[208]:
  9. one two
  10. a 0.583888 0.051514
  11. b -0.468040 0.191120
  12. c -0.115848 -0.242634
  13. In [209]: df.reindex_like(df2)
  14. Out[209]:
  15. one two
  16. a 1.394981 1.772517
  17. b 0.343054 1.912123
  18. c 0.695246 1.478369

align 对齐多个对象

align() 方法是对齐两个对象最快的方式,该方法支持 join 参数(请参阅 joining 与 merging):

  • join='outer':使用两个对象索引的合集,默认值
  • join='left':使用左侧调用对象的索引
  • join='right':使用右侧传递对象的索引
  • join='inner':使用两个对象索引的交集

该方法返回重置索引后的两个 Series 元组:

  1. In [210]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
  2. In [211]: s1 = s[:4]
  3. In [212]: s2 = s[1:]
  4. In [213]: s1.align(s2)
  5. Out[213]:
  6. (a -0.186646
  7. b -1.692424
  8. c -0.303893
  9. d -1.425662
  10. e NaN
  11. dtype: float64, a NaN
  12. b -1.692424
  13. c -0.303893
  14. d -1.425662
  15. e 1.114285
  16. dtype: float64)
  17. In [214]: s1.align(s2, join='inner')
  18. Out[214]:
  19. (b -1.692424
  20. c -0.303893
  21. d -1.425662
  22. dtype: float64, b -1.692424
  23. c -0.303893
  24. d -1.425662
  25. dtype: float64)
  26. In [215]: s1.align(s2, join='left')
  27. Out[215]:
  28. (a -0.186646
  29. b -1.692424
  30. c -0.303893
  31. d -1.425662
  32. dtype: float64, a NaN
  33. b -1.692424
  34. c -0.303893
  35. d -1.425662
  36. dtype: float64)

默认条件下, join 方法既应用于索引,也应用于列:

  1. In [216]: df.align(df2, join='inner')
  2. Out[216]:
  3. ( one two
  4. a 1.394981 1.772517
  5. b 0.343054 1.912123
  6. c 0.695246 1.478369, one two
  7. a 1.394981 1.772517
  8. b 0.343054 1.912123
  9. c 0.695246 1.478369)

align 方法还支持 axis 选项,用来指定要对齐的轴:

  1. In [217]: df.align(df2, join='inner', axis=0)
  2. Out[217]:
  3. ( one two three
  4. a 1.394981 1.772517 NaN
  5. b 0.343054 1.912123 -0.050390
  6. c 0.695246 1.478369 1.227435, one two
  7. a 1.394981 1.772517
  8. b 0.343054 1.912123
  9. c 0.695246 1.478369)

如果把 Series 传递给 DataFrame.align(),可以用 axis 参数选择是在 DataFrame 的索引,还是列上对齐两个对象:

  1. In [218]: df.align(df2.iloc[0], axis=1)
  2. Out[218]:
  3. ( one three two
  4. a 1.394981 NaN 1.772517
  5. b 0.343054 -0.050390 1.912123
  6. c 0.695246 1.227435 1.478369
  7. d NaN -0.613172 0.279344, one 1.394981
  8. three NaN
  9. two 1.772517
  10. Name: a, dtype: float64)
方法动作
pad / ffill先前填充
bfill / backfill向后填充
nearest从最近的索引值填充

下面用一个简单的 Series 展示 fill 方法:

  1. In [219]: rng = pd.date_range('1/3/2000', periods=8)
  2. In [220]: ts = pd.Series(np.random.randn(8), index=rng)
  3. In [221]: ts2 = ts[[0, 3, 6]]
  4. In [222]: ts
  5. Out[222]:
  6. 2000-01-03 0.183051
  7. 2000-01-04 0.400528
  8. 2000-01-05 -0.015083
  9. 2000-01-06 2.395489
  10. 2000-01-07 1.414806
  11. 2000-01-08 0.118428
  12. 2000-01-09 0.733639
  13. 2000-01-10 -0.936077
  14. Freq: D, dtype: float64
  15. In [223]: ts2
  16. Out[223]:
  17. 2000-01-03 0.183051
  18. 2000-01-06 2.395489
  19. 2000-01-09 0.733639
  20. dtype: float64
  21. In [224]: ts2.reindex(ts.index)
  22. Out[224]:
  23. 2000-01-03 0.183051
  24. 2000-01-04 NaN
  25. 2000-01-05 NaN
  26. 2000-01-06 2.395489
  27. 2000-01-07 NaN
  28. 2000-01-08 NaN
  29. 2000-01-09 0.733639
  30. 2000-01-10 NaN
  31. Freq: D, dtype: float64
  32. In [225]: ts2.reindex(ts.index, method='ffill')
  33. Out[225]:
  34. 2000-01-03 0.183051
  35. 2000-01-04 0.183051
  36. 2000-01-05 0.183051
  37. 2000-01-06 2.395489
  38. 2000-01-07 2.395489
  39. 2000-01-08 2.395489
  40. 2000-01-09 0.733639
  41. 2000-01-10 0.733639
  42. Freq: D, dtype: float64
  43. In [226]: ts2.reindex(ts.index, method='bfill')
  44. Out[226]:
  45. 2000-01-03 0.183051
  46. 2000-01-04 2.395489
  47. 2000-01-05 2.395489
  48. 2000-01-06 2.395489
  49. 2000-01-07 0.733639
  50. 2000-01-08 0.733639
  51. 2000-01-09 0.733639
  52. 2000-01-10 NaN
  53. Freq: D, dtype: float64
  54. In [227]: ts2.reindex(ts.index, method='nearest')
  55. Out[227]:
  56. 2000-01-03 0.183051
  57. 2000-01-04 0.183051
  58. 2000-01-05 2.395489
  59. 2000-01-06 2.395489
  60. 2000-01-07 2.395489
  61. 2000-01-08 0.733639
  62. 2000-01-09 0.733639
  63. 2000-01-10 0.733639
  64. Freq: D, dtype: float64

上述操作要求索引按递增或递减排序

注意:除了 method='nearest',用 fillnainterpolate 也能实现同样的效果:

  1. In [228]: ts2.reindex(ts.index).fillna(method='ffill')
  2. Out[228]:
  3. 2000-01-03 0.183051
  4. 2000-01-04 0.183051
  5. 2000-01-05 0.183051
  6. 2000-01-06 2.395489
  7. 2000-01-07 2.395489
  8. 2000-01-08 2.395489
  9. 2000-01-09 0.733639
  10. 2000-01-10 0.733639
  11. Freq: D, dtype: float64

如果索引不是按递增或递减排序,reindex() 会触发 ValueError 错误。fillna()interpolate() 则不检查索引的排序。

重置索引填充的限制

limittolerance 参数可以控制 reindex 的填充操作。limit 限定了连续匹配的最大数量:

  1. In [229]: ts2.reindex(ts.index, method='ffill', limit=1)
  2. Out[229]:
  3. 2000-01-03 0.183051
  4. 2000-01-04 0.183051
  5. 2000-01-05 NaN
  6. 2000-01-06 2.395489
  7. 2000-01-07 2.395489
  8. 2000-01-08 NaN
  9. 2000-01-09 0.733639
  10. 2000-01-10 0.733639
  11. Freq: D, dtype: float64

反之,tolerance 限定了索引与索引器值之间的最大距离:

  1. In [230]: ts2.reindex(ts.index, method='ffill', tolerance='1 day')
  2. Out[230]:
  3. 2000-01-03 0.183051
  4. 2000-01-04 0.183051
  5. 2000-01-05 NaN
  6. 2000-01-06 2.395489
  7. 2000-01-07 2.395489
  8. 2000-01-08 NaN
  9. 2000-01-09 0.733639
  10. 2000-01-10 0.733639
  11. Freq: D, dtype: float64

注意:索引为 DatetimeIndexTimedeltaIndexPeriodIndex 时,tolerance 会尽可能将这些索引强制转换为 Timedelta,这里要求用户用恰当的字符串设定 tolerance 参数。

去掉轴上的标签

drop() 函数与 reindex 经常配合使用,该函数用于删除轴上的一组标签:

  1. In [231]: df
  2. Out[231]:
  3. one two three
  4. a 1.394981 1.772517 NaN
  5. b 0.343054 1.912123 -0.050390
  6. c 0.695246 1.478369 1.227435
  7. d NaN 0.279344 -0.613172
  8. In [232]: df.drop(['a', 'd'], axis=0)
  9. Out[232]:
  10. one two three
  11. b 0.343054 1.912123 -0.050390
  12. c 0.695246 1.478369 1.227435
  13. In [233]: df.drop(['one'], axis=1)
  14. Out[233]:
  15. two three
  16. a 1.772517 NaN
  17. b 1.912123 -0.050390
  18. c 1.478369 1.227435
  19. d 0.279344 -0.613172

注意:下面的代码可以运行,但不够清晰:

  1. In [234]: df.reindex(df.index.difference(['a', 'd']))
  2. Out[234]:
  3. one two three
  4. b 0.343054 1.912123 -0.050390
  5. c 0.695246 1.478369 1.227435

重命名或映射标签

rename() 方法支持按不同的轴基于映射(字典或 Series)调整标签。

  1. In [235]: s
  2. Out[235]:
  3. a -0.186646
  4. b -1.692424
  5. c -0.303893
  6. d -1.425662
  7. e 1.114285
  8. dtype: float64
  9. In [236]: s.rename(str.upper)
  10. Out[236]:
  11. A -0.186646
  12. B -1.692424
  13. C -0.303893
  14. D -1.425662
  15. E 1.114285
  16. dtype: float64

如果调用的是函数,该函数在处理标签时,必须返回一个值,而且生成的必须是一组唯一值。此外,rename() 还可以调用字典或 Series。

  1. In [237]: df.rename(columns={'one': 'foo', 'two': 'bar'},
  2. .....: index={'a': 'apple', 'b': 'banana', 'd': 'durian'})
  3. .....:
  4. Out[237]:
  5. foo bar three
  6. apple 1.394981 1.772517 NaN
  7. banana 0.343054 1.912123 -0.050390
  8. c 0.695246 1.478369 1.227435
  9. durian NaN 0.279344 -0.613172

Pandas 不会重命名标签未包含在映射里的列或索引。注意,映射里多出的标签不会触发错误。

0.21.0 版新增

DataFrame.rename() 还支持“轴式”习语,用这种方式可以指定单个 mapper,及执行映射的 axis

  1. In [238]: df.rename({'one': 'foo', 'two': 'bar'}, axis='columns')
  2. Out[238]:
  3. foo bar three
  4. a 1.394981 1.772517 NaN
  5. b 0.343054 1.912123 -0.050390
  6. c 0.695246 1.478369 1.227435
  7. d NaN 0.279344 -0.613172
  8. In [239]: df.rename({'a': 'apple', 'b': 'banana', 'd': 'durian'}, axis='index')
  9. Out[239]:
  10. one two three
  11. apple 1.394981 1.772517 NaN
  12. banana 0.343054 1.912123 -0.050390
  13. c 0.695246 1.478369 1.227435
  14. durian NaN 0.279344 -0.613172

rename() 方法还提供了 inplace 命名参数,默认为 False,并会复制底层数据。inplace=True 时,会直接在原数据上重命名。

0.18.0 版新增

rename() 还支持用标量或列表更改 Series.name 属性。

  1. In [240]: s.rename("scalar-name")
  2. Out[240]:
  3. a -0.186646
  4. b -1.692424
  5. c -0.303893
  6. d -1.425662
  7. e 1.114285
  8. Name: scalar-name, dtype: float64

0.24.0 版新增

rename_axis() 方法支持指定 多层索引 名称,与标签相对应。

  1. In [241]: df = pd.DataFrame({'x': [1, 2, 3, 4, 5, 6],
  2. .....: 'y': [10, 20, 30, 40, 50, 60]},
  3. .....: index=pd.MultiIndex.from_product([['a', 'b', 'c'], [1, 2]],
  4. .....: names=['let', 'num']))
  5. .....:
  6. In [242]: df
  7. Out[242]:
  8. x y
  9. let num
  10. a 1 1 10
  11. 2 2 20
  12. b 1 3 30
  13. 2 4 40
  14. c 1 5 50
  15. 2 6 60
  16. In [243]: df.rename_axis(index={'let': 'abc'})
  17. Out[243]:
  18. x y
  19. abc num
  20. a 1 1 10
  21. 2 2 20
  22. b 1 3 30
  23. 2 4 40
  24. c 1 5 50
  25. 2 6 60
  26. In [244]: df.rename_axis(index=str.upper)
  27. Out[244]:
  28. x y
  29. LET NUM
  30. a 1 1 10
  31. 2 2 20
  32. b 1 3 30
  33. 2 4 40
  34. c 1 5 50
  35. 2 6 60

2.8. 迭代

Pandas 对象基于类型进行迭代操作。Series 迭代时被视为数组,基础迭代生成值。DataFrame 则遵循字典式习语,用对象的 key 实现迭代操作。

简言之,基础迭代(for i in object)生成:

  • Series :值
  • DataFrame:列标签

例如,DataFrame 迭代时输出列名:

  1. In [245]: df = pd.DataFrame({'col1': np.random.randn(3),
  2. .....: 'col2': np.random.randn(3)}, index=['a', 'b', 'c'])
  3. .....:
  4. In [246]: for col in df:
  5. .....: print(col)
  6. .....:
  7. col1
  8. col2

Pandas 对象还支持字典式的 items() 方法,通过键值对迭代。

用下列方法可以迭代 DataFrame 里的行:

  • iterrows():把 DataFrame 里的行当作 (index, Series)对进行迭代。该操作把行转为 Series,同时改变数据类型,并对性能有影响。
  • itertuples() 把 DataFrame 的行当作值的命名元组进行迭代。该操作比 iterrows() 快的多,建议尽量用这种方法迭代 DataFrame 的值。

::: danger 警告

Pandas 对象迭代的速度较慢。大部分情况下,没必要对行执行迭代操作,建议用以下几种替代方式:

  • 矢量化:很多操作可以用内置方法或 NumPy 函数,布尔索引……
  • 调用的函数不能在完整的 DataFrame / Series 上运行时,最好用 apply(),不要对值进行迭代操作。请参阅函数应用文档。
  • 如果必须对值进行迭代,请务必注意代码的性能,建议在 cython 或 numba 环境下实现内循环。参阅性能优化一节,查看这种操作方法的示例。

:::

::: danger 警告

永远不要修改迭代的内容,这种方式不能确保所有操作都能正常运作。基于数据类型,迭代器返回的是复制(copy)的结果,不是视图(view),这种写入可能不会生效!

下例中的赋值就不会生效:

  1. In [247]: df = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
  2. In [248]: for index, row in df.iterrows():
  3. .....: row['a'] = 10
  4. .....:
  5. In [249]: df
  6. Out[249]:
  7. a b
  8. 0 1 a
  9. 1 2 b
  10. 2 3 c

:::

项目(items)

与字典型接口类似,items() 通过键值对进行迭代:

  • Series:(Index,标量值)对
  • DataFrame:(列,Series)对

示例如下:

  1. In [250]: for label, ser in df.items():
  2. .....: print(label)
  3. .....: print(ser)
  4. .....:
  5. a
  6. 0 1
  7. 1 2
  8. 2 3
  9. Name: a, dtype: int64
  10. b
  11. 0 a
  12. 1 b
  13. 2 c
  14. Name: b, dtype: object

iterrows

iterrows() 迭代 DataFrame 或 Series 里的每一行数据。这个操作返回一个迭代器,生成索引值及包含每行数据的 Series:

  1. In [251]: for row_index, row in df.iterrows():
  2. .....: print(row_index, row, sep='\n')
  3. .....:
  4. 0
  5. a 1
  6. b a
  7. Name: 0, dtype: object
  8. 1
  9. a 2
  10. b b
  11. Name: 1, dtype: object
  12. 2
  13. a 3
  14. b c
  15. Name: 2, dtype: object

::: tip 注意

iterrows() 返回的是 Series 里的每一行数据,该操作保留每行数据的数据类型,因为数据类型是通过 DataFrame 的列界定的。

示例如下:

  1. In [252]: df_orig = pd.DataFrame([[1, 1.5]], columns=['int', 'float'])
  2. In [253]: df_orig.dtypes
  3. Out[253]:
  4. int int64
  5. float float64
  6. dtype: object
  7. In [254]: row = next(df_orig.iterrows())[1]
  8. In [255]: row
  9. Out[255]:
  10. int 1.0
  11. float 1.5
  12. Name: 0, dtype: float64

row 里的值以 Series 形式返回,并被转换为浮点数,原始的整数值则在列 X:

  1. In [256]: row['int'].dtype
  2. Out[256]: dtype('float64')
  3. In [257]: df_orig['int'].dtype
  4. Out[257]: dtype('int64')

要想在行迭代时保存数据类型,最好用 itertuples(),这个函数返回值的命名元组,总的来说,该操作比 iterrows() 速度更快。

:::

下例展示了怎样转置 DataFrame:

  1. In [258]: df2 = pd.DataFrame({'x': [1, 2, 3], 'y': [4, 5, 6]})
  2. In [259]: print(df2)
  3. x y
  4. 0 1 4
  5. 1 2 5
  6. 2 3 6
  7. In [260]: print(df2.T)
  8. 0 1 2
  9. x 1 2 3
  10. y 4 5 6
  11. In [261]: df2_t = pd.DataFrame({idx: values for idx, values in df2.iterrows()})
  12. In [262]: print(df2_t)
  13. 0 1 2
  14. x 1 2 3
  15. y 4 5 6

itertuples

itertuples() 方法返回为 DataFrame 里每行数据生成命名元组的迭代器。该元组的第一个元素是行的索引值,其余的值则是行的值。

示例如下:

  1. In [263]: for row in df.itertuples():
  2. .....: print(row)
  3. .....:
  4. Pandas(Index=0, a=1, b='a')
  5. Pandas(Index=1, a=2, b='b')
  6. Pandas(Index=2, a=3, b='c')

该方法不会把行转换为 Series,只是返回命名元组里的值。itertuples() 保存值的数据类型,而且比 iterrows() 快。

::: tip 注意

包含无效 Python 识别符的列名、重复的列名及以下划线开头的列名,会被重命名为位置名称。如果列数较大,比如大于 255 列,则返回正则元组。

:::

2.9. .dt 访问器

Series 提供一个可以简单、快捷地返回 datetime 属性值的访问器。这个访问器返回的也是 Series,索引与现有的 Series 一样。

  1. # datetime
  2. In [264]: s = pd.Series(pd.date_range('20130101 09:10:12', periods=4))
  3. In [265]: s
  4. Out[265]:
  5. 0 2013-01-01 09:10:12
  6. 1 2013-01-02 09:10:12
  7. 2 2013-01-03 09:10:12
  8. 3 2013-01-04 09:10:12
  9. dtype: datetime64[ns]
  10. In [266]: s.dt.hour
  11. Out[266]:
  12. 0 9
  13. 1 9
  14. 2 9
  15. 3 9
  16. dtype: int64
  17. In [267]: s.dt.second
  18. Out[267]:
  19. 0 12
  20. 1 12
  21. 2 12
  22. 3 12
  23. dtype: int64
  24. In [268]: s.dt.day
  25. Out[268]:
  26. 0 1
  27. 1 2
  28. 2 3
  29. 3 4
  30. dtype: int64

用下列表达式进行筛选非常方便:

  1. In [269]: s[s.dt.day == 2]
  2. Out[269]:
  3. 1 2013-01-02 09:10:12
  4. dtype: datetime64[ns]

时区转换也很轻松:

  1. In [270]: stz = s.dt.tz_localize('US/Eastern')
  2. In [271]: stz
  3. Out[271]:
  4. 0 2013-01-01 09:10:12-05:00
  5. 1 2013-01-02 09:10:12-05:00
  6. 2 2013-01-03 09:10:12-05:00
  7. 3 2013-01-04 09:10:12-05:00
  8. dtype: datetime64[ns, US/Eastern]
  9. In [272]: stz.dt.tz
  10. Out[272]: <DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD>

可以把这些操作连在一起:

  1. In [273]: s.dt.tz_localize('UTC').dt.tz_convert('US/Eastern')
  2. Out[273]:
  3. 0 2013-01-01 04:10:12-05:00
  4. 1 2013-01-02 04:10:12-05:00
  5. 2 2013-01-03 04:10:12-05:00
  6. 3 2013-01-04 04:10:12-05:00
  7. dtype: datetime64[ns, US/Eastern]

还可以用 Series.dt.strftime()datetime 的值当成字符串进行格式化,支持与标准 strftime() 同样的格式。

  1. # DatetimeIndex
  2. In [274]: s = pd.Series(pd.date_range('20130101', periods=4))
  3. In [275]: s
  4. Out[275]:
  5. 0 2013-01-01
  6. 1 2013-01-02
  7. 2 2013-01-03
  8. 3 2013-01-04
  9. dtype: datetime64[ns]
  10. In [276]: s.dt.strftime('%Y/%m/%d')
  11. Out[276]:
  12. 0 2013/01/01
  13. 1 2013/01/02
  14. 2 2013/01/03
  15. 3 2013/01/04
  16. dtype: object
  1. # PeriodIndex
  2. In [277]: s = pd.Series(pd.period_range('20130101', periods=4))
  3. In [278]: s
  4. Out[278]:
  5. 0 2013-01-01
  6. 1 2013-01-02
  7. 2 2013-01-03
  8. 3 2013-01-04
  9. dtype: period[D]
  10. In [279]: s.dt.strftime('%Y/%m/%d')
  11. Out[279]:
  12. 0 2013/01/01
  13. 1 2013/01/02
  14. 2 2013/01/03
  15. 3 2013/01/04
  16. dtype: object

.dt 访问器还支持 periodtimedelta

  1. # period
  2. In [280]: s = pd.Series(pd.period_range('20130101', periods=4, freq='D'))
  3. In [281]: s
  4. Out[281]:
  5. 0 2013-01-01
  6. 1 2013-01-02
  7. 2 2013-01-03
  8. 3 2013-01-04
  9. dtype: period[D]
  10. In [282]: s.dt.year
  11. Out[282]:
  12. 0 2013
  13. 1 2013
  14. 2 2013
  15. 3 2013
  16. dtype: int64
  17. In [283]: s.dt.day
  18. Out[283]:
  19. 0 1
  20. 1 2
  21. 2 3
  22. 3 4
  23. dtype: int64
  1. # timedelta
  2. In [284]: s = pd.Series(pd.timedelta_range('1 day 00:00:05', periods=4, freq='s'))
  3. In [285]: s
  4. Out[285]:
  5. 0 1 days 00:00:05
  6. 1 1 days 00:00:06
  7. 2 1 days 00:00:07
  8. 3 1 days 00:00:08
  9. dtype: timedelta64[ns]
  10. In [286]: s.dt.days
  11. Out[286]:
  12. 0 1
  13. 1 1
  14. 2 1
  15. 3 1
  16. dtype: int64
  17. In [287]: s.dt.seconds
  18. Out[287]:
  19. 0 5
  20. 1 6
  21. 2 7
  22. 3 8
  23. dtype: int64
  24. In [288]: s.dt.components
  25. Out[288]:
  26. days hours minutes seconds milliseconds microseconds nanoseconds
  27. 0 1 0 0 5 0 0 0
  28. 1 1 0 0 6 0 0 0
  29. 2 1 0 0 7 0 0 0
  30. 3 1 0 0 8 0 0 0

::: tip 注意

用这个访问器处理不是 datetime 类型的值时,Series.dt 会触发 TypeError 错误。

:::

2.10. 矢量化字符串方法

Series 支持字符串处理方法,可以非常方便地操作数组里的每个元素。这些方法会自动排除缺失值与空值,这也许是其最重要的特性。这些方法通过 Series 的 str 属性访问,一般情况下,这些操作的名称与内置的字符串方法一致。示例如下:

  1. In [289]: s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
  2. In [290]: s.str.lower()
  3. Out[290]:
  4. 0 a
  5. 1 b
  6. 2 c
  7. 3 aaba
  8. 4 baca
  9. 5 NaN
  10. 6 caba
  11. 7 dog
  12. 8 cat
  13. dtype: object

这里还提供了强大的模式匹配方法,但工业注意,模式匹配方法默认使用正则表达式

参阅矢量化字符串方法,了解完整内容。

2.11. 排序

Pandas 支持三种排序方式,按索引标签排序,按列里的值排序,按两种方式混合排序。

按索引排序

Series.sort_index()DataFrame.sort_index() 方法用于按索引层级对 Pandas 对象排序。

  1. In [291]: df = pd.DataFrame({
  2. .....: 'one': pd.Series(np.random.randn(3), index=['a', 'b', 'c']),
  3. .....: 'two': pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd']),
  4. .....: 'three': pd.Series(np.random.randn(3), index=['b', 'c', 'd'])})
  5. .....:
  6. In [292]: unsorted_df = df.reindex(index=['a', 'd', 'c', 'b'],
  7. .....: columns=['three', 'two', 'one'])
  8. .....:
  9. In [293]: unsorted_df
  10. Out[293]:
  11. three two one
  12. a NaN -1.152244 0.562973
  13. d -0.252916 -0.109597 NaN
  14. c 1.273388 -0.167123 0.640382
  15. b -0.098217 0.009797 -1.299504
  16. # DataFrame
  17. In [294]: unsorted_df.sort_index()
  18. Out[294]:
  19. three two one
  20. a NaN -1.152244 0.562973
  21. b -0.098217 0.009797 -1.299504
  22. c 1.273388 -0.167123 0.640382
  23. d -0.252916 -0.109597 NaN
  24. In [295]: unsorted_df.sort_index(ascending=False)
  25. Out[295]:
  26. three two one
  27. d -0.252916 -0.109597 NaN
  28. c 1.273388 -0.167123 0.640382
  29. b -0.098217 0.009797 -1.299504
  30. a NaN -1.152244 0.562973
  31. In [296]: unsorted_df.sort_index(axis=1)
  32. Out[296]:
  33. one three two
  34. a 0.562973 NaN -1.152244
  35. d NaN -0.252916 -0.109597
  36. c 0.640382 1.273388 -0.167123
  37. b -1.299504 -0.098217 0.009797
  38. # Series
  39. In [297]: unsorted_df['three'].sort_index()
  40. Out[297]:
  41. a NaN
  42. b -0.098217
  43. c 1.273388
  44. d -0.252916
  45. Name: three, dtype: float64

按值排序

Series.sort_values() 方法用于按值对 Series 排序。DataFrame.sort_values() 方法用于按行列的值对 DataFrame 排序。DataFrame.sort_values() 的可选参数 by 用于指定按哪列排序,该参数的值可以是一列或多列数据。

  1. In [298]: df1 = pd.DataFrame({'one': [2, 1, 1, 1],
  2. .....: 'two': [1, 3, 2, 4],
  3. .....: 'three': [5, 4, 3, 2]})
  4. .....:
  5. In [299]: df1.sort_values(by='two')
  6. Out[299]:
  7. one two three
  8. 0 2 1 5
  9. 2 1 2 3
  10. 1 1 3 4
  11. 3 1 4 2

参数 by 支持列名列表,示例如下:

  1. In [300]: df1[['one', 'two', 'three']].sort_values(by=['one', 'two'])
  2. Out[300]:
  3. one two three
  4. 2 1 2 3
  5. 1 1 3 4
  6. 3 1 4 2
  7. 0 2 1 5

这些方法支持用 na_position 参数处理空值。

  1. In [301]: s[2] = np.nan
  2. In [302]: s.sort_values()
  3. Out[302]:
  4. 0 A
  5. 3 Aaba
  6. 1 B
  7. 4 Baca
  8. 6 CABA
  9. 8 cat
  10. 7 dog
  11. 2 NaN
  12. 5 NaN
  13. dtype: object
  14. In [303]: s.sort_values(na_position='first')
  15. Out[303]:
  16. 2 NaN
  17. 5 NaN
  18. 0 A
  19. 3 Aaba
  20. 1 B
  21. 4 Baca
  22. 6 CABA
  23. 8 cat
  24. 7 dog
  25. dtype: object

按索引与值排序

0.23.0 版新增

通过参数 by 传递给 DataFrame.sort_values() 的字符串可以引用列或索引层名。

  1. # 创建 MultiIndex
  2. In [304]: idx = pd.MultiIndex.from_tuples([('a', 1), ('a', 2), ('a', 2),
  3. .....: ('b', 2), ('b', 1), ('b', 1)])
  4. .....:
  5. In [305]: idx.names = ['first', 'second']
  6. # 创建 DataFrame
  7. In [306]: df_multi = pd.DataFrame({'A': np.arange(6, 0, -1)},
  8. .....: index=idx)
  9. .....:
  10. In [307]: df_multi
  11. Out[307]:
  12. A
  13. first second
  14. a 1 6
  15. 2 5
  16. 2 4
  17. b 2 3
  18. 1 2
  19. 1 1

second(索引)与 A(列)排序。

  1. In [308]: df_multi.sort_values(by=['second', 'A'])
  2. Out[308]:
  3. A
  4. first second
  5. b 1 1
  6. 1 2
  7. a 1 6
  8. b 2 3
  9. a 2 4
  10. 2 5

::: tip 注意

字符串、列名、索引层名重名时,会触发警告提示,并以列名为准。后期版本中,这种情况将会触发模糊错误。

:::

搜索排序

Series 支持 searchsorted() 方法,这与numpy.ndarray.searchsorted() 的操作方式类似。

  1. In [309]: ser = pd.Series([1, 2, 3])
  2. In [310]: ser.searchsorted([0, 3])
  3. Out[310]: array([0, 2])
  4. In [311]: ser.searchsorted([0, 4])
  5. Out[311]: array([0, 3])
  6. In [312]: ser.searchsorted([1, 3], side='right')
  7. Out[312]: array([1, 3])
  8. In [313]: ser.searchsorted([1, 3], side='left')
  9. Out[313]: array([0, 2])
  10. In [314]: ser = pd.Series([3, 1, 2])
  11. In [315]: ser.searchsorted([0, 3], sorter=np.argsort(ser))
  12. Out[315]: array([0, 2])

最大值与最小值

Series 支持 nsmallest()nlargest() 方法,本方法返回 N 个最大或最小的值。对于数据量大的 Series 来说,该方法比先为整个 Series 排序,再调用 head(n) 这种方式的速度要快得多。

  1. In [316]: s = pd.Series(np.random.permutation(10))
  2. In [317]: s
  3. Out[317]:
  4. 0 2
  5. 1 0
  6. 2 3
  7. 3 7
  8. 4 1
  9. 5 5
  10. 6 9
  11. 7 6
  12. 8 8
  13. 9 4
  14. dtype: int64
  15. In [318]: s.sort_values()
  16. Out[318]:
  17. 1 0
  18. 4 1
  19. 0 2
  20. 2 3
  21. 9 4
  22. 5 5
  23. 7 6
  24. 3 7
  25. 8 8
  26. 6 9
  27. dtype: int64
  28. In [319]: s.nsmallest(3)
  29. Out[319]:
  30. 1 0
  31. 4 1
  32. 0 2
  33. dtype: int64
  34. In [320]: s.nlargest(3)
  35. Out[320]:
  36. 6 9
  37. 8 8
  38. 3 7
  39. dtype: int64

DataFrame 也支持 nlargestnsmallest 方法。

  1. In [321]: df = pd.DataFrame({'a': [-2, -1, 1, 10, 8, 11, -1],
  2. .....: 'b': list('abdceff'),
  3. .....: 'c': [1.0, 2.0, 4.0, 3.2, np.nan, 3.0, 4.0]})
  4. .....:
  5. In [322]: df.nlargest(3, 'a')
  6. Out[322]:
  7. a b c
  8. 5 11 f 3.0
  9. 3 10 c 3.2
  10. 4 8 e NaN
  11. In [323]: df.nlargest(5, ['a', 'c'])
  12. Out[323]:
  13. a b c
  14. 5 11 f 3.0
  15. 3 10 c 3.2
  16. 4 8 e NaN
  17. 2 1 d 4.0
  18. 6 -1 f 4.0
  19. In [324]: df.nsmallest(3, 'a')
  20. Out[324]:
  21. a b c
  22. 0 -2 a 1.0
  23. 1 -1 b 2.0
  24. 6 -1 f 4.0
  25. In [325]: df.nsmallest(5, ['a', 'c'])
  26. Out[325]:
  27. a b c
  28. 0 -2 a 1.0
  29. 1 -1 b 2.0
  30. 6 -1 f 4.0
  31. 2 1 d 4.0
  32. 4 8 e NaN

用多层索引的列排序

列为多层索引时,可以显式排序,用 by 指定所有层级。

  1. In [326]: df1.columns = pd.MultiIndex.from_tuples([('a', 'one'),
  2. .....: ('a', 'two'),
  3. .....: ('b', 'three')])
  4. .....:
  5. In [327]: df1.sort_values(by=('a', 'two'))
  6. Out[327]:
  7. a b
  8. one two three
  9. 0 2 1 5
  10. 2 1 2 3
  11. 1 1 3 4
  12. 3 1 4 2

2.12. 复制

在 Pandas 对象上执行 copy() 方法,将复制底层数据(但不包括轴索引,因为轴索引不可变),并返回一个新的对象。注意,复制对象这种操作一般来说不是必须的。比如说,以下几种方式可以***就地(inplace)*** 改变 DataFrame:

  • 插入、删除、修改列
  • indexcolumns 属性赋值
  • 对于同质数据,用 values 属性或高级索引即可直接修改值

注意,用 Pandas 方法修改数据不会带来任何副作用,几乎所有方法都返回新的对象,不会修改原始数据对象。如果原始数据有所改动,唯一的可能就是用户显式指定了要修改原始数据。

2.13. 数据类型

大多数情况下,Pandas 使用 NumPy 数组、Series 或 DataFrame 里某列的数据类型。NumPy 支持 floatintbooltimedelta[ns]datetime64[ns],注意,NumPy 不支持带时区信息的 datetime

Pandas 与第三方支持库扩充了 NumPy 类型系统,本节只介绍 Pandas 的内部扩展。如需了解如何编写与 Pandas 扩展类型,请参阅扩展类型,参阅扩展数据类型了解第三方支持库提供的扩展类型。

下表列出了 Pandas 扩展类型,参阅列出的文档内容,查看每种类型的详细说明。

数据种类数据类型标量数组文档
tz-aware datetimeDatetimeTZDtypeTimestamparrays.DatetimeArrayTime zone handling
CategoricalCategoricalDtype(无)CategoricalCategorical data
period (time spans)PeriodDtypePeriodarrays.PeriodArrayTime span representation
sparseSparseDtype(无)arrays.SparseArraySparse data structures
intervalsIntervalDtypeIntervalarrays.IntervalArrayIntervalIndex
nullable integerInt64Dtype, …(无)arrays.IntegerArrayNullable integer data type

Pandas 用 object 存储字符串。

虽然, object 数据类型能够存储任何对象,但应尽量避免这种操作,要了解与其它支持库与方法的性能与交互操作,参阅 对象转换

DataFrame 的 dtypes 属性用起来很方便,以 Series 形式返回每列的数据类型。

  1. In [328]: dft = pd.DataFrame({'A': np.random.rand(3),
  2. .....: 'B': 1,
  3. .....: 'C': 'foo',
  4. .....: 'D': pd.Timestamp('20010102'),
  5. .....: 'E': pd.Series([1.0] * 3).astype('float32'),
  6. .....: 'F': False,
  7. .....: 'G': pd.Series([1] * 3, dtype='int8')})
  8. .....:
  9. In [329]: dft
  10. Out[329]:
  11. A B C D E F G
  12. 0 0.035962 1 foo 2001-01-02 1.0 False 1
  13. 1 0.701379 1 foo 2001-01-02 1.0 False 1
  14. 2 0.281885 1 foo 2001-01-02 1.0 False 1
  15. In [330]: dft.dtypes
  16. Out[330]:
  17. A float64
  18. B int64
  19. C object
  20. D datetime64[ns]
  21. E float32
  22. F bool
  23. G int8
  24. dtype: object

要查看 Series 的数据类型,用 dtype 属性。

  1. In [331]: dft['A'].dtype
  2. Out[331]: dtype('float64')

Pandas 对象单列中含多种类型的数据时,该列的数据类型为可适配于各类数据的数据类型,通常为 object

  1. # 整数被强制转换为浮点数
  2. In [332]: pd.Series([1, 2, 3, 4, 5, 6.])
  3. Out[332]:
  4. 0 1.0
  5. 1 2.0
  6. 2 3.0
  7. 3 4.0
  8. 4 5.0
  9. 5 6.0
  10. dtype: float64
  11. # 字符串数据决定了该 Series 的数据类型为 ``object``
  12. In [333]: pd.Series([1, 2, 3, 6., 'foo'])
  13. Out[333]:
  14. 0 1
  15. 1 2
  16. 2 3
  17. 3 6
  18. 4 foo
  19. dtype: object

DataFrame.dtypes.value_counts() 用于统计 DataFrame 里不同数据类型的列数。

  1. In [334]: dft.dtypes.value_counts()
  2. Out[334]:
  3. float32 1
  4. object 1
  5. bool 1
  6. int8 1
  7. float64 1
  8. datetime64[ns] 1
  9. int64 1
  10. dtype: int64

多种数值型数据类型可以在 DataFrame 里共存。如果只传递一种数据类型,不论是通过 dtype 关键字直接传递,还是通过 ndarraySeries 传递,都会保存至 DataFrame 操作。此外,不同数值型数据类型不会合并。示例如下:

  1. In [335]: df1 = pd.DataFrame(np.random.randn(8, 1), columns=['A'], dtype='float32')
  2. In [336]: df1
  3. Out[336]:
  4. A
  5. 0 0.224364
  6. 1 1.890546
  7. 2 0.182879
  8. 3 0.787847
  9. 4 -0.188449
  10. 5 0.667715
  11. 6 -0.011736
  12. 7 -0.399073
  13. In [337]: df1.dtypes
  14. Out[337]:
  15. A float32
  16. dtype: object
  17. In [338]: df2 = pd.DataFrame({'A': pd.Series(np.random.randn(8), dtype='float16'),
  18. .....: 'B': pd.Series(np.random.randn(8)),
  19. .....: 'C': pd.Series(np.array(np.random.randn(8),
  20. .....: dtype='uint8'))})
  21. .....:
  22. In [339]: df2
  23. Out[339]:
  24. A B C
  25. 0 0.823242 0.256090 0
  26. 1 1.607422 1.426469 0
  27. 2 -0.333740 -0.416203 255
  28. 3 -0.063477 1.139976 0
  29. 4 -1.014648 -1.193477 0
  30. 5 0.678711 0.096706 0
  31. 6 -0.040863 -1.956850 1
  32. 7 -0.357422 -0.714337 0
  33. In [340]: df2.dtypes
  34. Out[340]:
  35. A float16
  36. B float64
  37. C uint8
  38. dtype: object

默认值

整数的默认类型为 int64,浮点数的默认类型为 float64,这里的默认值与系统平台无关,不管是 32 位系统,还是 64 位系统都是一样的。下列代码返回的结果都是 int64

  1. In [341]: pd.DataFrame([1, 2], columns=['a']).dtypes
  2. Out[341]:
  3. a int64
  4. dtype: object
  5. In [342]: pd.DataFrame({'a': [1, 2]}).dtypes
  6. Out[342]:
  7. a int64
  8. dtype: object
  9. In [343]: pd.DataFrame({'a': 1}, index=list(range(2))).dtypes
  10. Out[343]:
  11. a int64
  12. dtype: object

注意,NumPy 创建数组时,会根据系统选择类型。下列代码在 32 位系统上返回 int32

  1. In [344]: frame = pd.DataFrame(np.array([1, 2]))

向上转型

与其它类型合并时,用的是向上转型,指的是从现有类型转换为另一种类型,如int 变为 float

  1. In [345]: df3 = df1.reindex_like(df2).fillna(value=0.0) + df2
  2. In [346]: df3
  3. Out[346]:
  4. A B C
  5. 0 1.047606 0.256090 0.0
  6. 1 3.497968 1.426469 0.0
  7. 2 -0.150862 -0.416203 255.0
  8. 3 0.724370 1.139976 0.0
  9. 4 -1.203098 -1.193477 0.0
  10. 5 1.346426 0.096706 0.0
  11. 6 -0.052599 -1.956850 1.0
  12. 7 -0.756495 -0.714337 0.0
  13. In [347]: df3.dtypes
  14. Out[347]:
  15. A float32
  16. B float64
  17. C float64
  18. dtype: object

DataFrame.to_numpy() 返回多个数据类型里用得最多的数据类型,这里指的是,输出结果的数据类型,适用于所有同构 NumPy 数组的数据类型。此处强制执行向上转型

  1. In [348]: df3.to_numpy().dtype
  2. Out[348]: dtype('float64')

astype

astype() 方法显式地把一种数据类型转换为另一种,默认操作为复制数据,就算数据类型没有改变也会复制数据,copy=False 改变默认操作模式。此外,astype 无效时,会触发异常。

向上转型一般都遵循 NumPy 规则。操作中含有两种不同类型的数据时,返回更为通用的那种数据类型。

  1. In [349]: df3
  2. Out[349]:
  3. A B C
  4. 0 1.047606 0.256090 0.0
  5. 1 3.497968 1.426469 0.0
  6. 2 -0.150862 -0.416203 255.0
  7. 3 0.724370 1.139976 0.0
  8. 4 -1.203098 -1.193477 0.0
  9. 5 1.346426 0.096706 0.0
  10. 6 -0.052599 -1.956850 1.0
  11. 7 -0.756495 -0.714337 0.0
  12. In [350]: df3.dtypes
  13. Out[350]:
  14. A float32
  15. B float64
  16. C float64
  17. dtype: object
  18. # 转换数据类型
  19. In [351]: df3.astype('float32').dtypes
  20. Out[351]:
  21. A float32
  22. B float32
  23. C float32
  24. dtype: object

astype() 把一列或多列转换为指定类型 。

  1. In [352]: dft = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [7, 8, 9]})
  2. In [353]: dft[['a', 'b']] = dft[['a', 'b']].astype(np.uint8)
  3. In [354]: dft
  4. Out[354]:
  5. a b c
  6. 0 1 4 7
  7. 1 2 5 8
  8. 2 3 6 9
  9. In [355]: dft.dtypes
  10. Out[355]:
  11. a uint8
  12. b uint8
  13. c int64
  14. dtype: object

0.19.0 版新增。

astype() 通过字典指定哪些列转换为哪些类型。

  1. In [356]: dft1 = pd.DataFrame({'a': [1, 0, 1], 'b': [4, 5, 6], 'c': [7, 8, 9]})
  2. In [357]: dft1 = dft1.astype({'a': np.bool, 'c': np.float64})
  3. In [358]: dft1
  4. Out[358]:
  5. a b c
  6. 0 True 4 7.0
  7. 1 False 5 8.0
  8. 2 True 6 9.0
  9. In [359]: dft1.dtypes
  10. Out[359]:
  11. a bool
  12. b int64
  13. c float64
  14. dtype: object

::: tip 注意

astype()loc() 为部分列转换指定类型时,会发生向上转型。

loc() 尝试分配当前的数据类型,而 [] 则会从右方获取数据类型并进行覆盖。因此,下列代码会产出意料之外的结果:

  1. In [360]: dft = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [7, 8, 9]})
  2. In [361]: dft.loc[:, ['a', 'b']].astype(np.uint8).dtypes
  3. Out[361]:
  4. a uint8
  5. b uint8
  6. dtype: object
  7. In [362]: dft.loc[:, ['a', 'b']] = dft.loc[:, ['a', 'b']].astype(np.uint8)
  8. In [363]: dft.dtypes
  9. Out[363]:
  10. a int64
  11. b int64
  12. c int64
  13. dtype: object

:::

对象转换

Pandas 提供了多种函数可以把 object 从一种类型强制转为另一种类型。这是因为,数据有时存储的是正确类型,但在保存时却存成了 object 类型,此时,用 DataFrame.infer_objects()Series.infer_objects() 方法即可把数据转换为正确的类型。

  1. In [364]: import datetime
  2. In [365]: df = pd.DataFrame([[1, 2],
  3. .....: ['a', 'b'],
  4. .....: [datetime.datetime(2016, 3, 2),
  5. .....: datetime.datetime(2016, 3, 2)]])
  6. .....:
  7. In [366]: df = df.T
  8. In [367]: df
  9. Out[367]:
  10. 0 1 2
  11. 0 1 a 2016-03-02
  12. 1 2 b 2016-03-02
  13. In [368]: df.dtypes
  14. Out[368]:
  15. 0 object
  16. 1 object
  17. 2 datetime64[ns]
  18. dtype: object

因为数据被转置,所以把原始列的数据类型改成了 object,但使用 infer_objects 后就变正确了。

  1. In [369]: df.infer_objects().dtypes
  2. Out[369]:
  3. 0 int64
  4. 1 object
  5. 2 datetime64[ns]
  6. dtype: object

下列函数可以应用于一维数组与标量,执行硬转换,把对象转换为指定类型。

  1. In [370]: m = ['1.1', 2, 3]
  2. In [371]: pd.to_numeric(m)
  3. Out[371]: array([1.1, 2. , 3. ])
  1. In [372]: import datetime
  2. In [373]: m = ['2016-07-09', datetime.datetime(2016, 3, 2)]
  3. In [374]: pd.to_datetime(m)
  4. Out[374]: DatetimeIndex(['2016-07-09', '2016-03-02'], dtype='datetime64[ns]', freq=None)
  1. In [375]: m = ['5us', pd.Timedelta('1day')]
  2. In [376]: pd.to_timedelta(m)
  3. Out[376]: TimedeltaIndex(['0 days 00:00:00.000005', '1 days 00:00:00'], dtype='timedelta64[ns]', freq=None)

如需强制转换,则要加入 error 参数,指定 Pandas 怎样处理不能转换为成预期类型或对象的数据。errors 参数的默认值为 False,指的是在转换过程中,遇到任何问题都触发错误。设置为 errors='coerce' 时,pandas 会忽略错误,强制把问题数据转换为 pd.NaTdatetimetimedelta),或 np.nan(数值型)。读取数据时,如果大部分要转换的数据是数值型或 datetime,这种操作非常有用,但偶尔也会有非制式数据混合在一起,可能会导致展示数据缺失:

  1. In [377]: import datetime
  2. In [378]: m = ['apple', datetime.datetime(2016, 3, 2)]
  3. In [379]: pd.to_datetime(m, errors='coerce')
  4. Out[379]: DatetimeIndex(['NaT', '2016-03-02'], dtype='datetime64[ns]', freq=None)
  5. In [380]: m = ['apple', 2, 3]
  6. In [381]: pd.to_numeric(m, errors='coerce')
  7. Out[381]: array([nan, 2., 3.])
  8. In [382]: m = ['apple', pd.Timedelta('1day')]
  9. In [383]: pd.to_timedelta(m, errors='coerce')
  10. Out[383]: TimedeltaIndex([NaT, '1 days'], dtype='timedelta64[ns]', freq=None)

error 参数还有第三个选项,error='ignore'。转换数据时会忽略错误,直接输出问题数据:

  1. In [384]: import datetime
  2. In [385]: m = ['apple', datetime.datetime(2016, 3, 2)]
  3. In [386]: pd.to_datetime(m, errors='ignore')
  4. Out[386]: Index(['apple', 2016-03-02 00:00:00], dtype='object')
  5. In [387]: m = ['apple', 2, 3]
  6. In [388]: pd.to_numeric(m, errors='ignore')
  7. Out[388]: array(['apple', 2, 3], dtype=object)
  8. In [389]: m = ['apple', pd.Timedelta('1day')]
  9. In [390]: pd.to_timedelta(m, errors='ignore')
  10. Out[390]: array(['apple', Timedelta('1 days 00:00:00')], dtype=object)

执行转换操作时,to_numeric() 还有一个参数,downcast,即向下转型,可以把数值型转换为减少内存占用的数据类型:

  1. In [391]: m = ['1', 2, 3]
  2. In [392]: pd.to_numeric(m, downcast='integer') # smallest signed int dtype
  3. Out[392]: array([1, 2, 3], dtype=int8)
  4. In [393]: pd.to_numeric(m, downcast='signed') # same as 'integer'
  5. Out[393]: array([1, 2, 3], dtype=int8)
  6. In [394]: pd.to_numeric(m, downcast='unsigned') # smallest unsigned int dtype
  7. Out[394]: array([1, 2, 3], dtype=uint8)
  8. In [395]: pd.to_numeric(m, downcast='float') # smallest float dtype
  9. Out[395]: array([1., 2., 3.], dtype=float32)

上述方法仅能应用于一维数组、列表或标量;不能直接用于 DataFrame 等多维对象。不过,用 apply(),可以快速为每列应用函数:

  1. In [396]: import datetime
  2. In [397]: df = pd.DataFrame([
  3. .....: ['2016-07-09', datetime.datetime(2016, 3, 2)]] * 2, dtype='O')
  4. .....:
  5. In [398]: df
  6. Out[398]:
  7. 0 1
  8. 0 2016-07-09 2016-03-02 00:00:00
  9. 1 2016-07-09 2016-03-02 00:00:00
  10. In [399]: df.apply(pd.to_datetime)
  11. Out[399]:
  12. 0 1
  13. 0 2016-07-09 2016-03-02
  14. 1 2016-07-09 2016-03-02
  15. In [400]: df = pd.DataFrame([['1.1', 2, 3]] * 2, dtype='O')
  16. In [401]: df
  17. Out[401]:
  18. 0 1 2
  19. 0 1.1 2 3
  20. 1 1.1 2 3
  21. In [402]: df.apply(pd.to_numeric)
  22. Out[402]:
  23. 0 1 2
  24. 0 1.1 2 3
  25. 1 1.1 2 3
  26. In [403]: df = pd.DataFrame([['5us', pd.Timedelta('1day')]] * 2, dtype='O')
  27. In [404]: df
  28. Out[404]:
  29. 0 1
  30. 0 5us 1 days 00:00:00
  31. 1 5us 1 days 00:00:00
  32. In [405]: df.apply(pd.to_timedelta)
  33. Out[405]:
  34. 0 1
  35. 0 00:00:00.000005 1 days
  36. 1 00:00:00.000005 1 days

各种坑

integer 数据执行选择操作时,可以很轻而易举地把数据转换为 floating 。Pandas 会保存输入数据的数据类型,以防未引入 nans 的情况。参阅 对整数 NA 空值的支持

  1. In [406]: dfi = df3.astype('int32')
  2. In [407]: dfi['E'] = 1
  3. In [408]: dfi
  4. Out[408]:
  5. A B C E
  6. 0 1 0 0 1
  7. 1 3 1 0 1
  8. 2 0 0 255 1
  9. 3 0 1 0 1
  10. 4 -1 -1 0 1
  11. 5 1 0 0 1
  12. 6 0 -1 1 1
  13. 7 0 0 0 1
  14. In [409]: dfi.dtypes
  15. Out[409]:
  16. A int32
  17. B int32
  18. C int32
  19. E int64
  20. dtype: object
  21. In [410]: casted = dfi[dfi > 0]
  22. In [411]: casted
  23. Out[411]:
  24. A B C E
  25. 0 1.0 NaN NaN 1
  26. 1 3.0 1.0 NaN 1
  27. 2 NaN NaN 255.0 1
  28. 3 NaN 1.0 NaN 1
  29. 4 NaN NaN NaN 1
  30. 5 1.0 NaN NaN 1
  31. 6 NaN NaN 1.0 1
  32. 7 NaN NaN NaN 1
  33. In [412]: casted.dtypes
  34. Out[412]:
  35. A float64
  36. B float64
  37. C float64
  38. E int64
  39. dtype: object

浮点数类型未改变。

  1. In [413]: dfa = df3.copy()
  2. In [414]: dfa['A'] = dfa['A'].astype('float32')
  3. In [415]: dfa.dtypes
  4. Out[415]:
  5. A float32
  6. B float64
  7. C float64
  8. dtype: object
  9. In [416]: casted = dfa[df2 > 0]
  10. In [417]: casted
  11. Out[417]:
  12. A B C
  13. 0 1.047606 0.256090 NaN
  14. 1 3.497968 1.426469 NaN
  15. 2 NaN NaN 255.0
  16. 3 NaN 1.139976 NaN
  17. 4 NaN NaN NaN
  18. 5 1.346426 0.096706 NaN
  19. 6 NaN NaN 1.0
  20. 7 NaN NaN NaN
  21. In [418]: casted.dtypes
  22. Out[418]:
  23. A float32
  24. B float64
  25. C float64
  26. dtype: object

2.14. 基于 dtype 选择列

select_dtypes() 方法基于 dtype 选择列。

首先,创建一个由多种数据类型组成的 DataFrame:

  1. In [419]: df = pd.DataFrame({'string': list('abc'),
  2. .....: 'int64': list(range(1, 4)),
  3. .....: 'uint8': np.arange(3, 6).astype('u1'),
  4. .....: 'float64': np.arange(4.0, 7.0),
  5. .....: 'bool1': [True, False, True],
  6. .....: 'bool2': [False, True, False],
  7. .....: 'dates': pd.date_range('now', periods=3),
  8. .....: 'category': pd.Series(list("ABC")).astype('category')})
  9. .....:
  10. In [420]: df['tdeltas'] = df.dates.diff()
  11. In [421]: df['uint64'] = np.arange(3, 6).astype('u8')
  12. In [422]: df['other_dates'] = pd.date_range('20130101', periods=3)
  13. In [423]: df['tz_aware_dates'] = pd.date_range('20130101', periods=3, tz='US/Eastern')
  14. In [424]: df
  15. Out[424]:
  16. string int64 uint8 float64 bool1 bool2 dates category tdeltas uint64 other_dates tz_aware_dates
  17. 0 a 1 3 4.0 True False 2019-08-22 15:49:01.870038 A NaT 3 2013-01-01 2013-01-01 00:00:00-05:00
  18. 1 b 2 4 5.0 False True 2019-08-23 15:49:01.870038 B 1 days 4 2013-01-02 2013-01-02 00:00:00-05:00
  19. 2 c 3 5 6.0 True False 2019-08-24 15:49:01.870038 C 1 days 5 2013-01-03 2013-01-03 00:00:00-05:00

该 DataFrame 的数据类型:

  1. In [425]: df.dtypes
  2. Out[425]:
  3. string object
  4. int64 int64
  5. uint8 uint8
  6. float64 float64
  7. bool1 bool
  8. bool2 bool
  9. dates datetime64[ns]
  10. category category
  11. tdeltas timedelta64[ns]
  12. uint64 uint64
  13. other_dates datetime64[ns]
  14. tz_aware_dates datetime64[ns, US/Eastern]
  15. dtype: object

select_dtypes() 有两个参数,includeexclude,用于实现“提取这些数据类型的列” (include)或 “提取不是这些数据类型的列”(exclude)。

选择 bool 型的列,示例如下:

  1. In [426]: df.select_dtypes(include=[bool])
  2. Out[426]:
  3. bool1 bool2
  4. 0 True False
  5. 1 False True
  6. 2 True False

该方法还支持输入 NumPy 数据类型的名称:

  1. In [427]: df.select_dtypes(include=['bool'])
  2. Out[427]:
  3. bool1 bool2
  4. 0 True False
  5. 1 False True
  6. 2 True False

select_dtypes() 还支持通用数据类型。

比如,选择所有数值型与布尔型的列,同时,排除无符号整数:

  1. In [428]: df.select_dtypes(include=['number', 'bool'], exclude=['unsignedinteger'])
  2. Out[428]:
  3. int64 float64 bool1 bool2 tdeltas
  4. 0 1 4.0 True False NaT
  5. 1 2 5.0 False True 1 days
  6. 2 3 6.0 True False 1 days

选择字符串型的列必须要用 object

  1. In [429]: df.select_dtypes(include=['object'])
  2. Out[429]:
  3. string
  4. 0 a
  5. 1 b
  6. 2 c

要查看 numpy.number 等通用 dtype 的所有子类型,可以定义一个函数,返回子类型树:

  1. In [430]: def subdtypes(dtype):
  2. .....: subs = dtype.__subclasses__()
  3. .....: if not subs:
  4. .....: return dtype
  5. .....: return [dtype, [subdtypes(dt) for dt in subs]]
  6. .....:

所有 NumPy 数据类型都是 numpy.generic 的子类:

  1. In [431]: subdtypes(np.generic)
  2. Out[431]:
  3. [numpy.generic,
  4. [[numpy.number,
  5. [[numpy.integer,
  6. [[numpy.signedinteger,
  7. [numpy.int8,
  8. numpy.int16,
  9. numpy.int32,
  10. numpy.int64,
  11. numpy.int64,
  12. numpy.timedelta64]],
  13. [numpy.unsignedinteger,
  14. [numpy.uint8,
  15. numpy.uint16,
  16. numpy.uint32,
  17. numpy.uint64,
  18. numpy.uint64]]]],
  19. [numpy.inexact,
  20. [[numpy.floating,
  21. [numpy.float16, numpy.float32, numpy.float64, numpy.float128]],
  22. [numpy.complexfloating,
  23. [numpy.complex64, numpy.complex128, numpy.complex256]]]]]],
  24. [numpy.flexible,
  25. [[numpy.character, [numpy.bytes_, numpy.str_]],
  26. [numpy.void, [numpy.record]]]],
  27. numpy.bool_,
  28. numpy.datetime64,
  29. numpy.object_]]

tip 注意: Pandas 支持 categorydatetime64[ns, tz] 类型,但这两种类型未整合到 NumPy 架构,因此,上面的函数没有显示。