索引和数据选择器

Pandas对象中的轴标记信息有多种用途:

  • 使用已知指标识别数据(即提供元数据),这对于分析,可视化和交互式控制台显示非常重要。
  • 启用自动和显式数据对齐。
  • 允许直观地获取和设置数据集的子集。

在本节中,我们将重点关注最后一点:即如何切片,切块,以及通常获取和设置pandas对象的子集。主要关注的是Series和DataFrame,因为他们在这个领域受到了更多的开发关注。

::: tip 注意

Python和NumPy索引运算符[]和属性运算符. 可以在各种用例中快速轻松地访问pandas数据结构。这使得交互式工作变得直观,因为如果您已经知道如何处理Python字典和NumPy数组,那么几乎没有新的东西需要学习。但是,由于预先不知道要访问的数据类型,因此直接使用标准运算符会有一些优化限制。对于生产代码,我们建议您利用本章中介绍的优化的pandas数据访问方法。

:::

::: danger 警告

是否为设置操作返回副本或引用可能取决于上下文。这有时被称为应该避免。请参阅返回视图与复制chained assignment

:::

::: danger 警告

使用浮点数对基于整数的索引进行索引已在0.18.0中进行了说明,有关更改的摘要,请参见此处

:::

多指标/高级索引MultiIndex和更先进的索引文件。

有关一些高级策略,请参阅食谱

索引的不同选择

对象选择已经有许多用户请求的添加,以支持更明确的基于位置的索引。Pandas现在支持三种类型的多轴索引。

  • .loc主要是基于标签的,但也可以与布尔数组一起使用。当找不到物品时.loc会提高KeyError。允许的输入是:

    • 单个标签,例如5'a'(注意,它5被解释为索引的 标签。此用法不是索引的整数位置。)。
    • 列表或标签数组。['a', 'b', 'c']
    • 带标签的切片对象'a':'f'(注意,相反普通的Python片,开始和停止都包括在内,当存在于索引中!见有标签切片端点都包括在内。)
    • 布尔数组
    • 一个callable带有一个参数的函数(调用Series或DataFrame)并返回有效的索引输出(上面的一个)。

      版本0.18.1中的新功能。

      标签选择中查看更多信息。

  • .iloc是基于主要的整数位置(从0length-1所述轴的),但也可以用布尔阵列使用。 如果请求的索引器超出范围,.iloc则会引发IndexError,但允许越界索引的切片索引器除外。(这符合Python / NumPy 切片 语义)。允许的输入是:

    • 一个整数,例如5
    • 整数列表或数组。[4, 3, 0]
    • 带有整数的切片对象1:7
    • 布尔数组。
    • 一个callable带有一个参数的函数(调用Series或DataFrame)并返回有效的索引输出(上面的一个)。

      版本0.18.1中的新功能。

      有关详细信息,请参阅按位置选择高级索引高级层次结构

  • .loc.iloc以及[]索引也可以接受一个callable索引器。在Select By Callable中查看更多信息。

从具有多轴选择的对象获取值使用以下表示法(使用.loc作为示例,但以下也适用.iloc)。任何轴访问器可以是空切片:。假设超出规范的轴是:,例如p.loc['a']相当于 。p.loc['a', :, :]

对象类型 索引
系列 s.loc[indexer]
数据帧 df.loc[row_indexer,column_indexer]

基础知识

正如在上一节中介绍数据结构时所提到的,索引的主要功能[](也就是__getitem__ 那些熟悉在Python中实现类行为的人)是选择低维切片。下表显示了使用以下方法索引pandas对象时的返回类型值[]

对象类型 选择 返回值类型
系列 series[label] 标量值
数据帧 frame[colname] Series 对应于colname

在这里,我们构建一个简单的时间序列数据集,用于说明索引功能:

  1. In [1]: dates = pd.date_range('1/1/2000', periods=8)
  2. In [2]: df = pd.DataFrame(np.random.randn(8, 4),
  3. ...: index=dates, columns=['A', 'B', 'C', 'D'])
  4. ...:
  5. In [3]: df
  6. Out[3]:
  7. A B C D
  8. 2000-01-01 0.469112 -0.282863 -1.509059 -1.135632
  9. 2000-01-02 1.212112 -0.173215 0.119209 -1.044236
  10. 2000-01-03 -0.861849 -2.104569 -0.494929 1.071804
  11. 2000-01-04 0.721555 -0.706771 -1.039575 0.271860
  12. 2000-01-05 -0.424972 0.567020 0.276232 -1.087401
  13. 2000-01-06 -0.673690 0.113648 -1.478427 0.524988
  14. 2000-01-07 0.404705 0.577046 -1.715002 -1.039268
  15. 2000-01-08 -0.370647 -1.157892 -1.344312 0.844885

::: tip 注意

除非特别说明,否则索引功能都不是时间序列特定的。

:::

因此,如上所述,我们使用最基本的索引[]

  1. In [4]: s = df['A']
  2. In [5]: s[dates[5]]
  3. Out[5]: -0.6736897080883706

您可以传递列表列表[]以按该顺序选择列。如果DataFrame中未包含列,则会引发异常。也可以这种方式设置多列:

  1. In [6]: df
  2. Out[6]:
  3. A B C D
  4. 2000-01-01 0.469112 -0.282863 -1.509059 -1.135632
  5. 2000-01-02 1.212112 -0.173215 0.119209 -1.044236
  6. 2000-01-03 -0.861849 -2.104569 -0.494929 1.071804
  7. 2000-01-04 0.721555 -0.706771 -1.039575 0.271860
  8. 2000-01-05 -0.424972 0.567020 0.276232 -1.087401
  9. 2000-01-06 -0.673690 0.113648 -1.478427 0.524988
  10. 2000-01-07 0.404705 0.577046 -1.715002 -1.039268
  11. 2000-01-08 -0.370647 -1.157892 -1.344312 0.844885
  12. In [7]: df[['B', 'A']] = df[['A', 'B']]
  13. In [8]: df
  14. Out[8]:
  15. A B C D
  16. 2000-01-01 -0.282863 0.469112 -1.509059 -1.135632
  17. 2000-01-02 -0.173215 1.212112 0.119209 -1.044236
  18. 2000-01-03 -2.104569 -0.861849 -0.494929 1.071804
  19. 2000-01-04 -0.706771 0.721555 -1.039575 0.271860
  20. 2000-01-05 0.567020 -0.424972 0.276232 -1.087401
  21. 2000-01-06 0.113648 -0.673690 -1.478427 0.524988
  22. 2000-01-07 0.577046 0.404705 -1.715002 -1.039268
  23. 2000-01-08 -1.157892 -0.370647 -1.344312 0.844885

您可能会发现这对于将变换(就地)应用于列的子集非常有用。

::: danger 警告

pandas在设置SeriesDataFrame来自.loc和时对齐所有AXES .iloc

不会修改,df因为列对齐在赋值之前。

  1. In [9]: df[['A', 'B']]
  2. Out[9]:
  3. A B
  4. 2000-01-01 -0.282863 0.469112
  5. 2000-01-02 -0.173215 1.212112
  6. 2000-01-03 -2.104569 -0.861849
  7. 2000-01-04 -0.706771 0.721555
  8. 2000-01-05 0.567020 -0.424972
  9. 2000-01-06 0.113648 -0.673690
  10. 2000-01-07 0.577046 0.404705
  11. 2000-01-08 -1.157892 -0.370647
  12. In [10]: df.loc[:, ['B', 'A']] = df[['A', 'B']]
  13. In [11]: df[['A', 'B']]
  14. Out[11]:
  15. A B
  16. 2000-01-01 -0.282863 0.469112
  17. 2000-01-02 -0.173215 1.212112
  18. 2000-01-03 -2.104569 -0.861849
  19. 2000-01-04 -0.706771 0.721555
  20. 2000-01-05 0.567020 -0.424972
  21. 2000-01-06 0.113648 -0.673690
  22. 2000-01-07 0.577046 0.404705
  23. 2000-01-08 -1.157892 -0.370647

交换列值的正确方法是使用原始值:

  1. In [12]: df.loc[:, ['B', 'A']] = df[['A', 'B']].to_numpy()
  2. In [13]: df[['A', 'B']]
  3. Out[13]:
  4. A B
  5. 2000-01-01 0.469112 -0.282863
  6. 2000-01-02 1.212112 -0.173215
  7. 2000-01-03 -0.861849 -2.104569
  8. 2000-01-04 0.721555 -0.706771
  9. 2000-01-05 -0.424972 0.567020
  10. 2000-01-06 -0.673690 0.113648
  11. 2000-01-07 0.404705 0.577046
  12. 2000-01-08 -0.370647 -1.157892

:::

属性访问

您可以直接访问某个Series或列上的索引DataFrame作为属性:

  1. In [14]: sa = pd.Series([1, 2, 3], index=list('abc'))
  2. In [15]: dfa = df.copy()
  1. In [16]: sa.b
  2. Out[16]: 2
  3. In [17]: dfa.A
  4. Out[17]:
  5. 2000-01-01 0.469112
  6. 2000-01-02 1.212112
  7. 2000-01-03 -0.861849
  8. 2000-01-04 0.721555
  9. 2000-01-05 -0.424972
  10. 2000-01-06 -0.673690
  11. 2000-01-07 0.404705
  12. 2000-01-08 -0.370647
  13. Freq: D, Name: A, dtype: float64
  1. In [18]: sa.a = 5
  2. In [19]: sa
  3. Out[19]:
  4. a 5
  5. b 2
  6. c 3
  7. dtype: int64
  8. In [20]: dfa.A = list(range(len(dfa.index))) # ok if A already exists
  9. In [21]: dfa
  10. Out[21]:
  11. A B C D
  12. 2000-01-01 0 -0.282863 -1.509059 -1.135632
  13. 2000-01-02 1 -0.173215 0.119209 -1.044236
  14. 2000-01-03 2 -2.104569 -0.494929 1.071804
  15. 2000-01-04 3 -0.706771 -1.039575 0.271860
  16. 2000-01-05 4 0.567020 0.276232 -1.087401
  17. 2000-01-06 5 0.113648 -1.478427 0.524988
  18. 2000-01-07 6 0.577046 -1.715002 -1.039268
  19. 2000-01-08 7 -1.157892 -1.344312 0.844885
  20. In [22]: dfa['A'] = list(range(len(dfa.index))) # use this form to create a new column
  21. In [23]: dfa
  22. Out[23]:
  23. A B C D
  24. 2000-01-01 0 -0.282863 -1.509059 -1.135632
  25. 2000-01-02 1 -0.173215 0.119209 -1.044236
  26. 2000-01-03 2 -2.104569 -0.494929 1.071804
  27. 2000-01-04 3 -0.706771 -1.039575 0.271860
  28. 2000-01-05 4 0.567020 0.276232 -1.087401
  29. 2000-01-06 5 0.113648 -1.478427 0.524988
  30. 2000-01-07 6 0.577046 -1.715002 -1.039268
  31. 2000-01-08 7 -1.157892 -1.344312 0.844885

::: danger 警告

  • 仅当index元素是有效的Python标识符时才可以使用此访问权限,例如s.1,不允许。有关有效标识符的说明,请参见此处
  • 如果该属性与现有方法名称冲突,则该属性将不可用,例如s.min,不允许。
  • 同样的,如果它与任何下面的列表冲突的属性将不可用:indexmajor_axisminor_axisitems
  • 在任何一种情况下,标准索引仍然可以工作,例如s['1']s['min']s['index']将访问相应的元素或列。

:::

如果您使用的是IPython环境,则还可以使用tab-completion来查看这些可访问的属性。

您还可以将a分配dict给一行DataFrame

  1. In [24]: x = pd.DataFrame({'x': [1, 2, 3], 'y': [3, 4, 5]})
  2. In [25]: x.iloc[1] = {'x': 9, 'y': 99}
  3. In [26]: x
  4. Out[26]:
  5. x y
  6. 0 1 3
  7. 1 9 99
  8. 2 3 5

您可以使用属性访问来修改DataFrame的Series或列的现有元素,但要小心; 如果您尝试使用属性访问权来创建新列,则会创建新属性而不是新列。在0.21.0及更高版本中,这将引发UserWarning

  1. In [1]: df = pd.DataFrame({'one': [1., 2., 3.]})
  2. In [2]: df.two = [4, 5, 6]
  3. UserWarning: Pandas doesn't allow Series to be assigned into nonexistent columns - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute_access
  4. In [3]: df
  5. Out[3]:
  6. one
  7. 0 1.0
  8. 1 2.0
  9. 2 3.0

切片范围

沿着任意轴切割范围的最稳健和一致的方法在详细说明该方法的“ 按位置选择”部分中描述.iloc。现在,我们解释使用[]运算符切片的语义。

使用Series,语法与ndarray完全一样,返回值的一部分和相应的标签:

  1. In [27]: s[:5]
  2. Out[27]:
  3. 2000-01-01 0.469112
  4. 2000-01-02 1.212112
  5. 2000-01-03 -0.861849
  6. 2000-01-04 0.721555
  7. 2000-01-05 -0.424972
  8. Freq: D, Name: A, dtype: float64
  9. In [28]: s[::2]
  10. Out[28]:
  11. 2000-01-01 0.469112
  12. 2000-01-03 -0.861849
  13. 2000-01-05 -0.424972
  14. 2000-01-07 0.404705
  15. Freq: 2D, Name: A, dtype: float64
  16. In [29]: s[::-1]
  17. Out[29]:
  18. 2000-01-08 -0.370647
  19. 2000-01-07 0.404705
  20. 2000-01-06 -0.673690
  21. 2000-01-05 -0.424972
  22. 2000-01-04 0.721555
  23. 2000-01-03 -0.861849
  24. 2000-01-02 1.212112
  25. 2000-01-01 0.469112
  26. Freq: -1D, Name: A, dtype: float64

请注意,设置也适用:

  1. In [30]: s2 = s.copy()
  2. In [31]: s2[:5] = 0
  3. In [32]: s2
  4. Out[32]:
  5. 2000-01-01 0.000000
  6. 2000-01-02 0.000000
  7. 2000-01-03 0.000000
  8. 2000-01-04 0.000000
  9. 2000-01-05 0.000000
  10. 2000-01-06 -0.673690
  11. 2000-01-07 0.404705
  12. 2000-01-08 -0.370647
  13. Freq: D, Name: A, dtype: float64

使用DataFrame,切片内部[] 切片。这主要是为了方便而提供的,因为它是如此常见的操作。

  1. In [33]: df[:3]
  2. Out[33]:
  3. A B C D
  4. 2000-01-01 0.469112 -0.282863 -1.509059 -1.135632
  5. 2000-01-02 1.212112 -0.173215 0.119209 -1.044236
  6. 2000-01-03 -0.861849 -2.104569 -0.494929 1.071804
  7. In [34]: df[::-1]
  8. Out[34]:
  9. A B C D
  10. 2000-01-08 -0.370647 -1.157892 -1.344312 0.844885
  11. 2000-01-07 0.404705 0.577046 -1.715002 -1.039268
  12. 2000-01-06 -0.673690 0.113648 -1.478427 0.524988
  13. 2000-01-05 -0.424972 0.567020 0.276232 -1.087401
  14. 2000-01-04 0.721555 -0.706771 -1.039575 0.271860
  15. 2000-01-03 -0.861849 -2.104569 -0.494929 1.071804
  16. 2000-01-02 1.212112 -0.173215 0.119209 -1.044236
  17. 2000-01-01 0.469112 -0.282863 -1.509059 -1.135632

按标签选择

::: danger 警告

是否为设置操作返回副本或引用可能取决于上下文。这有时被称为应该避免。请参阅返回视图与复制chained assignment

:::

::: danger 警告

  1. In [35]: dfl = pd.DataFrame(np.random.randn(5, 4),
  2. ....: columns=list('ABCD'),
  3. ....: index=pd.date_range('20130101', periods=5))
  4. ....:
  5. In [36]: dfl
  6. Out[36]:
  7. A B C D
  8. 2013-01-01 1.075770 -0.109050 1.643563 -1.469388
  9. 2013-01-02 0.357021 -0.674600 -1.776904 -0.968914
  10. 2013-01-03 -1.294524 0.413738 0.276662 -0.472035
  11. 2013-01-04 -0.013960 -0.362543 -0.006154 -0.923061
  12. 2013-01-05 0.895717 0.805244 -1.206412 2.565646
  1. In [4]: dfl.loc[2:3]
  2. TypeError: cannot do slice indexing on <class 'pandas.tseries.index.DatetimeIndex'> with these indexers [2] of <type 'int'>

切片中的字符串喜欢可以转换为索引的类型并导致自然切片。

  1. In [37]: dfl.loc['20130102':'20130104']
  2. Out[37]:
  3. A B C D
  4. 2013-01-02 0.357021 -0.674600 -1.776904 -0.968914
  5. 2013-01-03 -1.294524 0.413738 0.276662 -0.472035
  6. 2013-01-04 -0.013960 -0.362543 -0.006154 -0.923061

:::

::: danger 警告

从0.21.0开始,pandas将显示FutureWarning带有缺少标签的列表的if索引。将来这会提高一个KeyError。请参阅list-like使用列表中缺少键的loc是不推荐使用

:::

pandas提供了一套方法,以便拥有纯粹基于标签的索引。这是一个严格的包含协议。要求的每个标签必须在索引中,否则KeyError将被提出。切片时,如果索引中存在,则包括起始绑定停止边界。整数是有效标签,但它们是指标签而不是位置**

.loc属性是主要访问方法。以下是有效输入:

  • 单个标签,例如5'a'(注意,它5被解释为索引的标签。此用法不是索引的整数位置。)。
  • 列表或标签数组。['a', 'b', 'c']
  • 带有标签的切片对象'a':'f'(注意,与通常的python切片相反,包括起始和停止,当存在于索引中时!请参见切片标签
  • 布尔数组。
  • A callable,参见按可调用选择
  1. In [38]: s1 = pd.Series(np.random.randn(6), index=list('abcdef'))
  2. In [39]: s1
  3. Out[39]:
  4. a 1.431256
  5. b 1.340309
  6. c -1.170299
  7. d -0.226169
  8. e 0.410835
  9. f 0.813850
  10. dtype: float64
  11. In [40]: s1.loc['c':]
  12. Out[40]:
  13. c -1.170299
  14. d -0.226169
  15. e 0.410835
  16. f 0.813850
  17. dtype: float64
  18. In [41]: s1.loc['b']
  19. Out[41]: 1.3403088497993827

请注意,设置也适用:

  1. In [42]: s1.loc['c':] = 0
  2. In [43]: s1
  3. Out[43]:
  4. a 1.431256
  5. b 1.340309
  6. c 0.000000
  7. d 0.000000
  8. e 0.000000
  9. f 0.000000
  10. dtype: float64

使用DataFrame:

  1. In [44]: df1 = pd.DataFrame(np.random.randn(6, 4),
  2. ....: index=list('abcdef'),
  3. ....: columns=list('ABCD'))
  4. ....:
  5. In [45]: df1
  6. Out[45]:
  7. A B C D
  8. a 0.132003 -0.827317 -0.076467 -1.187678
  9. b 1.130127 -1.436737 -1.413681 1.607920
  10. c 1.024180 0.569605 0.875906 -2.211372
  11. d 0.974466 -2.006747 -0.410001 -0.078638
  12. e 0.545952 -1.219217 -1.226825 0.769804
  13. f -1.281247 -0.727707 -0.121306 -0.097883
  14. In [46]: df1.loc[['a', 'b', 'd'], :]
  15. Out[46]:
  16. A B C D
  17. a 0.132003 -0.827317 -0.076467 -1.187678
  18. b 1.130127 -1.436737 -1.413681 1.607920
  19. d 0.974466 -2.006747 -0.410001 -0.078638

通过标签切片访问:

  1. In [47]: df1.loc['d':, 'A':'C']
  2. Out[47]:
  3. A B C
  4. d 0.974466 -2.006747 -0.410001
  5. e 0.545952 -1.219217 -1.226825
  6. f -1.281247 -0.727707 -0.121306

使用标签获取横截面(相当于df.xs('a')):

  1. In [48]: df1.loc['a']
  2. Out[48]:
  3. A 0.132003
  4. B -0.827317
  5. C -0.076467
  6. D -1.187678
  7. Name: a, dtype: float64

要使用布尔数组获取值:

  1. In [49]: df1.loc['a'] > 0
  2. Out[49]:
  3. A True
  4. B False
  5. C False
  6. D False
  7. Name: a, dtype: bool
  8. In [50]: df1.loc[:, df1.loc['a'] > 0]
  9. Out[50]:
  10. A
  11. a 0.132003
  12. b 1.130127
  13. c 1.024180
  14. d 0.974466
  15. e 0.545952
  16. f -1.281247

要明确获取值(相当于已弃用df.get_value('a','A')):

  1. # this is also equivalent to ``df1.at['a','A']``
  2. In [51]: df1.loc['a', 'A']
  3. Out[51]: 0.13200317033032932

用标签切片

使用.loc切片时,如果索引中存在开始和停止标签,则返回位于两者之间的元素(包括它们):

  1. In [52]: s = pd.Series(list('abcde'), index=[0, 3, 2, 5, 4])
  2. In [53]: s.loc[3:5]
  3. Out[53]:
  4. 3 b
  5. 2 c
  6. 5 d
  7. dtype: object

如果两个中至少有一个不存在,但索引已排序,并且可以与开始和停止标签进行比较,那么通过选择在两者之间排名的标签,切片仍将按预期工作:

  1. In [54]: s.sort_index()
  2. Out[54]:
  3. 0 a
  4. 2 c
  5. 3 b
  6. 4 e
  7. 5 d
  8. dtype: object
  9. In [55]: s.sort_index().loc[1:6]
  10. Out[55]:
  11. 2 c
  12. 3 b
  13. 4 e
  14. 5 d
  15. dtype: object

然而,如果两个中的至少一个不存在并且索引未被排序,则将引发错误(因为否则将是计算上昂贵的,并且对于混合类型索引可能是模糊的)。例如,在上面的例子中,s.loc[1:6]会提高KeyError

有关此行为背后的基本原理,请参阅 端点包含

按位置选择

::: danger 警告

是否为设置操作返回副本或引用可能取决于上下文。这有时被称为应该避免。请参阅返回视图与复制chained assignment

:::

Pandas提供了一套方法,以获得纯粹基于整数的索引。语义紧跟Python和NumPy切片。这些是0-based索引。切片时,所结合的开始被包括,而上限是排除。尝试使用非整数,甚至是有效的标签都会引发一个问题IndexError

.iloc属性是主要访问方法。以下是有效输入:

  • 一个整数,例如5
  • 整数列表或数组。[4, 3, 0]
  • 带有整数的切片对象1:7
  • 布尔数组。
  • A callable,参见按可调用选择
  1. In [56]: s1 = pd.Series(np.random.randn(5), index=list(range(0, 10, 2)))
  2. In [57]: s1
  3. Out[57]:
  4. 0 0.695775
  5. 2 0.341734
  6. 4 0.959726
  7. 6 -1.110336
  8. 8 -0.619976
  9. dtype: float64
  10. In [58]: s1.iloc[:3]
  11. Out[58]:
  12. 0 0.695775
  13. 2 0.341734
  14. 4 0.959726
  15. dtype: float64
  16. In [59]: s1.iloc[3]
  17. Out[59]: -1.110336102891167

请注意,设置也适用:

  1. In [60]: s1.iloc[:3] = 0
  2. In [61]: s1
  3. Out[61]:
  4. 0 0.000000
  5. 2 0.000000
  6. 4 0.000000
  7. 6 -1.110336
  8. 8 -0.619976
  9. dtype: float64

使用DataFrame:

  1. In [62]: df1 = pd.DataFrame(np.random.randn(6, 4),
  2. ....: index=list(range(0, 12, 2)),
  3. ....: columns=list(range(0, 8, 2)))
  4. ....:
  5. In [63]: df1
  6. Out[63]:
  7. 0 2 4 6
  8. 0 0.149748 -0.732339 0.687738 0.176444
  9. 2 0.403310 -0.154951 0.301624 -2.179861
  10. 4 -1.369849 -0.954208 1.462696 -1.743161
  11. 6 -0.826591 -0.345352 1.314232 0.690579
  12. 8 0.995761 2.396780 0.014871 3.357427
  13. 10 -0.317441 -1.236269 0.896171 -0.487602

通过整数切片选择:

  1. In [64]: df1.iloc[:3]
  2. Out[64]:
  3. 0 2 4 6
  4. 0 0.149748 -0.732339 0.687738 0.176444
  5. 2 0.403310 -0.154951 0.301624 -2.179861
  6. 4 -1.369849 -0.954208 1.462696 -1.743161
  7. In [65]: df1.iloc[1:5, 2:4]
  8. Out[65]:
  9. 4 6
  10. 2 0.301624 -2.179861
  11. 4 1.462696 -1.743161
  12. 6 1.314232 0.690579
  13. 8 0.014871 3.357427

通过整数列表选择:

  1. In [66]: df1.iloc[[1, 3, 5], [1, 3]]
  2. Out[66]:
  3. 2 6
  4. 2 -0.154951 -2.179861
  5. 6 -0.345352 0.690579
  6. 10 -1.236269 -0.487602
  1. In [67]: df1.iloc[1:3, :]
  2. Out[67]:
  3. 0 2 4 6
  4. 2 0.403310 -0.154951 0.301624 -2.179861
  5. 4 -1.369849 -0.954208 1.462696 -1.743161
  1. In [68]: df1.iloc[:, 1:3]
  2. Out[68]:
  3. 2 4
  4. 0 -0.732339 0.687738
  5. 2 -0.154951 0.301624
  6. 4 -0.954208 1.462696
  7. 6 -0.345352 1.314232
  8. 8 2.396780 0.014871
  9. 10 -1.236269 0.896171
  1. # this is also equivalent to ``df1.iat[1,1]``
  2. In [69]: df1.iloc[1, 1]
  3. Out[69]: -0.1549507744249032

使用整数位置(等效df.xs(1))得到横截面:

  1. In [70]: df1.iloc[1]
  2. Out[70]:
  3. 0 0.403310
  4. 2 -0.154951
  5. 4 0.301624
  6. 6 -2.179861
  7. Name: 2, dtype: float64

超出范围的切片索引正如Python / Numpy中一样优雅地处理。

  1. # these are allowed in python/numpy.
  2. In [71]: x = list('abcdef')
  3. In [72]: x
  4. Out[72]: ['a', 'b', 'c', 'd', 'e', 'f']
  5. In [73]: x[4:10]
  6. Out[73]: ['e', 'f']
  7. In [74]: x[8:10]
  8. Out[74]: []
  9. In [75]: s = pd.Series(x)
  10. In [76]: s
  11. Out[76]:
  12. 0 a
  13. 1 b
  14. 2 c
  15. 3 d
  16. 4 e
  17. 5 f
  18. dtype: object
  19. In [77]: s.iloc[4:10]
  20. Out[77]:
  21. 4 e
  22. 5 f
  23. dtype: object
  24. In [78]: s.iloc[8:10]
  25. Out[78]: Series([], dtype: object)

请注意,使用超出边界的切片可能会导致空轴(例如,返回一个空的DataFrame)。

  1. In [79]: dfl = pd.DataFrame(np.random.randn(5, 2), columns=list('AB'))
  2. In [80]: dfl
  3. Out[80]:
  4. A B
  5. 0 -0.082240 -2.182937
  6. 1 0.380396 0.084844
  7. 2 0.432390 1.519970
  8. 3 -0.493662 0.600178
  9. 4 0.274230 0.132885
  10. In [81]: dfl.iloc[:, 2:3]
  11. Out[81]:
  12. Empty DataFrame
  13. Columns: []
  14. Index: [0, 1, 2, 3, 4]
  15. In [82]: dfl.iloc[:, 1:3]
  16. Out[82]:
  17. B
  18. 0 -2.182937
  19. 1 0.084844
  20. 2 1.519970
  21. 3 0.600178
  22. 4 0.132885
  23. In [83]: dfl.iloc[4:6]
  24. Out[83]:
  25. A B
  26. 4 0.27423 0.132885

一个超出范围的索引器会引发一个IndexError。任何元素超出范围的索引器列表都会引发 IndexError

  1. >>> dfl.iloc[[4, 5, 6]]
  2. IndexError: positional indexers are out-of-bounds
  3. >>> dfl.iloc[:, 4]
  4. IndexError: single positional indexer is out-of-bounds

通过可调用选择

版本0.18.1中的新功能。

.loc.iloc以及[]索引也可以接受一个callable索引器。在callable必须与一个参数(调用系列或数据帧)返回的有效输出索引功能。

  1. In [84]: df1 = pd.DataFrame(np.random.randn(6, 4),
  2. ....: index=list('abcdef'),
  3. ....: columns=list('ABCD'))
  4. ....:
  5. In [85]: df1
  6. Out[85]:
  7. A B C D
  8. a -0.023688 2.410179 1.450520 0.206053
  9. b -0.251905 -2.213588 1.063327 1.266143
  10. c 0.299368 -0.863838 0.408204 -1.048089
  11. d -0.025747 -0.988387 0.094055 1.262731
  12. e 1.289997 0.082423 -0.055758 0.536580
  13. f -0.489682 0.369374 -0.034571 -2.484478
  14. In [86]: df1.loc[lambda df: df.A > 0, :]
  15. Out[86]:
  16. A B C D
  17. c 0.299368 -0.863838 0.408204 -1.048089
  18. e 1.289997 0.082423 -0.055758 0.536580
  19. In [87]: df1.loc[:, lambda df: ['A', 'B']]
  20. Out[87]:
  21. A B
  22. a -0.023688 2.410179
  23. b -0.251905 -2.213588
  24. c 0.299368 -0.863838
  25. d -0.025747 -0.988387
  26. e 1.289997 0.082423
  27. f -0.489682 0.369374
  28. In [88]: df1.iloc[:, lambda df: [0, 1]]
  29. Out[88]:
  30. A B
  31. a -0.023688 2.410179
  32. b -0.251905 -2.213588
  33. c 0.299368 -0.863838
  34. d -0.025747 -0.988387
  35. e 1.289997 0.082423
  36. f -0.489682 0.369374
  37. In [89]: df1[lambda df: df.columns[0]]
  38. Out[89]:
  39. a -0.023688
  40. b -0.251905
  41. c 0.299368
  42. d -0.025747
  43. e 1.289997
  44. f -0.489682
  45. Name: A, dtype: float64

您可以使用可调用索引Series

  1. In [90]: df1.A.loc[lambda s: s > 0]
  2. Out[90]:
  3. c 0.299368
  4. e 1.289997
  5. Name: A, dtype: float64

使用这些方法/索引器,您可以在不使用临时变量的情况下链接数据选择操作。

  1. In [91]: bb = pd.read_csv('data/baseball.csv', index_col='id')
  2. In [92]: (bb.groupby(['year', 'team']).sum()
  3. ....: .loc[lambda df: df.r > 100])
  4. ....:
  5. Out[92]:
  6. stint g ab r h X2b X3b hr rbi sb cs bb so ibb hbp sh sf gidp
  7. year team
  8. 2007 CIN 6 379 745 101 203 35 2 36 125.0 10.0 1.0 105 127.0 14.0 1.0 1.0 15.0 18.0
  9. DET 5 301 1062 162 283 54 4 37 144.0 24.0 7.0 97 176.0 3.0 10.0 4.0 8.0 28.0
  10. HOU 4 311 926 109 218 47 6 14 77.0 10.0 4.0 60 212.0 3.0 9.0 16.0 6.0 17.0
  11. LAN 11 413 1021 153 293 61 3 36 154.0 7.0 5.0 114 141.0 8.0 9.0 3.0 8.0 29.0
  12. NYN 13 622 1854 240 509 101 3 61 243.0 22.0 4.0 174 310.0 24.0 23.0 18.0 15.0 48.0
  13. SFN 5 482 1305 198 337 67 6 40 171.0 26.0 7.0 235 188.0 51.0 8.0 16.0 6.0 41.0
  14. TEX 2 198 729 115 200 40 4 28 115.0 21.0 4.0 73 140.0 4.0 5.0 2.0 8.0 16.0
  15. TOR 4 459 1408 187 378 96 2 58 223.0 4.0 2.0 190 265.0 16.0 12.0 4.0 16.0 38.0

不推荐使用IX索引器

::: danger 警告

在0.20.0开始,.ix索引器已被弃用,赞成更加严格.iloc.loc索引。

:::

.ix在推断用户想要做的事情上提供了很多魔力。也就是说,.ix可以根据索引的数据类型决定按位置或通过标签进行索引。多年来,这引起了相当多的用户混淆。

建议的索引方法是:

  • .loc如果你想标记索引。
  • .iloc如果你想要定位索引。
  1. In [93]: dfd = pd.DataFrame({'A': [1, 2, 3],
  2. ....: 'B': [4, 5, 6]},
  3. ....: index=list('abc'))
  4. ....:
  5. In [94]: dfd
  6. Out[94]:
  7. A B
  8. a 1 4
  9. b 2 5
  10. c 3 6

以前的行为,您希望从“A”列中获取索引中的第0个和第2个元素。

  1. In [3]: dfd.ix[[0, 2], 'A']
  2. Out[3]:
  3. a 1
  4. c 3
  5. Name: A, dtype: int64

.loc。这里我们将从索引中选择适当的索引,然后使用标签索引。

  1. In [95]: dfd.loc[dfd.index[[0, 2]], 'A']
  2. Out[95]:
  3. a 1
  4. c 3
  5. Name: A, dtype: int64

这也可以.iloc通过在索引器上显式获取位置,并使用 位置索引来选择事物来表达。

  1. In [96]: dfd.iloc[[0, 2], dfd.columns.get_loc('A')]
  2. Out[96]:
  3. a 1
  4. c 3
  5. Name: A, dtype: int64

要获得多个索引器,请使用.get_indexer

  1. In [97]: dfd.iloc[[0, 2], dfd.columns.get_indexer(['A', 'B'])]
  2. Out[97]:
  3. A B
  4. a 1 4
  5. c 3 6

不推荐使用缺少标签的列表进行索引

::: danger 警告

从0.21.0开始,使用.loc[]包含一个或多个缺少标签的列表,不赞成使用.reindex

:::

在以前的版本中,.loc[list-of-labels]只要找到至少1个密钥,使用就可以工作(否则会引起a KeyError)。不推荐使用此行为,并将显示指向此部分的警告消息。推荐的替代方案是使用.reindex()

例如。

  1. In [98]: s = pd.Series([1, 2, 3])
  2. In [99]: s
  3. Out[99]:
  4. 0 1
  5. 1 2
  6. 2 3
  7. dtype: int64

找到所有键的选择保持不变。

  1. In [100]: s.loc[[1, 2]]
  2. Out[100]:
  3. 1 2
  4. 2 3
  5. dtype: int64

以前的行为

  1. In [4]: s.loc[[1, 2, 3]]
  2. Out[4]:
  3. 1 2.0
  4. 2 3.0
  5. 3 NaN
  6. dtype: float64

目前的行为

  1. In [4]: s.loc[[1, 2, 3]]
  2. Passing list-likes to .loc with any non-matching elements will raise
  3. KeyError in the future, you can use .reindex() as an alternative.
  4. See the documentation here:
  5. http://pandas.pydata.org/pandas-docs/stable/indexing.html#deprecate-loc-reindex-listlike
  6. Out[4]:
  7. 1 2.0
  8. 2 3.0
  9. 3 NaN
  10. dtype: float64

重新索引

实现选择潜在的未找到元素的惯用方法是通过.reindex()。另请参阅重建索引部分。

  1. In [101]: s.reindex([1, 2, 3])
  2. Out[101]:
  3. 1 2.0
  4. 2 3.0
  5. 3 NaN
  6. dtype: float64

或者,如果您只想选择有效的密钥,则以下是惯用且有效的; 保证保留选择的dtype。

  1. In [102]: labels = [1, 2, 3]
  2. In [103]: s.loc[s.index.intersection(labels)]
  3. Out[103]:
  4. 1 2
  5. 2 3
  6. dtype: int64

拥有重复索引会引发.reindex()

  1. In [104]: s = pd.Series(np.arange(4), index=['a', 'a', 'b', 'c'])
  2. In [105]: labels = ['c', 'd']
  1. In [17]: s.reindex(labels)
  2. ValueError: cannot reindex from a duplicate axis

通常,您可以将所需标签与当前轴相交,然后重新索引。

  1. In [106]: s.loc[s.index.intersection(labels)].reindex(labels)
  2. Out[106]:
  3. c 3.0
  4. d NaN
  5. dtype: float64

但是,如果生成的索引重复,这仍然会提高。

  1. In [41]: labels = ['a', 'd']
  2. In [42]: s.loc[s.index.intersection(labels)].reindex(labels)
  3. ValueError: cannot reindex from a duplicate axis

选择随机样本

使用该sample()方法随机选择Series或DataFrame中的行或列。默认情况下,该方法将对行进行采样,并接受要返回的特定行数/列数或一小部分行。

  1. In [107]: s = pd.Series([0, 1, 2, 3, 4, 5])
  2. # When no arguments are passed, returns 1 row.
  3. In [108]: s.sample()
  4. Out[108]:
  5. 4 4
  6. dtype: int64
  7. # One may specify either a number of rows:
  8. In [109]: s.sample(n=3)
  9. Out[109]:
  10. 0 0
  11. 4 4
  12. 1 1
  13. dtype: int64
  14. # Or a fraction of the rows:
  15. In [110]: s.sample(frac=0.5)
  16. Out[110]:
  17. 5 5
  18. 3 3
  19. 1 1
  20. dtype: int64

默认情况下,sample最多会返回每行一次,但也可以使用以下replace选项进行替换:

  1. In [111]: s = pd.Series([0, 1, 2, 3, 4, 5])
  2. # Without replacement (default):
  3. In [112]: s.sample(n=6, replace=False)
  4. Out[112]:
  5. 0 0
  6. 1 1
  7. 5 5
  8. 3 3
  9. 2 2
  10. 4 4
  11. dtype: int64
  12. # With replacement:
  13. In [113]: s.sample(n=6, replace=True)
  14. Out[113]:
  15. 0 0
  16. 4 4
  17. 3 3
  18. 2 2
  19. 4 4
  20. 4 4
  21. dtype: int64

默认情况下,每行具有相同的选择概率,但如果您希望行具有不同的概率,则可以将sample函数采样权重作为 weights。这些权重可以是列表,NumPy数组或系列,但它们的长度必须与您采样的对象的长度相同。缺失的值将被视为零的权重,并且不允许使用inf值。如果权重不总和为1,则通过将所有权重除以权重之和来对它们进行重新规范化。例如:

  1. In [114]: s = pd.Series([0, 1, 2, 3, 4, 5])
  2. In [115]: example_weights = [0, 0, 0.2, 0.2, 0.2, 0.4]
  3. In [116]: s.sample(n=3, weights=example_weights)
  4. Out[116]:
  5. 5 5
  6. 4 4
  7. 3 3
  8. dtype: int64
  9. # Weights will be re-normalized automatically
  10. In [117]: example_weights2 = [0.5, 0, 0, 0, 0, 0]
  11. In [118]: s.sample(n=1, weights=example_weights2)
  12. Out[118]:
  13. 0 0
  14. dtype: int64

应用于DataFrame时,只需将列的名称作为字符串传递,就可以使用DataFrame的列作为采样权重(假设您要对行而不是列进行采样)。

  1. In [119]: df2 = pd.DataFrame({'col1': [9, 8, 7, 6],
  2. .....: 'weight_column': [0.5, 0.4, 0.1, 0]})
  3. .....:
  4. In [120]: df2.sample(n=3, weights='weight_column')
  5. Out[120]:
  6. col1 weight_column
  7. 1 8 0.4
  8. 0 9 0.5
  9. 2 7 0.1

sample还允许用户使用axis参数对列而不是行进行采样。

  1. In [121]: df3 = pd.DataFrame({'col1': [1, 2, 3], 'col2': [2, 3, 4]})
  2. In [122]: df3.sample(n=1, axis=1)
  3. Out[122]:
  4. col1
  5. 0 1
  6. 1 2
  7. 2 3

最后,还可以sample使用random_state参数为随机数生成器设置种子,该参数将接受整数(作为种子)或NumPy RandomState对象。

  1. In [123]: df4 = pd.DataFrame({'col1': [1, 2, 3], 'col2': [2, 3, 4]})
  2. # With a given seed, the sample will always draw the same rows.
  3. In [124]: df4.sample(n=2, random_state=2)
  4. Out[124]:
  5. col1 col2
  6. 2 3 4
  7. 1 2 3
  8. In [125]: df4.sample(n=2, random_state=2)
  9. Out[125]:
  10. col1 col2
  11. 2 3 4
  12. 1 2 3

用放大设定

.loc/[]当为该轴设置不存在的键时,操作可以执行放大。

在这种Series情况下,这实际上是一种附加操作。

  1. In [126]: se = pd.Series([1, 2, 3])
  2. In [127]: se
  3. Out[127]:
  4. 0 1
  5. 1 2
  6. 2 3
  7. dtype: int64
  8. In [128]: se[5] = 5.
  9. In [129]: se
  10. Out[129]:
  11. 0 1.0
  12. 1 2.0
  13. 2 3.0
  14. 5 5.0
  15. dtype: float64

A DataFrame可以在任一轴上放大.loc

  1. In [130]: dfi = pd.DataFrame(np.arange(6).reshape(3, 2),
  2. .....: columns=['A', 'B'])
  3. .....:
  4. In [131]: dfi
  5. Out[131]:
  6. A B
  7. 0 0 1
  8. 1 2 3
  9. 2 4 5
  10. In [132]: dfi.loc[:, 'C'] = dfi.loc[:, 'A']
  11. In [133]: dfi
  12. Out[133]:
  13. A B C
  14. 0 0 1 0
  15. 1 2 3 2
  16. 2 4 5 4

这就像是一个append操作DataFrame

  1. In [134]: dfi.loc[3] = 5
  2. In [135]: dfi
  3. Out[135]:
  4. A B C
  5. 0 0 1 0
  6. 1 2 3 2
  7. 2 4 5 4
  8. 3 5 5 5

快速标量值获取和设置

因为索引[]必须处理很多情况(单标签访问,切片,布尔索引等),所以它有一些开销以便弄清楚你要求的是什么。如果您只想访问标量值,最快的方法是使用在所有数据结构上实现的atiat方法。

与之类似locat提供基于标签的标量查找,同时iat提供类似于基于整数的查找iloc

  1. In [136]: s.iat[5]
  2. Out[136]: 5
  3. In [137]: df.at[dates[5], 'A']
  4. Out[137]: -0.6736897080883706
  5. In [138]: df.iat[3, 0]
  6. Out[138]: 0.7215551622443669

您也可以使用这些相同的索引器进行设置。

  1. In [139]: df.at[dates[5], 'E'] = 7
  2. In [140]: df.iat[3, 0] = 7

at 如果索引器丢失,可以如上所述放大对象。

  1. In [141]: df.at[dates[-1] + pd.Timedelta('1 day'), 0] = 7
  2. In [142]: df
  3. Out[142]:
  4. A B C D E 0
  5. 2000-01-01 0.469112 -0.282863 -1.509059 -1.135632 NaN NaN
  6. 2000-01-02 1.212112 -0.173215 0.119209 -1.044236 NaN NaN
  7. 2000-01-03 -0.861849 -2.104569 -0.494929 1.071804 NaN NaN
  8. 2000-01-04 7.000000 -0.706771 -1.039575 0.271860 NaN NaN
  9. 2000-01-05 -0.424972 0.567020 0.276232 -1.087401 NaN NaN
  10. 2000-01-06 -0.673690 0.113648 -1.478427 0.524988 7.0 NaN
  11. 2000-01-07 0.404705 0.577046 -1.715002 -1.039268 NaN NaN
  12. 2000-01-08 -0.370647 -1.157892 -1.344312 0.844885 NaN NaN
  13. 2000-01-09 NaN NaN NaN NaN NaN 7.0

布尔索引

另一种常见操作是使用布尔向量来过滤数据。运营商是:|for or&for and~for not必须使用括号对这些进行分组,因为默认情况下,Python将评估表达式,例如as ,而期望的评估顺序是 。df.A > 2 & df.B < 3````df.A > (2 & df.B) < 3````(df.A > 2) & (df.B < 3)

使用布尔向量索引系列的工作方式与NumPy ndarray完全相同:

  1. In [143]: s = pd.Series(range(-3, 4))
  2. In [144]: s
  3. Out[144]:
  4. 0 -3
  5. 1 -2
  6. 2 -1
  7. 3 0
  8. 4 1
  9. 5 2
  10. 6 3
  11. dtype: int64
  12. In [145]: s[s > 0]
  13. Out[145]:
  14. 4 1
  15. 5 2
  16. 6 3
  17. dtype: int64
  18. In [146]: s[(s < -1) | (s > 0.5)]
  19. Out[146]:
  20. 0 -3
  21. 1 -2
  22. 4 1
  23. 5 2
  24. 6 3
  25. dtype: int64
  26. In [147]: s[~(s < 0)]
  27. Out[147]:
  28. 3 0
  29. 4 1
  30. 5 2
  31. 6 3
  32. dtype: int64

您可以使用与DataFrame索引长度相同的布尔向量从DataFrame中选择行(例如,从DataFrame的其中一列派生的东西):

  1. In [148]: df[df['A'] > 0]
  2. Out[148]:
  3. A B C D E 0
  4. 2000-01-01 0.469112 -0.282863 -1.509059 -1.135632 NaN NaN
  5. 2000-01-02 1.212112 -0.173215 0.119209 -1.044236 NaN NaN
  6. 2000-01-04 7.000000 -0.706771 -1.039575 0.271860 NaN NaN
  7. 2000-01-07 0.404705 0.577046 -1.715002 -1.039268 NaN NaN

列表推导和map系列方法也可用于产生更复杂的标准:

  1. In [149]: df2 = pd.DataFrame({'a': ['one', 'one', 'two', 'three', 'two', 'one', 'six'],
  2. .....: 'b': ['x', 'y', 'y', 'x', 'y', 'x', 'x'],
  3. .....: 'c': np.random.randn(7)})
  4. .....:
  5. # only want 'two' or 'three'
  6. In [150]: criterion = df2['a'].map(lambda x: x.startswith('t'))
  7. In [151]: df2[criterion]
  8. Out[151]:
  9. a b c
  10. 2 two y 0.041290
  11. 3 three x 0.361719
  12. 4 two y -0.238075
  13. # equivalent but slower
  14. In [152]: df2[[x.startswith('t') for x in df2['a']]]
  15. Out[152]:
  16. a b c
  17. 2 two y 0.041290
  18. 3 three x 0.361719
  19. 4 two y -0.238075
  20. # Multiple criteria
  21. In [153]: df2[criterion & (df2['b'] == 'x')]
  22. Out[153]:
  23. a b c
  24. 3 three x 0.361719

随着选择方法通过标签选择通过位置选择高级索引,你可以沿着使用布尔向量与其他索引表达式中组合选择多个轴。

  1. In [154]: df2.loc[criterion & (df2['b'] == 'x'), 'b':'c']
  2. Out[154]:
  3. b c
  4. 3 x 0.361719

使用isin进行索引

考虑一下isin()方法Series,该方法返回一个布尔向量,只要Series元素存在于传递列表中,该向量就为真。这允许您选择一列或多列具有所需值的行:

  1. In [155]: s = pd.Series(np.arange(5), index=np.arange(5)[::-1], dtype='int64')
  2. In [156]: s
  3. Out[156]:
  4. 4 0
  5. 3 1
  6. 2 2
  7. 1 3
  8. 0 4
  9. dtype: int64
  10. In [157]: s.isin([2, 4, 6])
  11. Out[157]:
  12. 4 False
  13. 3 False
  14. 2 True
  15. 1 False
  16. 0 True
  17. dtype: bool
  18. In [158]: s[s.isin([2, 4, 6])]
  19. Out[158]:
  20. 2 2
  21. 0 4
  22. dtype: int64

Index对象可以使用相同的方法,当您不知道哪些搜索标签实际存在时,它们非常有用:

  1. In [159]: s[s.index.isin([2, 4, 6])]
  2. Out[159]:
  3. 4 0
  4. 2 2
  5. dtype: int64
  6. # compare it to the following
  7. In [160]: s.reindex([2, 4, 6])
  8. Out[160]:
  9. 2 2.0
  10. 4 0.0
  11. 6 NaN
  12. dtype: float64

除此之外,还MultiIndex允许选择在成员资格检查中使用的单独级别:

  1. In [161]: s_mi = pd.Series(np.arange(6),
  2. .....: index=pd.MultiIndex.from_product([[0, 1], ['a', 'b', 'c']]))
  3. .....:
  4. In [162]: s_mi
  5. Out[162]:
  6. 0 a 0
  7. b 1
  8. c 2
  9. 1 a 3
  10. b 4
  11. c 5
  12. dtype: int64
  13. In [163]: s_mi.iloc[s_mi.index.isin([(1, 'a'), (2, 'b'), (0, 'c')])]
  14. Out[163]:
  15. 0 c 2
  16. 1 a 3
  17. dtype: int64
  18. In [164]: s_mi.iloc[s_mi.index.isin(['a', 'c', 'e'], level=1)]
  19. Out[164]:
  20. 0 a 0
  21. c 2
  22. 1 a 3
  23. c 5
  24. dtype: int64

DataFrame也有一个isin()方法。调用时isin,将一组值作为数组或字典传递。如果values是一个数组,则isin返回与原始DataFrame形状相同的布尔数据框,并在元素序列中的任何位置使用True。

  1. In [165]: df = pd.DataFrame({'vals': [1, 2, 3, 4], 'ids': ['a', 'b', 'f', 'n'],
  2. .....: 'ids2': ['a', 'n', 'c', 'n']})
  3. .....:
  4. In [166]: values = ['a', 'b', 1, 3]
  5. In [167]: df.isin(values)
  6. Out[167]:
  7. vals ids ids2
  8. 0 True True True
  9. 1 False True False
  10. 2 True False False
  11. 3 False False False

通常,您需要将某些值与某些列匹配。只需将值设置dict为键为列的位置,值即为要检查的项目列表。

  1. In [168]: values = {'ids': ['a', 'b'], 'vals': [1, 3]}
  2. In [169]: df.isin(values)
  3. Out[169]:
  4. vals ids ids2
  5. 0 True True False
  6. 1 False True False
  7. 2 True False False
  8. 3 False False False

结合数据帧的isinany()all()方法来快速选择符合给定的标准对数据子集。要选择每列符合其自己标准的行:

  1. In [170]: values = {'ids': ['a', 'b'], 'ids2': ['a', 'c'], 'vals': [1, 3]}
  2. In [171]: row_mask = df.isin(values).all(1)
  3. In [172]: df[row_mask]
  4. Out[172]:
  5. vals ids ids2
  6. 0 1 a a

where()方法和屏蔽

从具有布尔向量的Series中选择值通常会返回数据的子集。为了保证选择输出与原始数据具有相同的形状,您可以whereSeries和中使用该方法DataFrame

仅返回选定的行:

  1. In [173]: s[s > 0]
  2. Out[173]:
  3. 3 1
  4. 2 2
  5. 1 3
  6. 0 4
  7. dtype: int64

要返回与原始形状相同的系列:

  1. In [174]: s.where(s > 0)
  2. Out[174]:
  3. 4 NaN
  4. 3 1.0
  5. 2 2.0
  6. 1 3.0
  7. 0 4.0
  8. dtype: float64

现在,使用布尔标准从DataFrame中选择值也可以保留输入数据形状。where在引擎盖下用作实现。下面的代码相当于。df.where(df < 0)

  1. In [175]: df[df < 0]
  2. Out[175]:
  3. A B C D
  4. 2000-01-01 -2.104139 -1.309525 NaN NaN
  5. 2000-01-02 -0.352480 NaN -1.192319 NaN
  6. 2000-01-03 -0.864883 NaN -0.227870 NaN
  7. 2000-01-04 NaN -1.222082 NaN -1.233203
  8. 2000-01-05 NaN -0.605656 -1.169184 NaN
  9. 2000-01-06 NaN -0.948458 NaN -0.684718
  10. 2000-01-07 -2.670153 -0.114722 NaN -0.048048
  11. 2000-01-08 NaN NaN -0.048788 -0.808838

此外,在返回的副本中,where使用可选other参数替换条件为False的值。

  1. In [176]: df.where(df < 0, -df)
  2. Out[176]:
  3. A B C D
  4. 2000-01-01 -2.104139 -1.309525 -0.485855 -0.245166
  5. 2000-01-02 -0.352480 -0.390389 -1.192319 -1.655824
  6. 2000-01-03 -0.864883 -0.299674 -0.227870 -0.281059
  7. 2000-01-04 -0.846958 -1.222082 -0.600705 -1.233203
  8. 2000-01-05 -0.669692 -0.605656 -1.169184 -0.342416
  9. 2000-01-06 -0.868584 -0.948458 -2.297780 -0.684718
  10. 2000-01-07 -2.670153 -0.114722 -0.168904 -0.048048
  11. 2000-01-08 -0.801196 -1.392071 -0.048788 -0.808838

您可能希望根据某些布尔条件设置值。这可以直观地完成,如下所示:

  1. In [177]: s2 = s.copy()
  2. In [178]: s2[s2 < 0] = 0
  3. In [179]: s2
  4. Out[179]:
  5. 4 0
  6. 3 1
  7. 2 2
  8. 1 3
  9. 0 4
  10. dtype: int64
  11. In [180]: df2 = df.copy()
  12. In [181]: df2[df2 < 0] = 0
  13. In [182]: df2
  14. Out[182]:
  15. A B C D
  16. 2000-01-01 0.000000 0.000000 0.485855 0.245166
  17. 2000-01-02 0.000000 0.390389 0.000000 1.655824
  18. 2000-01-03 0.000000 0.299674 0.000000 0.281059
  19. 2000-01-04 0.846958 0.000000 0.600705 0.000000
  20. 2000-01-05 0.669692 0.000000 0.000000 0.342416
  21. 2000-01-06 0.868584 0.000000 2.297780 0.000000
  22. 2000-01-07 0.000000 0.000000 0.168904 0.000000
  23. 2000-01-08 0.801196 1.392071 0.000000 0.000000

默认情况下,where返回数据的修改副本。有一个可选参数,inplace以便可以在不创建副本的情况下修改原始数据:

  1. In [183]: df_orig = df.copy()
  2. In [184]: df_orig.where(df > 0, -df, inplace=True)
  3. In [185]: df_orig
  4. Out[185]:
  5. A B C D
  6. 2000-01-01 2.104139 1.309525 0.485855 0.245166
  7. 2000-01-02 0.352480 0.390389 1.192319 1.655824
  8. 2000-01-03 0.864883 0.299674 0.227870 0.281059
  9. 2000-01-04 0.846958 1.222082 0.600705 1.233203
  10. 2000-01-05 0.669692 0.605656 1.169184 0.342416
  11. 2000-01-06 0.868584 0.948458 2.297780 0.684718
  12. 2000-01-07 2.670153 0.114722 0.168904 0.048048
  13. 2000-01-08 0.801196 1.392071 0.048788 0.808838

::: tip 注意

签名DataFrame.where()不同于numpy.where()。大致相当于。df1.where(m, df2)````np.where(m, df1, df2)

  1. In [186]: df.where(df < 0, -df) == np.where(df < 0, df, -df)
  2. Out[186]:
  3. A B C D
  4. 2000-01-01 True True True True
  5. 2000-01-02 True True True True
  6. 2000-01-03 True True True True
  7. 2000-01-04 True True True True
  8. 2000-01-05 True True True True
  9. 2000-01-06 True True True True
  10. 2000-01-07 True True True True
  11. 2000-01-08 True True True True

:::

对准

此外,where对齐输入布尔条件(ndarray或DataFrame),以便可以使用设置进行部分选择。这类似于部分设置通过.loc(但是在内容而不是轴标签上)。

  1. In [187]: df2 = df.copy()
  2. In [188]: df2[df2[1:4] > 0] = 3
  3. In [189]: df2
  4. Out[189]:
  5. A B C D
  6. 2000-01-01 -2.104139 -1.309525 0.485855 0.245166
  7. 2000-01-02 -0.352480 3.000000 -1.192319 3.000000
  8. 2000-01-03 -0.864883 3.000000 -0.227870 3.000000
  9. 2000-01-04 3.000000 -1.222082 3.000000 -1.233203
  10. 2000-01-05 0.669692 -0.605656 -1.169184 0.342416
  11. 2000-01-06 0.868584 -0.948458 2.297780 -0.684718
  12. 2000-01-07 -2.670153 -0.114722 0.168904 -0.048048
  13. 2000-01-08 0.801196 1.392071 -0.048788 -0.808838

哪里也可以接受axislevel参数在执行时对齐输入where

  1. In [190]: df2 = df.copy()
  2. In [191]: df2.where(df2 > 0, df2['A'], axis='index')
  3. Out[191]:
  4. A B C D
  5. 2000-01-01 -2.104139 -2.104139 0.485855 0.245166
  6. 2000-01-02 -0.352480 0.390389 -0.352480 1.655824
  7. 2000-01-03 -0.864883 0.299674 -0.864883 0.281059
  8. 2000-01-04 0.846958 0.846958 0.600705 0.846958
  9. 2000-01-05 0.669692 0.669692 0.669692 0.342416
  10. 2000-01-06 0.868584 0.868584 2.297780 0.868584
  11. 2000-01-07 -2.670153 -2.670153 0.168904 -2.670153
  12. 2000-01-08 0.801196 1.392071 0.801196 0.801196

这相当于(但快于)以下内容。

  1. In [192]: df2 = df.copy()
  2. In [193]: df.apply(lambda x, y: x.where(x > 0, y), y=df['A'])
  3. Out[193]:
  4. A B C D
  5. 2000-01-01 -2.104139 -2.104139 0.485855 0.245166
  6. 2000-01-02 -0.352480 0.390389 -0.352480 1.655824
  7. 2000-01-03 -0.864883 0.299674 -0.864883 0.281059
  8. 2000-01-04 0.846958 0.846958 0.600705 0.846958
  9. 2000-01-05 0.669692 0.669692 0.669692 0.342416
  10. 2000-01-06 0.868584 0.868584 2.297780 0.868584
  11. 2000-01-07 -2.670153 -2.670153 0.168904 -2.670153
  12. 2000-01-08 0.801196 1.392071 0.801196 0.801196

版本0.18.1中的新功能。

哪里可以接受一个可调用的条件和other参数。该函数必须带有一个参数(调用Series或DataFrame),并返回有效的输出作为条件和other参数。

  1. In [194]: df3 = pd.DataFrame({'A': [1, 2, 3],
  2. .....: 'B': [4, 5, 6],
  3. .....: 'C': [7, 8, 9]})
  4. .....:
  5. In [195]: df3.where(lambda x: x > 4, lambda x: x + 10)
  6. Out[195]:
  7. A B C
  8. 0 11 14 7
  9. 1 12 5 8
  10. 2 13 6 9

面具

mask()是的反布尔运算where

  1. In [196]: s.mask(s >= 0)
  2. Out[196]:
  3. 4 NaN
  4. 3 NaN
  5. 2 NaN
  6. 1 NaN
  7. 0 NaN
  8. dtype: float64
  9. In [197]: df.mask(df >= 0)
  10. Out[197]:
  11. A B C D
  12. 2000-01-01 -2.104139 -1.309525 NaN NaN
  13. 2000-01-02 -0.352480 NaN -1.192319 NaN
  14. 2000-01-03 -0.864883 NaN -0.227870 NaN
  15. 2000-01-04 NaN -1.222082 NaN -1.233203
  16. 2000-01-05 NaN -0.605656 -1.169184 NaN
  17. 2000-01-06 NaN -0.948458 NaN -0.684718
  18. 2000-01-07 -2.670153 -0.114722 NaN -0.048048
  19. 2000-01-08 NaN NaN -0.048788 -0.808838

query()方法

DataFrame对象有一个query() 允许使用表达式进行选择的方法。

您可以获取列的值,其中列b具有列值a和值之间的值c。例如:

  1. In [198]: n = 10
  2. In [199]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))
  3. In [200]: df
  4. Out[200]:
  5. a b c
  6. 0 0.438921 0.118680 0.863670
  7. 1 0.138138 0.577363 0.686602
  8. 2 0.595307 0.564592 0.520630
  9. 3 0.913052 0.926075 0.616184
  10. 4 0.078718 0.854477 0.898725
  11. 5 0.076404 0.523211 0.591538
  12. 6 0.792342 0.216974 0.564056
  13. 7 0.397890 0.454131 0.915716
  14. 8 0.074315 0.437913 0.019794
  15. 9 0.559209 0.502065 0.026437
  16. # pure python
  17. In [201]: df[(df.a < df.b) & (df.b < df.c)]
  18. Out[201]:
  19. a b c
  20. 1 0.138138 0.577363 0.686602
  21. 4 0.078718 0.854477 0.898725
  22. 5 0.076404 0.523211 0.591538
  23. 7 0.397890 0.454131 0.915716
  24. # query
  25. In [202]: df.query('(a < b) & (b < c)')
  26. Out[202]:
  27. a b c
  28. 1 0.138138 0.577363 0.686602
  29. 4 0.078718 0.854477 0.898725
  30. 5 0.076404 0.523211 0.591538
  31. 7 0.397890 0.454131 0.915716

如果没有名称的列,则执行相同的操作但返回命名索引a

  1. In [203]: df = pd.DataFrame(np.random.randint(n / 2, size=(n, 2)), columns=list('bc'))
  2. In [204]: df.index.name = 'a'
  3. In [205]: df
  4. Out[205]:
  5. b c
  6. a
  7. 0 0 4
  8. 1 0 1
  9. 2 3 4
  10. 3 4 3
  11. 4 1 4
  12. 5 0 3
  13. 6 0 1
  14. 7 3 4
  15. 8 2 3
  16. 9 1 1
  17. In [206]: df.query('a < b and b < c')
  18. Out[206]:
  19. b c
  20. a
  21. 2 3 4

如果您不希望或不能命名索引,则可以index在查询表达式中使用该名称 :

  1. In [207]: df = pd.DataFrame(np.random.randint(n, size=(n, 2)), columns=list('bc'))
  2. In [208]: df
  3. Out[208]:
  4. b c
  5. 0 3 1
  6. 1 3 0
  7. 2 5 6
  8. 3 5 2
  9. 4 7 4
  10. 5 0 1
  11. 6 2 5
  12. 7 0 1
  13. 8 6 0
  14. 9 7 9
  15. In [209]: df.query('index < b < c')
  16. Out[209]:
  17. b c
  18. 2 5 6

::: tip 注意

如果索引的名称与列名称重叠,则列名称优先。例如,

  1. In [210]: df = pd.DataFrame({'a': np.random.randint(5, size=5)})
  2. In [211]: df.index.name = 'a'
  3. In [212]: df.query('a > 2') # uses the column 'a', not the index
  4. Out[212]:
  5. a
  6. a
  7. 1 3
  8. 3 3

您仍然可以使用特殊标识符’index’在查询表达式中使用索引:

  1. In [213]: df.query('index > 2')
  2. Out[213]:
  3. a
  4. a
  5. 3 3
  6. 4 2

如果由于某种原因你有一个名为列的列index,那么你也可以引用索引ilevel_0,但是此时你应该考虑将列重命名为不那么模糊的列。

:::

MultiIndex query()语法

您还可以使用的水平DataFrameMultiIndex,好像他们是在框架柱:

  1. In [214]: n = 10
  2. In [215]: colors = np.random.choice(['red', 'green'], size=n)
  3. In [216]: foods = np.random.choice(['eggs', 'ham'], size=n)
  4. In [217]: colors
  5. Out[217]:
  6. array(['red', 'red', 'red', 'green', 'green', 'green', 'green', 'green',
  7. 'green', 'green'], dtype='<U5')
  8. In [218]: foods
  9. Out[218]:
  10. array(['ham', 'ham', 'eggs', 'eggs', 'eggs', 'ham', 'ham', 'eggs', 'eggs',
  11. 'eggs'], dtype='<U4')
  12. In [219]: index = pd.MultiIndex.from_arrays([colors, foods], names=['color', 'food'])
  13. In [220]: df = pd.DataFrame(np.random.randn(n, 2), index=index)
  14. In [221]: df
  15. Out[221]:
  16. 0 1
  17. color food
  18. red ham 0.194889 -0.381994
  19. ham 0.318587 2.089075
  20. eggs -0.728293 -0.090255
  21. green eggs -0.748199 1.318931
  22. eggs -2.029766 0.792652
  23. ham 0.461007 -0.542749
  24. ham -0.305384 -0.479195
  25. eggs 0.095031 -0.270099
  26. eggs -0.707140 -0.773882
  27. eggs 0.229453 0.304418
  28. In [222]: df.query('color == "red"')
  29. Out[222]:
  30. 0 1
  31. color food
  32. red ham 0.194889 -0.381994
  33. ham 0.318587 2.089075
  34. eggs -0.728293 -0.090255

如果MultiIndex未命名的级别,您可以使用特殊名称引用它们:

  1. In [223]: df.index.names = [None, None]
  2. In [224]: df
  3. Out[224]:
  4. 0 1
  5. red ham 0.194889 -0.381994
  6. ham 0.318587 2.089075
  7. eggs -0.728293 -0.090255
  8. green eggs -0.748199 1.318931
  9. eggs -2.029766 0.792652
  10. ham 0.461007 -0.542749
  11. ham -0.305384 -0.479195
  12. eggs 0.095031 -0.270099
  13. eggs -0.707140 -0.773882
  14. eggs 0.229453 0.304418
  15. In [225]: df.query('ilevel_0 == "red"')
  16. Out[225]:
  17. 0 1
  18. red ham 0.194889 -0.381994
  19. ham 0.318587 2.089075
  20. eggs -0.728293 -0.090255

约定是ilevel_0,这意味着第0级的“索引级别0” index

query()用例

用例query()是当您拥有一组具有共同 DataFrame列名(或索引级别/名称)子集的对象时。您可以将相同的查询传递给两个帧, 无需指定您对查询感兴趣的帧

  1. In [226]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))
  2. In [227]: df
  3. Out[227]:
  4. a b c
  5. 0 0.224283 0.736107 0.139168
  6. 1 0.302827 0.657803 0.713897
  7. 2 0.611185 0.136624 0.984960
  8. 3 0.195246 0.123436 0.627712
  9. 4 0.618673 0.371660 0.047902
  10. 5 0.480088 0.062993 0.185760
  11. 6 0.568018 0.483467 0.445289
  12. 7 0.309040 0.274580 0.587101
  13. 8 0.258993 0.477769 0.370255
  14. 9 0.550459 0.840870 0.304611
  15. In [228]: df2 = pd.DataFrame(np.random.rand(n + 2, 3), columns=df.columns)
  16. In [229]: df2
  17. Out[229]:
  18. a b c
  19. 0 0.357579 0.229800 0.596001
  20. 1 0.309059 0.957923 0.965663
  21. 2 0.123102 0.336914 0.318616
  22. 3 0.526506 0.323321 0.860813
  23. 4 0.518736 0.486514 0.384724
  24. 5 0.190804 0.505723 0.614533
  25. 6 0.891939 0.623977 0.676639
  26. 7 0.480559 0.378528 0.460858
  27. 8 0.420223 0.136404 0.141295
  28. 9 0.732206 0.419540 0.604675
  29. 10 0.604466 0.848974 0.896165
  30. 11 0.589168 0.920046 0.732716
  31. In [230]: expr = '0.0 <= a <= c <= 0.5'
  32. In [231]: map(lambda frame: frame.query(expr), [df, df2])
  33. Out[231]: <map at 0x7f65f7952d30>

query()Python与pandas语法比较

完全类似numpy的语法:

  1. In [232]: df = pd.DataFrame(np.random.randint(n, size=(n, 3)), columns=list('abc'))
  2. In [233]: df
  3. Out[233]:
  4. a b c
  5. 0 7 8 9
  6. 1 1 0 7
  7. 2 2 7 2
  8. 3 6 2 2
  9. 4 2 6 3
  10. 5 3 8 2
  11. 6 1 7 2
  12. 7 5 1 5
  13. 8 9 8 0
  14. 9 1 5 0
  15. In [234]: df.query('(a < b) & (b < c)')
  16. Out[234]:
  17. a b c
  18. 0 7 8 9
  19. In [235]: df[(df.a < df.b) & (df.b < df.c)]
  20. Out[235]:
  21. a b c
  22. 0 7 8 9

通过删除括号略微更好(通过绑定使比较运算符绑定比&和更紧|)。

  1. In [236]: df.query('a < b & b < c')
  2. Out[236]:
  3. a b c
  4. 0 7 8 9

使用英语而不是符号:

  1. In [237]: df.query('a < b and b < c')
  2. Out[237]:
  3. a b c
  4. 0 7 8 9

非常接近你如何在纸上写它:

  1. In [238]: df.query('a < b < c')
  2. Out[238]:
  3. a b c
  4. 0 7 8 9

in与运营商not in

query()还支持Python in和 比较运算符的特殊用法,为调用或的方法提供了简洁的语法 。not in````isin````Series````DataFrame

  1. # get all rows where columns "a" and "b" have overlapping values
  2. In [239]: df = pd.DataFrame({'a': list('aabbccddeeff'), 'b': list('aaaabbbbcccc'),
  3. .....: 'c': np.random.randint(5, size=12),
  4. .....: 'd': np.random.randint(9, size=12)})
  5. .....:
  6. In [240]: df
  7. Out[240]:
  8. a b c d
  9. 0 a a 2 6
  10. 1 a a 4 7
  11. 2 b a 1 6
  12. 3 b a 2 1
  13. 4 c b 3 6
  14. 5 c b 0 2
  15. 6 d b 3 3
  16. 7 d b 2 1
  17. 8 e c 4 3
  18. 9 e c 2 0
  19. 10 f c 0 6
  20. 11 f c 1 2
  21. In [241]: df.query('a in b')
  22. Out[241]:
  23. a b c d
  24. 0 a a 2 6
  25. 1 a a 4 7
  26. 2 b a 1 6
  27. 3 b a 2 1
  28. 4 c b 3 6
  29. 5 c b 0 2
  30. # How you'd do it in pure Python
  31. In [242]: df[df.a.isin(df.b)]
  32. Out[242]:
  33. a b c d
  34. 0 a a 2 6
  35. 1 a a 4 7
  36. 2 b a 1 6
  37. 3 b a 2 1
  38. 4 c b 3 6
  39. 5 c b 0 2
  40. In [243]: df.query('a not in b')
  41. Out[243]:
  42. a b c d
  43. 6 d b 3 3
  44. 7 d b 2 1
  45. 8 e c 4 3
  46. 9 e c 2 0
  47. 10 f c 0 6
  48. 11 f c 1 2
  49. # pure Python
  50. In [244]: df[~df.a.isin(df.b)]
  51. Out[244]:
  52. a b c d
  53. 6 d b 3 3
  54. 7 d b 2 1
  55. 8 e c 4 3
  56. 9 e c 2 0
  57. 10 f c 0 6
  58. 11 f c 1 2

您可以将此与其他表达式结合使用,以获得非常简洁的查询:

  1. # rows where cols a and b have overlapping values
  2. # and col c's values are less than col d's
  3. In [245]: df.query('a in b and c < d')
  4. Out[245]:
  5. a b c d
  6. 0 a a 2 6
  7. 1 a a 4 7
  8. 2 b a 1 6
  9. 4 c b 3 6
  10. 5 c b 0 2
  11. # pure Python
  12. In [246]: df[df.b.isin(df.a) & (df.c < df.d)]
  13. Out[246]:
  14. a b c d
  15. 0 a a 2 6
  16. 1 a a 4 7
  17. 2 b a 1 6
  18. 4 c b 3 6
  19. 5 c b 0 2
  20. 10 f c 0 6
  21. 11 f c 1 2

::: tip 注意

请注意in并在Python中进行评估,因为 它没有相应的操作。但是,只有 / expression本身在vanilla Python中进行评估。例如,在表达式中not in````numexpr** in````not in


  1. df.query('a in b + c + d')

(b + c + d)通过评估numexpr然后in 操作在普通的Python评价。通常,任何可以使用的评估操作numexpr都是。

:::

==运算符与list对象的特殊用法

一个比较list值的使用列==/ !=工程,以类似in/ 。not in

  1. In [247]: df.query('b == ["a", "b", "c"]')
  2. Out[247]:
  3. a b c d
  4. 0 a a 2 6
  5. 1 a a 4 7
  6. 2 b a 1 6
  7. 3 b a 2 1
  8. 4 c b 3 6
  9. 5 c b 0 2
  10. 6 d b 3 3
  11. 7 d b 2 1
  12. 8 e c 4 3
  13. 9 e c 2 0
  14. 10 f c 0 6
  15. 11 f c 1 2
  16. # pure Python
  17. In [248]: df[df.b.isin(["a", "b", "c"])]
  18. Out[248]:
  19. a b c d
  20. 0 a a 2 6
  21. 1 a a 4 7
  22. 2 b a 1 6
  23. 3 b a 2 1
  24. 4 c b 3 6
  25. 5 c b 0 2
  26. 6 d b 3 3
  27. 7 d b 2 1
  28. 8 e c 4 3
  29. 9 e c 2 0
  30. 10 f c 0 6
  31. 11 f c 1 2
  32. In [249]: df.query('c == [1, 2]')
  33. Out[249]:
  34. a b c d
  35. 0 a a 2 6
  36. 2 b a 1 6
  37. 3 b a 2 1
  38. 7 d b 2 1
  39. 9 e c 2 0
  40. 11 f c 1 2
  41. In [250]: df.query('c != [1, 2]')
  42. Out[250]:
  43. a b c d
  44. 1 a a 4 7
  45. 4 c b 3 6
  46. 5 c b 0 2
  47. 6 d b 3 3
  48. 8 e c 4 3
  49. 10 f c 0 6
  50. # using in/not in
  51. In [251]: df.query('[1, 2] in c')
  52. Out[251]:
  53. a b c d
  54. 0 a a 2 6
  55. 2 b a 1 6
  56. 3 b a 2 1
  57. 7 d b 2 1
  58. 9 e c 2 0
  59. 11 f c 1 2
  60. In [252]: df.query('[1, 2] not in c')
  61. Out[252]:
  62. a b c d
  63. 1 a a 4 7
  64. 4 c b 3 6
  65. 5 c b 0 2
  66. 6 d b 3 3
  67. 8 e c 4 3
  68. 10 f c 0 6
  69. # pure Python
  70. In [253]: df[df.c.isin([1, 2])]
  71. Out[253]:
  72. a b c d
  73. 0 a a 2 6
  74. 2 b a 1 6
  75. 3 b a 2 1
  76. 7 d b 2 1
  77. 9 e c 2 0
  78. 11 f c 1 2

布尔运算符

您可以使用单词not~运算符否定布尔表达式。

  1. In [254]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))
  2. In [255]: df['bools'] = np.random.rand(len(df)) > 0.5
  3. In [256]: df.query('~bools')
  4. Out[256]:
  5. a b c bools
  6. 2 0.697753 0.212799 0.329209 False
  7. 7 0.275396 0.691034 0.826619 False
  8. 8 0.190649 0.558748 0.262467 False
  9. In [257]: df.query('not bools')
  10. Out[257]:
  11. a b c bools
  12. 2 0.697753 0.212799 0.329209 False
  13. 7 0.275396 0.691034 0.826619 False
  14. 8 0.190649 0.558748 0.262467 False
  15. In [258]: df.query('not bools') == df[~df.bools]
  16. Out[258]:
  17. a b c bools
  18. 2 True True True True
  19. 7 True True True True
  20. 8 True True True True

当然,表达式也可以是任意复杂的:

  1. # short query syntax
  2. In [259]: shorter = df.query('a < b < c and (not bools) or bools > 2')
  3. # equivalent in pure Python
  4. In [260]: longer = df[(df.a < df.b) & (df.b < df.c) & (~df.bools) | (df.bools > 2)]
  5. In [261]: shorter
  6. Out[261]:
  7. a b c bools
  8. 7 0.275396 0.691034 0.826619 False
  9. In [262]: longer
  10. Out[262]:
  11. a b c bools
  12. 7 0.275396 0.691034 0.826619 False
  13. In [263]: shorter == longer
  14. Out[263]:
  15. a b c bools
  16. 7 True True True True

的表现¶query()

DataFrame.query()````numexpr对于大型帧,使用比Python略快。

query-perf

::: tip 注意

如果您的框架超过大约200,000行,您将只看到使用numexpr引擎的性能优势DataFrame.query()

query-perf-small

:::

此图是使用DataFrame3列创建的,每列包含使用生成的浮点值numpy.random.randn()

重复数据

如果要识别和删除DataFrame中的重复行,有两种方法可以提供帮助:duplicateddrop_duplicates。每个都将用于标识重复行的列作为参数。

  • duplicated 返回一个布尔向量,其长度为行数,表示行是否重复。
  • drop_duplicates 删除重复的行。

默认情况下,重复集的第一个观察行被认为是唯一的,但每个方法都有一个keep参数来指定要保留的目标。

  • keep='first' (默认值):标记/删除重复项,第一次出现除外。
  • keep='last':标记/删除重复项,除了最后一次出现。
  • keep=False:标记/删除所有重复项。
  1. In [264]: df2 = pd.DataFrame({'a': ['one', 'one', 'two', 'two', 'two', 'three', 'four'],
  2. .....: 'b': ['x', 'y', 'x', 'y', 'x', 'x', 'x'],
  3. .....: 'c': np.random.randn(7)})
  4. .....:
  5. In [265]: df2
  6. Out[265]:
  7. a b c
  8. 0 one x -1.067137
  9. 1 one y 0.309500
  10. 2 two x -0.211056
  11. 3 two y -1.842023
  12. 4 two x -0.390820
  13. 5 three x -1.964475
  14. 6 four x 1.298329
  15. In [266]: df2.duplicated('a')
  16. Out[266]:
  17. 0 False
  18. 1 True
  19. 2 False
  20. 3 True
  21. 4 True
  22. 5 False
  23. 6 False
  24. dtype: bool
  25. In [267]: df2.duplicated('a', keep='last')
  26. Out[267]:
  27. 0 True
  28. 1 False
  29. 2 True
  30. 3 True
  31. 4 False
  32. 5 False
  33. 6 False
  34. dtype: bool
  35. In [268]: df2.duplicated('a', keep=False)
  36. Out[268]:
  37. 0 True
  38. 1 True
  39. 2 True
  40. 3 True
  41. 4 True
  42. 5 False
  43. 6 False
  44. dtype: bool
  45. In [269]: df2.drop_duplicates('a')
  46. Out[269]:
  47. a b c
  48. 0 one x -1.067137
  49. 2 two x -0.211056
  50. 5 three x -1.964475
  51. 6 four x 1.298329
  52. In [270]: df2.drop_duplicates('a', keep='last')
  53. Out[270]:
  54. a b c
  55. 1 one y 0.309500
  56. 4 two x -0.390820
  57. 5 three x -1.964475
  58. 6 four x 1.298329
  59. In [271]: df2.drop_duplicates('a', keep=False)
  60. Out[271]:
  61. a b c
  62. 5 three x -1.964475
  63. 6 four x 1.298329

此外,您可以传递列表列表以识别重复。

  1. In [272]: df2.duplicated(['a', 'b'])
  2. Out[272]:
  3. 0 False
  4. 1 False
  5. 2 False
  6. 3 False
  7. 4 True
  8. 5 False
  9. 6 False
  10. dtype: bool
  11. In [273]: df2.drop_duplicates(['a', 'b'])
  12. Out[273]:
  13. a b c
  14. 0 one x -1.067137
  15. 1 one y 0.309500
  16. 2 two x -0.211056
  17. 3 two y -1.842023
  18. 5 three x -1.964475
  19. 6 four x 1.298329

要按索引值删除重复项,请使用Index.duplicated然后执行切片。keep参数可以使用相同的选项集。

  1. In [274]: df3 = pd.DataFrame({'a': np.arange(6),
  2. .....: 'b': np.random.randn(6)},
  3. .....: index=['a', 'a', 'b', 'c', 'b', 'a'])
  4. .....:
  5. In [275]: df3
  6. Out[275]:
  7. a b
  8. a 0 1.440455
  9. a 1 2.456086
  10. b 2 1.038402
  11. c 3 -0.894409
  12. b 4 0.683536
  13. a 5 3.082764
  14. In [276]: df3.index.duplicated()
  15. Out[276]: array([False, True, False, False, True, True])
  16. In [277]: df3[~df3.index.duplicated()]
  17. Out[277]:
  18. a b
  19. a 0 1.440455
  20. b 2 1.038402
  21. c 3 -0.894409
  22. In [278]: df3[~df3.index.duplicated(keep='last')]
  23. Out[278]:
  24. a b
  25. c 3 -0.894409
  26. b 4 0.683536
  27. a 5 3.082764
  28. In [279]: df3[~df3.index.duplicated(keep=False)]
  29. Out[279]:
  30. a b
  31. c 3 -0.894409

类字典get()方法

Series或DataFrame中的每一个都有一个get可以返回默认值的方法。

  1. In [280]: s = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
  2. In [281]: s.get('a') # equivalent to s['a']
  3. Out[281]: 1
  4. In [282]: s.get('x', default=-1)
  5. Out[282]: -1

lookup()方法

有时,您希望在给定一系列行标签和列标签的情况下提取一组值,并且该lookup方法允许此操作并返回NumPy数组。例如:

  1. In [283]: dflookup = pd.DataFrame(np.random.rand(20, 4), columns = ['A', 'B', 'C', 'D'])
  2. In [284]: dflookup.lookup(list(range(0, 10, 2)), ['B', 'C', 'A', 'B', 'D'])
  3. Out[284]: array([0.3506, 0.4779, 0.4825, 0.9197, 0.5019])

索引对象

pandas Index类及其子类可以视为实现有序的多集合。允许重复。但是,如果您尝试将Index具有重复条目的对象转换为a set,则会引发异常。

Index还提供了查找,数据对齐和重建索引所需的基础结构。Index直接创建的最简单方法 是将一个list或其他序列传递给 Index

  1. In [285]: index = pd.Index(['e', 'd', 'a', 'b'])
  2. In [286]: index
  3. Out[286]: Index(['e', 'd', 'a', 'b'], dtype='object')
  4. In [287]: 'd' in index
  5. Out[287]: True

您还可以传递一个name存储在索引中:

  1. In [288]: index = pd.Index(['e', 'd', 'a', 'b'], name='something')
  2. In [289]: index.name
  3. Out[289]: 'something'

名称(如果已设置)将显示在控制台显示中:

  1. In [290]: index = pd.Index(list(range(5)), name='rows')
  2. In [291]: columns = pd.Index(['A', 'B', 'C'], name='cols')
  3. In [292]: df = pd.DataFrame(np.random.randn(5, 3), index=index, columns=columns)
  4. In [293]: df
  5. Out[293]:
  6. cols A B C
  7. rows
  8. 0 1.295989 0.185778 0.436259
  9. 1 0.678101 0.311369 -0.528378
  10. 2 -0.674808 -1.103529 -0.656157
  11. 3 1.889957 2.076651 -1.102192
  12. 4 -1.211795 -0.791746 0.634724
  13. In [294]: df['A']
  14. Out[294]:
  15. rows
  16. 0 1.295989
  17. 1 0.678101
  18. 2 -0.674808
  19. 3 1.889957
  20. 4 -1.211795
  21. Name: A, dtype: float64

设置元数据

索引是“不可改变的大多是”,但它可以设置和改变它们的元数据,如指数name(或为MultiIndexlevelscodes)。

您可以使用renameset_namesset_levels,和set_codes 直接设置这些属性。他们默认返回一份副本; 但是,您可以指定inplace=True使数据更改到位。

有关MultiIndexes的使用,请参阅高级索引

  1. In [295]: ind = pd.Index([1, 2, 3])
  2. In [296]: ind.rename("apple")
  3. Out[296]: Int64Index([1, 2, 3], dtype='int64', name='apple')
  4. In [297]: ind
  5. Out[297]: Int64Index([1, 2, 3], dtype='int64')
  6. In [298]: ind.set_names(["apple"], inplace=True)
  7. In [299]: ind.name = "bob"
  8. In [300]: ind
  9. Out[300]: Int64Index([1, 2, 3], dtype='int64', name='bob')

set_namesset_levels并且set_codes还采用可选 level参数

  1. In [301]: index = pd.MultiIndex.from_product([range(3), ['one', 'two']], names=['first', 'second'])
  2. In [302]: index
  3. Out[302]:
  4. MultiIndex([(0, 'one'),
  5. (0, 'two'),
  6. (1, 'one'),
  7. (1, 'two'),
  8. (2, 'one'),
  9. (2, 'two')],
  10. names=['first', 'second'])
  11. In [303]: index.levels[1]
  12. Out[303]: Index(['one', 'two'], dtype='object', name='second')
  13. In [304]: index.set_levels(["a", "b"], level=1)
  14. Out[304]:
  15. MultiIndex([(0, 'a'),
  16. (0, 'b'),
  17. (1, 'a'),
  18. (1, 'b'),
  19. (2, 'a'),
  20. (2, 'b')],
  21. names=['first', 'second'])

在Index对象上设置操作

两个主要业务是和。这些可以直接称为实例方法,也可以通过重载运算符使用。通过该方法提供差异。union (|)````intersection (&)````.difference()

  1. In [305]: a = pd.Index(['c', 'b', 'a'])
  2. In [306]: b = pd.Index(['c', 'e', 'd'])
  3. In [307]: a | b
  4. Out[307]: Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
  5. In [308]: a & b
  6. Out[308]: Index(['c'], dtype='object')
  7. In [309]: a.difference(b)
  8. Out[309]: Index(['a', 'b'], dtype='object')

同时还提供了操作,它返回出现在任一元件或,但不是在两者。这相当于创建的索引,删除了重复项。symmetric_difference (^)````idx1````idx2````idx1.difference(idx2).union(idx2.difference(idx1))

  1. In [310]: idx1 = pd.Index([1, 2, 3, 4])
  2. In [311]: idx2 = pd.Index([2, 3, 4, 5])
  3. In [312]: idx1.symmetric_difference(idx2)
  4. Out[312]: Int64Index([1, 5], dtype='int64')
  5. In [313]: idx1 ^ idx2
  6. Out[313]: Int64Index([1, 5], dtype='int64')

::: tip 注意

来自设置操作的结果索引将按升序排序。

:::

Index.union()具有不同dtypes的索引之间执行时,必须将索引强制转换为公共dtype。通常,虽然并非总是如此,但这是对象dtype。例外是在整数和浮点数据之间执行联合。在这种情况下,整数值将转换为float

  1. In [314]: idx1 = pd.Index([0, 1, 2])
  2. In [315]: idx2 = pd.Index([0.5, 1.5])
  3. In [316]: idx1 | idx2
  4. Out[316]: Float64Index([0.0, 0.5, 1.0, 1.5, 2.0], dtype='float64')

缺少值

即使Index可以保存缺失值(NaN),但如果您不想要任何意外结果,也应该避免使用。例如,某些操作会隐式排除缺失值。

Index.fillna 使用指定的标量值填充缺失值。

  1. In [317]: idx1 = pd.Index([1, np.nan, 3, 4])
  2. In [318]: idx1
  3. Out[318]: Float64Index([1.0, nan, 3.0, 4.0], dtype='float64')
  4. In [319]: idx1.fillna(2)
  5. Out[319]: Float64Index([1.0, 2.0, 3.0, 4.0], dtype='float64')
  6. In [320]: idx2 = pd.DatetimeIndex([pd.Timestamp('2011-01-01'),
  7. .....: pd.NaT,
  8. .....: pd.Timestamp('2011-01-03')])
  9. .....:
  10. In [321]: idx2
  11. Out[321]: DatetimeIndex(['2011-01-01', 'NaT', '2011-01-03'], dtype='datetime64[ns]', freq=None)
  12. In [322]: idx2.fillna(pd.Timestamp('2011-01-02'))
  13. Out[322]: DatetimeIndex(['2011-01-01', '2011-01-02', '2011-01-03'], dtype='datetime64[ns]', freq=None)

设置/重置索引

有时您会将数据集加载或创建到DataFrame中,并希望在您已经完成之后添加索引。有几种不同的方式。

设置索引

DataFrame有一个set_index()方法,它采用列名(对于常规Index)或列名列表(对于a MultiIndex)。要创建新的重新索引的DataFrame:

  1. In [323]: data
  2. Out[323]:
  3. a b c d
  4. 0 bar one z 1.0
  5. 1 bar two y 2.0
  6. 2 foo one x 3.0
  7. 3 foo two w 4.0
  8. In [324]: indexed1 = data.set_index('c')
  9. In [325]: indexed1
  10. Out[325]:
  11. a b d
  12. c
  13. z bar one 1.0
  14. y bar two 2.0
  15. x foo one 3.0
  16. w foo two 4.0
  17. In [326]: indexed2 = data.set_index(['a', 'b'])
  18. In [327]: indexed2
  19. Out[327]:
  20. c d
  21. a b
  22. bar one z 1.0
  23. two y 2.0
  24. foo one x 3.0
  25. two w 4.0

append关键字选项让你保持现有索引并追加给列一个多指标:

  1. In [328]: frame = data.set_index('c', drop=False)
  2. In [329]: frame = frame.set_index(['a', 'b'], append=True)
  3. In [330]: frame
  4. Out[330]:
  5. c d
  6. c a b
  7. z bar one z 1.0
  8. y bar two y 2.0
  9. x foo one x 3.0
  10. w foo two w 4.0

其他选项set_index允许您不删除索引列或就地添加索引(不创建新对象):

  1. In [331]: data.set_index('c', drop=False)
  2. Out[331]:
  3. a b c d
  4. c
  5. z bar one z 1.0
  6. y bar two y 2.0
  7. x foo one x 3.0
  8. w foo two w 4.0
  9. In [332]: data.set_index(['a', 'b'], inplace=True)
  10. In [333]: data
  11. Out[333]:
  12. c d
  13. a b
  14. bar one z 1.0
  15. two y 2.0
  16. foo one x 3.0
  17. two w 4.0

重置索引

为方便起见,DataFrame上有一个新函数,它将 reset_index()索引值传输到DataFrame的列中并设置一个简单的整数索引。这是反向操作set_index()

  1. In [334]: data
  2. Out[334]:
  3. c d
  4. a b
  5. bar one z 1.0
  6. two y 2.0
  7. foo one x 3.0
  8. two w 4.0
  9. In [335]: data.reset_index()
  10. Out[335]:
  11. a b c d
  12. 0 bar one z 1.0
  13. 1 bar two y 2.0
  14. 2 foo one x 3.0
  15. 3 foo two w 4.0

输出更类似于SQL表或记录数组。从索引派生的列的名称是存储在names属性中的名称。

您可以使用level关键字仅删除索引的一部分:

  1. In [336]: frame
  2. Out[336]:
  3. c d
  4. c a b
  5. z bar one z 1.0
  6. y bar two y 2.0
  7. x foo one x 3.0
  8. w foo two w 4.0
  9. In [337]: frame.reset_index(level=1)
  10. Out[337]:
  11. a c d
  12. c b
  13. z one bar z 1.0
  14. y two bar y 2.0
  15. x one foo x 3.0
  16. w two foo w 4.0

reset_index采用一个可选参数drop,如果为true,则只丢弃索引,而不是将索引值放在DataFrame的列中。

添加ad hoc索引

如果您自己创建索引,则可以将其分配给index字段:

  1. data.index = index

返回视图与副本

在pandas对象中设置值时,必须注意避免调用所谓的对象 。这是一个例子。chained indexing

  1. In [338]: dfmi = pd.DataFrame([list('abcd'),
  2. .....: list('efgh'),
  3. .....: list('ijkl'),
  4. .....: list('mnop')],
  5. .....: columns=pd.MultiIndex.from_product([['one', 'two'],
  6. .....: ['first', 'second']]))
  7. .....:
  8. In [339]: dfmi
  9. Out[339]:
  10. one two
  11. first second first second
  12. 0 a b c d
  13. 1 e f g h
  14. 2 i j k l
  15. 3 m n o p

比较这两种访问方法:

  1. In [340]: dfmi['one']['second']
  2. Out[340]:
  3. 0 b
  4. 1 f
  5. 2 j
  6. 3 n
  7. Name: second, dtype: object
  1. In [341]: dfmi.loc[:, ('one', 'second')]
  2. Out[341]:
  3. 0 b
  4. 1 f
  5. 2 j
  6. 3 n
  7. Name: (one, second), dtype: object

这两者都产生相同的结果,所以你应该使用哪个?理解这些操作的顺序以及为什么方法2(.loc)比方法1(链接[])更受欢迎是有益的。

dfmi['one']选择列的第一级并返回单索引的DataFrame。然后另一个Python操作dfmi_with_one['second']选择索引的系列'second'。这由变量指示,dfmi_with_one因为pandas将这些操作视为单独的事件。例如,单独调用__getitem__,因此它必须将它们视为线性操作,它们一个接一个地发生。

对比这个df.loc[:,('one','second')]将一个嵌套的元组传递(slice(None),('one','second'))给一个单独的调用 __getitem__。这允许pandas将其作为单个实体来处理。此外,这种操作顺序可以明显更快,并且如果需要,允许人们对两个轴进行索引。

使用链式索引时为什么分配失败?

上一节中的问题只是一个性能问题。这是怎么回事与SettingWithCopy警示?当你做一些可能花费几毫秒的事情时,我们通常不会发出警告!

但事实证明,分配链式索引的产品具有固有的不可预测的结果。要看到这一点,请考虑Python解释器如何执行此代码:

  1. dfmi.loc[:, ('one', 'second')] = value
  2. # becomes
  3. dfmi.loc.__setitem__((slice(None), ('one', 'second')), value)

但是这个代码的处理方式不同:

  1. dfmi['one']['second'] = value
  2. # becomes
  3. dfmi.__getitem__('one').__setitem__('second', value)

看到__getitem__那里?除了简单的情况之外,很难预测它是否会返回一个视图或一个副本(它取决于数组的内存布局,关于哪些pandas不能保证),因此是否__setitem__会修改dfmi或者是一个临时对象之后立即抛出。什么SettingWithCopy是警告你!

::: tip 注意

您可能想知道我们是否应该关注loc 第一个示例中的属性。但dfmi.loc保证dfmi 本身具有修改的索引行为,因此dfmi.loc.__getitem__/ 直接dfmi.loc.__setitem__操作dfmi。当然, dfmi.loc.__getitem__(idx)可能是一个视图或副本dfmi

:::

有时SettingWithCopy,当没有明显的链式索引时,会出现警告。这些SettingWithCopy是旨在捕获的错误 !Pandas可能会试图警告你,你已经这样做了:

  1. def do_something(df):
  2. foo = df[['bar', 'baz']] # Is foo a view? A copy? Nobody knows!
  3. # ... many lines here ...
  4. # We don't know whether this will modify df or not!
  5. foo['quux'] = value
  6. return foo

哎呀!

评估订单事项

使用链式索引时,索引操作的顺序和类型会部分确定结果是原始对象的切片还是切片的副本。

Pandas有,SettingWithCopyWarning因为分配一个切片的副本通常不是故意的,而是由链式索引引起的错误返回一个预期切片的副本。

如果您希望pandas或多或少地信任链接索引表达式的赋值,则可以将选项 设置mode.chained_assignment为以下值之一:

  • 'warn',默认值表示SettingWithCopyWarning打印。
  • 'raise'意味着大Pandas会提出SettingWithCopyException 你必须处理的事情。
  • None 将完全压制警告。
  1. In [342]: dfb = pd.DataFrame({'a': ['one', 'one', 'two',
  2. .....: 'three', 'two', 'one', 'six'],
  3. .....: 'c': np.arange(7)})
  4. .....:
  5. # This will show the SettingWithCopyWarning
  6. # but the frame values will be set
  7. In [343]: dfb['c'][dfb.a.str.startswith('o')] = 42

然而,这是在副本上运行,不起作用。

  1. >>> pd.set_option('mode.chained_assignment','warn')
  2. >>> dfb[dfb.a.str.startswith('o')]['c'] = 42
  3. Traceback (most recent call last)
  4. ...
  5. SettingWithCopyWarning:
  6. A value is trying to be set on a copy of a slice from a DataFrame.
  7. Try using .loc[row_index,col_indexer] = value instead

链式分配也可以在混合dtype帧中进行设置。

::: tip 注意

这些设置规则适用于所有.loc/.iloc

:::

这是正确的访问方法:

  1. In [344]: dfc = pd.DataFrame({'A': ['aaa', 'bbb', 'ccc'], 'B': [1, 2, 3]})
  2. In [345]: dfc.loc[0, 'A'] = 11
  3. In [346]: dfc
  4. Out[346]:
  5. A B
  6. 0 11 1
  7. 1 bbb 2
  8. 2 ccc 3

这有时起作用,但不能保证,因此应该避免:

  1. In [347]: dfc = dfc.copy()
  2. In [348]: dfc['A'][0] = 111
  3. In [349]: dfc
  4. Out[349]:
  5. A B
  6. 0 111 1
  7. 1 bbb 2
  8. 2 ccc 3

根本不起作用,所以应该避免:

  1. >>> pd.set_option('mode.chained_assignment','raise')
  2. >>> dfc.loc[0]['A'] = 1111
  3. Traceback (most recent call last)
  4. ...
  5. SettingWithCopyException:
  6. A value is trying to be set on a copy of a slice from a DataFrame.
  7. Try using .loc[row_index,col_indexer] = value instead

::: danger 警告

链式分配警告/异常旨在通知用户可能无效的分配。可能存在误报; 无意中报告链式作业的情况。

:::