pandas对象中的轴标签信息有许多用途:
使用已知的指标标识数据(即提供元数据),这对于分析,可视化和交互式控制台显示很重要。
启用自动和显式数据对齐。
允许直观地获取和设置数据集的子集。
在本节中,我们将重点关注最后一点:即如何切片,切块,以及通常如何获取和设置熊猫对象的子集。主要重点将放在Series和DataFrame上,因为它们在该领域得到了更多的开发关注。
注意 Python和NumPy索引运算符[]和属性运算符. 可在各种用例中快速轻松地访问熊猫数据结构。这使交互式工作变得直观,因为如果您已经知道如何处理Python字典和NumPy数组,则没有什么新的知识要学习。但是,由于事先不知道要访问的数据类型,因此直接使用标准运算符存在一些优化限制。对于生产代码,我们建议您利用本章中介绍的优化的熊猫数据访问方法。
警告 为设置操作返回副本还是参考,可能取决于上下文。这有时被称为,应该避免。请参阅返回视图与复制。chained assignment
警告 在0.18.0中已阐明了对基于整数的带有浮点数的索引的索引,有关更改的摘要,请参见此处。
见多指标/高级索引的MultiIndex和更先进的索引文件。
有关某些高级策略,请参见本食谱。
不同的选择索引
对象选择具有许多用户请求的添加项,以支持更明确的基于位置的索引。熊猫现在支持三种类型的多轴索引。
.loc主要基于标签,但也可以与布尔数组一起使用。找不到物品时.loc将升高KeyError。允许的输入为:
单个标签,例如5或'a'(请注意,它5被解释为索引的 标签。此用法不是沿索引的整数位置。)
标签列表或标签数组。['a', 'b', 'c']
带标签的切片对象'a':'f'(注意,相反普通的Python片,都开始和停止都包括在内,存在于索引时!见切片用标签)。
布尔数组
一个callable带有一个参数的函数(调用Series或DataFrame),并且返回用于索引的有效输出(上述之一)。
0.18.1版中的新功能。
有关更多信息,请参见按标签选择。
.iloc主要是整数位置(来自0于 length-1所述轴线的),但也可以用布尔阵列使用。 如果请求的索引器超出边界,.iloc则将增加IndexError,但切片索引器除外,该索引允许越界索引。(这符合Python / NumPy slice 语义)。允许的输入为:
整数,例如5。
整数列表或数组。[4, 3, 0]
具有int的slice对象1:7。
布尔数组。
一个callable带有一个参数的函数(调用Series或DataFrame),并且返回用于索引的有效输出(上述之一)。
0.18.1版中的新功能。
请参阅“ 按位置选择”,“ 高级索引编制”和“ 高级层次结构”。
.loc,.iloc以及[]索引也可以接受callable作为索引器。有关更多信息,请参见“ 按呼叫选择”。
从具有多轴选择的对象中获取值使用以下符号(.loc作为示例,但以下内容同样适用.iloc)。任何轴访问器都可以为null slice :。轴冷落的规格被假定为:,例如p.loc['a']相当于 。p.loc['a', :, :]
对象类型 索引器
系列 s.loc[indexer]
数据框 df.loc[row_indexer,column_indexer]
基础
正如在上一节介绍数据结构时所提到的那样,使用[](__getitem__ 对于熟悉在Python中实现类行为的人员而言)进行索引的主要功能是选择低维切片。下表显示了使用索引pandas对象时的返回类型值[]:
对象类型 选拔 返回值类型
系列 series[label] 标量值
数据框 frame[colname] Series 对应于姓
在这里,我们构造了一个简单的时间序列数据集,用于说明索引功能:
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]: s = df['A']
In [5]: s[dates[5]]
Out[5]: -0.6736897080883706
您可以将列列表传递[]给以该顺序选择列。如果DataFrame中不包含列,则将引发异常。也可以以这种方式设置多列:
In [6]: df
Out[6]:
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 [7]: df[['B', 'A']] = df[['A', 'B']]
In [8]: df
Out[8]:
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
您可能会发现这对于将转换(就地)应用于列的子集很有用。
警告 设置Series和DataFrame从.loc和中时,pandas会对齐所有轴.iloc。
这不会修改,df因为列对齐是在赋值之前。
In [9]: df[['A', 'B']]
Out[9]:
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 [10]: df.loc[:, ['B', 'A']] = df[['A', 'B']]
In [11]: df[['A', 'B']]
Out[11]:
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 [12]: df.loc[:, ['B', 'A']] = df[['A', 'B']].to_numpy()
In [13]: df[['A', 'B']]
Out[13]:
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
属性访问
您可以直接将Series或上的索引DataFrame作为属性访问:
In [14]: sa = pd.Series([1, 2, 3], index=list('abc'))
In [15]: dfa = df.copy()
In [16]: sa.b
Out[16]: 2
In [17]: dfa.A
Out[17]:
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 [18]: sa.a = 5
In [19]: sa
Out[19]:
a 5
b 2
c 3
dtype: int64
In [20]: dfa.A = list(range(len(dfa.index))) # ok if A already exists
In [21]: dfa
Out[21]:
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 [22]: dfa['A'] = list(range(len(dfa.index))) # use this form to create a new column
In [23]: dfa
Out[23]:
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
警告
仅当index元素是有效的Python标识符(例如s.1,不允许使用)时,才能使用此访问权限。有关有效标识符的说明,请参见此处。
如果属性与现有方法名称冲突(例如s.min不允许),则该属性将不可用。
同样,该属性将不可用,如果它与下列任何名单的冲突:index, major_axis,minor_axis,items。
在任何一种情况下,标准索引仍然可以工作,例如s['1'],s['min']和s['index']将访问相应的元素或列。
如果使用的是IPython环境,则也可以使用制表符补全来查看这些可访问的属性。
您还可以将分配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]: x
Out[26]:
x y
0 1 3
1 9 99
2 3 5
您可以使用属性访问来修改Series或DataFrame列的现有元素,但要小心;如果您尝试使用属性访问来创建新列,则它将创建一个新属性而不是一个新列。在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_access
In [3]: df
Out[3]:
one
0 1.0
1 2.0
2 3.0
切片范围
在“ 按位置选择”部分详细介绍了该.iloc方法,介绍了沿任意轴切片范围的最可靠,最一致的方法。现在,我们解释使用[]运算符进行切片的语义。
使用Series时,语法与ndarray完全一样,返回值的一部分和相应的标签:
In [27]: s[:5]
Out[27]:
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 [28]: s[::2]
Out[28]:
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 [29]: s[::-1]
Out[29]:
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 [30]: s2 = s.copy()
In [31]: s2[:5] = 0
In [32]: s2
Out[32]:
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时,[] 在rows中对切片进行切片。由于这是一种常见的操作,因此在很大程度上是为了方便而提供的。
In [33]: df[:3]
Out[33]:
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 [34]: df[::-1]
Out[34]:
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
按标签选择
警告 为设置操作返回副本还是参考,可能取决于上下文。这有时被称为,应该避免。请参阅返回视图与复制。chained assignment
警告
.loc当您提供与索引类型不兼容(或可转换)的切片器时,它是严格的。例如在中使用整数DatetimeIndex。这些将引发一个TypeError。
In [35]: dfl = pd.DataFrame(np.random.randn(5, 4),
....: columns=list('ABCD'),
....: index=pd.date_range('20130101', periods=5))
....:
In [36]: dfl
Out[36]:
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 [37]: dfl.loc['20130102':'20130104']
Out[37]:
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
警告 从0.21.0开始,pandas将显示FutureWarningif索引,其中包含缺少标签的列表。在未来,这将引发KeyError。请参见类似列表的列表。不推荐使用在列表中缺少键的loc。
熊猫提供了一整套方法,以便具有纯基于标签的索引。这是一个基于严格包含的协议。要求的每个标签都必须在索引中,否则KeyError将引发a。切片时,如果索引中存在起始边界和终止边界,则都将包括在内。整数是有效的标签,但它们引用的是标签,而不是position。
该.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]: s1
Out[39]:
a 1.431256
b 1.340309
c -1.170299
d -0.226169
e 0.410835
f 0.813850
dtype: float64
In [40]: s1.loc['c':]
Out[40]:
c -1.170299
d -0.226169
e 0.410835
f 0.813850
dtype: float64
In [41]: s1.loc['b']
Out[41]: 1.3403088497993827
请注意,设置同样适用:
In [42]: s1.loc['c':] = 0
In [43]: s1
Out[43]:
a 1.431256
b 1.340309
c 0.000000
d 0.000000
e 0.000000
f 0.000000
dtype: float64
使用DataFrame:
In [44]: df1 = pd.DataFrame(np.random.randn(6, 4),
....: index=list('abcdef'),
....: columns=list('ABCD'))
....:
In [45]: df1
Out[45]:
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 [46]: df1.loc[['a', 'b', 'd'], :]
Out[46]:
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 [47]: df1.loc['d':, 'A':'C']
Out[47]:
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 [48]: df1.loc['a']
Out[48]:
A 0.132003
B -0.827317
C -0.076467
D -1.187678
Name: a, dtype: float64
要使用布尔数组获取值:
In [49]: df1.loc['a'] > 0
Out[49]:
A True
B False
C False
D False
Name: a, dtype: bool
In [50]: df1.loc[:, df1.loc['a'] > 0]
Out[50]:
A
a 0.132003
b 1.130127
c 1.024180
d 0.974466
e 0.545952
f -1.281247
为了显式地获取值(等效于deprecated 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 b
2 c
5 d
dtype: object
如果这两个中的至少一个不存在的,但该指数进行排序,并能对启动和停止的标签进行比较,然后切片仍然会按预期方式工作,通过选择的标签,其排名在两者之间:
In [54]: s.sort_index()
Out[54]:
0 a
2 c
3 b
4 e
5 d
dtype: object
In [55]: s.sort_index().loc[1:6]
Out[55]:
2 c
3 b
4 e
5 d
dtype: object
但是,如果不存在两者中的至少一个并且未对索引进行排序,则将引发错误(因为这样做会导致计算量大,并且可能对混合类型索引造成歧义)。例如,在上面的示例中,s.loc[1:6]将上升KeyError。
按位置选择
警告 为设置操作返回副本还是参考,可能取决于上下文。这有时被称为,应该避免。请参阅返回视图与复制。chained assignment
Pandas提供了一组方法,以便获得纯粹基于整数的索引。语义严格遵循Python和NumPy切片。这些正在0-based索引。当切片,开始结合被包含,而上限是排除。尝试使用非整数,即使有效标签也将引发IndexError。
该.iloc属性是主要的访问方法。以下是有效输入:
整数,例如5。
整数列表或数组。[4, 3, 0]
具有int的slice对象1:7。
布尔数组。
A callable,请参见按可调用选择。
In [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.110336102891167
请注意,设置同样适用:
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.1549507744249032
要使用整数位置(等于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.
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)
请注意,使用超出范围的切片可能会导致一个空轴(例如,返回一个空的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以及[]索引也可以接受callable作为索引器。在callable必须与一个参数(呼叫系列或数据帧)返回的有效输出索引功能。
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 ... so ibb hbp sh sf gidp
year team ...
2007 CIN 6 379 745 101 203 35 ... 127.0 14.0 1.0 1.0 15.0 18.0
DET 5 301 1062 162 283 54 ... 176.0 3.0 10.0 4.0 8.0 28.0
HOU 4 311 926 109 218 47 ... 212.0 3.0 9.0 16.0 6.0 17.0
LAN 11 413 1021 153 293 61 ... 141.0 8.0 9.0 3.0 8.0 29.0
NYN 13 622 1854 240 509 101 ... 310.0 24.0 23.0 18.0 15.0 48.0
SFN 5 482 1305 198 337 67 ... 188.0 51.0 8.0 16.0 6.0 41.0
TEX 2 198 729 115 200 40 ... 140.0 4.0 5.0 2.0 8.0 16.0
TOR 4 459 1408 187 378 96 ... 265.0 16.0 12.0 4.0 16.0 38.0
[8 rows x 18 columns]
IX Indexer已弃用
警告 在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]: dfd
Out[94]:
A B
a 1 4
b 2 5
c 3 6
以前的行为,您希望从“ A”列的索引中获取第0个元素和第2个元素。
In [3]: dfd.ix[[0, 2], 'A']
Out[3]:
a 1
c 3
Name: A, dtype: int64
使用.loc。在这里,我们将从索引中选择适当的索引,然后使用标签索引。
In [95]: dfd.loc[dfd.index[[0, 2]], 'A']
Out[95]:
a 1
c 3
Name: A, dtype: int64
也可以使用来表达这一点.iloc,方法是明确获取索引器上的位置,并使用 位置索引来选择事物。
In [96]: dfd.iloc[[0, 2], dfd.columns.get_loc('A')]
Out[96]:
a 1
c 3
Name: A, dtype: int64
要获取多个索引器,请使用.get_indexer:
In [97]: dfd.iloc[[0, 2], dfd.columns.get_indexer(['A', 'B'])]
Out[97]:
A B
a 1 4
c 3 6
不建议使用带有缺少标签的列表建立索引
警告 从0.21.0开始,不推荐使用.loc或[]带有一个或多个缺少标签的列表,而推荐使用.reindex。
在以前的版本中,.loc[list-of-labels]只要找到至少一个键,使用就可以工作(否则会引发KeyError)。不建议使用此行为,它将显示一条警告消息,指向此部分。推荐的替代方法是使用.reindex()。
例如。
In [98]: s = pd.Series([1, 2, 3])
In [99]: s
Out[99]:
0 1
1 2
2 3
dtype: int64
找到所有键的选择保持不变。
In [100]: s.loc[[1, 2]]
Out[100]:
1 2
2 3
dtype: int64
以前的行为
In [4]: s.loc[[1, 2, 3]]
Out[4]:
1 2.0
2 3.0
3 NaN
dtype: float64
当前行为
In [4]: s.loc[[1, 2, 3]]
Passing list-likes to .loc with any non-matching elements will raise
KeyError 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-listlike
Out[4]:
1 2.0
2 3.0
3 NaN
dtype: float64
重建索引
实现选择潜在未找到元素的惯用方式是通过.reindex()。另请参阅“ 重新索引编制 ”部分。
In [101]: s.reindex([1, 2, 3])
Out[101]:
1 2.0
2 3.0
3 NaN
dtype: float64
另外,如果您只想选择有效的密钥,则以下是惯用且有效的;保证保留选择的dtype。
In [102]: labels = [1, 2, 3]
In [103]: s.loc[s.index.intersection(labels)]
Out[103]:
1 2
2 3
dtype: 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.0
d NaN
dtype: 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 4
dtype: int64
# One may specify either a number of rows:
In [109]: s.sample(n=3)
Out[109]:
0 0
4 4
1 1
dtype: int64
# Or a fraction of the rows:
In [110]: s.sample(frac=0.5)
Out[110]:
5 5
3 3
1 1
dtype: 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 0
1 1
5 5
3 3
2 2
4 4
dtype: int64
# With replacement:
In [113]: s.sample(n=6, replace=True)
Out[113]:
0 0
4 4
3 3
2 2
4 4
4 4
dtype: 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 5
4 4
3 3
dtype: int64
# Weights will be re-normalized automatically
In [117]: example_weights2 = [0.5, 0, 0, 0, 0, 0]
In [118]: s.sample(n=1, weights=example_weights2)
Out[118]:
0 0
dtype: 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_column
1 8 0.4
0 9 0.5
2 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]:
col1
0 1
1 2
2 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 col2
2 3 4
1 2 3
In [125]: df4.sample(n=2, random_state=2)
Out[125]:
col1 col2
2 3 4
1 2 3
放大设置
.loc/[]当为该轴设置不存在的键时,这些操作可以执行放大操作。
在这种Series情况下,这实际上是附加操作。
In [126]: se = pd.Series([1, 2, 3])
In [127]: se
Out[127]:
0 1
1 2
2 3
dtype: int64
In [128]: se[5] = 5.
In [129]: se
Out[129]:
0 1.0
1 2.0
2 3.0
5 5.0
dtype: float64
阿DataFrame可以在任一轴通过被放大.loc。
In [130]: dfi = pd.DataFrame(np.arange(6).reshape(3, 2),
.....: columns=['A', 'B'])
.....:
In [131]: dfi
Out[131]:
A B
0 0 1
1 2 3
2 4 5
In [132]: dfi.loc[:, 'C'] = dfi.loc[:, 'A']
In [133]: dfi
Out[133]:
A B C
0 0 1 0
1 2 3 2
2 4 5 4
这就像对的append操作DataFrame。
In [134]: dfi.loc[3] = 5
In [135]: dfi
Out[135]:
A B C
0 0 1 0
1 2 3 2
2 4 5 4
3 5 5 5
快速获取和设置标量值
由于with索引[]必须处理很多情况(单标签访问,切片,布尔索引等),因此要弄清楚您要的内容有一点开销。如果只想访问标量值,最快的方法是使用at和iat方法,它们在所有数据结构上实现。
与相似loc,at提供基于标签的标量查找,而类似于iat提供基于整数的查找iloc
In [136]: s.iat[5]
Out[136]: 5
In [137]: df.at[dates[5], 'A']
Out[137]: -0.6736897080883706
In [138]: df.iat[3, 0]
Out[138]: 0.7215551622443669
您也可以使用这些相同的索引器进行设置。
In [139]: df.at[dates[5], 'E'] = 7
In [140]: df.iat[3, 0] = 7
at 如果缺少索引器,可能会像上面一样就地放大对象。
In [141]: df.at[dates[-1] + pd.Timedelta('1 day'), 0] = 7
In [142]: df
Out[142]:
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
布尔索引
另一个常见的操作是使用布尔向量来过滤数据。运算符是:|for or,&for and和~for not。这些必须通过使用括号中,由于默认Python会计算表达式如被分组为 ,而所希望的评价顺序是 。df.A > 2 & df.B < 3df.A > (2 & df.B) < 3(df.A > 2) & (df.B < 3)
使用布尔向量为Series编制索引的方式与NumPy ndarray完全相同:
In [143]: s = pd.Series(range(-3, 4))
In [144]: s
Out[144]:
0 -3
1 -2
2 -1
3 0
4 1
5 2
6 3
dtype: int64
In [145]: s[s > 0]
Out[145]:
4 1
5 2
6 3
dtype: int64
In [146]: s[(s < -1) | (s > 0.5)]
Out[146]:
0 -3
1 -2
4 1
5 2
6 3
dtype: int64
In [147]: s[~(s < 0)]
Out[147]:
3 0
4 1
5 2
6 3
dtype: int64
您可以使用布尔向量从DataFrame中选择行,该布尔向量的长度与DataFrame的索引相同(例如,从DataFrame的列之一派生的值):
In [148]: df[df['A'] > 0]
Out[148]:
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
列表推导和mapSeries方法也可以用于产生更复杂的条件:
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 c
2 two y 0.041290
3 three x 0.361719
4 two y -0.238075
# equivalent but slower
In [152]: df2[[x.startswith('t') for x in df2['a']]]
Out[152]:
a b c
2 two y 0.041290
3 three x 0.361719
4 two y -0.238075
# Multiple criteria
In [153]: df2[criterion & (df2['b'] == 'x')]
Out[153]:
a b c
3 three x 0.361719
随着选择方法通过标签选择,选择的位置,和高级索引你可能比一个轴使用布尔向量与其他索引表达式中合并一起更选择。
In [154]: df2.loc[criterion & (df2['b'] == 'x'), 'b':'c']
Out[154]:
b c
3 x 0.361719
用isin索引
考虑isin()方法Series,该方法将返回一个布尔向量,该布尔向量Series在传递的列表中存在的任何元素处都为真。这使您可以选择一行或多列具有所需值的行:
In [155]: s = pd.Series(np.arange(5), index=np.arange(5)[::-1], dtype='int64')
In [156]: s
Out[156]:
4 0
3 1
2 2
1 3
0 4
dtype: int64
In [157]: s.isin([2, 4, 6])
Out[157]:
4 False
3 False
2 True
1 False
0 True
dtype: bool
In [158]: s[s.isin([2, 4, 6])]
Out[158]:
2 2
0 4
dtype: int64
相同的方法可用于Index对象,并且在您不知道实际上找到了哪个标签的情况下很有用:
In [159]: s[s.index.isin([2, 4, 6])]
Out[159]:
4 0
2 2
dtype: int64
# compare it to the following
In [160]: s.reindex([2, 4, 6])
Out[160]:
2 2.0
4 0.0
6 NaN
dtype: float64
除此之外,还MultiIndex允许选择一个单独的级别以用于成员资格检查:
In [161]: s_mi = pd.Series(np.arange(6),
.....: index=pd.MultiIndex.from_product([[0, 1], ['a', 'b', 'c']]))
.....:
In [162]: s_mi
Out[162]:
0 a 0
b 1
c 2
1 a 3
b 4
c 5
dtype: int64
In [163]: s_mi.iloc[s_mi.index.isin([(1, 'a'), (2, 'b'), (0, 'c')])]
Out[163]:
0 c 2
1 a 3
dtype: int64
In [164]: s_mi.iloc[s_mi.index.isin(['a', 'c', 'e'], level=1)]
Out[164]:
0 a 0
c 2
1 a 3
c 5
dtype: int64
DataFrame也有一个isin()方法。调用时isin,将一组值作为数组或dict传递。如果values是一个数组,则isin返回一个与原始DataFrame形状相同的布尔值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 ids2
0 True True True
1 False True False
2 True False False
3 False False False
通常,您需要将某些值与某些列匹配。只需将值设置为a即可dict,键是列,而值是要检查的项目列表。
In [168]: values = {'ids': ['a', 'b'], 'vals': [1, 3]}
In [169]: df.isin(values)
Out[169]:
vals ids ids2
0 True True False
1 False True False
2 True False False
3 False False False
将DataFrame 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 ids2
0 1 a a
该where()方法和屏蔽
从具有布尔向量的Series中选择值通常会返回数据的子集。为了确保选择输出具有与原始数据相同的形状,可以where在Series和中使用方法DataFrame。
要仅返回选定的行:
In [173]: s[s > 0]
Out[173]:
3 1
2 2
1 3
0 4
dtype: int64
要返回与原始形状相同的系列:
In [174]: s.where(s > 0)
Out[174]:
4 NaN
3 1.0
2 2.0
1 3.0
0 4.0
dtype: float64
现在,从具有布尔条件的DataFrame中选择值还可以保留输入数据的形状。where在后台使用作为实现。以下代码等效于。df.where(df < 0)
In [175]: df[df < 0]
Out[175]:
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 [176]: df.where(df < 0, -df)
Out[176]:
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 [177]: s2 = s.copy()
In [178]: s2[s2 < 0] = 0
In [179]: s2
Out[179]:
4 0
3 1
2 2
1 3
0 4
dtype: int64
In [180]: df2 = df.copy()
In [181]: df2[df2 < 0] = 0
In [182]: df2
Out[182]:
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 [183]: df_orig = df.copy()
In [184]: df_orig.where(df > 0, -df, inplace=True)
In [185]: df_orig
Out[185]:
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()。大致相当于。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 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
对准
此外,where对齐输入的布尔条件(ndarray或DataFrame),以便可以通过设置进行部分选择。这类似于通过进行部分设置.loc(但在内容而非轴标签上)。
In [187]: df2 = df.copy()
In [188]: df2[df2[1:4] > 0] = 3
In [189]: df2
Out[189]:
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
执行时,where还可以接受axis和level参数以对齐输入where。
In [190]: df2 = df.copy()
In [191]: df2.where(df2 > 0, df2['A'], axis='index')
Out[191]:
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 [192]: df2 = df.copy()
In [193]: df.apply(lambda x, y: x.where(x > 0, y), y=df['A'])
Out[193]:
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版中的新功能。
在哪里可以接受一个callable作为条件和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 C
0 11 14 7
1 12 5 8
2 13 6 9
遮罩
mask()是的逆布尔运算where。
In [196]: s.mask(s >= 0)
Out[196]:
4 NaN
3 NaN
2 NaN
1 NaN
0 NaN
dtype: float64
In [197]: df.mask(df >= 0)
Out[197]:
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()方法
DataFrame对象具有query() 允许使用表达式进行选择的方法。
您可以获取框架的值,其中column b的值在column a和的值之间c。例如:
In [198]: n = 10
In [199]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))
In [200]: df
Out[200]:
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 [201]: df[(df.a < df.b) & (df.b < df.c)]
Out[201]:
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 [202]: df.query('(a < b) & (b < c)')
Out[202]:
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 [203]: df = pd.DataFrame(np.random.randint(n / 2, size=(n, 2)), columns=list('bc'))
In [204]: df.index.name = 'a'
In [205]: df
Out[205]:
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 [206]: df.query('a < b and b < c')
Out[206]:
b c
a
2 3 4
相反,如果您不想或无法命名索引,则可以index在查询表达式中使用该名称 :
In [207]: df = pd.DataFrame(np.random.randint(n, size=(n, 2)), columns=list('bc'))
In [208]: df
Out[208]:
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 [209]: df.query('index < b < c')
Out[209]:
b c
2 5 6
注意 如果索引名与列名重叠,则列名优先。例如,
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 index
Out[212]:
a
a
1 3
3 3
您仍然可以通过使用特殊标识符'index'在查询表达式中使用索引:
In [213]: df.query('index > 2')
Out[213]:
a
a
3 3
4 2
如果由于某种原因您有一个名为的列index,那么您也可以引用该索引ilevel_0,但是在这一点上,您应该考虑将列重命名为不太模糊的名称。
MultiIndex query()语法
您也可以将a的级别与a DataFrame一起使用 MultiIndex,就好像它们是框架中的列一样:
In [214]: n = 10
In [215]: colors = np.random.choice(['red', 'green'], size=n)
In [216]: foods = np.random.choice(['eggs', 'ham'], size=n)
In [217]: colors
Out[217]:
array(['red', 'red', 'red', 'green', 'green', 'green', 'green', 'green',
'green', 'green'], dtype='<U5')
In [218]: foods
Out[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]: df
Out[221]:
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 [222]: df.query('color == "red"')
Out[222]:
0 1
color food
red ham 0.194889 -0.381994
ham 0.318587 2.089075
eggs -0.728293 -0.090255
如果的级别MultiIndex未命名,则可以使用特殊名称来引用它们:
In [223]: df.index.names = [None, None]
In [224]: df
Out[224]:
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 [225]: df.query('ilevel_0 == "red"')
Out[225]:
0 1
red ham 0.194889 -0.381994
ham 0.318587 2.089075
eggs -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]: df
Out[227]:
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 [228]: df2 = pd.DataFrame(np.random.rand(n + 2, 3), columns=df.columns)
In [229]: df2
Out[229]:
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 [230]: expr = '0.0 <= a <= c <= 0.5'
In [231]: map(lambda frame: frame.query(expr), [df, df2])
Out[231]: <map at 0x7fb06bd71cf8>
query()Python与Pandas语法比较
完整的类似numpy的语法:
In [232]: df = pd.DataFrame(np.random.randint(n, size=(n, 3)), columns=list('abc'))
In [233]: df
Out[233]:
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 [234]: df.query('(a < b) & (b < c)')
Out[234]:
a b c
0 7 8 9
In [235]: df[(df.a < df.b) & (df.b < df.c)]
Out[235]:
a b c
0 7 8 9
删除括号会稍微好一点(通过绑定使比较运算符比&和更紧密地绑定|)。
In [236]: df.query('a < b & b < c')
Out[236]:
a b c
0 7 8 9
使用英语代替符号:
In [237]: df.query('a < b and b < c')
Out[237]:
a b c
0 7 8 9
非常接近您在纸上书写的方式:
In [238]: df.query('a < b < c')
Out[238]:
a b c
0 7 8 9
在in与运营商not in
query()还支持Python in和 比较运算符的特殊用法,为调用a 或方法提供了简洁的语法 。not inisinSeriesDataFrame
# get all rows where columns "a" and "b" have overlapping values
In [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]: df
Out[240]:
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 [241]: df.query('a in b')
Out[241]:
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 [242]: df[df.a.isin(df.b)]
Out[242]:
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 [243]: df.query('a not in b')
Out[243]:
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 [244]: df[~df.a.isin(df.b)]
Out[244]:
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 [245]: df.query('a in b and c < d')
Out[245]:
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 [246]: df[df.b.isin(df.a) & (df.c < df.d)]
Out[246]:
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
注意 请注意,在Python中对in和进行了评估,因为 该操作不等效。但是,在香草Python中仅对 / 表达式本身进行求值。例如,在表达式中not innumexpr innot in
df.query('a in b + c + d')
(b + c + d)通过评估numexpr和然后的in 操作在普通的Python评价。通常,将使用可以评估的任何操作numexpr。
==运算符与list对象的特殊用法
list使用==/ 将值a与列进行比较!=类似于in/ 。not in
In [247]: df.query('b == ["a", "b", "c"]')
Out[247]:
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 [248]: df[df.b.isin(["a", "b", "c"])]
Out[248]:
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 [249]: df.query('c == [1, 2]')
Out[249]:
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 [250]: df.query('c != [1, 2]')
Out[250]:
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 [251]: df.query('[1, 2] in c')
Out[251]:
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 [252]: df.query('[1, 2] not in c')
Out[252]:
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 [253]: df[df.c.isin([1, 2])]
Out[253]:
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 [254]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))
In [255]: df['bools'] = np.random.rand(len(df)) > 0.5
In [256]: df.query('~bools')
Out[256]:
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 [257]: df.query('not bools')
Out[257]:
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 [258]: df.query('not bools') == df[~df.bools]
Out[258]:
a b c bools
2 True True True True
7 True True True True
8 True True True True
当然,表达式也可以任意复杂:
# short query syntax
In [259]: shorter = df.query('a < b < c and (not bools) or bools > 2')
# equivalent in pure Python
In [260]: longer = df[(df.a < df.b) & (df.b < df.c) & (~df.bools) | (df.bools > 2)]
In [261]: shorter
Out[261]:
a b c bools
7 0.275396 0.691034 0.826619 False
In [262]: longer
Out[262]:
a b c bools
7 0.275396 0.691034 0.826619 False
In [263]: shorter == longer
Out[263]:
a b c bools
7 True True True True
性能query()
DataFrame.query()numexpr对于大型框架,使用速度比Python快。
../_images/query-perf.png
注意 仅当您的框架中有大约200,000行以上时,才可以看到使用numexpr引擎的性能优势DataFrame.query()。
../_images/query-perf-small.png
此图是使用组成的DataFrame,其中包含3列,每个列包含使用生成的浮点值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]: df2
Out[265]:
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 [266]: df2.duplicated('a')
Out[266]:
0 False
1 True
2 False
3 True
4 True
5 False
6 False
dtype: bool
In [267]: df2.duplicated('a', keep='last')
Out[267]:
0 True
1 False
2 True
3 True
4 False
5 False
6 False
dtype: bool
In [268]: df2.duplicated('a', keep=False)
Out[268]:
0 True
1 True
2 True
3 True
4 True
5 False
6 False
dtype: bool
In [269]: df2.drop_duplicates('a')
Out[269]:
a b c
0 one x -1.067137
2 two x -0.211056
5 three x -1.964475
6 four x 1.298329
In [270]: df2.drop_duplicates('a', keep='last')
Out[270]:
a b c
1 one y 0.309500
4 two x -0.390820
5 three x -1.964475
6 four x 1.298329
In [271]: df2.drop_duplicates('a', keep=False)
Out[271]:
a b c
5 three x -1.964475
6 four x 1.298329
另外,您可以传递列列表以标识重复项。
In [272]: df2.duplicated(['a', 'b'])
Out[272]:
0 False
1 False
2 False
3 False
4 True
5 False
6 False
dtype: bool
In [273]: df2.drop_duplicates(['a', 'b'])
Out[273]:
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 [274]: df3 = pd.DataFrame({'a': np.arange(6),
.....: 'b': np.random.randn(6)},
.....: index=['a', 'a', 'b', 'c', 'b', 'a'])
.....:
In [275]: df3
Out[275]:
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 [276]: df3.index.duplicated()
Out[276]: array([False, True, False, False, True, True])
In [277]: df3[~df3.index.duplicated()]
Out[277]:
a b
a 0 1.440455
b 2 1.038402
c 3 -0.894409
In [278]: df3[~df3.index.duplicated(keep='last')]
Out[278]:
a b
c 3 -0.894409
b 4 0.683536
a 5 3.082764
In [279]: df3[~df3.index.duplicated(keep=False)]
Out[279]:
a b
c 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]: 1
In [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具有重复条目的对象转换为 set,则会引发异常。
Index还提供了查找,数据对齐和重新索引所需的基础结构。Index直接创建一个最简单的方法 是将a list或其他序列传递给 Index:
In [285]: index = pd.Index(['e', 'd', 'a', 'b'])
In [286]: index
Out[286]: Index(['e', 'd', 'a', 'b'], dtype='object')
In [287]: 'd' in index
Out[287]: True
您还可以传递name要存储在索引中的:
In [288]: index = pd.Index(['e', 'd', 'a', 'b'], name='something')
In [289]: index.name
Out[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]: df
Out[293]:
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 [294]: df['A']
Out[294]:
rows
0 1.295989
1 0.678101
2 -0.674808
3 1.889957
4 -1.211795
Name: 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]: ind
Out[297]: Int64Index([1, 2, 3], dtype='int64')
In [298]: ind.set_names(["apple"], inplace=True)
In [299]: ind.name = "bob"
In [300]: ind
Out[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]: index
Out[302]:
MultiIndex(levels=[[0, 1, 2], ['one', 'two']],
codes=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]],
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(levels=[[0, 1, 2], ['a', 'b']],
codes=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]],
names=['first', 'second'])
在索引对象设置操作
两个主要操作是和。这些可以直接称为实例方法,也可以通过重载运算符使用。通过该方法提供差异。union (|)intersection (&).difference()
In [305]: a = pd.Index(['c', 'b', 'a'])
In [306]: b = pd.Index(['c', 'e', 'd'])
In [307]: a | b
Out[307]: Index(['a', 'b', 'c', 'd', 'e'], dtype='object')
In [308]: a & b
Out[308]: Index(['c'], dtype='object')
In [309]: a.difference(b)
Out[309]: Index(['a', 'b'], dtype='object')
该操作也可用,该操作返回出现在或中的元素,但不同时出现在这两个元素中。这等效于所创建的索引,其中删除了重复项。symmetric_difference (^)idx1idx2idx1.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 ^ idx2
Out[313]: Int64Index([1, 5], dtype='int64')
注意 设置操作产生的索引将按升序排序。
缺失值
重要 即使Index可以保留缺少的值(NaN),如果您不希望有任何意外的结果,也应避免使用。例如,某些操作会隐式排除缺失值。
Index.fillna 用指定的标量值填充缺少的值。
In [314]: idx1 = pd.Index([1, np.nan, 3, 4])
In [315]: idx1
Out[315]: Float64Index([1.0, nan, 3.0, 4.0], dtype='float64')
In [316]: idx1.fillna(2)
Out[316]: Float64Index([1.0, 2.0, 3.0, 4.0], dtype='float64')
In [317]: idx2 = pd.DatetimeIndex([pd.Timestamp('2011-01-01'),
.....: pd.NaT,
.....: pd.Timestamp('2011-01-03')])
.....:
In [318]: idx2
Out[318]: DatetimeIndex(['2011-01-01', 'NaT', '2011-01-03'], dtype='datetime64[ns]', freq=None)
In [319]: idx2.fillna(pd.Timestamp('2011-01-02'))
Out[319]: DatetimeIndex(['2011-01-01', '2011-01-02', '2011-01-03'], dtype='datetime64[ns]', freq=None)
设置/重置索引
有时候,您会在DataFrame中加载或创建数据集,并希望在完成后添加索引。有几种不同的方法。
设置索引
DataFrame有一个set_index()方法,该方法采用列名(对于常规Index)或列名列表(对于MultiIndex)。要创建一个新的,重新索引的DataFrame:
In [320]: data
Out[320]:
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 [321]: indexed1 = data.set_index('c')
In [322]: indexed1
Out[322]:
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 [323]: indexed2 = data.set_index(['a', 'b'])
In [324]: indexed2
Out[324]:
c d
a b
bar one z 1.0
two y 2.0
foo one x 3.0
two w 4.0
该append关键字选项让你保持现有索引并追加给列一个多指标:
In [325]: frame = data.set_index('c', drop=False)
In [326]: frame = frame.set_index(['a', 'b'], append=True)
In [327]: frame
Out[327]:
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 [328]: data.set_index('c', drop=False)
Out[328]:
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 [329]: data.set_index(['a', 'b'], inplace=True)
In [330]: data
Out[330]:
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 [331]: data
Out[331]:
c d
a b
bar one z 1.0
two y 2.0
foo one x 3.0
two w 4.0
In [332]: data.reset_index()
Out[332]:
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 [333]: frame
Out[333]:
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 [334]: frame.reset_index(level=1)
Out[334]:
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的列中。
添加临时索引
如果您自己创建索引,则可以将其分配给该index字段:
data.index = index
返回视图与副本
在熊猫对象中设置值时,必须注意避免所谓的 。这是一个例子。chained indexing
In [335]: dfmi = pd.DataFrame([list('abcd'),
.....: list('efgh'),
.....: list('ijkl'),
.....: list('mnop')],
.....: columns=pd.MultiIndex.from_product([['one', 'two'],
.....: ['first', 'second']]))
.....:
In [336]: dfmi
Out[336]:
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 [337]: dfmi['one']['second']
Out[337]:
0 b
1 f
2 j
3 n
Name: second, dtype: object
In [338]: dfmi.loc[:, ('one', 'second')]
Out[338]:
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因为熊猫将这些操作视为单独的事件。例如,对的单独调用__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__那里吗?在简单情况之外,很难预测它是否将返回视图或副本(这取决于数组的内存布局,有关大熊猫对此不做任何保证),因此很难确定将__setitem__要修改dfmi还是返回一个临时对象。之后立即扔出去。那什么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 ...
# We don't know whether this will modify df or not!
foo['quux'] = value
return foo
kes!
评估顺序很重要
使用链式索引时,索引操作的顺序和类型将部分确定结果是原始对象的切片还是该切片的副本。
Pandas之所以这样,是SettingWithCopyWarning因为分配分片的副本通常不是故意的,而是由链式索引导致的错误,该错误将原本应有分片的副本返回。
如果您希望熊猫在某种程度上信任链式索引表达式的分配,可以将选项 设置mode.chained_assignment为以下值之一:
'warn',即默认值,表示SettingWithCopyWarning已打印a。
'raise'意味着大熊猫会筹集一个SettingWithCopyException 你必须处理的。
None 将完全消除警告。
In [339]: 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 [340]: 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。
这是正确的访问方法:
In [341]: dfc = pd.DataFrame({'A': ['aaa', 'bbb', 'ccc'], 'B': [1, 2, 3]})
In [342]: dfc.loc[0, 'A'] = 11
In [343]: dfc
Out[343]:
A B
0 11 1
1 bbb 2
2 ccc 3
这可以在次工作,但它不能保证,因此应避免:
In [344]: dfc = dfc.copy()
In [345]: dfc['A'][0] = 111
In [346]: dfc
Out[346]:
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
警告 链接的作业警告/异常旨在通知用户可能无效的作业。可能存在误报;意外报告链接分配的情况