索引和数据选择器
Pandas对象中的轴标记信息有多种用途:
- 使用已知指标识别数据(即提供元数据),这对于分析,可视化和交互式控制台显示非常重要。
- 启用自动和显式数据对齐。
- 允许直观地获取和设置数据集的子集。
在本节中,我们将重点关注最后一点:即如何切片,切块,以及通常获取和设置pandas对象的子集。主要关注的是Series和DataFrame,因为他们在这个领域受到了更多的开发关注。
::: tip 注意
Python和NumPy索引运算符[]和属性运算符.
可以在各种用例中快速轻松地访问pandas数据结构。这使得交互式工作变得直观,因为如果您已经知道如何处理Python字典和NumPy数组,那么几乎没有新的东西需要学习。但是,由于预先不知道要访问的数据类型,因此直接使用标准运算符会有一些优化限制。对于生产代码,我们建议您利用本章中介绍的优化的pandas数据访问方法。
:::
::: danger 警告
是否为设置操作返回副本或引用可能取决于上下文。这有时被称为应该避免。请参阅返回视图与复制。chained assignment
:::
::: danger 警告
使用浮点数对基于整数的索引进行索引已在0.18.0中进行了说明,有关更改的摘要,请参见此处。
:::
见多指标/高级索引的MultiIndex和更先进的索引文件。
有关一些高级策略,请参阅食谱。
索引的不同选择
对象选择已经有许多用户请求的添加,以支持更明确的基于位置的索引。Pandas现在支持三种类型的多轴索引。
.loc主要是基于标签的,但也可以与布尔数组一起使用。当找不到物品时.loc会提高KeyError。允许的输入是:.iloc是基于主要的整数位置(从0到length-1所述轴的),但也可以用布尔阵列使用。 如果请求的索引器超出范围,.iloc则会引发IndexError,但允许越界索引的切片索引器除外。(这符合Python / NumPy 切片 语义)。允许的输入是:.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 |
在这里,我们构建一个简单的时间序列数据集,用于说明索引功能:
In [1]: dates = pd.date_range('1/1/2000', periods=8)In [2]: df = pd.DataFrame(np.random.randn(8, 4),...: index=dates, columns=['A', 'B', 'C', 'D'])...:In [3]: dfOut[3]:A B C D2000-01-01 0.469112 -0.282863 -1.509059 -1.1356322000-01-02 1.212112 -0.173215 0.119209 -1.0442362000-01-03 -0.861849 -2.104569 -0.494929 1.0718042000-01-04 0.721555 -0.706771 -1.039575 0.2718602000-01-05 -0.424972 0.567020 0.276232 -1.0874012000-01-06 -0.673690 0.113648 -1.478427 0.5249882000-01-07 0.404705 0.577046 -1.715002 -1.0392682000-01-08 -0.370647 -1.157892 -1.344312 0.844885
::: tip 注意
除非特别说明,否则索引功能都不是时间序列特定的。
:::
因此,如上所述,我们使用最基本的索引[]:
In [4]: s = df['A']In [5]: s[dates[5]]Out[5]: -0.6736897080883706
您可以传递列表列表[]以按该顺序选择列。如果DataFrame中未包含列,则会引发异常。也可以这种方式设置多列:
In [6]: dfOut[6]:A B C D2000-01-01 0.469112 -0.282863 -1.509059 -1.1356322000-01-02 1.212112 -0.173215 0.119209 -1.0442362000-01-03 -0.861849 -2.104569 -0.494929 1.0718042000-01-04 0.721555 -0.706771 -1.039575 0.2718602000-01-05 -0.424972 0.567020 0.276232 -1.0874012000-01-06 -0.673690 0.113648 -1.478427 0.5249882000-01-07 0.404705 0.577046 -1.715002 -1.0392682000-01-08 -0.370647 -1.157892 -1.344312 0.844885In [7]: df[['B', 'A']] = df[['A', 'B']]In [8]: dfOut[8]:A B C D2000-01-01 -0.282863 0.469112 -1.509059 -1.1356322000-01-02 -0.173215 1.212112 0.119209 -1.0442362000-01-03 -2.104569 -0.861849 -0.494929 1.0718042000-01-04 -0.706771 0.721555 -1.039575 0.2718602000-01-05 0.567020 -0.424972 0.276232 -1.0874012000-01-06 0.113648 -0.673690 -1.478427 0.5249882000-01-07 0.577046 0.404705 -1.715002 -1.0392682000-01-08 -1.157892 -0.370647 -1.344312 0.844885
您可能会发现这对于将变换(就地)应用于列的子集非常有用。
::: danger 警告
pandas在设置Series和DataFrame来自.loc和时对齐所有AXES .iloc。
这不会修改,df因为列对齐在赋值之前。
In [9]: df[['A', 'B']]Out[9]:A B2000-01-01 -0.282863 0.4691122000-01-02 -0.173215 1.2121122000-01-03 -2.104569 -0.8618492000-01-04 -0.706771 0.7215552000-01-05 0.567020 -0.4249722000-01-06 0.113648 -0.6736902000-01-07 0.577046 0.4047052000-01-08 -1.157892 -0.370647In [10]: df.loc[:, ['B', 'A']] = df[['A', 'B']]In [11]: df[['A', 'B']]Out[11]:A B2000-01-01 -0.282863 0.4691122000-01-02 -0.173215 1.2121122000-01-03 -2.104569 -0.8618492000-01-04 -0.706771 0.7215552000-01-05 0.567020 -0.4249722000-01-06 0.113648 -0.6736902000-01-07 0.577046 0.4047052000-01-08 -1.157892 -0.370647
交换列值的正确方法是使用原始值:
In [12]: df.loc[:, ['B', 'A']] = df[['A', 'B']].to_numpy()In [13]: df[['A', 'B']]Out[13]:A B2000-01-01 0.469112 -0.2828632000-01-02 1.212112 -0.1732152000-01-03 -0.861849 -2.1045692000-01-04 0.721555 -0.7067712000-01-05 -0.424972 0.5670202000-01-06 -0.673690 0.1136482000-01-07 0.404705 0.5770462000-01-08 -0.370647 -1.157892
:::
属性访问
您可以直接访问某个Series或列上的索引DataFrame作为属性:
In [14]: sa = pd.Series([1, 2, 3], index=list('abc'))In [15]: dfa = df.copy()
In [16]: sa.bOut[16]: 2In [17]: dfa.AOut[17]:2000-01-01 0.4691122000-01-02 1.2121122000-01-03 -0.8618492000-01-04 0.7215552000-01-05 -0.4249722000-01-06 -0.6736902000-01-07 0.4047052000-01-08 -0.370647Freq: D, Name: A, dtype: float64
In [18]: sa.a = 5In [19]: saOut[19]:a 5b 2c 3dtype: int64In [20]: dfa.A = list(range(len(dfa.index))) # ok if A already existsIn [21]: dfaOut[21]:A B C D2000-01-01 0 -0.282863 -1.509059 -1.1356322000-01-02 1 -0.173215 0.119209 -1.0442362000-01-03 2 -2.104569 -0.494929 1.0718042000-01-04 3 -0.706771 -1.039575 0.2718602000-01-05 4 0.567020 0.276232 -1.0874012000-01-06 5 0.113648 -1.478427 0.5249882000-01-07 6 0.577046 -1.715002 -1.0392682000-01-08 7 -1.157892 -1.344312 0.844885In [22]: dfa['A'] = list(range(len(dfa.index))) # use this form to create a new columnIn [23]: dfaOut[23]:A B C D2000-01-01 0 -0.282863 -1.509059 -1.1356322000-01-02 1 -0.173215 0.119209 -1.0442362000-01-03 2 -2.104569 -0.494929 1.0718042000-01-04 3 -0.706771 -1.039575 0.2718602000-01-05 4 0.567020 0.276232 -1.0874012000-01-06 5 0.113648 -1.478427 0.5249882000-01-07 6 0.577046 -1.715002 -1.0392682000-01-08 7 -1.157892 -1.344312 0.844885
::: danger 警告
- 仅当index元素是有效的Python标识符时才可以使用此访问权限,例如
s.1,不允许。有关有效标识符的说明,请参见此处。 - 如果该属性与现有方法名称冲突,则该属性将不可用,例如
s.min,不允许。 - 同样的,如果它与任何下面的列表冲突的属性将不可用:
index,major_axis,minor_axis,items。 - 在任何一种情况下,标准索引仍然可以工作,例如
s['1'],s['min']和s['index']将访问相应的元素或列。
:::
如果您使用的是IPython环境,则还可以使用tab-completion来查看这些可访问的属性。
您还可以将a分配dict给一行DataFrame:
In [24]: x = pd.DataFrame({'x': [1, 2, 3], 'y': [3, 4, 5]})In [25]: x.iloc[1] = {'x': 9, 'y': 99}In [26]: xOut[26]:x y0 1 31 9 992 3 5
您可以使用属性访问来修改DataFrame的Series或列的现有元素,但要小心; 如果您尝试使用属性访问权来创建新列,则会创建新属性而不是新列。在0.21.0及更高版本中,这将引发UserWarning:
In [1]: df = pd.DataFrame({'one': [1., 2., 3.]})In [2]: df.two = [4, 5, 6]UserWarning: Pandas doesn't allow Series to be assigned into nonexistent columns - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute_accessIn [3]: dfOut[3]:one0 1.01 2.02 3.0
切片范围
沿着任意轴切割范围的最稳健和一致的方法在详细说明该方法的“ 按位置选择”部分中描述.iloc。现在,我们解释使用[]运算符切片的语义。
使用Series,语法与ndarray完全一样,返回值的一部分和相应的标签:
In [27]: s[:5]Out[27]:2000-01-01 0.4691122000-01-02 1.2121122000-01-03 -0.8618492000-01-04 0.7215552000-01-05 -0.424972Freq: D, Name: A, dtype: float64In [28]: s[::2]Out[28]:2000-01-01 0.4691122000-01-03 -0.8618492000-01-05 -0.4249722000-01-07 0.404705Freq: 2D, Name: A, dtype: float64In [29]: s[::-1]Out[29]:2000-01-08 -0.3706472000-01-07 0.4047052000-01-06 -0.6736902000-01-05 -0.4249722000-01-04 0.7215552000-01-03 -0.8618492000-01-02 1.2121122000-01-01 0.469112Freq: -1D, Name: A, dtype: float64
请注意,设置也适用:
In [30]: s2 = s.copy()In [31]: s2[:5] = 0In [32]: s2Out[32]:2000-01-01 0.0000002000-01-02 0.0000002000-01-03 0.0000002000-01-04 0.0000002000-01-05 0.0000002000-01-06 -0.6736902000-01-07 0.4047052000-01-08 -0.370647Freq: D, Name: A, dtype: float64
使用DataFrame,切片内部[] 切片。这主要是为了方便而提供的,因为它是如此常见的操作。
In [33]: df[:3]Out[33]:A B C D2000-01-01 0.469112 -0.282863 -1.509059 -1.1356322000-01-02 1.212112 -0.173215 0.119209 -1.0442362000-01-03 -0.861849 -2.104569 -0.494929 1.071804In [34]: df[::-1]Out[34]:A B C D2000-01-08 -0.370647 -1.157892 -1.344312 0.8448852000-01-07 0.404705 0.577046 -1.715002 -1.0392682000-01-06 -0.673690 0.113648 -1.478427 0.5249882000-01-05 -0.424972 0.567020 0.276232 -1.0874012000-01-04 0.721555 -0.706771 -1.039575 0.2718602000-01-03 -0.861849 -2.104569 -0.494929 1.0718042000-01-02 1.212112 -0.173215 0.119209 -1.0442362000-01-01 0.469112 -0.282863 -1.509059 -1.135632
按标签选择
::: danger 警告
是否为设置操作返回副本或引用可能取决于上下文。这有时被称为应该避免。请参阅返回视图与复制。chained assignment
:::
::: danger 警告
In [35]: dfl = pd.DataFrame(np.random.randn(5, 4),....: columns=list('ABCD'),....: index=pd.date_range('20130101', periods=5))....:In [36]: dflOut[36]:A B C D2013-01-01 1.075770 -0.109050 1.643563 -1.4693882013-01-02 0.357021 -0.674600 -1.776904 -0.9689142013-01-03 -1.294524 0.413738 0.276662 -0.4720352013-01-04 -0.013960 -0.362543 -0.006154 -0.9230612013-01-05 0.895717 0.805244 -1.206412 2.565646
In [4]: dfl.loc[2:3]TypeError: cannot do slice indexing on <class 'pandas.tseries.index.DatetimeIndex'> with these indexers [2] of <type 'int'>
切片中的字符串喜欢可以转换为索引的类型并导致自然切片。
In [37]: dfl.loc['20130102':'20130104']Out[37]:A B C D2013-01-02 0.357021 -0.674600 -1.776904 -0.9689142013-01-03 -1.294524 0.413738 0.276662 -0.4720352013-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,参见按可调用选择。
In [38]: s1 = pd.Series(np.random.randn(6), index=list('abcdef'))In [39]: s1Out[39]:a 1.431256b 1.340309c -1.170299d -0.226169e 0.410835f 0.813850dtype: float64In [40]: s1.loc['c':]Out[40]:c -1.170299d -0.226169e 0.410835f 0.813850dtype: float64In [41]: s1.loc['b']Out[41]: 1.3403088497993827
请注意,设置也适用:
In [42]: s1.loc['c':] = 0In [43]: s1Out[43]:a 1.431256b 1.340309c 0.000000d 0.000000e 0.000000f 0.000000dtype: float64
使用DataFrame:
In [44]: df1 = pd.DataFrame(np.random.randn(6, 4),....: index=list('abcdef'),....: columns=list('ABCD'))....:In [45]: df1Out[45]:A B C Da 0.132003 -0.827317 -0.076467 -1.187678b 1.130127 -1.436737 -1.413681 1.607920c 1.024180 0.569605 0.875906 -2.211372d 0.974466 -2.006747 -0.410001 -0.078638e 0.545952 -1.219217 -1.226825 0.769804f -1.281247 -0.727707 -0.121306 -0.097883In [46]: df1.loc[['a', 'b', 'd'], :]Out[46]:A B C Da 0.132003 -0.827317 -0.076467 -1.187678b 1.130127 -1.436737 -1.413681 1.607920d 0.974466 -2.006747 -0.410001 -0.078638
通过标签切片访问:
In [47]: df1.loc['d':, 'A':'C']Out[47]:A B Cd 0.974466 -2.006747 -0.410001e 0.545952 -1.219217 -1.226825f -1.281247 -0.727707 -0.121306
使用标签获取横截面(相当于df.xs('a')):
In [48]: df1.loc['a']Out[48]:A 0.132003B -0.827317C -0.076467D -1.187678Name: a, dtype: float64
要使用布尔数组获取值:
In [49]: df1.loc['a'] > 0Out[49]:A TrueB FalseC FalseD FalseName: a, dtype: boolIn [50]: df1.loc[:, df1.loc['a'] > 0]Out[50]:Aa 0.132003b 1.130127c 1.024180d 0.974466e 0.545952f -1.281247
要明确获取值(相当于已弃用df.get_value('a','A')):
# this is also equivalent to ``df1.at['a','A']``In [51]: df1.loc['a', 'A']Out[51]: 0.13200317033032932
用标签切片
使用.loc切片时,如果索引中存在开始和停止标签,则返回位于两者之间的元素(包括它们):
In [52]: s = pd.Series(list('abcde'), index=[0, 3, 2, 5, 4])In [53]: s.loc[3:5]Out[53]:3 b2 c5 ddtype: object
如果两个中至少有一个不存在,但索引已排序,并且可以与开始和停止标签进行比较,那么通过选择在两者之间排名的标签,切片仍将按预期工作:
In [54]: s.sort_index()Out[54]:0 a2 c3 b4 e5 ddtype: objectIn [55]: s.sort_index().loc[1:6]Out[55]:2 c3 b4 e5 ddtype: object
然而,如果两个中的至少一个不存在并且索引未被排序,则将引发错误(因为否则将是计算上昂贵的,并且对于混合类型索引可能是模糊的)。例如,在上面的例子中,s.loc[1:6]会提高KeyError。
有关此行为背后的基本原理,请参阅 端点包含。
按位置选择
::: danger 警告
是否为设置操作返回副本或引用可能取决于上下文。这有时被称为应该避免。请参阅返回视图与复制。chained assignment
:::
Pandas提供了一套方法,以获得纯粹基于整数的索引。语义紧跟Python和NumPy切片。这些是0-based索引。切片时,所结合的开始被包括,而上限是排除。尝试使用非整数,甚至是有效的标签都会引发一个问题IndexError。
该.iloc属性是主要访问方法。以下是有效输入:
- 一个整数,例如
5。 - 整数列表或数组。
[4, 3, 0] - 带有整数的切片对象
1:7。 - 布尔数组。
- A
callable,参见按可调用选择。
In [56]: s1 = pd.Series(np.random.randn(5), index=list(range(0, 10, 2)))In [57]: s1Out[57]:0 0.6957752 0.3417344 0.9597266 -1.1103368 -0.619976dtype: float64In [58]: s1.iloc[:3]Out[58]:0 0.6957752 0.3417344 0.959726dtype: float64In [59]: s1.iloc[3]Out[59]: -1.110336102891167
请注意,设置也适用:
In [60]: s1.iloc[:3] = 0In [61]: s1Out[61]:0 0.0000002 0.0000004 0.0000006 -1.1103368 -0.619976dtype: float64
使用DataFrame:
In [62]: df1 = pd.DataFrame(np.random.randn(6, 4),....: index=list(range(0, 12, 2)),....: columns=list(range(0, 8, 2)))....:In [63]: df1Out[63]:0 2 4 60 0.149748 -0.732339 0.687738 0.1764442 0.403310 -0.154951 0.301624 -2.1798614 -1.369849 -0.954208 1.462696 -1.7431616 -0.826591 -0.345352 1.314232 0.6905798 0.995761 2.396780 0.014871 3.35742710 -0.317441 -1.236269 0.896171 -0.487602
通过整数切片选择:
In [64]: df1.iloc[:3]Out[64]:0 2 4 60 0.149748 -0.732339 0.687738 0.1764442 0.403310 -0.154951 0.301624 -2.1798614 -1.369849 -0.954208 1.462696 -1.743161In [65]: df1.iloc[1:5, 2:4]Out[65]:4 62 0.301624 -2.1798614 1.462696 -1.7431616 1.314232 0.6905798 0.014871 3.357427
通过整数列表选择:
In [66]: df1.iloc[[1, 3, 5], [1, 3]]Out[66]:2 62 -0.154951 -2.1798616 -0.345352 0.69057910 -1.236269 -0.487602
In [67]: df1.iloc[1:3, :]Out[67]:0 2 4 62 0.403310 -0.154951 0.301624 -2.1798614 -1.369849 -0.954208 1.462696 -1.743161
In [68]: df1.iloc[:, 1:3]Out[68]:2 40 -0.732339 0.6877382 -0.154951 0.3016244 -0.954208 1.4626966 -0.345352 1.3142328 2.396780 0.01487110 -1.236269 0.896171
# this is also equivalent to ``df1.iat[1,1]``In [69]: df1.iloc[1, 1]Out[69]: -0.1549507744249032
使用整数位置(等效df.xs(1))得到横截面:
In [70]: df1.iloc[1]Out[70]:0 0.4033102 -0.1549514 0.3016246 -2.179861Name: 2, dtype: float64
超出范围的切片索引正如Python / Numpy中一样优雅地处理。
# these are allowed in python/numpy.In [71]: x = list('abcdef')In [72]: xOut[72]: ['a', 'b', 'c', 'd', 'e', 'f']In [73]: x[4:10]Out[73]: ['e', 'f']In [74]: x[8:10]Out[74]: []In [75]: s = pd.Series(x)In [76]: sOut[76]:0 a1 b2 c3 d4 e5 fdtype: objectIn [77]: s.iloc[4:10]Out[77]:4 e5 fdtype: objectIn [78]: s.iloc[8:10]Out[78]: Series([], dtype: object)
请注意,使用超出边界的切片可能会导致空轴(例如,返回一个空的DataFrame)。
In [79]: dfl = pd.DataFrame(np.random.randn(5, 2), columns=list('AB'))In [80]: dflOut[80]:A B0 -0.082240 -2.1829371 0.380396 0.0848442 0.432390 1.5199703 -0.493662 0.6001784 0.274230 0.132885In [81]: dfl.iloc[:, 2:3]Out[81]:Empty DataFrameColumns: []Index: [0, 1, 2, 3, 4]In [82]: dfl.iloc[:, 1:3]Out[82]:B0 -2.1829371 0.0848442 1.5199703 0.6001784 0.132885In [83]: dfl.iloc[4:6]Out[83]:A B4 0.27423 0.132885
一个超出范围的索引器会引发一个IndexError。任何元素超出范围的索引器列表都会引发
IndexError。
>>> dfl.iloc[[4, 5, 6]]IndexError: positional indexers are out-of-bounds>>> dfl.iloc[:, 4]IndexError: single positional indexer is out-of-bounds
通过可调用选择
版本0.18.1中的新功能。
.loc,.iloc以及[]索引也可以接受一个callable索引器。在callable必须与一个参数(调用系列或数据帧)返回的有效输出索引功能。
In [84]: df1 = pd.DataFrame(np.random.randn(6, 4),....: index=list('abcdef'),....: columns=list('ABCD'))....:In [85]: df1Out[85]:A B C Da -0.023688 2.410179 1.450520 0.206053b -0.251905 -2.213588 1.063327 1.266143c 0.299368 -0.863838 0.408204 -1.048089d -0.025747 -0.988387 0.094055 1.262731e 1.289997 0.082423 -0.055758 0.536580f -0.489682 0.369374 -0.034571 -2.484478In [86]: df1.loc[lambda df: df.A > 0, :]Out[86]:A B C Dc 0.299368 -0.863838 0.408204 -1.048089e 1.289997 0.082423 -0.055758 0.536580In [87]: df1.loc[:, lambda df: ['A', 'B']]Out[87]:A Ba -0.023688 2.410179b -0.251905 -2.213588c 0.299368 -0.863838d -0.025747 -0.988387e 1.289997 0.082423f -0.489682 0.369374In [88]: df1.iloc[:, lambda df: [0, 1]]Out[88]:A Ba -0.023688 2.410179b -0.251905 -2.213588c 0.299368 -0.863838d -0.025747 -0.988387e 1.289997 0.082423f -0.489682 0.369374In [89]: df1[lambda df: df.columns[0]]Out[89]:a -0.023688b -0.251905c 0.299368d -0.025747e 1.289997f -0.489682Name: A, dtype: float64
您可以使用可调用索引Series。
In [90]: df1.A.loc[lambda s: s > 0]Out[90]:c 0.299368e 1.289997Name: A, dtype: float64
使用这些方法/索引器,您可以在不使用临时变量的情况下链接数据选择操作。
In [91]: bb = pd.read_csv('data/baseball.csv', index_col='id')In [92]: (bb.groupby(['year', 'team']).sum()....: .loc[lambda df: df.r > 100])....:Out[92]:stint g ab r h X2b X3b hr rbi sb cs bb so ibb hbp sh sf gidpyear team2007 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.0DET 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.0HOU 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.0LAN 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.0NYN 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.0SFN 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.0TEX 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.0TOR 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如果你想要定位索引。
In [93]: dfd = pd.DataFrame({'A': [1, 2, 3],....: 'B': [4, 5, 6]},....: index=list('abc'))....:In [94]: dfdOut[94]:A Ba 1 4b 2 5c 3 6
以前的行为,您希望从“A”列中获取索引中的第0个和第2个元素。
In [3]: dfd.ix[[0, 2], 'A']Out[3]:a 1c 3Name: A, dtype: int64
用.loc。这里我们将从索引中选择适当的索引,然后使用标签索引。
In [95]: dfd.loc[dfd.index[[0, 2]], 'A']Out[95]:a 1c 3Name: A, dtype: int64
这也可以.iloc通过在索引器上显式获取位置,并使用
位置索引来选择事物来表达。
In [96]: dfd.iloc[[0, 2], dfd.columns.get_loc('A')]Out[96]:a 1c 3Name: A, dtype: int64
要获得多个索引器,请使用.get_indexer:
In [97]: dfd.iloc[[0, 2], dfd.columns.get_indexer(['A', 'B'])]Out[97]:A Ba 1 4c 3 6
不推荐使用缺少标签的列表进行索引
::: danger 警告
从0.21.0开始,使用.loc或[]包含一个或多个缺少标签的列表,不赞成使用.reindex。
:::
在以前的版本中,.loc[list-of-labels]只要找到至少1个密钥,使用就可以工作(否则会引起a KeyError)。不推荐使用此行为,并将显示指向此部分的警告消息。推荐的替代方案是使用.reindex()。
例如。
In [98]: s = pd.Series([1, 2, 3])In [99]: sOut[99]:0 11 22 3dtype: int64
找到所有键的选择保持不变。
In [100]: s.loc[[1, 2]]Out[100]:1 22 3dtype: int64
以前的行为
In [4]: s.loc[[1, 2, 3]]Out[4]:1 2.02 3.03 NaNdtype: float64
目前的行为
In [4]: s.loc[[1, 2, 3]]Passing list-likes to .loc with any non-matching elements will raiseKeyError in the future, you can use .reindex() as an alternative.See the documentation here:http://pandas.pydata.org/pandas-docs/stable/indexing.html#deprecate-loc-reindex-listlikeOut[4]:1 2.02 3.03 NaNdtype: float64
重新索引
实现选择潜在的未找到元素的惯用方法是通过.reindex()。另请参阅重建索引部分。
In [101]: s.reindex([1, 2, 3])Out[101]:1 2.02 3.03 NaNdtype: float64
或者,如果您只想选择有效的密钥,则以下是惯用且有效的; 保证保留选择的dtype。
In [102]: labels = [1, 2, 3]In [103]: s.loc[s.index.intersection(labels)]Out[103]:1 22 3dtype: int64
拥有重复索引会引发.reindex():
In [104]: s = pd.Series(np.arange(4), index=['a', 'a', 'b', 'c'])In [105]: labels = ['c', 'd']
In [17]: s.reindex(labels)ValueError: cannot reindex from a duplicate axis
通常,您可以将所需标签与当前轴相交,然后重新索引。
In [106]: s.loc[s.index.intersection(labels)].reindex(labels)Out[106]:c 3.0d NaNdtype: float64
但是,如果生成的索引重复,这仍然会提高。
In [41]: labels = ['a', 'd']In [42]: s.loc[s.index.intersection(labels)].reindex(labels)ValueError: cannot reindex from a duplicate axis
选择随机样本
使用该sample()方法随机选择Series或DataFrame中的行或列。默认情况下,该方法将对行进行采样,并接受要返回的特定行数/列数或一小部分行。
In [107]: s = pd.Series([0, 1, 2, 3, 4, 5])# When no arguments are passed, returns 1 row.In [108]: s.sample()Out[108]:4 4dtype: int64# One may specify either a number of rows:In [109]: s.sample(n=3)Out[109]:0 04 41 1dtype: int64# Or a fraction of the rows:In [110]: s.sample(frac=0.5)Out[110]:5 53 31 1dtype: int64
默认情况下,sample最多会返回每行一次,但也可以使用以下replace选项进行替换:
In [111]: s = pd.Series([0, 1, 2, 3, 4, 5])# Without replacement (default):In [112]: s.sample(n=6, replace=False)Out[112]:0 01 15 53 32 24 4dtype: int64# With replacement:In [113]: s.sample(n=6, replace=True)Out[113]:0 04 43 32 24 44 4dtype: int64
默认情况下,每行具有相同的选择概率,但如果您希望行具有不同的概率,则可以将sample函数采样权重作为
weights。这些权重可以是列表,NumPy数组或系列,但它们的长度必须与您采样的对象的长度相同。缺失的值将被视为零的权重,并且不允许使用inf值。如果权重不总和为1,则通过将所有权重除以权重之和来对它们进行重新规范化。例如:
In [114]: s = pd.Series([0, 1, 2, 3, 4, 5])In [115]: example_weights = [0, 0, 0.2, 0.2, 0.2, 0.4]In [116]: s.sample(n=3, weights=example_weights)Out[116]:5 54 43 3dtype: int64# Weights will be re-normalized automaticallyIn [117]: example_weights2 = [0.5, 0, 0, 0, 0, 0]In [118]: s.sample(n=1, weights=example_weights2)Out[118]:0 0dtype: int64
应用于DataFrame时,只需将列的名称作为字符串传递,就可以使用DataFrame的列作为采样权重(假设您要对行而不是列进行采样)。
In [119]: df2 = pd.DataFrame({'col1': [9, 8, 7, 6],.....: 'weight_column': [0.5, 0.4, 0.1, 0]}).....:In [120]: df2.sample(n=3, weights='weight_column')Out[120]:col1 weight_column1 8 0.40 9 0.52 7 0.1
sample还允许用户使用axis参数对列而不是行进行采样。
In [121]: df3 = pd.DataFrame({'col1': [1, 2, 3], 'col2': [2, 3, 4]})In [122]: df3.sample(n=1, axis=1)Out[122]:col10 11 22 3
最后,还可以sample使用random_state参数为随机数生成器设置种子,该参数将接受整数(作为种子)或NumPy RandomState对象。
In [123]: df4 = pd.DataFrame({'col1': [1, 2, 3], 'col2': [2, 3, 4]})# With a given seed, the sample will always draw the same rows.In [124]: df4.sample(n=2, random_state=2)Out[124]:col1 col22 3 41 2 3In [125]: df4.sample(n=2, random_state=2)Out[125]:col1 col22 3 41 2 3
用放大设定
.loc/[]当为该轴设置不存在的键时,操作可以执行放大。
在这种Series情况下,这实际上是一种附加操作。
In [126]: se = pd.Series([1, 2, 3])In [127]: seOut[127]:0 11 22 3dtype: int64In [128]: se[5] = 5.In [129]: seOut[129]:0 1.01 2.02 3.05 5.0dtype: float64
A DataFrame可以在任一轴上放大.loc。
In [130]: dfi = pd.DataFrame(np.arange(6).reshape(3, 2),.....: columns=['A', 'B']).....:In [131]: dfiOut[131]:A B0 0 11 2 32 4 5In [132]: dfi.loc[:, 'C'] = dfi.loc[:, 'A']In [133]: dfiOut[133]:A B C0 0 1 01 2 3 22 4 5 4
这就像是一个append操作DataFrame。
In [134]: dfi.loc[3] = 5In [135]: dfiOut[135]:A B C0 0 1 01 2 3 22 4 5 43 5 5 5
快速标量值获取和设置
因为索引[]必须处理很多情况(单标签访问,切片,布尔索引等),所以它有一些开销以便弄清楚你要求的是什么。如果您只想访问标量值,最快的方法是使用在所有数据结构上实现的at和iat方法。
与之类似loc,at提供基于标签的标量查找,同时iat提供类似于基于整数的查找iloc
In [136]: s.iat[5]Out[136]: 5In [137]: df.at[dates[5], 'A']Out[137]: -0.6736897080883706In [138]: df.iat[3, 0]Out[138]: 0.7215551622443669
您也可以使用这些相同的索引器进行设置。
In [139]: df.at[dates[5], 'E'] = 7In [140]: df.iat[3, 0] = 7
at 如果索引器丢失,可以如上所述放大对象。
In [141]: df.at[dates[-1] + pd.Timedelta('1 day'), 0] = 7In [142]: dfOut[142]:A B C D E 02000-01-01 0.469112 -0.282863 -1.509059 -1.135632 NaN NaN2000-01-02 1.212112 -0.173215 0.119209 -1.044236 NaN NaN2000-01-03 -0.861849 -2.104569 -0.494929 1.071804 NaN NaN2000-01-04 7.000000 -0.706771 -1.039575 0.271860 NaN NaN2000-01-05 -0.424972 0.567020 0.276232 -1.087401 NaN NaN2000-01-06 -0.673690 0.113648 -1.478427 0.524988 7.0 NaN2000-01-07 0.404705 0.577046 -1.715002 -1.039268 NaN NaN2000-01-08 -0.370647 -1.157892 -1.344312 0.844885 NaN NaN2000-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完全相同:
In [143]: s = pd.Series(range(-3, 4))In [144]: sOut[144]:0 -31 -22 -13 04 15 26 3dtype: int64In [145]: s[s > 0]Out[145]:4 15 26 3dtype: int64In [146]: s[(s < -1) | (s > 0.5)]Out[146]:0 -31 -24 15 26 3dtype: int64In [147]: s[~(s < 0)]Out[147]:3 04 15 26 3dtype: int64
您可以使用与DataFrame索引长度相同的布尔向量从DataFrame中选择行(例如,从DataFrame的其中一列派生的东西):
In [148]: df[df['A'] > 0]Out[148]:A B C D E 02000-01-01 0.469112 -0.282863 -1.509059 -1.135632 NaN NaN2000-01-02 1.212112 -0.173215 0.119209 -1.044236 NaN NaN2000-01-04 7.000000 -0.706771 -1.039575 0.271860 NaN NaN2000-01-07 0.404705 0.577046 -1.715002 -1.039268 NaN NaN
列表推导和map系列方法也可用于产生更复杂的标准:
In [149]: df2 = pd.DataFrame({'a': ['one', 'one', 'two', 'three', 'two', 'one', 'six'],.....: 'b': ['x', 'y', 'y', 'x', 'y', 'x', 'x'],.....: 'c': np.random.randn(7)}).....:# only want 'two' or 'three'In [150]: criterion = df2['a'].map(lambda x: x.startswith('t'))In [151]: df2[criterion]Out[151]:a b c2 two y 0.0412903 three x 0.3617194 two y -0.238075# equivalent but slowerIn [152]: df2[[x.startswith('t') for x in df2['a']]]Out[152]:a b c2 two y 0.0412903 three x 0.3617194 two y -0.238075# Multiple criteriaIn [153]: df2[criterion & (df2['b'] == 'x')]Out[153]:a b c3 three x 0.361719
随着选择方法通过标签选择,通过位置选择和高级索引,你可以沿着使用布尔向量与其他索引表达式中组合选择多个轴。
In [154]: df2.loc[criterion & (df2['b'] == 'x'), 'b':'c']Out[154]:b c3 x 0.361719
使用isin进行索引
考虑一下isin()方法Series,该方法返回一个布尔向量,只要Series元素存在于传递列表中,该向量就为真。这允许您选择一列或多列具有所需值的行:
In [155]: s = pd.Series(np.arange(5), index=np.arange(5)[::-1], dtype='int64')In [156]: sOut[156]:4 03 12 21 30 4dtype: int64In [157]: s.isin([2, 4, 6])Out[157]:4 False3 False2 True1 False0 Truedtype: boolIn [158]: s[s.isin([2, 4, 6])]Out[158]:2 20 4dtype: int64
Index对象可以使用相同的方法,当您不知道哪些搜索标签实际存在时,它们非常有用:
In [159]: s[s.index.isin([2, 4, 6])]Out[159]:4 02 2dtype: int64# compare it to the followingIn [160]: s.reindex([2, 4, 6])Out[160]:2 2.04 0.06 NaNdtype: float64
除此之外,还MultiIndex允许选择在成员资格检查中使用的单独级别:
In [161]: s_mi = pd.Series(np.arange(6),.....: index=pd.MultiIndex.from_product([[0, 1], ['a', 'b', 'c']])).....:In [162]: s_miOut[162]:0 a 0b 1c 21 a 3b 4c 5dtype: int64In [163]: s_mi.iloc[s_mi.index.isin([(1, 'a'), (2, 'b'), (0, 'c')])]Out[163]:0 c 21 a 3dtype: int64In [164]: s_mi.iloc[s_mi.index.isin(['a', 'c', 'e'], level=1)]Out[164]:0 a 0c 21 a 3c 5dtype: int64
DataFrame也有一个isin()方法。调用时isin,将一组值作为数组或字典传递。如果values是一个数组,则isin返回与原始DataFrame形状相同的布尔数据框,并在元素序列中的任何位置使用True。
In [165]: df = pd.DataFrame({'vals': [1, 2, 3, 4], 'ids': ['a', 'b', 'f', 'n'],.....: 'ids2': ['a', 'n', 'c', 'n']}).....:In [166]: values = ['a', 'b', 1, 3]In [167]: df.isin(values)Out[167]:vals ids ids20 True True True1 False True False2 True False False3 False False False
通常,您需要将某些值与某些列匹配。只需将值设置dict为键为列的位置,值即为要检查的项目列表。
In [168]: values = {'ids': ['a', 'b'], 'vals': [1, 3]}In [169]: df.isin(values)Out[169]:vals ids ids20 True True False1 False True False2 True False False3 False False False
结合数据帧的isin同any()和all()方法来快速选择符合给定的标准对数据子集。要选择每列符合其自己标准的行:
In [170]: values = {'ids': ['a', 'b'], 'ids2': ['a', 'c'], 'vals': [1, 3]}In [171]: row_mask = df.isin(values).all(1)In [172]: df[row_mask]Out[172]:vals ids ids20 1 a a
该where()方法和屏蔽
从具有布尔向量的Series中选择值通常会返回数据的子集。为了保证选择输出与原始数据具有相同的形状,您可以where在Series和中使用该方法DataFrame。
仅返回选定的行:
In [173]: s[s > 0]Out[173]:3 12 21 30 4dtype: int64
要返回与原始形状相同的系列:
In [174]: s.where(s > 0)Out[174]:4 NaN3 1.02 2.01 3.00 4.0dtype: float64
现在,使用布尔标准从DataFrame中选择值也可以保留输入数据形状。where在引擎盖下用作实现。下面的代码相当于。df.where(df < 0)
In [175]: df[df < 0]Out[175]:A B C D2000-01-01 -2.104139 -1.309525 NaN NaN2000-01-02 -0.352480 NaN -1.192319 NaN2000-01-03 -0.864883 NaN -0.227870 NaN2000-01-04 NaN -1.222082 NaN -1.2332032000-01-05 NaN -0.605656 -1.169184 NaN2000-01-06 NaN -0.948458 NaN -0.6847182000-01-07 -2.670153 -0.114722 NaN -0.0480482000-01-08 NaN NaN -0.048788 -0.808838
此外,在返回的副本中,where使用可选other参数替换条件为False的值。
In [176]: df.where(df < 0, -df)Out[176]:A B C D2000-01-01 -2.104139 -1.309525 -0.485855 -0.2451662000-01-02 -0.352480 -0.390389 -1.192319 -1.6558242000-01-03 -0.864883 -0.299674 -0.227870 -0.2810592000-01-04 -0.846958 -1.222082 -0.600705 -1.2332032000-01-05 -0.669692 -0.605656 -1.169184 -0.3424162000-01-06 -0.868584 -0.948458 -2.297780 -0.6847182000-01-07 -2.670153 -0.114722 -0.168904 -0.0480482000-01-08 -0.801196 -1.392071 -0.048788 -0.808838
您可能希望根据某些布尔条件设置值。这可以直观地完成,如下所示:
In [177]: s2 = s.copy()In [178]: s2[s2 < 0] = 0In [179]: s2Out[179]:4 03 12 21 30 4dtype: int64In [180]: df2 = df.copy()In [181]: df2[df2 < 0] = 0In [182]: df2Out[182]:A B C D2000-01-01 0.000000 0.000000 0.485855 0.2451662000-01-02 0.000000 0.390389 0.000000 1.6558242000-01-03 0.000000 0.299674 0.000000 0.2810592000-01-04 0.846958 0.000000 0.600705 0.0000002000-01-05 0.669692 0.000000 0.000000 0.3424162000-01-06 0.868584 0.000000 2.297780 0.0000002000-01-07 0.000000 0.000000 0.168904 0.0000002000-01-08 0.801196 1.392071 0.000000 0.000000
默认情况下,where返回数据的修改副本。有一个可选参数,inplace以便可以在不创建副本的情况下修改原始数据:
In [183]: df_orig = df.copy()In [184]: df_orig.where(df > 0, -df, inplace=True)In [185]: df_origOut[185]:A B C D2000-01-01 2.104139 1.309525 0.485855 0.2451662000-01-02 0.352480 0.390389 1.192319 1.6558242000-01-03 0.864883 0.299674 0.227870 0.2810592000-01-04 0.846958 1.222082 0.600705 1.2332032000-01-05 0.669692 0.605656 1.169184 0.3424162000-01-06 0.868584 0.948458 2.297780 0.6847182000-01-07 2.670153 0.114722 0.168904 0.0480482000-01-08 0.801196 1.392071 0.048788 0.808838
::: tip 注意
签名DataFrame.where()不同于numpy.where()。大致相当于。df1.where(m, df2)````np.where(m, df1, df2)
In [186]: df.where(df < 0, -df) == np.where(df < 0, df, -df)Out[186]:A B C D2000-01-01 True True True True2000-01-02 True True True True2000-01-03 True True True True2000-01-04 True True True True2000-01-05 True True True True2000-01-06 True True True True2000-01-07 True True True True2000-01-08 True True True True
:::
对准
此外,where对齐输入布尔条件(ndarray或DataFrame),以便可以使用设置进行部分选择。这类似于部分设置通过.loc(但是在内容而不是轴标签上)。
In [187]: df2 = df.copy()In [188]: df2[df2[1:4] > 0] = 3In [189]: df2Out[189]:A B C D2000-01-01 -2.104139 -1.309525 0.485855 0.2451662000-01-02 -0.352480 3.000000 -1.192319 3.0000002000-01-03 -0.864883 3.000000 -0.227870 3.0000002000-01-04 3.000000 -1.222082 3.000000 -1.2332032000-01-05 0.669692 -0.605656 -1.169184 0.3424162000-01-06 0.868584 -0.948458 2.297780 -0.6847182000-01-07 -2.670153 -0.114722 0.168904 -0.0480482000-01-08 0.801196 1.392071 -0.048788 -0.808838
哪里也可以接受axis和level参数在执行时对齐输入where。
In [190]: df2 = df.copy()In [191]: df2.where(df2 > 0, df2['A'], axis='index')Out[191]:A B C D2000-01-01 -2.104139 -2.104139 0.485855 0.2451662000-01-02 -0.352480 0.390389 -0.352480 1.6558242000-01-03 -0.864883 0.299674 -0.864883 0.2810592000-01-04 0.846958 0.846958 0.600705 0.8469582000-01-05 0.669692 0.669692 0.669692 0.3424162000-01-06 0.868584 0.868584 2.297780 0.8685842000-01-07 -2.670153 -2.670153 0.168904 -2.6701532000-01-08 0.801196 1.392071 0.801196 0.801196
这相当于(但快于)以下内容。
In [192]: df2 = df.copy()In [193]: df.apply(lambda x, y: x.where(x > 0, y), y=df['A'])Out[193]:A B C D2000-01-01 -2.104139 -2.104139 0.485855 0.2451662000-01-02 -0.352480 0.390389 -0.352480 1.6558242000-01-03 -0.864883 0.299674 -0.864883 0.2810592000-01-04 0.846958 0.846958 0.600705 0.8469582000-01-05 0.669692 0.669692 0.669692 0.3424162000-01-06 0.868584 0.868584 2.297780 0.8685842000-01-07 -2.670153 -2.670153 0.168904 -2.6701532000-01-08 0.801196 1.392071 0.801196 0.801196
版本0.18.1中的新功能。
哪里可以接受一个可调用的条件和other参数。该函数必须带有一个参数(调用Series或DataFrame),并返回有效的输出作为条件和other参数。
In [194]: df3 = pd.DataFrame({'A': [1, 2, 3],.....: 'B': [4, 5, 6],.....: 'C': [7, 8, 9]}).....:In [195]: df3.where(lambda x: x > 4, lambda x: x + 10)Out[195]:A B C0 11 14 71 12 5 82 13 6 9
面具
mask()是的反布尔运算where。
In [196]: s.mask(s >= 0)Out[196]:4 NaN3 NaN2 NaN1 NaN0 NaNdtype: float64In [197]: df.mask(df >= 0)Out[197]:A B C D2000-01-01 -2.104139 -1.309525 NaN NaN2000-01-02 -0.352480 NaN -1.192319 NaN2000-01-03 -0.864883 NaN -0.227870 NaN2000-01-04 NaN -1.222082 NaN -1.2332032000-01-05 NaN -0.605656 -1.169184 NaN2000-01-06 NaN -0.948458 NaN -0.6847182000-01-07 -2.670153 -0.114722 NaN -0.0480482000-01-08 NaN NaN -0.048788 -0.808838
该query()方法
DataFrame对象有一个query()
允许使用表达式进行选择的方法。
您可以获取列的值,其中列b具有列值a和值之间的值c。例如:
In [198]: n = 10In [199]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))In [200]: dfOut[200]:a b c0 0.438921 0.118680 0.8636701 0.138138 0.577363 0.6866022 0.595307 0.564592 0.5206303 0.913052 0.926075 0.6161844 0.078718 0.854477 0.8987255 0.076404 0.523211 0.5915386 0.792342 0.216974 0.5640567 0.397890 0.454131 0.9157168 0.074315 0.437913 0.0197949 0.559209 0.502065 0.026437# pure pythonIn [201]: df[(df.a < df.b) & (df.b < df.c)]Out[201]:a b c1 0.138138 0.577363 0.6866024 0.078718 0.854477 0.8987255 0.076404 0.523211 0.5915387 0.397890 0.454131 0.915716# queryIn [202]: df.query('(a < b) & (b < c)')Out[202]:a b c1 0.138138 0.577363 0.6866024 0.078718 0.854477 0.8987255 0.076404 0.523211 0.5915387 0.397890 0.454131 0.915716
如果没有名称的列,则执行相同的操作但返回命名索引a。
In [203]: df = pd.DataFrame(np.random.randint(n / 2, size=(n, 2)), columns=list('bc'))In [204]: df.index.name = 'a'In [205]: dfOut[205]:b ca0 0 41 0 12 3 43 4 34 1 45 0 36 0 17 3 48 2 39 1 1In [206]: df.query('a < b and b < c')Out[206]:b ca2 3 4
如果您不希望或不能命名索引,则可以index在查询表达式中使用该名称
:
In [207]: df = pd.DataFrame(np.random.randint(n, size=(n, 2)), columns=list('bc'))In [208]: dfOut[208]:b c0 3 11 3 02 5 63 5 24 7 45 0 16 2 57 0 18 6 09 7 9In [209]: df.query('index < b < c')Out[209]:b c2 5 6
::: tip 注意
如果索引的名称与列名称重叠,则列名称优先。例如,
In [210]: df = pd.DataFrame({'a': np.random.randint(5, size=5)})In [211]: df.index.name = 'a'In [212]: df.query('a > 2') # uses the column 'a', not the indexOut[212]:aa1 33 3
您仍然可以使用特殊标识符’index’在查询表达式中使用索引:
In [213]: df.query('index > 2')Out[213]:aa3 34 2
如果由于某种原因你有一个名为列的列index,那么你也可以引用索引ilevel_0,但是此时你应该考虑将列重命名为不那么模糊的列。
:::
MultiIndex query()语法
您还可以使用的水平DataFrame带
MultiIndex,好像他们是在框架柱:
In [214]: n = 10In [215]: colors = np.random.choice(['red', 'green'], size=n)In [216]: foods = np.random.choice(['eggs', 'ham'], size=n)In [217]: colorsOut[217]:array(['red', 'red', 'red', 'green', 'green', 'green', 'green', 'green','green', 'green'], dtype='<U5')In [218]: foodsOut[218]:array(['ham', 'ham', 'eggs', 'eggs', 'eggs', 'ham', 'ham', 'eggs', 'eggs','eggs'], dtype='<U4')In [219]: index = pd.MultiIndex.from_arrays([colors, foods], names=['color', 'food'])In [220]: df = pd.DataFrame(np.random.randn(n, 2), index=index)In [221]: dfOut[221]:0 1color foodred ham 0.194889 -0.381994ham 0.318587 2.089075eggs -0.728293 -0.090255green eggs -0.748199 1.318931eggs -2.029766 0.792652ham 0.461007 -0.542749ham -0.305384 -0.479195eggs 0.095031 -0.270099eggs -0.707140 -0.773882eggs 0.229453 0.304418In [222]: df.query('color == "red"')Out[222]:0 1color foodred ham 0.194889 -0.381994ham 0.318587 2.089075eggs -0.728293 -0.090255
如果MultiIndex未命名的级别,您可以使用特殊名称引用它们:
In [223]: df.index.names = [None, None]In [224]: dfOut[224]:0 1red ham 0.194889 -0.381994ham 0.318587 2.089075eggs -0.728293 -0.090255green eggs -0.748199 1.318931eggs -2.029766 0.792652ham 0.461007 -0.542749ham -0.305384 -0.479195eggs 0.095031 -0.270099eggs -0.707140 -0.773882eggs 0.229453 0.304418In [225]: df.query('ilevel_0 == "red"')Out[225]:0 1red ham 0.194889 -0.381994ham 0.318587 2.089075eggs -0.728293 -0.090255
约定是ilevel_0,这意味着第0级的“索引级别0” index。
query()用例
用例query()是当您拥有一组具有共同
DataFrame列名(或索引级别/名称)子集的对象时。您可以将相同的查询传递给两个帧,而
无需指定您对查询感兴趣的帧
In [226]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))In [227]: dfOut[227]:a b c0 0.224283 0.736107 0.1391681 0.302827 0.657803 0.7138972 0.611185 0.136624 0.9849603 0.195246 0.123436 0.6277124 0.618673 0.371660 0.0479025 0.480088 0.062993 0.1857606 0.568018 0.483467 0.4452897 0.309040 0.274580 0.5871018 0.258993 0.477769 0.3702559 0.550459 0.840870 0.304611In [228]: df2 = pd.DataFrame(np.random.rand(n + 2, 3), columns=df.columns)In [229]: df2Out[229]:a b c0 0.357579 0.229800 0.5960011 0.309059 0.957923 0.9656632 0.123102 0.336914 0.3186163 0.526506 0.323321 0.8608134 0.518736 0.486514 0.3847245 0.190804 0.505723 0.6145336 0.891939 0.623977 0.6766397 0.480559 0.378528 0.4608588 0.420223 0.136404 0.1412959 0.732206 0.419540 0.60467510 0.604466 0.848974 0.89616511 0.589168 0.920046 0.732716In [230]: expr = '0.0 <= a <= c <= 0.5'In [231]: map(lambda frame: frame.query(expr), [df, df2])Out[231]: <map at 0x7f65f7952d30>
query()Python与pandas语法比较
完全类似numpy的语法:
In [232]: df = pd.DataFrame(np.random.randint(n, size=(n, 3)), columns=list('abc'))In [233]: dfOut[233]:a b c0 7 8 91 1 0 72 2 7 23 6 2 24 2 6 35 3 8 26 1 7 27 5 1 58 9 8 09 1 5 0In [234]: df.query('(a < b) & (b < c)')Out[234]:a b c0 7 8 9In [235]: df[(df.a < df.b) & (df.b < df.c)]Out[235]:a b c0 7 8 9
通过删除括号略微更好(通过绑定使比较运算符绑定比&和更紧|)。
In [236]: df.query('a < b & b < c')Out[236]:a b c0 7 8 9
使用英语而不是符号:
In [237]: df.query('a < b and b < c')Out[237]:a b c0 7 8 9
非常接近你如何在纸上写它:
In [238]: df.query('a < b < c')Out[238]:a b c0 7 8 9
在in与运营商not in
query()还支持Python in和
比较运算符的特殊用法,为调用或的方法提供了简洁的语法
。not in````isin````Series````DataFrame
# get all rows where columns "a" and "b" have overlapping valuesIn [239]: df = pd.DataFrame({'a': list('aabbccddeeff'), 'b': list('aaaabbbbcccc'),.....: 'c': np.random.randint(5, size=12),.....: 'd': np.random.randint(9, size=12)}).....:In [240]: dfOut[240]:a b c d0 a a 2 61 a a 4 72 b a 1 63 b a 2 14 c b 3 65 c b 0 26 d b 3 37 d b 2 18 e c 4 39 e c 2 010 f c 0 611 f c 1 2In [241]: df.query('a in b')Out[241]:a b c d0 a a 2 61 a a 4 72 b a 1 63 b a 2 14 c b 3 65 c b 0 2# How you'd do it in pure PythonIn [242]: df[df.a.isin(df.b)]Out[242]:a b c d0 a a 2 61 a a 4 72 b a 1 63 b a 2 14 c b 3 65 c b 0 2In [243]: df.query('a not in b')Out[243]:a b c d6 d b 3 37 d b 2 18 e c 4 39 e c 2 010 f c 0 611 f c 1 2# pure PythonIn [244]: df[~df.a.isin(df.b)]Out[244]:a b c d6 d b 3 37 d b 2 18 e c 4 39 e c 2 010 f c 0 611 f c 1 2
您可以将此与其他表达式结合使用,以获得非常简洁的查询:
# rows where cols a and b have overlapping values# and col c's values are less than col d'sIn [245]: df.query('a in b and c < d')Out[245]:a b c d0 a a 2 61 a a 4 72 b a 1 64 c b 3 65 c b 0 2# pure PythonIn [246]: df[df.b.isin(df.a) & (df.c < df.d)]Out[246]:a b c d0 a a 2 61 a a 4 72 b a 1 64 c b 3 65 c b 0 210 f c 0 611 f c 1 2
::: tip 注意
请注意in并在Python中进行评估,因为
它没有相应的操作。但是,只有 / expression本身在vanilla Python中进行评估。例如,在表达式中not in````numexpr** in````not in
df.query('a in b + c + d')
(b + c + d)通过评估numexpr和然后的in
操作在普通的Python评价。通常,任何可以使用的评估操作numexpr都是。
:::
==运算符与list对象的特殊用法
一个比较list值的使用列==/ !=工程,以类似in/ 。not in
In [247]: df.query('b == ["a", "b", "c"]')Out[247]:a b c d0 a a 2 61 a a 4 72 b a 1 63 b a 2 14 c b 3 65 c b 0 26 d b 3 37 d b 2 18 e c 4 39 e c 2 010 f c 0 611 f c 1 2# pure PythonIn [248]: df[df.b.isin(["a", "b", "c"])]Out[248]:a b c d0 a a 2 61 a a 4 72 b a 1 63 b a 2 14 c b 3 65 c b 0 26 d b 3 37 d b 2 18 e c 4 39 e c 2 010 f c 0 611 f c 1 2In [249]: df.query('c == [1, 2]')Out[249]:a b c d0 a a 2 62 b a 1 63 b a 2 17 d b 2 19 e c 2 011 f c 1 2In [250]: df.query('c != [1, 2]')Out[250]:a b c d1 a a 4 74 c b 3 65 c b 0 26 d b 3 38 e c 4 310 f c 0 6# using in/not inIn [251]: df.query('[1, 2] in c')Out[251]:a b c d0 a a 2 62 b a 1 63 b a 2 17 d b 2 19 e c 2 011 f c 1 2In [252]: df.query('[1, 2] not in c')Out[252]:a b c d1 a a 4 74 c b 3 65 c b 0 26 d b 3 38 e c 4 310 f c 0 6# pure PythonIn [253]: df[df.c.isin([1, 2])]Out[253]:a b c d0 a a 2 62 b a 1 63 b a 2 17 d b 2 19 e c 2 011 f c 1 2
布尔运算符
您可以使用单词not或~运算符否定布尔表达式。
In [254]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))In [255]: df['bools'] = np.random.rand(len(df)) > 0.5In [256]: df.query('~bools')Out[256]:a b c bools2 0.697753 0.212799 0.329209 False7 0.275396 0.691034 0.826619 False8 0.190649 0.558748 0.262467 FalseIn [257]: df.query('not bools')Out[257]:a b c bools2 0.697753 0.212799 0.329209 False7 0.275396 0.691034 0.826619 False8 0.190649 0.558748 0.262467 FalseIn [258]: df.query('not bools') == df[~df.bools]Out[258]:a b c bools2 True True True True7 True True True True8 True True True True
当然,表达式也可以是任意复杂的:
# short query syntaxIn [259]: shorter = df.query('a < b < c and (not bools) or bools > 2')# equivalent in pure PythonIn [260]: longer = df[(df.a < df.b) & (df.b < df.c) & (~df.bools) | (df.bools > 2)]In [261]: shorterOut[261]:a b c bools7 0.275396 0.691034 0.826619 FalseIn [262]: longerOut[262]:a b c bools7 0.275396 0.691034 0.826619 FalseIn [263]: shorter == longerOut[263]:a b c bools7 True True True True
的表现¶query()
DataFrame.query()````numexpr对于大型帧,使用比Python略快。

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

:::
此图是使用DataFrame3列创建的,每列包含使用生成的浮点值numpy.random.randn()。
重复数据
如果要识别和删除DataFrame中的重复行,有两种方法可以提供帮助:duplicated和drop_duplicates。每个都将用于标识重复行的列作为参数。
duplicated返回一个布尔向量,其长度为行数,表示行是否重复。drop_duplicates删除重复的行。
默认情况下,重复集的第一个观察行被认为是唯一的,但每个方法都有一个keep参数来指定要保留的目标。
keep='first'(默认值):标记/删除重复项,第一次出现除外。keep='last':标记/删除重复项,除了最后一次出现。keep=False:标记/删除所有重复项。
In [264]: df2 = pd.DataFrame({'a': ['one', 'one', 'two', 'two', 'two', 'three', 'four'],.....: 'b': ['x', 'y', 'x', 'y', 'x', 'x', 'x'],.....: 'c': np.random.randn(7)}).....:In [265]: df2Out[265]:a b c0 one x -1.0671371 one y 0.3095002 two x -0.2110563 two y -1.8420234 two x -0.3908205 three x -1.9644756 four x 1.298329In [266]: df2.duplicated('a')Out[266]:0 False1 True2 False3 True4 True5 False6 Falsedtype: boolIn [267]: df2.duplicated('a', keep='last')Out[267]:0 True1 False2 True3 True4 False5 False6 Falsedtype: boolIn [268]: df2.duplicated('a', keep=False)Out[268]:0 True1 True2 True3 True4 True5 False6 Falsedtype: boolIn [269]: df2.drop_duplicates('a')Out[269]:a b c0 one x -1.0671372 two x -0.2110565 three x -1.9644756 four x 1.298329In [270]: df2.drop_duplicates('a', keep='last')Out[270]:a b c1 one y 0.3095004 two x -0.3908205 three x -1.9644756 four x 1.298329In [271]: df2.drop_duplicates('a', keep=False)Out[271]:a b c5 three x -1.9644756 four x 1.298329
此外,您可以传递列表列表以识别重复。
In [272]: df2.duplicated(['a', 'b'])Out[272]:0 False1 False2 False3 False4 True5 False6 Falsedtype: boolIn [273]: df2.drop_duplicates(['a', 'b'])Out[273]:a b c0 one x -1.0671371 one y 0.3095002 two x -0.2110563 two y -1.8420235 three x -1.9644756 four x 1.298329
要按索引值删除重复项,请使用Index.duplicated然后执行切片。keep参数可以使用相同的选项集。
In [274]: df3 = pd.DataFrame({'a': np.arange(6),.....: 'b': np.random.randn(6)},.....: index=['a', 'a', 'b', 'c', 'b', 'a']).....:In [275]: df3Out[275]:a ba 0 1.440455a 1 2.456086b 2 1.038402c 3 -0.894409b 4 0.683536a 5 3.082764In [276]: df3.index.duplicated()Out[276]: array([False, True, False, False, True, True])In [277]: df3[~df3.index.duplicated()]Out[277]:a ba 0 1.440455b 2 1.038402c 3 -0.894409In [278]: df3[~df3.index.duplicated(keep='last')]Out[278]:a bc 3 -0.894409b 4 0.683536a 5 3.082764In [279]: df3[~df3.index.duplicated(keep=False)]Out[279]:a bc 3 -0.894409
类字典get()方法
Series或DataFrame中的每一个都有一个get可以返回默认值的方法。
In [280]: s = pd.Series([1, 2, 3], index=['a', 'b', 'c'])In [281]: s.get('a') # equivalent to s['a']Out[281]: 1In [282]: s.get('x', default=-1)Out[282]: -1
该lookup()方法
有时,您希望在给定一系列行标签和列标签的情况下提取一组值,并且该lookup方法允许此操作并返回NumPy数组。例如:
In [283]: dflookup = pd.DataFrame(np.random.rand(20, 4), columns = ['A', 'B', 'C', 'D'])In [284]: dflookup.lookup(list(range(0, 10, 2)), ['B', 'C', 'A', 'B', 'D'])Out[284]: array([0.3506, 0.4779, 0.4825, 0.9197, 0.5019])
索引对象
pandas Index类及其子类可以视为实现有序的多集合。允许重复。但是,如果您尝试将Index具有重复条目的对象转换为a
set,则会引发异常。
Index还提供了查找,数据对齐和重建索引所需的基础结构。Index直接创建的最简单方法
是将一个list或其他序列传递给
Index:
In [285]: index = pd.Index(['e', 'd', 'a', 'b'])In [286]: indexOut[286]: Index(['e', 'd', 'a', 'b'], dtype='object')In [287]: 'd' in indexOut[287]: True
您还可以传递一个name存储在索引中:
In [288]: index = pd.Index(['e', 'd', 'a', 'b'], name='something')In [289]: index.nameOut[289]: 'something'
名称(如果已设置)将显示在控制台显示中:
In [290]: index = pd.Index(list(range(5)), name='rows')In [291]: columns = pd.Index(['A', 'B', 'C'], name='cols')In [292]: df = pd.DataFrame(np.random.randn(5, 3), index=index, columns=columns)In [293]: dfOut[293]:cols A B Crows0 1.295989 0.185778 0.4362591 0.678101 0.311369 -0.5283782 -0.674808 -1.103529 -0.6561573 1.889957 2.076651 -1.1021924 -1.211795 -0.791746 0.634724In [294]: df['A']Out[294]:rows0 1.2959891 0.6781012 -0.6748083 1.8899574 -1.211795Name: A, dtype: float64
设置元数据
索引是“不可改变的大多是”,但它可以设置和改变它们的元数据,如指数name(或为MultiIndex,levels和
codes)。
您可以使用rename,set_names,set_levels,和set_codes
直接设置这些属性。他们默认返回一份副本; 但是,您可以指定inplace=True使数据更改到位。
有关MultiIndexes的使用,请参阅高级索引。
In [295]: ind = pd.Index([1, 2, 3])In [296]: ind.rename("apple")Out[296]: Int64Index([1, 2, 3], dtype='int64', name='apple')In [297]: indOut[297]: Int64Index([1, 2, 3], dtype='int64')In [298]: ind.set_names(["apple"], inplace=True)In [299]: ind.name = "bob"In [300]: indOut[300]: Int64Index([1, 2, 3], dtype='int64', name='bob')
set_names,set_levels并且set_codes还采用可选
level参数
In [301]: index = pd.MultiIndex.from_product([range(3), ['one', 'two']], names=['first', 'second'])In [302]: indexOut[302]:MultiIndex([(0, 'one'),(0, 'two'),(1, 'one'),(1, 'two'),(2, 'one'),(2, 'two')],names=['first', 'second'])In [303]: index.levels[1]Out[303]: Index(['one', 'two'], dtype='object', name='second')In [304]: index.set_levels(["a", "b"], level=1)Out[304]:MultiIndex([(0, 'a'),(0, 'b'),(1, 'a'),(1, 'b'),(2, 'a'),(2, 'b')],names=['first', 'second'])
在Index对象上设置操作
两个主要业务是和。这些可以直接称为实例方法,也可以通过重载运算符使用。通过该方法提供差异。union (|)````intersection (&)````.difference()
In [305]: a = pd.Index(['c', 'b', 'a'])In [306]: b = pd.Index(['c', 'e', 'd'])In [307]: a | bOut[307]: Index(['a', 'b', 'c', 'd', 'e'], dtype='object')In [308]: a & bOut[308]: Index(['c'], dtype='object')In [309]: a.difference(b)Out[309]: Index(['a', 'b'], dtype='object')
同时还提供了操作,它返回出现在任一元件或,但不是在两者。这相当于创建的索引,删除了重复项。symmetric_difference (^)````idx1````idx2````idx1.difference(idx2).union(idx2.difference(idx1))
In [310]: idx1 = pd.Index([1, 2, 3, 4])In [311]: idx2 = pd.Index([2, 3, 4, 5])In [312]: idx1.symmetric_difference(idx2)Out[312]: Int64Index([1, 5], dtype='int64')In [313]: idx1 ^ idx2Out[313]: Int64Index([1, 5], dtype='int64')
::: tip 注意
来自设置操作的结果索引将按升序排序。
:::
在Index.union()具有不同dtypes的索引之间执行时,必须将索引强制转换为公共dtype。通常,虽然并非总是如此,但这是对象dtype。例外是在整数和浮点数据之间执行联合。在这种情况下,整数值将转换为float
In [314]: idx1 = pd.Index([0, 1, 2])In [315]: idx2 = pd.Index([0.5, 1.5])In [316]: idx1 | idx2Out[316]: Float64Index([0.0, 0.5, 1.0, 1.5, 2.0], dtype='float64')
缺少值
即使Index可以保存缺失值(NaN),但如果您不想要任何意外结果,也应该避免使用。例如,某些操作会隐式排除缺失值。
Index.fillna 使用指定的标量值填充缺失值。
In [317]: idx1 = pd.Index([1, np.nan, 3, 4])In [318]: idx1Out[318]: Float64Index([1.0, nan, 3.0, 4.0], dtype='float64')In [319]: idx1.fillna(2)Out[319]: Float64Index([1.0, 2.0, 3.0, 4.0], dtype='float64')In [320]: idx2 = pd.DatetimeIndex([pd.Timestamp('2011-01-01'),.....: pd.NaT,.....: pd.Timestamp('2011-01-03')]).....:In [321]: idx2Out[321]: DatetimeIndex(['2011-01-01', 'NaT', '2011-01-03'], dtype='datetime64[ns]', freq=None)In [322]: idx2.fillna(pd.Timestamp('2011-01-02'))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:
In [323]: dataOut[323]:a b c d0 bar one z 1.01 bar two y 2.02 foo one x 3.03 foo two w 4.0In [324]: indexed1 = data.set_index('c')In [325]: indexed1Out[325]:a b dcz bar one 1.0y bar two 2.0x foo one 3.0w foo two 4.0In [326]: indexed2 = data.set_index(['a', 'b'])In [327]: indexed2Out[327]:c da bbar one z 1.0two y 2.0foo one x 3.0two w 4.0
该append关键字选项让你保持现有索引并追加给列一个多指标:
In [328]: frame = data.set_index('c', drop=False)In [329]: frame = frame.set_index(['a', 'b'], append=True)In [330]: frameOut[330]:c dc a bz bar one z 1.0y bar two y 2.0x foo one x 3.0w foo two w 4.0
其他选项set_index允许您不删除索引列或就地添加索引(不创建新对象):
In [331]: data.set_index('c', drop=False)Out[331]:a b c dcz bar one z 1.0y bar two y 2.0x foo one x 3.0w foo two w 4.0In [332]: data.set_index(['a', 'b'], inplace=True)In [333]: dataOut[333]:c da bbar one z 1.0two y 2.0foo one x 3.0two w 4.0
重置索引
为方便起见,DataFrame上有一个新函数,它将
reset_index()索引值传输到DataFrame的列中并设置一个简单的整数索引。这是反向操作set_index()。
In [334]: dataOut[334]:c da bbar one z 1.0two y 2.0foo one x 3.0two w 4.0In [335]: data.reset_index()Out[335]:a b c d0 bar one z 1.01 bar two y 2.02 foo one x 3.03 foo two w 4.0
输出更类似于SQL表或记录数组。从索引派生的列的名称是存储在names属性中的名称。
您可以使用level关键字仅删除索引的一部分:
In [336]: frameOut[336]:c dc a bz bar one z 1.0y bar two y 2.0x foo one x 3.0w foo two w 4.0In [337]: frame.reset_index(level=1)Out[337]:a c dc bz one bar z 1.0y two bar y 2.0x one foo x 3.0w two foo w 4.0
reset_index采用一个可选参数drop,如果为true,则只丢弃索引,而不是将索引值放在DataFrame的列中。
添加ad hoc索引
如果您自己创建索引,则可以将其分配给index字段:
data.index = index
返回视图与副本
在pandas对象中设置值时,必须注意避免调用所谓的对象
。这是一个例子。chained indexing
In [338]: dfmi = pd.DataFrame([list('abcd'),.....: list('efgh'),.....: list('ijkl'),.....: list('mnop')],.....: columns=pd.MultiIndex.from_product([['one', 'two'],.....: ['first', 'second']])).....:In [339]: dfmiOut[339]:one twofirst second first second0 a b c d1 e f g h2 i j k l3 m n o p
比较这两种访问方法:
In [340]: dfmi['one']['second']Out[340]:0 b1 f2 j3 nName: second, dtype: object
In [341]: dfmi.loc[:, ('one', 'second')]Out[341]:0 b1 f2 j3 nName: (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解释器如何执行此代码:
dfmi.loc[:, ('one', 'second')] = value# becomesdfmi.loc.__setitem__((slice(None), ('one', 'second')), value)
但是这个代码的处理方式不同:
dfmi['one']['second'] = value# becomesdfmi.__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可能会试图警告你,你已经这样做了:
def do_something(df):foo = df[['bar', 'baz']] # Is foo a view? A copy? Nobody knows!# ... many lines here ...# We don't know whether this will modify df or not!foo['quux'] = valuereturn foo
哎呀!
评估订单事项
使用链式索引时,索引操作的顺序和类型会部分确定结果是原始对象的切片还是切片的副本。
Pandas有,SettingWithCopyWarning因为分配一个切片的副本通常不是故意的,而是由链式索引引起的错误返回一个预期切片的副本。
如果您希望pandas或多或少地信任链接索引表达式的赋值,则可以将选项
设置mode.chained_assignment为以下值之一:
'warn',默认值表示SettingWithCopyWarning打印。'raise'意味着大Pandas会提出SettingWithCopyException你必须处理的事情。None将完全压制警告。
In [342]: dfb = pd.DataFrame({'a': ['one', 'one', 'two',.....: 'three', 'two', 'one', 'six'],.....: 'c': np.arange(7)}).....:# This will show the SettingWithCopyWarning# but the frame values will be setIn [343]: dfb['c'][dfb.a.str.startswith('o')] = 42
然而,这是在副本上运行,不起作用。
>>> pd.set_option('mode.chained_assignment','warn')>>> dfb[dfb.a.str.startswith('o')]['c'] = 42Traceback (most recent call last)...SettingWithCopyWarning:A value is trying to be set on a copy of a slice from a DataFrame.Try using .loc[row_index,col_indexer] = value instead
链式分配也可以在混合dtype帧中进行设置。
::: tip 注意
这些设置规则适用于所有.loc/.iloc。
:::
这是正确的访问方法:
In [344]: dfc = pd.DataFrame({'A': ['aaa', 'bbb', 'ccc'], 'B': [1, 2, 3]})In [345]: dfc.loc[0, 'A'] = 11In [346]: dfcOut[346]:A B0 11 11 bbb 22 ccc 3
这有时会起作用,但不能保证,因此应该避免:
In [347]: dfc = dfc.copy()In [348]: dfc['A'][0] = 111In [349]: dfcOut[349]:A B0 111 11 bbb 22 ccc 3
这根本不起作用,所以应该避免:
>>> pd.set_option('mode.chained_assignment','raise')>>> dfc.loc[0]['A'] = 1111Traceback (most recent call last)...SettingWithCopyException:A value is trying to be set on a copy of a slice from a DataFrame.Try using .loc[row_index,col_indexer] = value instead
::: danger 警告
链式分配警告/异常旨在通知用户可能无效的分配。可能存在误报; 无意中报告链式作业的情况。
:::
