Pandas 索引和选择数据
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 警告 链接的作业警告/异常旨在通知用户可能无效的作业。可能存在误报;意外报告链接分配的情况