原文:http://pandas.pydata.org/pandas-docs/stable/indexing.html
校对:(虚位以待)
pandas对象中的轴标签信息有很多用途:
- 使用已知指标识别数据(即提供元数据),对于分析,可视化和交互式控制台显示非常重要
- 启用自动和显式数据对齐
- 允许直观获取和设置数据集的子集
在本节中,我们将关注最后一点:即,如何切片,删除,以及一般获取和设置pandas对象的子集。主要关注的是系列和数据框架,因为他们在这一领域受到更多的发展关注。期望在将来对更高维数据结构(包括Panel
)投入更多的工作,尤其是在基于标签的高级索引中。
注意
Python和NumPy索引操作符[]
和属性操作符.
提供在大范围的用例中快速和容易地访问pandas数据结构。这使得交互式工作直观,因为如果你已经知道如何处理Python字典和NumPy数组,没有什么新的学习。但是,由于要访问的数据的类型并不是事先知道的,直接使用标准操作符有一些优化的限制。对于生产代码,我们建议您利用本章中介绍的优化的熊猫数据访问方法。
警告
是否为设置操作返回副本或引用可以取决于上下文。这有时被称为链式赋值
,应该避免。请参见Returning a View versus Copy
警告
在0.15.0 Index
内部被重构为不再子类化ndarray
,而是子类化PandasObject
,类似于其余的pandas对象。这应该是一个透明的变化,只有非常有限的API影响(参见Internal Refactoring)
警告
对于具有浮点数的整数索引的索引已经在0.18.0中阐明,对于变化的总结,参见here。
有关MultiIndex
和更高级的索引文档,请参阅MultiIndex / Advanced Indexing。
有关某些高级策略,请参阅cookbook
版本0.11.0中的新功能。
对象选择已经有了许多用户请求的添加,以便支持更明确的基于位置的索引。pandas现在支持三种类型的多轴索引。
.loc
主要是基于标签的,但也可以与布尔数组一起使用。.loc
会在找不到项目时产生KeyError
。允许输入为:
单个标签,例如5
或'a'
(注意,5
被解释为索引的标签。这种使用是不是沿着索引的整数位置)
标签的列表或数组['a', 'b', 'c']
具有标签'a':'f'
的切片对象(请注意,与通常的python切片相反,包括开始和停止)
一个布尔数组
具有一个参数(调用Series,DataFrame或Panel)的callable
函数,并返回有效的索引输出(上述之一)
版本0.18.1中的新功能。
有关详情,请参阅Selection by Label
.iloc
主要是基于整数位置(从轴的0
到length-1
),但也可以与布尔数组一起使用。如果所请求的索引器超出边界,则.iloc
将引发IndexError
,除了允许超出索引的slice索引器。(这符合python / numpy slice语义)。允许输入为:
整数例如5
整数列表或数组[4, 3, 0]
int 1:7
的slice对象
一个布尔数组
具有一个参数(调用Series,DataFrame或Panel)的callable
函数,并返回有效的索引输出(上述之一)
版本0.18.1中的新功能。
.ix
支持混合整数和基于标签的访问。它主要是基于标签的,但将回落到整数位置访问,除非相应的轴是整数类型。.ix
是最常用的,并且将支持.loc
和.iloc
中的任何输入。.ix
也支持浮点标签方案。.ix
在处理混合位置和基于标签的分层索引时非常有用。
但是,当轴是基于整数的时,仅支持基于标签的访问,而不支持位置访问。因此,在这种情况下,通常最好是显式并使用.iloc
或.loc
。
.loc
,.iloc
,.ix
以及[]
索引可以接受callable
查看更多Selection By Callable。
从多轴选择的对象获取值使用以下符号(使用.loc
作为示例,但适用于.iloc
和.ix
任何轴访问器可以是空片:
。忽略规范的轴假定为:
。(例如p.loc['a']
等同于p.loc ['a', :, :]
)
对象类型 | 索引器 |
---|---|
Series | s.loc[indexer] |
DataFrame | df.loc[row_indexer,column_indexer] |
Panel | p.loc[item_indexer,major_indexer,minor_indexer] |
如在在last section中引入数据结构时提到的,用[]
(a.k.a.__getitem__
用于熟悉在Python中实现类行为的人)选择低维切片。从而,
对象类型 | 选择 | 返回值类型 |
---|---|---|
Series | series[label] |
标量值 |
DataFrame | frame[colname] |
Series 对应于colname |
Panel | panel[itemname] |
DataFrame 对应于项目名称 |
这里我们构造一个简单的时间序列数据集用于说明索引功能:
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]: df
Out[3]:
A B C D
2000-01-01 0.469112 -0.282863 -1.509059 -1.135632
2000-01-02 1.212112 -0.173215 0.119209 -1.044236
2000-01-03 -0.861849 -2.104569 -0.494929 1.071804
2000-01-04 0.721555 -0.706771 -1.039575 0.271860
2000-01-05 -0.424972 0.567020 0.276232 -1.087401
2000-01-06 -0.673690 0.113648 -1.478427 0.524988
2000-01-07 0.404705 0.577046 -1.715002 -1.039268
2000-01-08 -0.370647 -1.157892 -1.344312 0.844885
In [4]: panel = pd.Panel({'one' : df, 'two' : df - df.mean()})
In [5]: panel
Out[5]:
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 8 (major_axis) x 4 (minor_axis)
Items axis: one to two
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-08 00:00:00
Minor_axis axis: A to D
注意
除非特别声明,否则索引功能不是时间序列特定的。
因此,如上所述,我们有使用[]
的最基本的索引:
In [6]: s = df['A']
In [7]: s[dates[5]]
Out[7]: -0.67368970808837059
In [8]: panel['two']
Out[8]:
A B C D
2000-01-01 0.409571 0.113086 -0.610826 -0.936507
2000-01-02 1.152571 0.222735 1.017442 -0.845111
2000-01-03 -0.921390 -1.708620 0.403304 1.270929
2000-01-04 0.662014 -0.310822 -0.141342 0.470985
2000-01-05 -0.484513 0.962970 1.174465 -0.888276
2000-01-06 -0.733231 0.509598 -0.580194 0.724113
2000-01-07 0.345164 0.972995 -0.816769 -0.840143
2000-01-08 -0.430188 -0.761943 -0.446079 1.044010
您可以将列的列表传递到[]
,以按该顺序选择列。如果DataFrame中不包含列,则会引发异常。也可以以这种方式设置多个列:
In [9]: df
Out[9]:
A B C D
2000-01-01 0.469112 -0.282863 -1.509059 -1.135632
2000-01-02 1.212112 -0.173215 0.119209 -1.044236
2000-01-03 -0.861849 -2.104569 -0.494929 1.071804
2000-01-04 0.721555 -0.706771 -1.039575 0.271860
2000-01-05 -0.424972 0.567020 0.276232 -1.087401
2000-01-06 -0.673690 0.113648 -1.478427 0.524988
2000-01-07 0.404705 0.577046 -1.715002 -1.039268
2000-01-08 -0.370647 -1.157892 -1.344312 0.844885
In [10]: df[['B', 'A']] = df[['A', 'B']]
In [11]: df
Out[11]:
A B C D
2000-01-01 -0.282863 0.469112 -1.509059 -1.135632
2000-01-02 -0.173215 1.212112 0.119209 -1.044236
2000-01-03 -2.104569 -0.861849 -0.494929 1.071804
2000-01-04 -0.706771 0.721555 -1.039575 0.271860
2000-01-05 0.567020 -0.424972 0.276232 -1.087401
2000-01-06 0.113648 -0.673690 -1.478427 0.524988
2000-01-07 0.577046 0.404705 -1.715002 -1.039268
2000-01-08 -1.157892 -0.370647 -1.344312 0.844885
您可能会发现这对于将变换(就地)应用于列的子集很有用。
警告
pandas aligns all AXES when setting Series
and DataFrame
from .loc
, .iloc
and .ix
.
这将不会修改df
,因为列对齐在赋值之前。
In [12]: df[['A', 'B']]
Out[12]:
A B
2000-01-01 -0.282863 0.469112
2000-01-02 -0.173215 1.212112
2000-01-03 -2.104569 -0.861849
2000-01-04 -0.706771 0.721555
2000-01-05 0.567020 -0.424972
2000-01-06 0.113648 -0.673690
2000-01-07 0.577046 0.404705
2000-01-08 -1.157892 -0.370647
In [13]: df.loc[:,['B', 'A']] = df[['A', 'B']]
In [14]: df[['A', 'B']]
Out[14]:
A B
2000-01-01 -0.282863 0.469112
2000-01-02 -0.173215 1.212112
2000-01-03 -2.104569 -0.861849
2000-01-04 -0.706771 0.721555
2000-01-05 0.567020 -0.424972
2000-01-06 0.113648 -0.673690
2000-01-07 0.577046 0.404705
2000-01-08 -1.157892 -0.370647
正确的方法是使用原始值
In [15]: df.loc[:,['B', 'A']] = df[['A', 'B']].values
In [16]: df[['A', 'B']]
Out[16]:
A B
2000-01-01 0.469112 -0.282863
2000-01-02 1.212112 -0.173215
2000-01-03 -0.861849 -2.104569
2000-01-04 0.721555 -0.706771
2000-01-05 -0.424972 0.567020
2000-01-06 -0.673690 0.113648
2000-01-07 0.404705 0.577046
2000-01-08 -0.370647 -1.157892
You may access an index on a Series
, column on a DataFrame
, and an item on a Panel
directly as an attribute:
In [17]: sa = pd.Series([1,2,3],index=list('abc'))
In [18]: dfa = df.copy()
In [19]: sa.b
Out[19]: 2
In [20]: dfa.A
Out[20]:
2000-01-01 0.469112
2000-01-02 1.212112
2000-01-03 -0.861849
2000-01-04 0.721555
2000-01-05 -0.424972
2000-01-06 -0.673690
2000-01-07 0.404705
2000-01-08 -0.370647
Freq: D, Name: A, dtype: float64
In [21]: panel.one
Out[21]:
A B C D
2000-01-01 0.469112 -0.282863 -1.509059 -1.135632
2000-01-02 1.212112 -0.173215 0.119209 -1.044236
2000-01-03 -0.861849 -2.104569 -0.494929 1.071804
2000-01-04 0.721555 -0.706771 -1.039575 0.271860
2000-01-05 -0.424972 0.567020 0.276232 -1.087401
2000-01-06 -0.673690 0.113648 -1.478427 0.524988
2000-01-07 0.404705 0.577046 -1.715002 -1.039268
2000-01-08 -0.370647 -1.157892 -1.344312 0.844885
您可以使用属性访问来修改DataFrame的系列或列的现有元素,但要小心;如果您尝试使用属性访问来创建新列,则会无声地失败,从而创建新属性而不是新列。
In [22]: sa.a = 5
In [23]: sa
Out[23]:
a 5
b 2
c 3
dtype: int64
In [24]: dfa.A = list(range(len(dfa.index))) # ok if A already exists
In [25]: dfa
Out[25]:
A B C D
2000-01-01 0 -0.282863 -1.509059 -1.135632
2000-01-02 1 -0.173215 0.119209 -1.044236
2000-01-03 2 -2.104569 -0.494929 1.071804
2000-01-04 3 -0.706771 -1.039575 0.271860
2000-01-05 4 0.567020 0.276232 -1.087401
2000-01-06 5 0.113648 -1.478427 0.524988
2000-01-07 6 0.577046 -1.715002 -1.039268
2000-01-08 7 -1.157892 -1.344312 0.844885
In [26]: dfa['A'] = list(range(len(dfa.index))) # use this form to create a new column
In [27]: dfa
Out[27]:
A B C D
2000-01-01 0 -0.282863 -1.509059 -1.135632
2000-01-02 1 -0.173215 0.119209 -1.044236
2000-01-03 2 -2.104569 -0.494929 1.071804
2000-01-04 3 -0.706771 -1.039575 0.271860
2000-01-05 4 0.567020 0.276232 -1.087401
2000-01-06 5 0.113648 -1.478427 0.524988
2000-01-07 6 0.577046 -1.715002 -1.039268
2000-01-08 7 -1.157892 -1.344312 0.844885
警告
s.1
不允许。有关有效标识符的说明,请参见。s.min
不允许。index
, major_axis
, minor_axis
, items
, labels
.s['1']
,s['min']
和s['index']
将访问相应的元素或列。Series/Panel
访问从0.13.0开始提供。如果使用IPython环境,您还可以使用制表符完成来查看这些可访问的属性。
您还可以将dict
分配给DataFrame
的行:
In [28]: x = pd.DataFrame({'x': [1, 2, 3], 'y': [3, 4, 5]})
In [29]: x.iloc[1] = dict(x=9, y=99)
In [30]: x
Out[30]:
x y
0 1 3
1 9 99
2 3 5
在.iloc
方法的Selection by Position部分中描述了沿任意轴切分范围的最稳健和一致的方法。现在,我们使用[]
运算符解释切片的语义。
使用Series,语法与ndarray完全一样,返回值的一部分和相应的标签:
In [31]: s[:5]
Out[31]:
2000-01-01 0.469112
2000-01-02 1.212112
2000-01-03 -0.861849
2000-01-04 0.721555
2000-01-05 -0.424972
Freq: D, Name: A, dtype: float64
In [32]: s[::2]
Out[32]:
2000-01-01 0.469112
2000-01-03 -0.861849
2000-01-05 -0.424972
2000-01-07 0.404705
Freq: 2D, Name: A, dtype: float64
In [33]: s[::-1]
Out[33]:
2000-01-08 -0.370647
2000-01-07 0.404705
2000-01-06 -0.673690
2000-01-05 -0.424972
2000-01-04 0.721555
2000-01-03 -0.861849
2000-01-02 1.212112
2000-01-01 0.469112
Freq: -1D, Name: A, dtype: float64
请注意,也可以通过切片赋值:
In [34]: s2 = s.copy()
In [35]: s2[:5] = 0
In [36]: s2
Out[36]:
2000-01-01 0.000000
2000-01-02 0.000000
2000-01-03 0.000000
2000-01-04 0.000000
2000-01-05 0.000000
2000-01-06 -0.673690
2000-01-07 0.404705
2000-01-08 -0.370647
Freq: D, Name: A, dtype: float64
使用DataFrame,在[]
内切片将切片。这主要是为了方便,因为它是这样的常见操作。
In [37]: df[:3]
Out[37]:
A B C D
2000-01-01 0.469112 -0.282863 -1.509059 -1.135632
2000-01-02 1.212112 -0.173215 0.119209 -1.044236
2000-01-03 -0.861849 -2.104569 -0.494929 1.071804
In [38]: df[::-1]
Out[38]:
A B C D
2000-01-08 -0.370647 -1.157892 -1.344312 0.844885
2000-01-07 0.404705 0.577046 -1.715002 -1.039268
2000-01-06 -0.673690 0.113648 -1.478427 0.524988
2000-01-05 -0.424972 0.567020 0.276232 -1.087401
2000-01-04 0.721555 -0.706771 -1.039575 0.271860
2000-01-03 -0.861849 -2.104569 -0.494929 1.071804
2000-01-02 1.212112 -0.173215 0.119209 -1.044236
2000-01-01 0.469112 -0.282863 -1.509059 -1.135632
警告
是否为设置操作返回副本或引用可以取决于上下文。这有时被称为链接 分配
,应该避免。请参见Returning a View versus Copy
警告
.loc
在您呈现不兼容(或可转换)索引类型的切片器时是严格的。例如,在DatetimeIndex
中使用整数。这将产生TypeError
。
In [39]: dfl = pd.DataFrame(np.random.randn(5,4), columns=list('ABCD'), index=pd.date_range('20130101',periods=5))
In [40]: dfl
Out[40]:
A B C D
2013-01-01 1.075770 -0.109050 1.643563 -1.469388
2013-01-02 0.357021 -0.674600 -1.776904 -0.968914
2013-01-03 -1.294524 0.413738 0.276662 -0.472035
2013-01-04 -0.013960 -0.362543 -0.006154 -0.923061
2013-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 [41]: dfl.loc['20130102':'20130104']
Out[41]:
A B C D
2013-01-02 0.357021 -0.674600 -1.776904 -0.968914
2013-01-03 -1.294524 0.413738 0.276662 -0.472035
2013-01-04 -0.013960 -0.362543 -0.006154 -0.923061
pandas提供了一套方法,以便完全基于标签的索引。这是一个严格的包含协议。您要求的标签的至少1个必须在索引中,否则会出现KeyError
!当切片时,起始边界是包括,AND停止边界是包括。整数是有效标签,但它们指的是标签,而不是位置。
.loc
属性是主访问方法。以下是有效输入:
5
或'a'
(注意,5
被解释为索引的标签。这种使用是不是沿着索引的整数位置)['a', 'b', 'c']
'a':'f'
的切片对象(请注意,与通常的python切片相反,包括开始和停止)callable
,请参阅Selection By CallableIn [42]: s1 = pd.Series(np.random.randn(6),index=list('abcdef'))
In [43]: s1
Out[43]:
a 1.431256
b 1.340309
c -1.170299
d -0.226169
e 0.410835
f 0.813850
dtype: float64
In [44]: s1.loc['c':]
Out[44]:
c -1.170299
d -0.226169
e 0.410835
f 0.813850
dtype: float64
In [45]: s1.loc['b']
Out[45]: 1.3403088497993827
请注意,设置也很好:
In [46]: s1.loc['c':] = 0
In [47]: s1
Out[47]:
a 1.431256
b 1.340309
c 0.000000
d 0.000000
e 0.000000
f 0.000000
dtype: float64
用DataFrame
In [48]: df1 = pd.DataFrame(np.random.randn(6,4),
....: index=list('abcdef'),
....: columns=list('ABCD'))
....:
In [49]: df1
Out[49]:
A B C D
a 0.132003 -0.827317 -0.076467 -1.187678
b 1.130127 -1.436737 -1.413681 1.607920
c 1.024180 0.569605 0.875906 -2.211372
d 0.974466 -2.006747 -0.410001 -0.078638
e 0.545952 -1.219217 -1.226825 0.769804
f -1.281247 -0.727707 -0.121306 -0.097883
In [50]: df1.loc[['a', 'b', 'd'], :]
Out[50]:
A B C D
a 0.132003 -0.827317 -0.076467 -1.187678
b 1.130127 -1.436737 -1.413681 1.607920
d 0.974466 -2.006747 -0.410001 -0.078638
通过标签切片访问
In [51]: df1.loc['d':, 'A':'C']
Out[51]:
A B C
d 0.974466 -2.006747 -0.410001
e 0.545952 -1.219217 -1.226825
f -1.281247 -0.727707 -0.121306
要获取使用标签的横截面(等效于df.xs('a')
)
In [52]: df1.loc['a']
Out[52]:
A 0.132003
B -0.827317
C -0.076467
D -1.187678
Name: a, dtype: float64
获取带有布尔数组的值
In [53]: df1.loc['a'] > 0
Out[53]:
A True
B False
C False
D False
Name: a, dtype: bool
In [54]: df1.loc[:, df1.loc['a'] > 0]
Out[54]:
A
a 0.132003
b 1.130127
c 1.024180
d 0.974466
e 0.545952
f -1.281247
显式获取值(等同于弃用的df.get_value('a','A')
)
# this is also equivalent to ``df1.at['a','A']``
In [55]: df1.loc['a', 'A']
Out[55]: 0.13200317033032932
警告
是否为设置操作返回副本或引用可以取决于上下文。这有时被称为链接 分配
,应该避免。请参见Returning a View versus Copy
pandas提供了一套方法,以便获得纯粹基于整数的索引。语义遵循python和numpy切片。这些是基于0-based
索引。当切片时,起始边界是包括,而上边界是排除。尝试使用非整数,即使是有效的标签也会产生IndexError
。
.iloc
属性是主要访问方法。以下是有效输入:
5
[4, 3, 0]
1:7
的slice对象callable
,请参阅Selection By CallableIn [56]: s1 = pd.Series(np.random.randn(5), index=list(range(0,10,2)))
In [57]: s1
Out[57]:
0 0.695775
2 0.341734
4 0.959726
6 -1.110336
8 -0.619976
dtype: float64
In [58]: s1.iloc[:3]
Out[58]:
0 0.695775
2 0.341734
4 0.959726
dtype: float64
In [59]: s1.iloc[3]
Out[59]: -1.1103361028911669
请注意,iloc也可以用来赋值:
In [60]: s1.iloc[:3] = 0
In [61]: s1
Out[61]:
0 0.000000
2 0.000000
4 0.000000
6 -1.110336
8 -0.619976
dtype: 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]: df1
Out[63]:
0 2 4 6
0 0.149748 -0.732339 0.687738 0.176444
2 0.403310 -0.154951 0.301624 -2.179861
4 -1.369849 -0.954208 1.462696 -1.743161
6 -0.826591 -0.345352 1.314232 0.690579
8 0.995761 2.396780 0.014871 3.357427
10 -0.317441 -1.236269 0.896171 -0.487602
通过整数切片选择
In [64]: df1.iloc[:3]
Out[64]:
0 2 4 6
0 0.149748 -0.732339 0.687738 0.176444
2 0.403310 -0.154951 0.301624 -2.179861
4 -1.369849 -0.954208 1.462696 -1.743161
In [65]: df1.iloc[1:5, 2:4]
Out[65]:
4 6
2 0.301624 -2.179861
4 1.462696 -1.743161
6 1.314232 0.690579
8 0.014871 3.357427
通过整数列表选择
In [66]: df1.iloc[[1, 3, 5], [1, 3]]
Out[66]:
2 6
2 -0.154951 -2.179861
6 -0.345352 0.690579
10 -1.236269 -0.487602
In [67]: df1.iloc[1:3, :]
Out[67]:
0 2 4 6
2 0.403310 -0.154951 0.301624 -2.179861
4 -1.369849 -0.954208 1.462696 -1.743161
In [68]: df1.iloc[:, 1:3]
Out[68]:
2 4
0 -0.732339 0.687738
2 -0.154951 0.301624
4 -0.954208 1.462696
6 -0.345352 1.314232
8 2.396780 0.014871
10 -1.236269 0.896171
# this is also equivalent to ``df1.iat[1,1]``
In [69]: df1.iloc[1, 1]
Out[69]: -0.15495077442490321
为了获得使用整数位置的横截面(等于df.xs(1)
)
In [70]: df1.iloc[1]
Out[70]:
0 0.403310
2 -0.154951
4 0.301624
6 -2.179861
Name: 2, dtype: float64
超出范围的切片索引会像在Python / Numpy中一样优雅地处理。
# these are allowed in python/numpy.
# Only works in Pandas starting from v0.14.0.
In [71]: x = list('abcdef')
In [72]: x
Out[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]: s
Out[76]:
0 a
1 b
2 c
3 d
4 e
5 f
dtype: object
In [77]: s.iloc[4:10]
Out[77]:
4 e
5 f
dtype: object
In [78]: s.iloc[8:10]
Out[78]: Series([], dtype: object)
注意
在v0.14.0之前,iloc
将不接受切片的边界索引器,例如。超过被索引的对象的长度的值。
请注意,这可能会导致空的轴(例如返回一个空DataFrame)
In [79]: dfl = pd.DataFrame(np.random.randn(5,2), columns=list('AB'))
In [80]: dfl
Out[80]:
A B
0 -0.082240 -2.182937
1 0.380396 0.084844
2 0.432390 1.519970
3 -0.493662 0.600178
4 0.274230 0.132885
In [81]: dfl.iloc[:, 2:3]
Out[81]:
Empty DataFrame
Columns: []
Index: [0, 1, 2, 3, 4]
In [82]: dfl.iloc[:, 1:3]
Out[82]:
B
0 -2.182937
1 0.084844
2 1.519970
3 0.600178
4 0.132885
In [83]: dfl.iloc[4:6]
Out[83]:
A B
4 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
,.ix
以及[]
索引可以接受callable
callable
必须是具有一个参数(调用Series,DataFrame或Panel)的函数,并返回有效的索引输出。
In [84]: df1 = pd.DataFrame(np.random.randn(6, 4),
....: index=list('abcdef'),
....: columns=list('ABCD'))
....:
In [85]: df1
Out[85]:
A B C D
a -0.023688 2.410179 1.450520 0.206053
b -0.251905 -2.213588 1.063327 1.266143
c 0.299368 -0.863838 0.408204 -1.048089
d -0.025747 -0.988387 0.094055 1.262731
e 1.289997 0.082423 -0.055758 0.536580
f -0.489682 0.369374 -0.034571 -2.484478
In [86]: df1.loc[lambda df: df.A > 0, :]
Out[86]:
A B C D
c 0.299368 -0.863838 0.408204 -1.048089
e 1.289997 0.082423 -0.055758 0.536580
In [87]: df1.loc[:, lambda df: ['A', 'B']]
Out[87]:
A B
a -0.023688 2.410179
b -0.251905 -2.213588
c 0.299368 -0.863838
d -0.025747 -0.988387
e 1.289997 0.082423
f -0.489682 0.369374
In [88]: df1.iloc[:, lambda df: [0, 1]]
Out[88]:
A B
a -0.023688 2.410179
b -0.251905 -2.213588
c 0.299368 -0.863838
d -0.025747 -0.988387
e 1.289997 0.082423
f -0.489682 0.369374
In [89]: df1[lambda df: df.columns[0]]
Out[89]:
a -0.023688
b -0.251905
c 0.299368
d -0.025747
e 1.289997
f -0.489682
Name: A, dtype: float64
您可以在Series
中使用可调用索引。
In [90]: df1.A.loc[lambda s: s > 0]
Out[90]:
c 0.299368
e 1.289997
Name: 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 \
year team
2007 CIN 6 379 745 101 203 35 2 36 125.0 10.0 1.0 105
DET 5 301 1062 162 283 54 4 37 144.0 24.0 7.0 97
HOU 4 311 926 109 218 47 6 14 77.0 10.0 4.0 60
LAN 11 413 1021 153 293 61 3 36 154.0 7.0 5.0 114
NYN 13 622 1854 240 509 101 3 61 243.0 22.0 4.0 174
SFN 5 482 1305 198 337 67 6 40 171.0 26.0 7.0 235
TEX 2 198 729 115 200 40 4 28 115.0 21.0 4.0 73
TOR 4 459 1408 187 378 96 2 58 223.0 4.0 2.0 190
so ibb hbp sh sf gidp
year team
2007 CIN 127.0 14.0 1.0 1.0 15.0 18.0
DET 176.0 3.0 10.0 4.0 8.0 28.0
HOU 212.0 3.0 9.0 16.0 6.0 17.0
LAN 141.0 8.0 9.0 3.0 8.0 29.0
NYN 310.0 24.0 23.0 18.0 15.0 48.0
SFN 188.0 51.0 8.0 16.0 6.0 41.0
TEX 140.0 4.0 5.0 2.0 8.0 16.0
TOR 265.0 16.0 12.0 4.0 16.0 38.0
使用sample()
方法从Series,DataFrame或Panel随机选择行或列。该方法将默认对行进行抽样,并接受要返回的特定行数/列数,或一小部分行数。
In [93]: s = pd.Series([0,1,2,3,4,5])
# When no arguments are passed, returns 1 row.
In [94]: s.sample()
Out[94]:
4 4
dtype: int64
# One may specify either a number of rows:
In [95]: s.sample(n=3)
Out[95]:
0 0
4 4
1 1
dtype: int64
# Or a fraction of the rows:
In [96]: s.sample(frac=0.5)
Out[96]:
5 5
3 3
1 1
dtype: int64
默认情况下,sample
最多只返回一行,但也可以使用replace
选项表示能否重复抽取:
In [97]: s = pd.Series([0,1,2,3,4,5])
# Without replacement (default):
In [98]: s.sample(n=6, replace=False)
Out[98]:
0 0
1 1
5 5
3 3
2 2
4 4
dtype: int64
# With replacement:
In [99]: s.sample(n=6, replace=True)
Out[99]:
0 0
4 4
3 3
2 2
4 4
4 4
dtype: int64
默认情况下,每行具有相等的选择概率,但如果您希望行具有不同的概率,则可以将sample
函数抽样权重作为weights
。这些权重可以是列表,numpy数组或系列,但它们必须与要采样的对象长度相同。缺少的值将被视为零的权重,不允许使用inf值。如果权重不等于1,则它们将通过将所有权重除以权重的总和而被重新归一化。例如:
In [100]: s = pd.Series([0,1,2,3,4,5])
In [101]: example_weights = [0, 0, 0.2, 0.2, 0.2, 0.4]
In [102]: s.sample(n=3, weights=example_weights)
Out[102]:
5 5
4 4
3 3
dtype: int64
# Weights will be re-normalized automatically
In [103]: example_weights2 = [0.5, 0, 0, 0, 0, 0]
In [104]: s.sample(n=1, weights=example_weights2)
Out[104]:
0 0
dtype: int64
应用于DataFrame时,只需将列的名称作为字符串传递,就可以使用DataFrame的列作为抽样权重(前提是您正在对行进行抽样而不是列)。
In [105]: df2 = pd.DataFrame({'col1':[9,8,7,6], 'weight_column':[0.5, 0.4, 0.1, 0]})
In [106]: df2.sample(n = 3, weights = 'weight_column')
Out[106]:
col1 weight_column
1 8 0.4
0 9 0.5
2 7 0.1
sample
还允许用户使用axis
参数对列而不是行进行抽样。
In [107]: df3 = pd.DataFrame({'col1':[1,2,3], 'col2':[2,3,4]})
In [108]: df3.sample(n=1, axis=1)
Out[108]:
col1
0 1
1 2
2 3
最后,还可以使用random_state
参数为sample
的随机数生成器设置种子,它将接受整数(作为种子)或numpy RandomState对象。
In [109]: df4 = pd.DataFrame({'col1':[1,2,3], 'col2':[2,3,4]})
# With a given seed, the sample will always draw the same rows.
In [110]: df4.sample(n=2, random_state=2)
Out[110]:
col1 col2
2 3 4
1 2 3
In [111]: df4.sample(n=2, random_state=2)
Out[111]:
col1 col2
2 3 4
1 2 3
版本0.13中的新功能。
当为该轴设置不存在的键时,.loc/.ix/[]
操作可以执行放大。
在Series
情况下,这实际上是一个附加操作
In [112]: se = pd.Series([1,2,3])
In [113]: se
Out[113]:
0 1
1 2
2 3
dtype: int64
In [114]: se[5] = 5.
In [115]: se
Out[115]:
0 1.0
1 2.0
2 3.0
5 5.0
dtype: float64
可以通过.loc
在任一轴上放大DataFrame
In [116]: dfi = pd.DataFrame(np.arange(6).reshape(3,2),
.....: columns=['A','B'])
.....:
In [117]: dfi
Out[117]:
A B
0 0 1
1 2 3
2 4 5
In [118]: dfi.loc[:,'C'] = dfi.loc[:,'A']
In [119]: dfi
Out[119]:
A B C
0 0 1 0
1 2 3 2
2 4 5 4
这类似于DataFrame
上的append
操作。
In [120]: dfi.loc[3] = 5
In [121]: dfi
Out[121]:
A B C
0 0 1 0
1 2 3 2
2 4 5 4
3 5 5 5
由于索引与[]
必须处理很多情况(单标签访问,切片,布尔索引等)。),它有一点开销,以找出你要求什么。如果只想访问标量值,最快的方法是使用at
和iat
方法,这是在所有的数据结构上实现的。
Similarly to loc
, at
provides label based scalar lookups, while, iat
provides integer based lookups analogously to iloc
In [122]: s.iat[5]
Out[122]: 5
In [123]: df.at[dates[5], 'A']
Out[123]: -0.67368970808837059
In [124]: df.iat[3, 0]
Out[124]: 0.72155516224436689
您还可以使用这些相同的索引器进行设置。
In [125]: df.at[dates[5], 'E'] = 7
In [126]: df.iat[3, 0] = 7
如果索引器丢失,at
可以如上所述就地放大对象。
In [127]: df.at[dates[-1]+1, 0] = 7
In [128]: df
Out[128]:
A B C D E 0
2000-01-01 0.469112 -0.282863 -1.509059 -1.135632 NaN NaN
2000-01-02 1.212112 -0.173215 0.119209 -1.044236 NaN NaN
2000-01-03 -0.861849 -2.104569 -0.494929 1.071804 NaN NaN
2000-01-04 7.000000 -0.706771 -1.039575 0.271860 NaN NaN
2000-01-05 -0.424972 0.567020 0.276232 -1.087401 NaN NaN
2000-01-06 -0.673690 0.113648 -1.478427 0.524988 7.0 NaN
2000-01-07 0.404705 0.577046 -1.715002 -1.039268 NaN NaN
2000-01-08 -0.370647 -1.157892 -1.344312 0.844885 NaN NaN
2000-01-09 NaN NaN NaN NaN NaN 7.0
另一个常见的操作是使用布尔向量来过滤数据。The operators are: |
for or
, &
for and
, and ~
for not
. 这些必须使用括号分组。
使用布尔向量索引一个系列的工作原理与numpy ndarray完全一样:
In [129]: s = pd.Series(range(-3, 4))
In [130]: s
Out[130]:
0 -3
1 -2
2 -1
3 0
4 1
5 2
6 3
dtype: int64
In [131]: s[s > 0]
Out[131]:
4 1
5 2
6 3
dtype: int64
In [132]: s[(s < -1) | (s > 0.5)]
Out[132]:
0 -3
1 -2
4 1
5 2
6 3
dtype: int64
In [133]: s[~(s < 0)]
Out[133]:
3 0
4 1
5 2
6 3
dtype: int64
您可以使用与DataFrame的索引长度相同的布尔向量从DataFrame中选择行(例如,从DataFrame的某个列派生的内容):
In [134]: df[df['A'] > 0]
Out[134]:
A B C D E 0
2000-01-01 0.469112 -0.282863 -1.509059 -1.135632 NaN NaN
2000-01-02 1.212112 -0.173215 0.119209 -1.044236 NaN NaN
2000-01-04 7.000000 -0.706771 -1.039575 0.271860 NaN NaN
2000-01-07 0.404705 0.577046 -1.715002 -1.039268 NaN NaN
列表推导和系列的map
方法也可用于产生更复杂的标准:
In [135]: 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 [136]: criterion = df2['a'].map(lambda x: x.startswith('t'))
In [137]: df2[criterion]
Out[137]:
a b c
2 two y 0.041290
3 three x 0.361719
4 two y -0.238075
# equivalent but slower
In [138]: df2[[x.startswith('t') for x in df2['a']]]
Out[138]:
a b c
2 two y 0.041290
3 three x 0.361719
4 two y -0.238075
# Multiple criteria
In [139]: df2[criterion & (df2['b'] == 'x')]
Out[139]:
a b c
3 three x 0.361719
注意,选择方法Selection by Label,Selection by Position和Advanced Indexing可以使用布尔向量组合选择多个轴与其他索引表达式。
In [140]: df2.loc[criterion & (df2['b'] == 'x'),'b':'c']
Out[140]:
b c
3 x 0.361719
考虑Series的isin
方法,它返回一个布尔向量,它在传递列表中存在Series元素的地方。这允许您选择一个或多个列具有所需值的行:
In [141]: s = pd.Series(np.arange(5), index=np.arange(5)[::-1], dtype='int64')
In [142]: s
Out[142]:
4 0
3 1
2 2
1 3
0 4
dtype: int64
In [143]: s.isin([2, 4, 6])
Out[143]:
4 False
3 False
2 True
1 False
0 True
dtype: bool
In [144]: s[s.isin([2, 4, 6])]
Out[144]:
2 2
0 4
dtype: int64
对于Index
对象也可以使用相同的方法,并且当您不知道哪些查找的标签实际上存在时非常有用:
In [145]: s[s.index.isin([2, 4, 6])]
Out[145]:
4 0
2 2
dtype: int64
# compare it to the following
In [146]: s[[2, 4, 6]]
Out[146]:
2 2.0
4 0.0
6 NaN
dtype: float64
除此之外,MultiIndex
允许选择一个单独的级别在成员资格检查中使用:
In [147]: s_mi = pd.Series(np.arange(6),
.....: index=pd.MultiIndex.from_product([[0, 1], ['a', 'b', 'c']]))
.....:
In [148]: s_mi
Out[148]:
0 a 0
b 1
c 2
1 a 3
b 4
c 5
dtype: int64
In [149]: s_mi.iloc[s_mi.index.isin([(1, 'a'), (2, 'b'), (0, 'c')])]
Out[149]:
0 c 2
1 a 3
dtype: int64
In [150]: s_mi.iloc[s_mi.index.isin(['a', 'c', 'e'], level=1)]
Out[150]:
0 a 0
c 2
1 a 3
c 5
dtype: int64
DataFrame也有一个isin
方法。当调用isin
时,传递一组值作为数组或dict。如果值是数组,则isin
返回与原始DataFrame形状相同的布尔数据框架,如果元素位于值序列中,则返回True。
In [151]: df = pd.DataFrame({'vals': [1, 2, 3, 4], 'ids': ['a', 'b', 'f', 'n'],
.....: 'ids2': ['a', 'n', 'c', 'n']})
.....:
In [152]: values = ['a', 'b', 1, 3]
In [153]: df.isin(values)
Out[153]:
ids ids2 vals
0 True True True
1 True False False
2 False False True
3 False False False
通常,您需要将某些值与某些列匹配。只需将值设置为dict
,其中键是列,值是要检查的项目列表。
In [154]: values = {'ids': ['a', 'b'], 'vals': [1, 3]}
In [155]: df.isin(values)
Out[155]:
ids ids2 vals
0 True False True
1 True False False
2 False False True
3 False False False
将DataFrame的isin
与any()
和all()
组合,以快速选择满足给定条件的数据子集。要选择每个列满足其自己的条件的行:
In [156]: values = {'ids': ['a', 'b'], 'ids2': ['a', 'c'], 'vals': [1, 3]}
In [157]: row_mask = df.isin(values).all(1)
In [158]: df[row_mask]
Out[158]:
ids ids2 vals
0 a a 1
where()
Method and Masking使用布尔向量从系列中选择值通常返回数据的子集。为了确保选择输出具有与原始数据相同的形状,可以使用Series
和DataFrame
中的where
方法。
仅返回所选行
In [159]: s[s > 0]
Out[159]:
3 1
2 2
1 3
0 4
dtype: int64
返回与原始形状相同的系列
In [160]: s.where(s > 0)
Out[160]:
4 NaN
3 1.0
2 2.0
1 3.0
0 4.0
dtype: float64
使用布尔标准从DataFrame中选择值现在也保留输入数据形状。where
在引擎下用作实现。等价于df.其中(df 0)
In [161]: df[df < 0]
Out[161]:
A B C D
2000-01-01 -2.104139 -1.309525 NaN NaN
2000-01-02 -0.352480 NaN -1.192319 NaN
2000-01-03 -0.864883 NaN -0.227870 NaN
2000-01-04 NaN -1.222082 NaN -1.233203
2000-01-05 NaN -0.605656 -1.169184 NaN
2000-01-06 NaN -0.948458 NaN -0.684718
2000-01-07 -2.670153 -0.114722 NaN -0.048048
2000-01-08 NaN NaN -0.048788 -0.808838
此外,where
在返回的副本中采用可选的other
参数替换条件为False的值。
In [162]: df.where(df < 0, -df)
Out[162]:
A B C D
2000-01-01 -2.104139 -1.309525 -0.485855 -0.245166
2000-01-02 -0.352480 -0.390389 -1.192319 -1.655824
2000-01-03 -0.864883 -0.299674 -0.227870 -0.281059
2000-01-04 -0.846958 -1.222082 -0.600705 -1.233203
2000-01-05 -0.669692 -0.605656 -1.169184 -0.342416
2000-01-06 -0.868584 -0.948458 -2.297780 -0.684718
2000-01-07 -2.670153 -0.114722 -0.168904 -0.048048
2000-01-08 -0.801196 -1.392071 -0.048788 -0.808838
您可能希望基于一些布尔值标准设置值。这可以直观地这样做:
In [163]: s2 = s.copy()
In [164]: s2[s2 < 0] = 0
In [165]: s2
Out[165]:
4 0
3 1
2 2
1 3
0 4
dtype: int64
In [166]: df2 = df.copy()
In [167]: df2[df2 < 0] = 0
In [168]: df2
Out[168]:
A B C D
2000-01-01 0.000000 0.000000 0.485855 0.245166
2000-01-02 0.000000 0.390389 0.000000 1.655824
2000-01-03 0.000000 0.299674 0.000000 0.281059
2000-01-04 0.846958 0.000000 0.600705 0.000000
2000-01-05 0.669692 0.000000 0.000000 0.342416
2000-01-06 0.868584 0.000000 2.297780 0.000000
2000-01-07 0.000000 0.000000 0.168904 0.000000
2000-01-08 0.801196 1.392071 0.000000 0.000000
默认情况下,where
返回数据的修改副本。有一个可选参数inplace
,以便可以在不创建副本的情况下修改原始数据:
In [169]: df_orig = df.copy()
In [170]: df_orig.where(df > 0, -df, inplace=True);
In [171]: df_orig
Out[171]:
A B C D
2000-01-01 2.104139 1.309525 0.485855 0.245166
2000-01-02 0.352480 0.390389 1.192319 1.655824
2000-01-03 0.864883 0.299674 0.227870 0.281059
2000-01-04 0.846958 1.222082 0.600705 1.233203
2000-01-05 0.669692 0.605656 1.169184 0.342416
2000-01-06 0.868584 0.948458 2.297780 0.684718
2000-01-07 2.670153 0.114722 0.168904 0.048048
2000-01-08 0.801196 1.392071 0.048788 0.808838
注意
DataFrame.where()
的签名与numpy.where()
不同。Roughly df1.where(m, df2)
is equivalent to np.where(m, df1, df2)
.
In [172]: df.where(df < 0, -df) == np.where(df < 0, df, -df)
Out[172]:
A B C D
2000-01-01 True True True True
2000-01-02 True True True True
2000-01-03 True True True True
2000-01-04 True True True True
2000-01-05 True True True True
2000-01-06 True True True True
2000-01-07 True True True True
2000-01-08 True True True True
alignment
此外,where
对齐输入布尔条件(ndarray或DataFrame),以便可以进行带设置的部分选择。这类似于通过.ix
(但是在内容而不是轴标签上)的部分设置,
In [173]: df2 = df.copy()
In [174]: df2[ df2[1:4] > 0 ] = 3
In [175]: df2
Out[175]:
A B C D
2000-01-01 -2.104139 -1.309525 0.485855 0.245166
2000-01-02 -0.352480 3.000000 -1.192319 3.000000
2000-01-03 -0.864883 3.000000 -0.227870 3.000000
2000-01-04 3.000000 -1.222082 3.000000 -1.233203
2000-01-05 0.669692 -0.605656 -1.169184 0.342416
2000-01-06 0.868584 -0.948458 2.297780 -0.684718
2000-01-07 -2.670153 -0.114722 0.168904 -0.048048
2000-01-08 0.801196 1.392071 -0.048788 -0.808838
版本0.13中的新功能。
在执行where
时,还可以接受axis
和level
参数来对齐输入。
In [176]: df2 = df.copy()
In [177]: df2.where(df2>0,df2['A'],axis='index')
Out[177]:
A B C D
2000-01-01 -2.104139 -2.104139 0.485855 0.245166
2000-01-02 -0.352480 0.390389 -0.352480 1.655824
2000-01-03 -0.864883 0.299674 -0.864883 0.281059
2000-01-04 0.846958 0.846958 0.600705 0.846958
2000-01-05 0.669692 0.669692 0.669692 0.342416
2000-01-06 0.868584 0.868584 2.297780 0.868584
2000-01-07 -2.670153 -2.670153 0.168904 -2.670153
2000-01-08 0.801196 1.392071 0.801196 0.801196
这是等价的(但比以下更快)。
In [178]: df2 = df.copy()
In [179]: df.apply(lambda x, y: x.where(x>0,y), y=df['A'])
Out[179]:
A B C D
2000-01-01 -2.104139 -2.104139 0.485855 0.245166
2000-01-02 -0.352480 0.390389 -0.352480 1.655824
2000-01-03 -0.864883 0.299674 -0.864883 0.281059
2000-01-04 0.846958 0.846958 0.600705 0.846958
2000-01-05 0.669692 0.669692 0.669692 0.342416
2000-01-06 0.868584 0.868584 2.297780 0.868584
2000-01-07 -2.670153 -2.670153 0.168904 -2.670153
2000-01-08 0.801196 1.392071 0.801196 0.801196
版本0.18.1中的新功能。
在哪里可以接受可调用的条件和other
参数。该函数必须带有一个参数(调用Series或DataFrame),并返回有效的输出作为条件和other
参数。
In [180]: df3 = pd.DataFrame({'A': [1, 2, 3],
.....: 'B': [4, 5, 6],
.....: 'C': [7, 8, 9]})
.....:
In [181]: df3.where(lambda x: x > 4, lambda x: x + 10)
Out[181]:
A B C
0 11 14 7
1 12 5 8
2 13 6 9
掩码
mask
是where
。
In [182]: s.mask(s >= 0)
Out[182]:
4 NaN
3 NaN
2 NaN
1 NaN
0 NaN
dtype: float64
In [183]: df.mask(df >= 0)
Out[183]:
A B C D
2000-01-01 -2.104139 -1.309525 NaN NaN
2000-01-02 -0.352480 NaN -1.192319 NaN
2000-01-03 -0.864883 NaN -0.227870 NaN
2000-01-04 NaN -1.222082 NaN -1.233203
2000-01-05 NaN -0.605656 -1.169184 NaN
2000-01-06 NaN -0.948458 NaN -0.684718
2000-01-07 -2.670153 -0.114722 NaN -0.048048
2000-01-08 NaN NaN -0.048788 -0.808838
query()
Method (Experimental)版本0.13中的新功能。
DataFrame
对象具有允许使用表达式进行选择的query()
方法。
您可以获取列b
在列a
和c
之间的值的帧的值。例如:
In [184]: n = 10
In [185]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))
In [186]: df
Out[186]:
a b c
0 0.438921 0.118680 0.863670
1 0.138138 0.577363 0.686602
2 0.595307 0.564592 0.520630
3 0.913052 0.926075 0.616184
4 0.078718 0.854477 0.898725
5 0.076404 0.523211 0.591538
6 0.792342 0.216974 0.564056
7 0.397890 0.454131 0.915716
8 0.074315 0.437913 0.019794
9 0.559209 0.502065 0.026437
# pure python
In [187]: df[(df.a < df.b) & (df.b < df.c)]
Out[187]:
a b c
1 0.138138 0.577363 0.686602
4 0.078718 0.854477 0.898725
5 0.076404 0.523211 0.591538
7 0.397890 0.454131 0.915716
# query
In [188]: df.query('(a < b) & (b < c)')
Out[188]:
a b c
1 0.138138 0.577363 0.686602
4 0.078718 0.854477 0.898725
5 0.076404 0.523211 0.591538
7 0.397890 0.454131 0.915716
如果没有名称为a
的列,请执行相同的操作,但返回到命名的索引。
In [189]: df = pd.DataFrame(np.random.randint(n / 2, size=(n, 2)), columns=list('bc'))
In [190]: df.index.name = 'a'
In [191]: df
Out[191]:
b c
a
0 0 4
1 0 1
2 3 4
3 4 3
4 1 4
5 0 3
6 0 1
7 3 4
8 2 3
9 1 1
In [192]: df.query('a < b and b < c')
Out[192]:
b c
a
2 3 4
如果您不想或不能为索引命名,则可以在查询表达式中使用名称index
:
In [193]: df = pd.DataFrame(np.random.randint(n, size=(n, 2)), columns=list('bc'))
In [194]: df
Out[194]:
b c
0 3 1
1 3 0
2 5 6
3 5 2
4 7 4
5 0 1
6 2 5
7 0 1
8 6 0
9 7 9
In [195]: df.query('index < b < c')
Out[195]:
b c
2 5 6
注意
如果索引的名称与列名称重叠,则列名称将优先。例如,
In [196]: df = pd.DataFrame({'a': np.random.randint(5, size=5)})
In [197]: df.index.name = 'a'
In [198]: df.query('a > 2') # uses the column 'a', not the index
Out[198]:
a
a
1 3
3 3
您仍然可以通过使用特殊标识符“index”在查询表达式中使用索引:
In [199]: df.query('index > 2')
Out[199]:
a
a
3 3
4 2
如果由于某种原因你有一个名为index
的列,那么你也可以将索引称为ilevel_0
,但在这一点上你应该考虑将列重命名为暧昧。
MultiIndex
query()
Syntax您还可以使用DataFrame
和MultiIndex
的级别,如同它们是框架中的列:
In [200]: n = 10
In [201]: colors = np.random.choice(['red', 'green'], size=n)
In [202]: foods = np.random.choice(['eggs', 'ham'], size=n)
In [203]: colors
Out[203]:
array(['red', 'red', 'red', 'green', 'green', 'green', 'green', 'green',
'green', 'green'],
dtype='|S5')
In [204]: foods
Out[204]:
array(['ham', 'ham', 'eggs', 'eggs', 'eggs', 'ham', 'ham', 'eggs', 'eggs',
'eggs'],
dtype='|S4')
In [205]: index = pd.MultiIndex.from_arrays([colors, foods], names=['color', 'food'])
In [206]: df = pd.DataFrame(np.random.randn(n, 2), index=index)
In [207]: df
Out[207]:
0 1
color food
red ham 0.194889 -0.381994
ham 0.318587 2.089075
eggs -0.728293 -0.090255
green eggs -0.748199 1.318931
eggs -2.029766 0.792652
ham 0.461007 -0.542749
ham -0.305384 -0.479195
eggs 0.095031 -0.270099
eggs -0.707140 -0.773882
eggs 0.229453 0.304418
In [208]: df.query('color == "red"')
Out[208]:
0 1
color food
red ham 0.194889 -0.381994
ham 0.318587 2.089075
eggs -0.728293 -0.090255
如果MultiIndex
的级别未命名,则可以使用特殊名称引用它们:
In [209]: df.index.names = [None, None]
In [210]: df
Out[210]:
0 1
red ham 0.194889 -0.381994
ham 0.318587 2.089075
eggs -0.728293 -0.090255
green eggs -0.748199 1.318931
eggs -2.029766 0.792652
ham 0.461007 -0.542749
ham -0.305384 -0.479195
eggs 0.095031 -0.270099
eggs -0.707140 -0.773882
eggs 0.229453 0.304418
In [211]: df.query('ilevel_0 == "red"')
Out[211]:
0 1
red ham 0.194889 -0.381994
ham 0.318587 2.089075
eggs -0.728293 -0.090255
约定是ilevel_0
,这意味着index
的第0级的“索引级别0”。
query()
Use Casesquery()
的用例是当您拥有一个具有共同的列名(或索引级别/名称)子集的DataFrame
对象的集合时。您可以向两个框架传递相同的查询,而不必指定您感兴趣的框架
In [212]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))
In [213]: df
Out[213]:
a b c
0 0.224283 0.736107 0.139168
1 0.302827 0.657803 0.713897
2 0.611185 0.136624 0.984960
3 0.195246 0.123436 0.627712
4 0.618673 0.371660 0.047902
5 0.480088 0.062993 0.185760
6 0.568018 0.483467 0.445289
7 0.309040 0.274580 0.587101
8 0.258993 0.477769 0.370255
9 0.550459 0.840870 0.304611
In [214]: df2 = pd.DataFrame(np.random.rand(n + 2, 3), columns=df.columns)
In [215]: df2
Out[215]:
a b c
0 0.357579 0.229800 0.596001
1 0.309059 0.957923 0.965663
2 0.123102 0.336914 0.318616
3 0.526506 0.323321 0.860813
4 0.518736 0.486514 0.384724
5 0.190804 0.505723 0.614533
6 0.891939 0.623977 0.676639
7 0.480559 0.378528 0.460858
8 0.420223 0.136404 0.141295
9 0.732206 0.419540 0.604675
10 0.604466 0.848974 0.896165
11 0.589168 0.920046 0.732716
In [216]: expr = '0.0 <= a <= c <= 0.5'
In [217]: map(lambda frame: frame.query(expr), [df, df2])
Out[217]:
[ a b c
8 0.258993 0.477769 0.370255, a b c
2 0.123102 0.336914 0.318616]
query()
Python versus pandas Syntax Comparison类似numpy的语法
In [218]: df = pd.DataFrame(np.random.randint(n, size=(n, 3)), columns=list('abc'))
In [219]: df
Out[219]:
a b c
0 7 8 9
1 1 0 7
2 2 7 2
3 6 2 2
4 2 6 3
5 3 8 2
6 1 7 2
7 5 1 5
8 9 8 0
9 1 5 0
In [220]: df.query('(a < b) & (b < c)')
Out[220]:
a b c
0 7 8 9
In [221]: df[(df.a < df.b) & (df.b < df.c)]
Out[221]:
a b c
0 7 8 9
通过删除括号略微更好一些(通过绑定使比较运算符绑定比&
/ |
更紧密)
In [222]: df.query('a < b & b < c')
Out[222]:
a b c
0 7 8 9
使用英语而不是符号
In [223]: df.query('a < b and b < c')
Out[223]:
a b c
0 7 8 9
很接近你怎么可能写在纸上
In [224]: df.query('a < b < c')
Out[224]:
a b c
0 7 8 9
in
and not in
operatorsquery()
also supports special use of Python’s in
and not in
comparison operators, providing a succinct syntax for calling the isin
method of a Series
or DataFrame
.
# get all rows where columns "a" and "b" have overlapping values
In [225]: df = pd.DataFrame({'a': list('aabbccddeeff'), 'b': list('aaaabbbbcccc'),
.....: 'c': np.random.randint(5, size=12),
.....: 'd': np.random.randint(9, size=12)})
.....:
In [226]: df
Out[226]:
a b c d
0 a a 2 6
1 a a 4 7
2 b a 1 6
3 b a 2 1
4 c b 3 6
5 c b 0 2
6 d b 3 3
7 d b 2 1
8 e c 4 3
9 e c 2 0
10 f c 0 6
11 f c 1 2
In [227]: df.query('a in b')
Out[227]:
a b c d
0 a a 2 6
1 a a 4 7
2 b a 1 6
3 b a 2 1
4 c b 3 6
5 c b 0 2
# How you'd do it in pure Python
In [228]: df[df.a.isin(df.b)]
Out[228]:
a b c d
0 a a 2 6
1 a a 4 7
2 b a 1 6
3 b a 2 1
4 c b 3 6
5 c b 0 2
In [229]: df.query('a not in b')
Out[229]:
a b c d
6 d b 3 3
7 d b 2 1
8 e c 4 3
9 e c 2 0
10 f c 0 6
11 f c 1 2
# pure Python
In [230]: df[~df.a.isin(df.b)]
Out[230]:
a b c d
6 d b 3 3
7 d b 2 1
8 e c 4 3
9 e c 2 0
10 f c 0 6
11 f c 1 2
您可以将其与其他表达式结合使用,以获得非常简洁的查询:
# rows where cols a and b have overlapping values and col c's values are less than col d's
In [231]: df.query('a in b and c < d')
Out[231]:
a b c d
0 a a 2 6
1 a a 4 7
2 b a 1 6
4 c b 3 6
5 c b 0 2
# pure Python
In [232]: df[df.b.isin(df.a) & (df.c < df.d)]
Out[232]:
a b c d
0 a a 2 6
1 a a 4 7
2 b a 1 6
4 c b 3 6
5 c b 0 2
10 f c 0 6
11 f c 1 2
注意
Note that in
and not in
are evaluated in Python, since numexpr
has no equivalent of this operation. However, only the in
/not in
expression itself is evaluated in vanilla Python. 例如,在表达式中
df.query('a in b + c + d')
(b + c + d) 在普通Python中评估
通常,可以使用numexpr
和然后中的in
numexpr
计算的任何操作都将是。
==
operator with list
objects使用==
/ !=
将list
与in
/ 不是 在
中
In [233]: df.query('b == ["a", "b", "c"]')
Out[233]:
a b c d
0 a a 2 6
1 a a 4 7
2 b a 1 6
3 b a 2 1
4 c b 3 6
5 c b 0 2
6 d b 3 3
7 d b 2 1
8 e c 4 3
9 e c 2 0
10 f c 0 6
11 f c 1 2
# pure Python
In [234]: df[df.b.isin(["a", "b", "c"])]
Out[234]:
a b c d
0 a a 2 6
1 a a 4 7
2 b a 1 6
3 b a 2 1
4 c b 3 6
5 c b 0 2
6 d b 3 3
7 d b 2 1
8 e c 4 3
9 e c 2 0
10 f c 0 6
11 f c 1 2
In [235]: df.query('c == [1, 2]')
Out[235]:
a b c d
0 a a 2 6
2 b a 1 6
3 b a 2 1
7 d b 2 1
9 e c 2 0
11 f c 1 2
In [236]: df.query('c != [1, 2]')
Out[236]:
a b c d
1 a a 4 7
4 c b 3 6
5 c b 0 2
6 d b 3 3
8 e c 4 3
10 f c 0 6
# using in/not in
In [237]: df.query('[1, 2] in c')
Out[237]:
a b c d
0 a a 2 6
2 b a 1 6
3 b a 2 1
7 d b 2 1
9 e c 2 0
11 f c 1 2
In [238]: df.query('[1, 2] not in c')
Out[238]:
a b c d
1 a a 4 7
4 c b 3 6
5 c b 0 2
6 d b 3 3
8 e c 4 3
10 f c 0 6
# pure Python
In [239]: df[df.c.isin([1, 2])]
Out[239]:
a b c d
0 a a 2 6
2 b a 1 6
3 b a 2 1
7 d b 2 1
9 e c 2 0
11 f c 1 2
您可以使用字not
或~
运算符来否定布尔表达式。
In [240]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))
In [241]: df['bools'] = np.random.rand(len(df)) > 0.5
In [242]: df.query('~bools')
Out[242]:
a b c bools
2 0.697753 0.212799 0.329209 False
7 0.275396 0.691034 0.826619 False
8 0.190649 0.558748 0.262467 False
In [243]: df.query('not bools')
Out[243]:
a b c bools
2 0.697753 0.212799 0.329209 False
7 0.275396 0.691034 0.826619 False
8 0.190649 0.558748 0.262467 False
In [244]: df.query('not bools') == df[~df.bools]
Out[244]:
a b c bools
2 True True True True
7 True True True True
8 True True True True
当然,表达式也可以是任意复杂的
# short query syntax
In [245]: shorter = df.query('a < b < c and (not bools) or bools > 2')
# equivalent in pure Python
In [246]: longer = df[(df.a < df.b) & (df.b < df.c) & (~df.bools) | (df.bools > 2)]
In [247]: shorter
Out[247]:
a b c bools
7 0.275396 0.691034 0.826619 False
In [248]: longer
Out[248]:
a b c bools
7 0.275396 0.691034 0.826619 False
In [249]: shorter == longer
Out[249]:
a b c bools
7 True True True True
query()
对于大数据,DataFrame.query()
使用numexpr
稍快于Python
注意
如果您的框架超过大约20万行,您将只能看到使用numexpr
引擎和DataFrame.query()
的性能优势
此图使用DataFrame
创建,每个列包含使用numpy.random.randn()
生成的浮点值。
如果要在DataFrame中标识和删除重复行,有两种方法将有助于:duplicated
和drop_duplicates
。每个都将用作标识重复行的列作为参数。
duplicated
返回布尔向量,其长度为行数,并指示行是否重复。drop_duplicates
删除重复的行。默认情况下,重复集的第一个观察到的行被认为是唯一的,但每个方法都有一个keep
参数来指定要保留的目标。
keep='first'
(默认):除第一次出现之外,标记/删除重复项。keep='last'
:标记/删除除最后一次出现的副本。keep=False
:标记/删除所有重复项。In [250]: 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 [251]: df2
Out[251]:
a b c
0 one x -1.067137
1 one y 0.309500
2 two x -0.211056
3 two y -1.842023
4 two x -0.390820
5 three x -1.964475
6 four x 1.298329
In [252]: df2.duplicated('a')
Out[252]:
0 False
1 True
2 False
3 True
4 True
5 False
6 False
dtype: bool
In [253]: df2.duplicated('a', keep='last')
Out[253]:
0 True
1 False
2 True
3 True
4 False
5 False
6 False
dtype: bool
In [254]: df2.duplicated('a', keep=False)
Out[254]:
0 True
1 True
2 True
3 True
4 True
5 False
6 False
dtype: bool
In [255]: df2.drop_duplicates('a')
Out[255]:
a b c
0 one x -1.067137
2 two x -0.211056
5 three x -1.964475
6 four x 1.298329
In [256]: df2.drop_duplicates('a', keep='last')
Out[256]:
a b c
1 one y 0.309500
4 two x -0.390820
5 three x -1.964475
6 four x 1.298329
In [257]: df2.drop_duplicates('a', keep=False)
Out[257]:
a b c
5 three x -1.964475
6 four x 1.298329
此外,您可以传递列的列表以识别重复。
In [258]: df2.duplicated(['a', 'b'])
Out[258]:
0 False
1 False
2 False
3 False
4 True
5 False
6 False
dtype: bool
In [259]: df2.drop_duplicates(['a', 'b'])
Out[259]:
a b c
0 one x -1.067137
1 one y 0.309500
2 two x -0.211056
3 two y -1.842023
5 three x -1.964475
6 four x 1.298329
要按索引值删除重复项,请使用Index.duplicated
,然后执行切片。相同的选项在keep
参数中可用。
In [260]: df3 = pd.DataFrame({'a': np.arange(6),
.....: 'b': np.random.randn(6)},
.....: index=['a', 'a', 'b', 'c', 'b', 'a'])
.....:
In [261]: df3
Out[261]:
a b
a 0 1.440455
a 1 2.456086
b 2 1.038402
c 3 -0.894409
b 4 0.683536
a 5 3.082764
In [262]: df3.index.duplicated()
Out[262]: array([False, True, False, False, True, True], dtype=bool)
In [263]: df3[~df3.index.duplicated()]
Out[263]:
a b
a 0 1.440455
b 2 1.038402
c 3 -0.894409
In [264]: df3[~df3.index.duplicated(keep='last')]
Out[264]:
a b
c 3 -0.894409
b 4 0.683536
a 5 3.082764
In [265]: df3[~df3.index.duplicated(keep=False)]
Out[265]:
a b
c 3 -0.894409
get()
methodSeries,DataFrame和Panel中的每一个都有一个get
方法,可以返回默认值。
In [266]: s = pd.Series([1,2,3], index=['a','b','c'])
In [267]: s.get('a') # equivalent to s['a']
Out[267]: 1
In [268]: s.get('x', default=-1)
Out[268]: -1
select()
Method从对象中提取切片的另一种方法是使用Series,DataFrame和Panel的select
方法。这个方法应该只在没有更多的直接方式时使用。select
采用对axis
的标签进行操作的函数,并返回布尔值。例如:
In [269]: df.select(lambda x: x == 'A', axis=1)
Out[269]:
A
2000-01-01 0.355794
2000-01-02 1.635763
2000-01-03 0.854409
2000-01-04 -0.216659
2000-01-05 2.414688
2000-01-06 -1.206215
2000-01-07 0.779461
2000-01-08 -0.878999
lookup()
Method有时,您希望提取一组给定一系列行标签和列标签的值,而lookup
方法允许此操作并返回numpy数组。例如,
In [270]: dflookup = pd.DataFrame(np.random.rand(20,4), columns = ['A','B','C','D'])
In [271]: dflookup.lookup(list(range(0,10,2)), ['B','C','A','B','D'])
Out[271]: array([ 0.3506, 0.4779, 0.4825, 0.9197, 0.5019])
pandas Index
类及其子类可以被视为实现有序多集。允许重复。但是,如果您尝试将具有重复条目的Index
对象转换为set
,则会引发异常。
Index
还提供了查找,数据对齐和重建索引所需的基础结构。要直接创建Index
的最简单方法是将list
或其他序列传递给Index
:
In [272]: index = pd.Index(['e', 'd', 'a', 'b'])
In [273]: index
Out[273]: Index([u'e', u'd', u'a', u'b'], dtype='object')
In [274]: 'd' in index
Out[274]: True
您还可以传递name
以存储在索引中:
In [275]: index = pd.Index(['e', 'd', 'a', 'b'], name='something')
In [276]: index.name
Out[276]: 'something'
名称(如果设置)将显示在控制台显示中:
In [277]: index = pd.Index(list(range(5)), name='rows')
In [278]: columns = pd.Index(['A', 'B', 'C'], name='cols')
In [279]: df = pd.DataFrame(np.random.randn(5, 3), index=index, columns=columns)
In [280]: df
Out[280]:
cols A B C
rows
0 1.295989 0.185778 0.436259
1 0.678101 0.311369 -0.528378
2 -0.674808 -1.103529 -0.656157
3 1.889957 2.076651 -1.102192
4 -1.211795 -0.791746 0.634724
In [281]: df['A']
Out[281]:
rows
0 1.295989
1 0.678101
2 -0.674808
3 1.889957
4 -1.211795
Name: A, dtype: float64
版本0.13.0中的新功能。
Indexes are “mostly immutable”, but it is possible to set and change their metadata, like the index name
(or, for MultiIndex
, levels
and labels
).
您可以使用rename
,set_names
,set_levels
和set_labels
直接设置这些属性。他们默认返回一份副本;但是,您可以指定inplace=True
以使数据更改到位。
有关MultiIndexes的用法,请参见Advanced Indexing。
In [282]: ind = pd.Index([1, 2, 3])
In [283]: ind.rename("apple")
Out[283]: Int64Index([1, 2, 3], dtype='int64', name=u'apple')
In [284]: ind
Out[284]: Int64Index([1, 2, 3], dtype='int64')
In [285]: ind.set_names(["apple"], inplace=True)
In [286]: ind.name = "bob"
In [287]: ind
Out[287]: Int64Index([1, 2, 3], dtype='int64', name=u'bob')
版本0.15.0中的新功能。
set_names
,set_levels
和set_labels
也采用可选的级别参数
In [288]: index = pd.MultiIndex.from_product([range(3), ['one', 'two']], names=['first', 'second'])
In [289]: index
Out[289]:
MultiIndex(levels=[[0, 1, 2], [u'one', u'two']],
labels=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]],
names=[u'first', u'second'])
In [290]: index.levels[1]
Out[290]: Index([u'one', u'two'], dtype='object', name=u'second')
In [291]: index.set_levels(["a", "b"], level=1)
Out[291]:
MultiIndex(levels=[[0, 1, 2], [u'a', u'b']],
labels=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]],
names=[u'first', u'second'])
警告
在0.15.0. 不建议使用set操作+
和-
,以便为某些索引类型的数字类型操作提供这些操作。+
can be replace by .union()
or |
, and -
by .difference()
.
两个主要操作是联合 (|)
,交集 (&amp; / t5>
这些可以直接调用为实例方法或通过重载运算符使用。差异通过.difference()
方法提供。
In [292]: a = pd.Index(['c', 'b', 'a'])
In [293]: b = pd.Index(['c', 'e', 'd'])
In [294]: a | b
Out[294]: Index([u'a', u'b', u'c', u'd', u'e'], dtype='object')
In [295]: a & b
Out[295]: Index([u'c'], dtype='object')
In [296]: a.difference(b)
Out[296]: Index([u'a', u'b'], dtype='object')
还可以使用symmetric_difference (^)
操作,返回出现在idx1
或idx2
,但不能同时包含两者。这相当于由idx1.difference(idx2).union(idx2.difference(idx1))
创建的索引,重复项被删除。
In [297]: idx1 = pd.Index([1, 2, 3, 4])
In [298]: idx2 = pd.Index([2, 3, 4, 5])
In [299]: idx1.symmetric_difference(idx2)
Out[299]: Int64Index([1, 5], dtype='int64')
In [300]: idx1 ^ idx2
Out[300]: Int64Index([1, 5], dtype='int64')
版本0.17.1中的新功能。
重要
即使Index
可以保存缺失值(NaN
),如果不想要任何意外结果,应该避免。例如,某些操作会隐式地排除缺失值。
Index.fillna
使用指定的标量值填充缺失值。
In [301]: idx1 = pd.Index([1, np.nan, 3, 4])
In [302]: idx1
Out[302]: Float64Index([1.0, nan, 3.0, 4.0], dtype='float64')
In [303]: idx1.fillna(2)
Out[303]: Float64Index([1.0, 2.0, 3.0, 4.0], dtype='float64')
In [304]: idx2 = pd.DatetimeIndex([pd.Timestamp('2011-01-01'), pd.NaT, pd.Timestamp('2011-01-03')])
In [305]: idx2
Out[305]: DatetimeIndex(['2011-01-01', 'NaT', '2011-01-03'], dtype='datetime64[ns]', freq=None)
In [306]: idx2.fillna(pd.Timestamp('2011-01-02'))
Out[306]: DatetimeIndex(['2011-01-01', '2011-01-02', '2011-01-03'], dtype='datetime64[ns]', freq=None)
有时,您将在DataFrame中加载或创建数据集,并且希望在已经这样做之后添加索引。有两种不同的方法。
DataFrame有一个set_index
方法,它使用列名(对于常规Index
)或列名列表(对于MultiIndex
),创建一个新的,索引的DataFrame:
In [307]: data
Out[307]:
a b c d
0 bar one z 1.0
1 bar two y 2.0
2 foo one x 3.0
3 foo two w 4.0
In [308]: indexed1 = data.set_index('c')
In [309]: indexed1
Out[309]:
a b d
c
z bar one 1.0
y bar two 2.0
x foo one 3.0
w foo two 4.0
In [310]: indexed2 = data.set_index(['a', 'b'])
In [311]: indexed2
Out[311]:
c d
a b
bar one z 1.0
two y 2.0
foo one x 3.0
two w 4.0
append
关键字选项允许您保留现有索引并将给定列附加到MultiIndex:
In [312]: frame = data.set_index('c', drop=False)
In [313]: frame = frame.set_index(['a', 'b'], append=True)
In [314]: frame
Out[314]:
c d
c a b
z bar one z 1.0
y bar two y 2.0
x foo one x 3.0
w foo two w 4.0
set_index
中的其他选项允许您不删除索引列或在现场添加索引(不创建新对象):
In [315]: data.set_index('c', drop=False)
Out[315]:
a b c d
c
z bar one z 1.0
y bar two y 2.0
x foo one x 3.0
w foo two w 4.0
In [316]: data.set_index(['a', 'b'], inplace=True)
In [317]: data
Out[317]:
c d
a b
bar one z 1.0
two y 2.0
foo one x 3.0
two w 4.0
为方便起见,DataFrame上有一个称为reset_index
的新函数,它将索引值传输到DataFrame的列中,并设置一个简单的整数索引。这是set_index
的逆操作
In [318]: data
Out[318]:
c d
a b
bar one z 1.0
two y 2.0
foo one x 3.0
two w 4.0
In [319]: data.reset_index()
Out[319]:
a b c d
0 bar one z 1.0
1 bar two y 2.0
2 foo one x 3.0
3 foo two w 4.0
输出与SQL表或记录数组更相似。从索引派生的列的名称是存储在names
属性中的名称。
您可以使用level
关键字仅删除索引的一部分:
In [320]: frame
Out[320]:
c d
c a b
z bar one z 1.0
y bar two y 2.0
x foo one x 3.0
w foo two w 4.0
In [321]: frame.reset_index(level=1)
Out[321]:
a c d
c b
z one bar z 1.0
y two bar y 2.0
x one foo x 3.0
w two foo w 4.0
reset_index
使用一个可选参数drop
,如果为true,只是丢弃索引,而不是在DataFrame的列中添加索引值。
注意
reset_index
方法以前称为delevel
,现在已被弃用。
如果您自己创建索引,则只需将其分配给index
字段:
data.index = index
在pandas对象中设置值时,必须注意避免使用链接 索引
。这里是一个例子。
In [322]: dfmi = pd.DataFrame([list('abcd'),
.....: list('efgh'),
.....: list('ijkl'),
.....: list('mnop')],
.....: columns=pd.MultiIndex.from_product([['one','two'],
.....: ['first','second']]))
.....:
In [323]: dfmi
Out[323]:
one two
first second first second
0 a b c d
1 e f g h
2 i j k l
3 m n o p
比较这两种访问方法:
In [324]: dfmi['one']['second']
Out[324]:
0 b
1 f
2 j
3 n
Name: second, dtype: object
In [325]: dfmi.loc[:,('one','second')]
Out[325]:
0 b
1 f
2 j
3 n
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__
。这允许熊猫作为一个单一的实体处理。此外,这种操作顺序可以明显更快,并且如果需要的话,允许索引两个轴。
上一节中的问题只是一个性能问题。什么是SettingWithCopy
警告?我们不会通常在您执行可能需要花费更多毫秒的操作时抛出警告!
但事实证明,对链接索引的产品分配具有固有的不可预测的结果。要看到这一点,想想Python解释器如何执行这段代码:
dfmi.loc[:,('one','second')] = value
# becomes
dfmi.loc.__setitem__((slice(None), ('one', 'second')), value)
但是这个代码处理方式不同:
dfmi['one']['second'] = value
# becomes
dfmi.__getitem__('one').__setitem__('second', value)
看到__getitem__
在那里?Outside of simple cases, it’s very hard to predict whether it will return a view or a copy (it depends on the memory layout of the array, about which pandas makes no guarantees), and therefore whether the __setitem__
will modify dfmi
or a temporary object that gets thrown out immediately afterward. 这是什么SettingWithCopy
警告你!
注意
您可能想知道我们是否应该关注第一个示例中的loc
属性。但是dfmi.loc
保证为dfmi
本身具有修改的索引行为,因此dfmi.loc.__getitem__
/ dfmi.loc.__setitem__
直接操作dfmi
。当然,dfmi.loc.__getitem__(idx)
可以是dfmi
的视图或副本。
有时,当没有明显的链接索引时,会出现SettingWithCopy
警告。这些是SettingWithCopy
旨在捕获的错误!熊猫可能试图警告你,你这样做:
def do_something(df):
foo = df[['bar', 'baz']] # Is foo a view? A copy? Nobody knows!
# ... many lines here ...
foo['quux'] = value # We don't know whether this will modify df or not!
return foo
Yikes!
此外,在链接表达式中,顺序可以确定是否返回副本。如果一个表达式在一个slice的副本上设置值,那么会出现一个SettingWithCopy
异常(这个从0.13.0开始的raise / warn行为是新的)
您可以通过选项mode.chained_assignment
控制链接分配的操作,该选项可以取值['raise','warn',None]
warning是默认值。
In [326]: 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 set
In [327]: dfb['c'][dfb.a.str.startswith('o')] = 42
然而,这是操作一个副本,将不工作。
>>> pd.set_option('mode.chained_assignment','warn')
>>> dfb[dfb.a.str.startswith('o')]['c'] = 42
Traceback (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帧中的设置中向上裁剪。
注意
这些设置规则适用于所有.loc/.iloc/.ix
这是正确的访问方法
In [328]: dfc = pd.DataFrame({'A':['aaa','bbb','ccc'],'B':[1,2,3]})
In [329]: dfc.loc[0,'A'] = 11
In [330]: dfc
Out[330]:
A B
0 11 1
1 bbb 2
2 ccc 3
这可以有时工作,但不能保证,因此应该避免
In [331]: dfc = dfc.copy()
In [332]: dfc['A'][0] = 111
In [333]: dfc
Out[333]:
A B
0 111 1
1 bbb 2
2 ccc 3
这将不是工作,所以应该避免
>>> pd.set_option('mode.chained_assignment','raise')
>>> dfc.loc[0]['A'] = 1111
Traceback (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
警告
链接的分配警告/异常旨在通知用户可能无效的分配。可能有假阳性;无意中报告了链式分配的情况。