Indexing and Selecting Data

原文:http://pandas.pydata.org/pandas-docs/stable/indexing.html

译者:飞龙 UsyiyiCN

校对:(虚位以待)

pandas对象中的轴标签信息有很多用途:

在本节中,我们将关注最后一点:即,如何切片,删除,以及一般获取和设置pandas对象的子集。主要关注的是系列和数据框架,因为他们在这一领域受到更多的发展关注。期望在将来对更高维数据结构(包括Panel)投入更多的工作,尤其是在基于标签的高级索引中。

注意

Python和NumPy索引操作符[]和属性操作符.提供在大范围的用例中快速和容易地访问pandas数据结构。这使得交互式工作直观,因为如果你已经知道如何处理Python字典和NumPy数组,没有什么新的学习。但是,由于要访问的数据的类型并不是事先知道的,直接使用标准操作符有一些优化的限制。对于生产代码,我们建议您利用本章中介绍的优化的熊猫数据访问方法。

警告

是否为设置操作返回副本或引用可以取决于上下文。这有时被称为链式赋值,应该避免。请参见Returning a View versus Copy

警告

在0.15.0 Index内部被重构为不再子类化ndarray,而是子类化PandasObject,类似于其余的pandas对象。这应该是一个透明的变化,只有非常有限的API影响(参见Internal Refactoring

警告

对于具有浮点数的整数索引的索引已经在0.18.0中阐明,对于变化的总结,参见here

有关MultiIndex和更高级的索引文档,请参阅MultiIndex / Advanced Indexing

有关某些高级策略,请参阅cookbook

Different Choices for Indexing

版本0.11.0中的新功能。

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

从多轴选择的对象获取值使用以下符号(使用.loc作为示例,但适用于.iloc.ix任何轴访问器可以是空片:忽略规范的轴假定为:(例如p.loc['a']等同于p.loc ['a', :, :]

对象类型 索引器
Series s.loc[indexer]
DataFrame df.loc[row_indexer,column_indexer]
Panel p.loc[item_indexer,major_indexer,minor_indexer]

基础知识

如在在last section中引入数据结构时提到的,用[](a.k.a.__getitem__用于熟悉在Python中实现类行为的人)选择低维切片。从而,

对象类型 选择 返回值类型
Series series[label] 标量值
DataFrame frame[colname] Series对应于colname
Panel panel[itemname] DataFrame对应于项目名称

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

In [1]: dates = pd.date_range('1/1/2000', periods=8)

In [2]: df = pd.DataFrame(np.random.randn(8, 4), index=dates, columns=['A', 'B', 'C', 'D'])

In [3]: df
Out[3]: 
                   A         B         C         D
2000-01-01  0.469112 -0.282863 -1.509059 -1.135632
2000-01-02  1.212112 -0.173215  0.119209 -1.044236
2000-01-03 -0.861849 -2.104569 -0.494929  1.071804
2000-01-04  0.721555 -0.706771 -1.039575  0.271860
2000-01-05 -0.424972  0.567020  0.276232 -1.087401
2000-01-06 -0.673690  0.113648 -1.478427  0.524988
2000-01-07  0.404705  0.577046 -1.715002 -1.039268
2000-01-08 -0.370647 -1.157892 -1.344312  0.844885

In [4]: panel = pd.Panel({'one' : df, 'two' : df - df.mean()})

In [5]: panel
Out[5]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 8 (major_axis) x 4 (minor_axis)
Items axis: one to two
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-08 00:00:00
Minor_axis axis: A to D

注意

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

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

In [6]: s = df['A']

In [7]: s[dates[5]]
Out[7]: -0.67368970808837059

In [8]: panel['two']
Out[8]: 
                   A         B         C         D
2000-01-01  0.409571  0.113086 -0.610826 -0.936507
2000-01-02  1.152571  0.222735  1.017442 -0.845111
2000-01-03 -0.921390 -1.708620  0.403304  1.270929
2000-01-04  0.662014 -0.310822 -0.141342  0.470985
2000-01-05 -0.484513  0.962970  1.174465 -0.888276
2000-01-06 -0.733231  0.509598 -0.580194  0.724113
2000-01-07  0.345164  0.972995 -0.816769 -0.840143
2000-01-08 -0.430188 -0.761943 -0.446079  1.044010

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

In [9]: df
Out[9]: 
                   A         B         C         D
2000-01-01  0.469112 -0.282863 -1.509059 -1.135632
2000-01-02  1.212112 -0.173215  0.119209 -1.044236
2000-01-03 -0.861849 -2.104569 -0.494929  1.071804
2000-01-04  0.721555 -0.706771 -1.039575  0.271860
2000-01-05 -0.424972  0.567020  0.276232 -1.087401
2000-01-06 -0.673690  0.113648 -1.478427  0.524988
2000-01-07  0.404705  0.577046 -1.715002 -1.039268
2000-01-08 -0.370647 -1.157892 -1.344312  0.844885

In [10]: df[['B', 'A']] = df[['A', 'B']]

In [11]: df
Out[11]: 
                   A         B         C         D
2000-01-01 -0.282863  0.469112 -1.509059 -1.135632
2000-01-02 -0.173215  1.212112  0.119209 -1.044236
2000-01-03 -2.104569 -0.861849 -0.494929  1.071804
2000-01-04 -0.706771  0.721555 -1.039575  0.271860
2000-01-05  0.567020 -0.424972  0.276232 -1.087401
2000-01-06  0.113648 -0.673690 -1.478427  0.524988
2000-01-07  0.577046  0.404705 -1.715002 -1.039268
2000-01-08 -1.157892 -0.370647 -1.344312  0.844885

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

警告

pandas aligns all AXES when setting Series and DataFrame from .loc, .iloc and .ix.

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

In [12]: df[['A', 'B']]
Out[12]: 
                   A         B
2000-01-01 -0.282863  0.469112
2000-01-02 -0.173215  1.212112
2000-01-03 -2.104569 -0.861849
2000-01-04 -0.706771  0.721555
2000-01-05  0.567020 -0.424972
2000-01-06  0.113648 -0.673690
2000-01-07  0.577046  0.404705
2000-01-08 -1.157892 -0.370647

In [13]: df.loc[:,['B', 'A']] = df[['A', 'B']]

In [14]: df[['A', 'B']]
Out[14]: 
                   A         B
2000-01-01 -0.282863  0.469112
2000-01-02 -0.173215  1.212112
2000-01-03 -2.104569 -0.861849
2000-01-04 -0.706771  0.721555
2000-01-05  0.567020 -0.424972
2000-01-06  0.113648 -0.673690
2000-01-07  0.577046  0.404705
2000-01-08 -1.157892 -0.370647

正确的方法是使用原始值

In [15]: df.loc[:,['B', 'A']] = df[['A', 'B']].values

In [16]: df[['A', 'B']]
Out[16]: 
                   A         B
2000-01-01  0.469112 -0.282863
2000-01-02  1.212112 -0.173215
2000-01-03 -0.861849 -2.104569
2000-01-04  0.721555 -0.706771
2000-01-05 -0.424972  0.567020
2000-01-06 -0.673690  0.113648
2000-01-07  0.404705  0.577046
2000-01-08 -0.370647 -1.157892

Attribute Access

You may access an index on a Series, column on a DataFrame, and an item on a Panel directly as an attribute:

In [17]: sa = pd.Series([1,2,3],index=list('abc'))

In [18]: dfa = df.copy()
In [19]: sa.b
Out[19]: 2

In [20]: dfa.A
Out[20]: 
2000-01-01    0.469112
2000-01-02    1.212112
2000-01-03   -0.861849
2000-01-04    0.721555
2000-01-05   -0.424972
2000-01-06   -0.673690
2000-01-07    0.404705
2000-01-08   -0.370647
Freq: D, Name: A, dtype: float64

In [21]: panel.one
Out[21]: 
                   A         B         C         D
2000-01-01  0.469112 -0.282863 -1.509059 -1.135632
2000-01-02  1.212112 -0.173215  0.119209 -1.044236
2000-01-03 -0.861849 -2.104569 -0.494929  1.071804
2000-01-04  0.721555 -0.706771 -1.039575  0.271860
2000-01-05 -0.424972  0.567020  0.276232 -1.087401
2000-01-06 -0.673690  0.113648 -1.478427  0.524988
2000-01-07  0.404705  0.577046 -1.715002 -1.039268
2000-01-08 -0.370647 -1.157892 -1.344312  0.844885

您可以使用属性访问来修改DataFrame的系列或列的现有元素,但要小心;如果您尝试使用属性访问来创建新列,则会无声地失败,从而创建新属性而不是新列。

In [22]: sa.a = 5

In [23]: sa
Out[23]: 
a    5
b    2
c    3
dtype: int64

In [24]: dfa.A = list(range(len(dfa.index)))  # ok if A already exists

In [25]: dfa
Out[25]: 
            A         B         C         D
2000-01-01  0 -0.282863 -1.509059 -1.135632
2000-01-02  1 -0.173215  0.119209 -1.044236
2000-01-03  2 -2.104569 -0.494929  1.071804
2000-01-04  3 -0.706771 -1.039575  0.271860
2000-01-05  4  0.567020  0.276232 -1.087401
2000-01-06  5  0.113648 -1.478427  0.524988
2000-01-07  6  0.577046 -1.715002 -1.039268
2000-01-08  7 -1.157892 -1.344312  0.844885

In [26]: dfa['A'] = list(range(len(dfa.index)))  # use this form to create a new column

In [27]: dfa
Out[27]: 
            A         B         C         D
2000-01-01  0 -0.282863 -1.509059 -1.135632
2000-01-02  1 -0.173215  0.119209 -1.044236
2000-01-03  2 -2.104569 -0.494929  1.071804
2000-01-04  3 -0.706771 -1.039575  0.271860
2000-01-05  4  0.567020  0.276232 -1.087401
2000-01-06  5  0.113648 -1.478427  0.524988
2000-01-07  6  0.577046 -1.715002 -1.039268
2000-01-08  7 -1.157892 -1.344312  0.844885

警告

如果使用IPython环境,您还可以使用制表符完成来查看这些可访问的属性。

您还可以将dict分配给DataFrame的行:

In [28]: x = pd.DataFrame({'x': [1, 2, 3], 'y': [3, 4, 5]})

In [29]: x.iloc[1] = dict(x=9, y=99)

In [30]: x
Out[30]: 
   x   y
0  1   3
1  9  99
2  3   5

Slicing ranges

.iloc方法的Selection by Position部分中描述了沿任意轴切分范围的最稳健和一致的方法。现在,我们使用[]运算符解释切片的语义。

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

In [31]: s[:5]
Out[31]: 
2000-01-01    0.469112
2000-01-02    1.212112
2000-01-03   -0.861849
2000-01-04    0.721555
2000-01-05   -0.424972
Freq: D, Name: A, dtype: float64

In [32]: s[::2]
Out[32]: 
2000-01-01    0.469112
2000-01-03   -0.861849
2000-01-05   -0.424972
2000-01-07    0.404705
Freq: 2D, Name: A, dtype: float64

In [33]: s[::-1]
Out[33]: 
2000-01-08   -0.370647
2000-01-07    0.404705
2000-01-06   -0.673690
2000-01-05   -0.424972
2000-01-04    0.721555
2000-01-03   -0.861849
2000-01-02    1.212112
2000-01-01    0.469112
Freq: -1D, Name: A, dtype: float64

请注意,也可以通过切片赋值:

In [34]: s2 = s.copy()

In [35]: s2[:5] = 0

In [36]: s2
Out[36]: 
2000-01-01    0.000000
2000-01-02    0.000000
2000-01-03    0.000000
2000-01-04    0.000000
2000-01-05    0.000000
2000-01-06   -0.673690
2000-01-07    0.404705
2000-01-08   -0.370647
Freq: D, Name: A, dtype: float64

使用DataFrame,在[] 内切片将切片。这主要是为了方便,因为它是这样的常见操作。

In [37]: df[:3]
Out[37]: 
                   A         B         C         D
2000-01-01  0.469112 -0.282863 -1.509059 -1.135632
2000-01-02  1.212112 -0.173215  0.119209 -1.044236
2000-01-03 -0.861849 -2.104569 -0.494929  1.071804

In [38]: df[::-1]
Out[38]: 
                   A         B         C         D
2000-01-08 -0.370647 -1.157892 -1.344312  0.844885
2000-01-07  0.404705  0.577046 -1.715002 -1.039268
2000-01-06 -0.673690  0.113648 -1.478427  0.524988
2000-01-05 -0.424972  0.567020  0.276232 -1.087401
2000-01-04  0.721555 -0.706771 -1.039575  0.271860
2000-01-03 -0.861849 -2.104569 -0.494929  1.071804
2000-01-02  1.212112 -0.173215  0.119209 -1.044236
2000-01-01  0.469112 -0.282863 -1.509059 -1.135632

Selection By Label

警告

是否为设置操作返回副本或引用可以取决于上下文。这有时被称为链接 分配,应该避免。请参见Returning a View versus Copy

警告

.loc在您呈现不兼容(或可转换)索引类型的切片器时是严格的。例如,在DatetimeIndex中使用整数。这将产生TypeError
In [39]: dfl = pd.DataFrame(np.random.randn(5,4), columns=list('ABCD'), index=pd.date_range('20130101',periods=5))

In [40]: dfl
Out[40]: 
                   A         B         C         D
2013-01-01  1.075770 -0.109050  1.643563 -1.469388
2013-01-02  0.357021 -0.674600 -1.776904 -0.968914
2013-01-03 -1.294524  0.413738  0.276662 -0.472035
2013-01-04 -0.013960 -0.362543 -0.006154 -0.923061
2013-01-05  0.895717  0.805244 -1.206412  2.565646
In [4]: dfl.loc[2:3]
TypeError: cannot do slice indexing on <class 'pandas.tseries.index.DatetimeIndex'> with these indexers [2] of <type 'int'>

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

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

pandas提供了一套方法,以便完全基于标签的索引这是一个严格的包含协议。您要求的标签的至少1个必须在索引中,否则会出现KeyError当切片时,起始边界是包括AND停止边界是包括整数是有效标签,但它们指的是标签,而不是位置

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

In [42]: s1 = pd.Series(np.random.randn(6),index=list('abcdef'))

In [43]: s1
Out[43]: 
a    1.431256
b    1.340309
c   -1.170299
d   -0.226169
e    0.410835
f    0.813850
dtype: float64

In [44]: s1.loc['c':]
Out[44]: 
c   -1.170299
d   -0.226169
e    0.410835
f    0.813850
dtype: float64

In [45]: s1.loc['b']
Out[45]: 1.3403088497993827

请注意,设置也很好:

In [46]: s1.loc['c':] = 0

In [47]: s1
Out[47]: 
a    1.431256
b    1.340309
c    0.000000
d    0.000000
e    0.000000
f    0.000000
dtype: float64

用DataFrame

In [48]: df1 = pd.DataFrame(np.random.randn(6,4),
   ....:                    index=list('abcdef'),
   ....:                    columns=list('ABCD'))
   ....: 

In [49]: df1
Out[49]: 
          A         B         C         D
a  0.132003 -0.827317 -0.076467 -1.187678
b  1.130127 -1.436737 -1.413681  1.607920
c  1.024180  0.569605  0.875906 -2.211372
d  0.974466 -2.006747 -0.410001 -0.078638
e  0.545952 -1.219217 -1.226825  0.769804
f -1.281247 -0.727707 -0.121306 -0.097883

In [50]: df1.loc[['a', 'b', 'd'], :]
Out[50]: 
          A         B         C         D
a  0.132003 -0.827317 -0.076467 -1.187678
b  1.130127 -1.436737 -1.413681  1.607920
d  0.974466 -2.006747 -0.410001 -0.078638

通过标签切片访问

In [51]: df1.loc['d':, 'A':'C']
Out[51]: 
          A         B         C
d  0.974466 -2.006747 -0.410001
e  0.545952 -1.219217 -1.226825
f -1.281247 -0.727707 -0.121306

要获取使用标签的横截面(等效于df.xs('a')

In [52]: df1.loc['a']
Out[52]: 
A    0.132003
B   -0.827317
C   -0.076467
D   -1.187678
Name: a, dtype: float64

获取带有布尔数组的值

In [53]: df1.loc['a'] > 0
Out[53]: 
A     True
B    False
C    False
D    False
Name: a, dtype: bool

In [54]: df1.loc[:, df1.loc['a'] > 0]
Out[54]: 
          A
a  0.132003
b  1.130127
c  1.024180
d  0.974466
e  0.545952
f -1.281247

显式获取值(等同于弃用的df.get_value('a','A')

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

Selection By Position

警告

是否为设置操作返回副本或引用可以取决于上下文。这有时被称为链接 分配,应该避免。请参见Returning a View versus Copy

pandas提供了一套方法,以便获得纯粹基于整数的索引语义遵循python和numpy切片。这些是基于0-based索引。当切片时,起始边界是包括,而上边界是排除尝试使用非整数,即使是有效的标签也会产生IndexError

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

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.1103361028911669

请注意,iloc也可以用来赋值:

In [60]: s1.iloc[:3] = 0

In [61]: s1
Out[61]: 
0    0.000000
2    0.000000
4    0.000000
6   -1.110336
8   -0.619976
dtype: float64

用DataFrame

In [62]: df1 = pd.DataFrame(np.random.randn(6,4),
   ....:                    index=list(range(0,12,2)),
   ....:                    columns=list(range(0,8,2)))
   ....: 

In [63]: df1
Out[63]: 
           0         2         4         6
0   0.149748 -0.732339  0.687738  0.176444
2   0.403310 -0.154951  0.301624 -2.179861
4  -1.369849 -0.954208  1.462696 -1.743161
6  -0.826591 -0.345352  1.314232  0.690579
8   0.995761  2.396780  0.014871  3.357427
10 -0.317441 -1.236269  0.896171 -0.487602

通过整数切片选择

In [64]: df1.iloc[:3]
Out[64]: 
          0         2         4         6
0  0.149748 -0.732339  0.687738  0.176444
2  0.403310 -0.154951  0.301624 -2.179861
4 -1.369849 -0.954208  1.462696 -1.743161

In [65]: df1.iloc[1:5, 2:4]
Out[65]: 
          4         6
2  0.301624 -2.179861
4  1.462696 -1.743161
6  1.314232  0.690579
8  0.014871  3.357427

通过整数列表选择

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

为了获得使用整数位置的横截面(等于df.xs(1)

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

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

# these are allowed in python/numpy.
# Only works in Pandas starting from v0.14.0.
In [71]: x = list('abcdef')

In [72]: x
Out[72]: ['a', 'b', 'c', 'd', 'e', 'f']

In [73]: x[4:10]
Out[73]: ['e', 'f']

In [74]: x[8:10]
Out[74]: []

In [75]: s = pd.Series(x)

In [76]: s
Out[76]: 
0    a
1    b
2    c
3    d
4    e
5    f
dtype: object

In [77]: s.iloc[4:10]
Out[77]: 
4    e
5    f
dtype: object

In [78]: s.iloc[8:10]
Out[78]: Series([], dtype: object)

注意

在v0.14.0之前,iloc将不接受切片的边界索引器,例如。超过被索引的对象的长度的值。

请注意,这可能会导致空的轴(例如返回一个空DataFrame)

In [79]: dfl = pd.DataFrame(np.random.randn(5,2), columns=list('AB'))

In [80]: dfl
Out[80]: 
          A         B
0 -0.082240 -2.182937
1  0.380396  0.084844
2  0.432390  1.519970
3 -0.493662  0.600178
4  0.274230  0.132885

In [81]: dfl.iloc[:, 2:3]
Out[81]: 
Empty DataFrame
Columns: []
Index: [0, 1, 2, 3, 4]

In [82]: dfl.iloc[:, 1:3]
Out[82]: 
          B
0 -2.182937
1  0.084844
2  1.519970
3  0.600178
4  0.132885

In [83]: dfl.iloc[4:6]
Out[83]: 
         A         B
4  0.27423  0.132885

超出范围的单个索引器将生成IndexError任何元素超出边界的索引器列表将生成IndexError

dfl.iloc[[4, 5, 6]]
IndexError: positional indexers are out-of-bounds

dfl.iloc[:, 4]
IndexError: single positional indexer is out-of-bounds

Selection By Callable

版本0.18.1中的新功能。

.loc.iloc.ix以及[]索引可以接受callablecallable必须是具有一个参数(调用Series,DataFrame或Panel)的函数,并返回有效的索引输出。

In [84]: df1 = pd.DataFrame(np.random.randn(6, 4),
   ....:                    index=list('abcdef'),
   ....:                    columns=list('ABCD'))
   ....: 

In [85]: df1
Out[85]: 
          A         B         C         D
a -0.023688  2.410179  1.450520  0.206053
b -0.251905 -2.213588  1.063327  1.266143
c  0.299368 -0.863838  0.408204 -1.048089
d -0.025747 -0.988387  0.094055  1.262731
e  1.289997  0.082423 -0.055758  0.536580
f -0.489682  0.369374 -0.034571 -2.484478

In [86]: df1.loc[lambda df: df.A > 0, :]
Out[86]: 
          A         B         C         D
c  0.299368 -0.863838  0.408204 -1.048089
e  1.289997  0.082423 -0.055758  0.536580

In [87]: df1.loc[:, lambda df: ['A', 'B']]
Out[87]: 
          A         B
a -0.023688  2.410179
b -0.251905 -2.213588
c  0.299368 -0.863838
d -0.025747 -0.988387
e  1.289997  0.082423
f -0.489682  0.369374

In [88]: df1.iloc[:, lambda df: [0, 1]]
Out[88]: 
          A         B
a -0.023688  2.410179
b -0.251905 -2.213588
c  0.299368 -0.863838
d -0.025747 -0.988387
e  1.289997  0.082423
f -0.489682  0.369374

In [89]: df1[lambda df: df.columns[0]]
Out[89]: 
a   -0.023688
b   -0.251905
c    0.299368
d   -0.025747
e    1.289997
f   -0.489682
Name: A, dtype: float64

您可以在Series中使用可调用索引。

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

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

In [91]: bb = pd.read_csv('data/baseball.csv', index_col='id')

In [92]: (bb.groupby(['year', 'team']).sum()
   ....:    .loc[lambda df: df.r > 100])
   ....: 
Out[92]: 
           stint    g    ab    r    h  X2b  X3b  hr    rbi    sb   cs   bb  \
year team                                                                    
2007 CIN       6  379   745  101  203   35    2  36  125.0  10.0  1.0  105   
     DET       5  301  1062  162  283   54    4  37  144.0  24.0  7.0   97   
     HOU       4  311   926  109  218   47    6  14   77.0  10.0  4.0   60   
     LAN      11  413  1021  153  293   61    3  36  154.0   7.0  5.0  114   
     NYN      13  622  1854  240  509  101    3  61  243.0  22.0  4.0  174   
     SFN       5  482  1305  198  337   67    6  40  171.0  26.0  7.0  235   
     TEX       2  198   729  115  200   40    4  28  115.0  21.0  4.0   73   
     TOR       4  459  1408  187  378   96    2  58  223.0   4.0  2.0  190   

              so   ibb   hbp    sh    sf  gidp  
year team                                       
2007 CIN   127.0  14.0   1.0   1.0  15.0  18.0  
     DET   176.0   3.0  10.0   4.0   8.0  28.0  
     HOU   212.0   3.0   9.0  16.0   6.0  17.0  
     LAN   141.0   8.0   9.0   3.0   8.0  29.0  
     NYN   310.0  24.0  23.0  18.0  15.0  48.0  
     SFN   188.0  51.0   8.0  16.0   6.0  41.0  
     TEX   140.0   4.0   5.0   2.0   8.0  16.0  
     TOR   265.0  16.0  12.0   4.0  16.0  38.0  

Selecting Random Samples

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

In [93]: s = pd.Series([0,1,2,3,4,5])

# When no arguments are passed, returns 1 row.
In [94]: s.sample()
Out[94]: 
4    4
dtype: int64

# One may specify either a number of rows:
In [95]: s.sample(n=3)
Out[95]: 
0    0
4    4
1    1
dtype: int64

# Or a fraction of the rows:
In [96]: s.sample(frac=0.5)
Out[96]: 
5    5
3    3
1    1
dtype: int64

默认情况下,sample最多只返回一行,但也可以使用replace选项表示能否重复抽取:

In [97]: s = pd.Series([0,1,2,3,4,5])

 # Without replacement (default):
In [98]: s.sample(n=6, replace=False)
Out[98]: 
0    0
1    1
5    5
3    3
2    2
4    4
dtype: int64

 # With replacement:
In [99]: s.sample(n=6, replace=True)
Out[99]: 
0    0
4    4
3    3
2    2
4    4
4    4
dtype: int64

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

In [100]: s = pd.Series([0,1,2,3,4,5])

In [101]: example_weights = [0, 0, 0.2, 0.2, 0.2, 0.4]

In [102]: s.sample(n=3, weights=example_weights)
Out[102]: 
5    5
4    4
3    3
dtype: int64

# Weights will be re-normalized automatically
In [103]: example_weights2 = [0.5, 0, 0, 0, 0, 0]

In [104]: s.sample(n=1, weights=example_weights2)
Out[104]: 
0    0
dtype: int64

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

In [105]: df2 = pd.DataFrame({'col1':[9,8,7,6], 'weight_column':[0.5, 0.4, 0.1, 0]})

In [106]: df2.sample(n = 3, weights = 'weight_column')
Out[106]: 
   col1  weight_column
1     8            0.4
0     9            0.5
2     7            0.1

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

In [107]: df3 = pd.DataFrame({'col1':[1,2,3], 'col2':[2,3,4]})

In [108]: df3.sample(n=1, axis=1)
Out[108]: 
   col1
0     1
1     2
2     3

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

In [109]: df4 = pd.DataFrame({'col1':[1,2,3], 'col2':[2,3,4]})

# With a given seed, the sample will always draw the same rows.
In [110]: df4.sample(n=2, random_state=2)
Out[110]: 
   col1  col2
2     3     4
1     2     3

In [111]: df4.sample(n=2, random_state=2)
Out[111]: 
   col1  col2
2     3     4
1     2     3

Setting With Enlargement

版本0.13中的新功能。

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

Series情况下,这实际上是一个附加操作

In [112]: se = pd.Series([1,2,3])

In [113]: se
Out[113]: 
0    1
1    2
2    3
dtype: int64

In [114]: se[5] = 5.

In [115]: se
Out[115]: 
0    1.0
1    2.0
2    3.0
5    5.0
dtype: float64

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

In [116]: dfi = pd.DataFrame(np.arange(6).reshape(3,2),
   .....:                 columns=['A','B'])
   .....: 

In [117]: dfi
Out[117]: 
   A  B
0  0  1
1  2  3
2  4  5

In [118]: dfi.loc[:,'C'] = dfi.loc[:,'A']

In [119]: dfi
Out[119]: 
   A  B  C
0  0  1  0
1  2  3  2
2  4  5  4

这类似于DataFrame上的append操作。

In [120]: dfi.loc[3] = 5

In [121]: dfi
Out[121]: 
   A  B  C
0  0  1  0
1  2  3  2
2  4  5  4
3  5  5  5

Fast scalar value getting and setting

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

Similarly to loc, at provides label based scalar lookups, while, iat provides integer based lookups analogously to iloc

In [122]: s.iat[5]
Out[122]: 5

In [123]: df.at[dates[5], 'A']
Out[123]: -0.67368970808837059

In [124]: df.iat[3, 0]
Out[124]: 0.72155516224436689

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

In [125]: df.at[dates[5], 'E'] = 7

In [126]: df.iat[3, 0] = 7

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

In [127]: df.at[dates[-1]+1, 0] = 7

In [128]: df
Out[128]: 
                   A         B         C         D    E    0
2000-01-01  0.469112 -0.282863 -1.509059 -1.135632  NaN  NaN
2000-01-02  1.212112 -0.173215  0.119209 -1.044236  NaN  NaN
2000-01-03 -0.861849 -2.104569 -0.494929  1.071804  NaN  NaN
2000-01-04  7.000000 -0.706771 -1.039575  0.271860  NaN  NaN
2000-01-05 -0.424972  0.567020  0.276232 -1.087401  NaN  NaN
2000-01-06 -0.673690  0.113648 -1.478427  0.524988  7.0  NaN
2000-01-07  0.404705  0.577046 -1.715002 -1.039268  NaN  NaN
2000-01-08 -0.370647 -1.157892 -1.344312  0.844885  NaN  NaN
2000-01-09       NaN       NaN       NaN       NaN  NaN  7.0

Boolean indexing

另一个常见的操作是使用布尔向量来过滤数据。The operators are: | for or, & for and, and ~ for not. 这些必须使用括号分组。

使用布尔向量索引一个系列的工作原理与numpy ndarray完全一样:

In [129]: s = pd.Series(range(-3, 4))

In [130]: s
Out[130]: 
0   -3
1   -2
2   -1
3    0
4    1
5    2
6    3
dtype: int64

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

In [132]: s[(s < -1) | (s > 0.5)]
Out[132]: 
0   -3
1   -2
4    1
5    2
6    3
dtype: int64

In [133]: s[~(s < 0)]
Out[133]: 
3    0
4    1
5    2
6    3
dtype: int64

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

In [134]: df[df['A'] > 0]
Out[134]: 
                   A         B         C         D   E   0
2000-01-01  0.469112 -0.282863 -1.509059 -1.135632 NaN NaN
2000-01-02  1.212112 -0.173215  0.119209 -1.044236 NaN NaN
2000-01-04  7.000000 -0.706771 -1.039575  0.271860 NaN NaN
2000-01-07  0.404705  0.577046 -1.715002 -1.039268 NaN NaN

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

In [135]: df2 = pd.DataFrame({'a' : ['one', 'one', 'two', 'three', 'two', 'one', 'six'],
   .....:                     'b' : ['x', 'y', 'y', 'x', 'y', 'x', 'x'],
   .....:                     'c' : np.random.randn(7)})
   .....: 

# only want 'two' or 'three'
In [136]: criterion = df2['a'].map(lambda x: x.startswith('t'))

In [137]: df2[criterion]
Out[137]: 
       a  b         c
2    two  y  0.041290
3  three  x  0.361719
4    two  y -0.238075

# equivalent but slower
In [138]: df2[[x.startswith('t') for x in df2['a']]]
Out[138]: 
       a  b         c
2    two  y  0.041290
3  three  x  0.361719
4    two  y -0.238075

# Multiple criteria
In [139]: df2[criterion & (df2['b'] == 'x')]
Out[139]: 
       a  b         c
3  three  x  0.361719

注意,选择方法Selection by LabelSelection by PositionAdvanced Indexing可以使用布尔向量组合选择多个轴与其他索引表达式。

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

Indexing with isin

考虑Series的isin方法,它返回一个布尔向量,它在传递列表中存在Series元素的地方。这允许您选择一个或多个列具有所需值的行:

In [141]: s = pd.Series(np.arange(5), index=np.arange(5)[::-1], dtype='int64')

In [142]: s
Out[142]: 
4    0
3    1
2    2
1    3
0    4
dtype: int64

In [143]: s.isin([2, 4, 6])
Out[143]: 
4    False
3    False
2     True
1    False
0     True
dtype: bool

In [144]: s[s.isin([2, 4, 6])]
Out[144]: 
2    2
0    4
dtype: int64

对于Index对象也可以使用相同的方法,并且当您不知道哪些查找的标签实际上存在时非常有用:

In [145]: s[s.index.isin([2, 4, 6])]
Out[145]: 
4    0
2    2
dtype: int64

# compare it to the following
In [146]: s[[2, 4, 6]]
Out[146]: 
2    2.0
4    0.0
6    NaN
dtype: float64

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

In [147]: s_mi = pd.Series(np.arange(6),
   .....:                  index=pd.MultiIndex.from_product([[0, 1], ['a', 'b', 'c']]))
   .....: 

In [148]: s_mi
Out[148]: 
0  a    0
   b    1
   c    2
1  a    3
   b    4
   c    5
dtype: int64

In [149]: s_mi.iloc[s_mi.index.isin([(1, 'a'), (2, 'b'), (0, 'c')])]
Out[149]: 
0  c    2
1  a    3
dtype: int64

In [150]: s_mi.iloc[s_mi.index.isin(['a', 'c', 'e'], level=1)]
Out[150]: 
0  a    0
   c    2
1  a    3
   c    5
dtype: int64

DataFrame也有一个isin方法。当调用isin时,传递一组值作为数组或dict。如果值是数组,则isin返回与原始DataFrame形状相同的布尔数据框架,如果元素位于值序列中,则返回True。

In [151]: df = pd.DataFrame({'vals': [1, 2, 3, 4], 'ids': ['a', 'b', 'f', 'n'],
   .....:                    'ids2': ['a', 'n', 'c', 'n']})
   .....: 

In [152]: values = ['a', 'b', 1, 3]

In [153]: df.isin(values)
Out[153]: 
     ids   ids2   vals
0   True   True   True
1   True  False  False
2  False  False   True
3  False  False  False

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

In [154]: values = {'ids': ['a', 'b'], 'vals': [1, 3]}

In [155]: df.isin(values)
Out[155]: 
     ids   ids2   vals
0   True  False   True
1   True  False  False
2  False  False   True
3  False  False  False

将DataFrame的isinany()all()组合,以快速选择满足给定条件的数据子集。要选择每个列满足其自己的条件的行:

In [156]: values = {'ids': ['a', 'b'], 'ids2': ['a', 'c'], 'vals': [1, 3]}

In [157]: row_mask = df.isin(values).all(1)

In [158]: df[row_mask]
Out[158]: 
  ids ids2  vals
0   a    a     1

The where() Method and Masking

使用布尔向量从系列中选择值通常返回数据的子集。为了确保选择输出具有与原始数据相同的形状,可以使用SeriesDataFrame中的where方法。

仅返回所选行

In [159]: s[s > 0]
Out[159]: 
3    1
2    2
1    3
0    4
dtype: int64

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

In [160]: s.where(s > 0)
Out[160]: 
4    NaN
3    1.0
2    2.0
1    3.0
0    4.0
dtype: float64

使用布尔标准从DataFrame中选择值现在也保留输入数据形状。where在引擎下用作实现。等价于df.其中(df 0)

In [161]: df[df < 0]
Out[161]: 
                   A         B         C         D
2000-01-01 -2.104139 -1.309525       NaN       NaN
2000-01-02 -0.352480       NaN -1.192319       NaN
2000-01-03 -0.864883       NaN -0.227870       NaN
2000-01-04       NaN -1.222082       NaN -1.233203
2000-01-05       NaN -0.605656 -1.169184       NaN
2000-01-06       NaN -0.948458       NaN -0.684718
2000-01-07 -2.670153 -0.114722       NaN -0.048048
2000-01-08       NaN       NaN -0.048788 -0.808838

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

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

您可能希望基于一些布尔值标准设置值。这可以直观地这样做:

In [163]: s2 = s.copy()

In [164]: s2[s2 < 0] = 0

In [165]: s2
Out[165]: 
4    0
3    1
2    2
1    3
0    4
dtype: int64

In [166]: df2 = df.copy()

In [167]: df2[df2 < 0] = 0

In [168]: df2
Out[168]: 
                   A         B         C         D
2000-01-01  0.000000  0.000000  0.485855  0.245166
2000-01-02  0.000000  0.390389  0.000000  1.655824
2000-01-03  0.000000  0.299674  0.000000  0.281059
2000-01-04  0.846958  0.000000  0.600705  0.000000
2000-01-05  0.669692  0.000000  0.000000  0.342416
2000-01-06  0.868584  0.000000  2.297780  0.000000
2000-01-07  0.000000  0.000000  0.168904  0.000000
2000-01-08  0.801196  1.392071  0.000000  0.000000

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

In [169]: df_orig = df.copy()

In [170]: df_orig.where(df > 0, -df, inplace=True);

In [171]: df_orig
Out[171]: 
                   A         B         C         D
2000-01-01  2.104139  1.309525  0.485855  0.245166
2000-01-02  0.352480  0.390389  1.192319  1.655824
2000-01-03  0.864883  0.299674  0.227870  0.281059
2000-01-04  0.846958  1.222082  0.600705  1.233203
2000-01-05  0.669692  0.605656  1.169184  0.342416
2000-01-06  0.868584  0.948458  2.297780  0.684718
2000-01-07  2.670153  0.114722  0.168904  0.048048
2000-01-08  0.801196  1.392071  0.048788  0.808838

注意

DataFrame.where()的签名与numpy.where()不同。Roughly df1.where(m, df2) is equivalent to np.where(m, df1, df2).

In [172]: df.where(df < 0, -df) == np.where(df < 0, df, -df)
Out[172]: 
               A     B     C     D
2000-01-01  True  True  True  True
2000-01-02  True  True  True  True
2000-01-03  True  True  True  True
2000-01-04  True  True  True  True
2000-01-05  True  True  True  True
2000-01-06  True  True  True  True
2000-01-07  True  True  True  True
2000-01-08  True  True  True  True

alignment

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

In [173]: df2 = df.copy()

In [174]: df2[ df2[1:4] > 0 ] = 3

In [175]: df2
Out[175]: 
                   A         B         C         D
2000-01-01 -2.104139 -1.309525  0.485855  0.245166
2000-01-02 -0.352480  3.000000 -1.192319  3.000000
2000-01-03 -0.864883  3.000000 -0.227870  3.000000
2000-01-04  3.000000 -1.222082  3.000000 -1.233203
2000-01-05  0.669692 -0.605656 -1.169184  0.342416
2000-01-06  0.868584 -0.948458  2.297780 -0.684718
2000-01-07 -2.670153 -0.114722  0.168904 -0.048048
2000-01-08  0.801196  1.392071 -0.048788 -0.808838

版本0.13中的新功能。

在执行where时,还可以接受axislevel参数来对齐输入。

In [176]: df2 = df.copy()

In [177]: df2.where(df2>0,df2['A'],axis='index')
Out[177]: 
                   A         B         C         D
2000-01-01 -2.104139 -2.104139  0.485855  0.245166
2000-01-02 -0.352480  0.390389 -0.352480  1.655824
2000-01-03 -0.864883  0.299674 -0.864883  0.281059
2000-01-04  0.846958  0.846958  0.600705  0.846958
2000-01-05  0.669692  0.669692  0.669692  0.342416
2000-01-06  0.868584  0.868584  2.297780  0.868584
2000-01-07 -2.670153 -2.670153  0.168904 -2.670153
2000-01-08  0.801196  1.392071  0.801196  0.801196

这是等价的(但比以下更快)。

In [178]: df2 = df.copy()

In [179]: df.apply(lambda x, y: x.where(x>0,y), y=df['A'])
Out[179]: 
                   A         B         C         D
2000-01-01 -2.104139 -2.104139  0.485855  0.245166
2000-01-02 -0.352480  0.390389 -0.352480  1.655824
2000-01-03 -0.864883  0.299674 -0.864883  0.281059
2000-01-04  0.846958  0.846958  0.600705  0.846958
2000-01-05  0.669692  0.669692  0.669692  0.342416
2000-01-06  0.868584  0.868584  2.297780  0.868584
2000-01-07 -2.670153 -2.670153  0.168904 -2.670153
2000-01-08  0.801196  1.392071  0.801196  0.801196

版本0.18.1中的新功能。

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

In [180]: df3 = pd.DataFrame({'A': [1, 2, 3],
   .....:                     'B': [4, 5, 6],
   .....:                     'C': [7, 8, 9]})
   .....: 

In [181]: df3.where(lambda x: x > 4, lambda x: x + 10)
Out[181]: 
    A   B  C
0  11  14  7
1  12   5  8
2  13   6  9

掩码

maskwhere

In [182]: s.mask(s >= 0)
Out[182]: 
4   NaN
3   NaN
2   NaN
1   NaN
0   NaN
dtype: float64

In [183]: df.mask(df >= 0)
Out[183]: 
                   A         B         C         D
2000-01-01 -2.104139 -1.309525       NaN       NaN
2000-01-02 -0.352480       NaN -1.192319       NaN
2000-01-03 -0.864883       NaN -0.227870       NaN
2000-01-04       NaN -1.222082       NaN -1.233203
2000-01-05       NaN -0.605656 -1.169184       NaN
2000-01-06       NaN -0.948458       NaN -0.684718
2000-01-07 -2.670153 -0.114722       NaN -0.048048
2000-01-08       NaN       NaN -0.048788 -0.808838

The query() Method (Experimental)

版本0.13中的新功能。

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

您可以获取列b在列ac之间的值的帧的值。例如:

In [184]: n = 10

In [185]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))

In [186]: df
Out[186]: 
          a         b         c
0  0.438921  0.118680  0.863670
1  0.138138  0.577363  0.686602
2  0.595307  0.564592  0.520630
3  0.913052  0.926075  0.616184
4  0.078718  0.854477  0.898725
5  0.076404  0.523211  0.591538
6  0.792342  0.216974  0.564056
7  0.397890  0.454131  0.915716
8  0.074315  0.437913  0.019794
9  0.559209  0.502065  0.026437

# pure python
In [187]: df[(df.a < df.b) & (df.b < df.c)]
Out[187]: 
          a         b         c
1  0.138138  0.577363  0.686602
4  0.078718  0.854477  0.898725
5  0.076404  0.523211  0.591538
7  0.397890  0.454131  0.915716

# query
In [188]: df.query('(a < b) & (b < c)')
Out[188]: 
          a         b         c
1  0.138138  0.577363  0.686602
4  0.078718  0.854477  0.898725
5  0.076404  0.523211  0.591538
7  0.397890  0.454131  0.915716

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

In [189]: df = pd.DataFrame(np.random.randint(n / 2, size=(n, 2)), columns=list('bc'))

In [190]: df.index.name = 'a'

In [191]: df
Out[191]: 
   b  c
a      
0  0  4
1  0  1
2  3  4
3  4  3
4  1  4
5  0  3
6  0  1
7  3  4
8  2  3
9  1  1

In [192]: df.query('a < b and b < c')
Out[192]: 
   b  c
a      
2  3  4

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

In [193]: df = pd.DataFrame(np.random.randint(n, size=(n, 2)), columns=list('bc'))

In [194]: df
Out[194]: 
   b  c
0  3  1
1  3  0
2  5  6
3  5  2
4  7  4
5  0  1
6  2  5
7  0  1
8  6  0
9  7  9

In [195]: df.query('index < b < c')
Out[195]: 
   b  c
2  5  6

注意

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

In [196]: df = pd.DataFrame({'a': np.random.randint(5, size=5)})

In [197]: df.index.name = 'a'

In [198]: df.query('a > 2') # uses the column 'a', not the index
Out[198]: 
   a
a   
1  3
3  3

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

In [199]: df.query('index > 2')
Out[199]: 
   a
a   
3  3
4  2

如果由于某种原因你有一个名为index的列,那么你也可以将索引称为ilevel_0,但在这一点上你应该考虑将列重命名为暧昧。

MultiIndex query() Syntax

您还可以使用DataFrameMultiIndex的级别,如同它们是框架中的列:

In [200]: n = 10

In [201]: colors = np.random.choice(['red', 'green'], size=n)

In [202]: foods = np.random.choice(['eggs', 'ham'], size=n)

In [203]: colors
Out[203]: 
array(['red', 'red', 'red', 'green', 'green', 'green', 'green', 'green',
       'green', 'green'], 
      dtype='|S5')

In [204]: foods
Out[204]: 
array(['ham', 'ham', 'eggs', 'eggs', 'eggs', 'ham', 'ham', 'eggs', 'eggs',
       'eggs'], 
      dtype='|S4')

In [205]: index = pd.MultiIndex.from_arrays([colors, foods], names=['color', 'food'])

In [206]: df = pd.DataFrame(np.random.randn(n, 2), index=index)

In [207]: df
Out[207]: 
                   0         1
color food                    
red   ham   0.194889 -0.381994
      ham   0.318587  2.089075
      eggs -0.728293 -0.090255
green eggs -0.748199  1.318931
      eggs -2.029766  0.792652
      ham   0.461007 -0.542749
      ham  -0.305384 -0.479195
      eggs  0.095031 -0.270099
      eggs -0.707140 -0.773882
      eggs  0.229453  0.304418

In [208]: df.query('color == "red"')
Out[208]: 
                   0         1
color food                    
red   ham   0.194889 -0.381994
      ham   0.318587  2.089075
      eggs -0.728293 -0.090255

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

In [209]: df.index.names = [None, None]

In [210]: df
Out[210]: 
                   0         1
red   ham   0.194889 -0.381994
      ham   0.318587  2.089075
      eggs -0.728293 -0.090255
green eggs -0.748199  1.318931
      eggs -2.029766  0.792652
      ham   0.461007 -0.542749
      ham  -0.305384 -0.479195
      eggs  0.095031 -0.270099
      eggs -0.707140 -0.773882
      eggs  0.229453  0.304418

In [211]: df.query('ilevel_0 == "red"')
Out[211]: 
                 0         1
red ham   0.194889 -0.381994
    ham   0.318587  2.089075
    eggs -0.728293 -0.090255

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

query() Use Cases

query()的用例是当您拥有一个具有共同的列名(或索引级别/名称)子集的DataFrame对象的集合时。您可以向两个框架传递相同的查询,而不必指定您感兴趣的框架

In [212]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))

In [213]: df
Out[213]: 
          a         b         c
0  0.224283  0.736107  0.139168
1  0.302827  0.657803  0.713897
2  0.611185  0.136624  0.984960
3  0.195246  0.123436  0.627712
4  0.618673  0.371660  0.047902
5  0.480088  0.062993  0.185760
6  0.568018  0.483467  0.445289
7  0.309040  0.274580  0.587101
8  0.258993  0.477769  0.370255
9  0.550459  0.840870  0.304611

In [214]: df2 = pd.DataFrame(np.random.rand(n + 2, 3), columns=df.columns)

In [215]: df2
Out[215]: 
           a         b         c
0   0.357579  0.229800  0.596001
1   0.309059  0.957923  0.965663
2   0.123102  0.336914  0.318616
3   0.526506  0.323321  0.860813
4   0.518736  0.486514  0.384724
5   0.190804  0.505723  0.614533
6   0.891939  0.623977  0.676639
7   0.480559  0.378528  0.460858
8   0.420223  0.136404  0.141295
9   0.732206  0.419540  0.604675
10  0.604466  0.848974  0.896165
11  0.589168  0.920046  0.732716

In [216]: expr = '0.0 <= a <= c <= 0.5'

In [217]: map(lambda frame: frame.query(expr), [df, df2])
Out[217]: 
[          a         b         c
 8  0.258993  0.477769  0.370255,           a         b         c
 2  0.123102  0.336914  0.318616]

query() Python versus pandas Syntax Comparison

类似numpy的语法

In [218]: df = pd.DataFrame(np.random.randint(n, size=(n, 3)), columns=list('abc'))

In [219]: df
Out[219]: 
   a  b  c
0  7  8  9
1  1  0  7
2  2  7  2
3  6  2  2
4  2  6  3
5  3  8  2
6  1  7  2
7  5  1  5
8  9  8  0
9  1  5  0

In [220]: df.query('(a < b) & (b < c)')
Out[220]: 
   a  b  c
0  7  8  9

In [221]: df[(df.a < df.b) & (df.b < df.c)]
Out[221]: 
   a  b  c
0  7  8  9

通过删除括号略微更好一些(通过绑定使比较运算符绑定比& / |更紧密)

In [222]: df.query('a < b & b < c')
Out[222]: 
   a  b  c
0  7  8  9

使用英语而不是符号

In [223]: df.query('a < b and b < c')
Out[223]: 
   a  b  c
0  7  8  9

很接近你怎么可能写在纸上

In [224]: df.query('a < b < c')
Out[224]: 
   a  b  c
0  7  8  9

The in and not in operators

query() also supports special use of Python’s in and not in comparison operators, providing a succinct syntax for calling the isin method of a Series or DataFrame.

# get all rows where columns "a" and "b" have overlapping values
In [225]: df = pd.DataFrame({'a': list('aabbccddeeff'), 'b': list('aaaabbbbcccc'),
   .....:                    'c': np.random.randint(5, size=12),
   .....:                    'd': np.random.randint(9, size=12)})
   .....: 

In [226]: df
Out[226]: 
    a  b  c  d
0   a  a  2  6
1   a  a  4  7
2   b  a  1  6
3   b  a  2  1
4   c  b  3  6
5   c  b  0  2
6   d  b  3  3
7   d  b  2  1
8   e  c  4  3
9   e  c  2  0
10  f  c  0  6
11  f  c  1  2

In [227]: df.query('a in b')
Out[227]: 
   a  b  c  d
0  a  a  2  6
1  a  a  4  7
2  b  a  1  6
3  b  a  2  1
4  c  b  3  6
5  c  b  0  2

# How you'd do it in pure Python
In [228]: df[df.a.isin(df.b)]
Out[228]: 
   a  b  c  d
0  a  a  2  6
1  a  a  4  7
2  b  a  1  6
3  b  a  2  1
4  c  b  3  6
5  c  b  0  2

In [229]: df.query('a not in b')
Out[229]: 
    a  b  c  d
6   d  b  3  3
7   d  b  2  1
8   e  c  4  3
9   e  c  2  0
10  f  c  0  6
11  f  c  1  2

# pure Python
In [230]: df[~df.a.isin(df.b)]
Out[230]: 
    a  b  c  d
6   d  b  3  3
7   d  b  2  1
8   e  c  4  3
9   e  c  2  0
10  f  c  0  6
11  f  c  1  2

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

# rows where cols a and b have overlapping values and col c's values are less than col d's
In [231]: df.query('a in b and c < d')
Out[231]: 
   a  b  c  d
0  a  a  2  6
1  a  a  4  7
2  b  a  1  6
4  c  b  3  6
5  c  b  0  2

# pure Python
In [232]: df[df.b.isin(df.a) & (df.c < df.d)]
Out[232]: 
    a  b  c  d
0   a  a  2  6
1   a  a  4  7
2   b  a  1  6
4   c  b  3  6
5   c  b  0  2
10  f  c  0  6
11  f  c  1  2

注意

Note that in and not in are evaluated in Python, since numexpr has no equivalent of this operation. However, only the in/not in expression itself is evaluated in vanilla Python. 例如,在表达式中

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

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

Special use of the == operator with list objects

使用== / !=listin / 不是

In [233]: df.query('b == ["a", "b", "c"]')
Out[233]: 
    a  b  c  d
0   a  a  2  6
1   a  a  4  7
2   b  a  1  6
3   b  a  2  1
4   c  b  3  6
5   c  b  0  2
6   d  b  3  3
7   d  b  2  1
8   e  c  4  3
9   e  c  2  0
10  f  c  0  6
11  f  c  1  2

# pure Python
In [234]: df[df.b.isin(["a", "b", "c"])]
Out[234]: 
    a  b  c  d
0   a  a  2  6
1   a  a  4  7
2   b  a  1  6
3   b  a  2  1
4   c  b  3  6
5   c  b  0  2
6   d  b  3  3
7   d  b  2  1
8   e  c  4  3
9   e  c  2  0
10  f  c  0  6
11  f  c  1  2

In [235]: df.query('c == [1, 2]')
Out[235]: 
    a  b  c  d
0   a  a  2  6
2   b  a  1  6
3   b  a  2  1
7   d  b  2  1
9   e  c  2  0
11  f  c  1  2

In [236]: df.query('c != [1, 2]')
Out[236]: 
    a  b  c  d
1   a  a  4  7
4   c  b  3  6
5   c  b  0  2
6   d  b  3  3
8   e  c  4  3
10  f  c  0  6

# using in/not in
In [237]: df.query('[1, 2] in c')
Out[237]: 
    a  b  c  d
0   a  a  2  6
2   b  a  1  6
3   b  a  2  1
7   d  b  2  1
9   e  c  2  0
11  f  c  1  2

In [238]: df.query('[1, 2] not in c')
Out[238]: 
    a  b  c  d
1   a  a  4  7
4   c  b  3  6
5   c  b  0  2
6   d  b  3  3
8   e  c  4  3
10  f  c  0  6

# pure Python
In [239]: df[df.c.isin([1, 2])]
Out[239]: 
    a  b  c  d
0   a  a  2  6
2   b  a  1  6
3   b  a  2  1
7   d  b  2  1
9   e  c  2  0
11  f  c  1  2

Boolean Operators

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

In [240]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))

In [241]: df['bools'] = np.random.rand(len(df)) > 0.5

In [242]: df.query('~bools')
Out[242]: 
          a         b         c  bools
2  0.697753  0.212799  0.329209  False
7  0.275396  0.691034  0.826619  False
8  0.190649  0.558748  0.262467  False

In [243]: df.query('not bools')
Out[243]: 
          a         b         c  bools
2  0.697753  0.212799  0.329209  False
7  0.275396  0.691034  0.826619  False
8  0.190649  0.558748  0.262467  False

In [244]: df.query('not bools') == df[~df.bools]
Out[244]: 
      a     b     c bools
2  True  True  True  True
7  True  True  True  True
8  True  True  True  True

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

# short query syntax
In [245]: shorter = df.query('a < b < c and (not bools) or bools > 2')

# equivalent in pure Python
In [246]: longer = df[(df.a < df.b) & (df.b < df.c) & (~df.bools) | (df.bools > 2)]

In [247]: shorter
Out[247]: 
          a         b         c  bools
7  0.275396  0.691034  0.826619  False

In [248]: longer
Out[248]: 
          a         b         c  bools
7  0.275396  0.691034  0.826619  False

In [249]: shorter == longer
Out[249]: 
      a     b     c bools
7  True  True  True  True

Performance of query()

对于大数据,DataFrame.query()使用numexpr稍快于Python

http://pandas.pydata.org/pandas-docs/version/0.19.2/_images/query-perf.png

注意

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

http://pandas.pydata.org/pandas-docs/version/0.19.2/_images/query-perf-small.png

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

Duplicate Data

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

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

In [250]: df2 = pd.DataFrame({'a': ['one', 'one', 'two', 'two', 'two', 'three', 'four'],
   .....:                     'b': ['x', 'y', 'x', 'y', 'x', 'x', 'x'],
   .....:                     'c': np.random.randn(7)})
   .....: 

In [251]: df2
Out[251]: 
       a  b         c
0    one  x -1.067137
1    one  y  0.309500
2    two  x -0.211056
3    two  y -1.842023
4    two  x -0.390820
5  three  x -1.964475
6   four  x  1.298329

In [252]: df2.duplicated('a')
Out[252]: 
0    False
1     True
2    False
3     True
4     True
5    False
6    False
dtype: bool

In [253]: df2.duplicated('a', keep='last')
Out[253]: 
0     True
1    False
2     True
3     True
4    False
5    False
6    False
dtype: bool

In [254]: df2.duplicated('a', keep=False)
Out[254]: 
0     True
1     True
2     True
3     True
4     True
5    False
6    False
dtype: bool

In [255]: df2.drop_duplicates('a')
Out[255]: 
       a  b         c
0    one  x -1.067137
2    two  x -0.211056
5  three  x -1.964475
6   four  x  1.298329

In [256]: df2.drop_duplicates('a', keep='last')
Out[256]: 
       a  b         c
1    one  y  0.309500
4    two  x -0.390820
5  three  x -1.964475
6   four  x  1.298329

In [257]: df2.drop_duplicates('a', keep=False)
Out[257]: 
       a  b         c
5  three  x -1.964475
6   four  x  1.298329

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

In [258]: df2.duplicated(['a', 'b'])
Out[258]: 
0    False
1    False
2    False
3    False
4     True
5    False
6    False
dtype: bool

In [259]: df2.drop_duplicates(['a', 'b'])
Out[259]: 
       a  b         c
0    one  x -1.067137
1    one  y  0.309500
2    two  x -0.211056
3    two  y -1.842023
5  three  x -1.964475
6   four  x  1.298329

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

In [260]: df3 = pd.DataFrame({'a': np.arange(6),
   .....:                     'b': np.random.randn(6)},
   .....:                    index=['a', 'a', 'b', 'c', 'b', 'a'])
   .....: 

In [261]: df3
Out[261]: 
   a         b
a  0  1.440455
a  1  2.456086
b  2  1.038402
c  3 -0.894409
b  4  0.683536
a  5  3.082764

In [262]: df3.index.duplicated()
Out[262]: array([False,  True, False, False,  True,  True], dtype=bool)

In [263]: df3[~df3.index.duplicated()]
Out[263]: 
   a         b
a  0  1.440455
b  2  1.038402
c  3 -0.894409

In [264]: df3[~df3.index.duplicated(keep='last')]
Out[264]: 
   a         b
c  3 -0.894409
b  4  0.683536
a  5  3.082764

In [265]: df3[~df3.index.duplicated(keep=False)]
Out[265]: 
   a         b
c  3 -0.894409

Dictionary-like get() method

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

In [266]: s = pd.Series([1,2,3], index=['a','b','c'])

In [267]: s.get('a')               # equivalent to s['a']
Out[267]: 1

In [268]: s.get('x', default=-1)
Out[268]: -1

The select() Method

从对象中提取切片的另一种方法是使用Series,DataFrame和Panel的select方法。这个方法应该只在没有更多的直接方式时使用。select采用对axis的标签进行操作的函数,并返回布尔值。例如:

In [269]: df.select(lambda x: x == 'A', axis=1)
Out[269]: 
                   A
2000-01-01  0.355794
2000-01-02  1.635763
2000-01-03  0.854409
2000-01-04 -0.216659
2000-01-05  2.414688
2000-01-06 -1.206215
2000-01-07  0.779461
2000-01-08 -0.878999

The lookup() Method

有时,您希望提取一组给定一系列行标签和列标签的值,而lookup方法允许此操作并返回numpy数组。例如,

In [270]: dflookup = pd.DataFrame(np.random.rand(20,4), columns = ['A','B','C','D'])

In [271]: dflookup.lookup(list(range(0,10,2)), ['B','C','A','B','D'])
Out[271]: array([ 0.3506,  0.4779,  0.4825,  0.9197,  0.5019])

Index objects

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

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

In [272]: index = pd.Index(['e', 'd', 'a', 'b'])

In [273]: index
Out[273]: Index([u'e', u'd', u'a', u'b'], dtype='object')

In [274]: 'd' in index
Out[274]: True

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

In [275]: index = pd.Index(['e', 'd', 'a', 'b'], name='something')

In [276]: index.name
Out[276]: 'something'

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

In [277]: index = pd.Index(list(range(5)), name='rows')

In [278]: columns = pd.Index(['A', 'B', 'C'], name='cols')

In [279]: df = pd.DataFrame(np.random.randn(5, 3), index=index, columns=columns)

In [280]: df
Out[280]: 
cols         A         B         C
rows                              
0     1.295989  0.185778  0.436259
1     0.678101  0.311369 -0.528378
2    -0.674808 -1.103529 -0.656157
3     1.889957  2.076651 -1.102192
4    -1.211795 -0.791746  0.634724

In [281]: df['A']
Out[281]: 
rows
0    1.295989
1    0.678101
2   -0.674808
3    1.889957
4   -1.211795
Name: A, dtype: float64

Setting metadata

版本0.13.0中的新功能。

Indexes are “mostly immutable”, but it is possible to set and change their metadata, like the index name (or, for MultiIndex, levels and labels).

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

有关MultiIndexes的用法,请参见Advanced Indexing

In [282]: ind = pd.Index([1, 2, 3])

In [283]: ind.rename("apple")
Out[283]: Int64Index([1, 2, 3], dtype='int64', name=u'apple')

In [284]: ind
Out[284]: Int64Index([1, 2, 3], dtype='int64')

In [285]: ind.set_names(["apple"], inplace=True)

In [286]: ind.name = "bob"

In [287]: ind
Out[287]: Int64Index([1, 2, 3], dtype='int64', name=u'bob')

版本0.15.0中的新功能。

set_namesset_levelsset_labels也采用可选的级别参数

In [288]: index = pd.MultiIndex.from_product([range(3), ['one', 'two']], names=['first', 'second'])

In [289]: index
Out[289]: 
MultiIndex(levels=[[0, 1, 2], [u'one', u'two']],
           labels=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]],
           names=[u'first', u'second'])

In [290]: index.levels[1]
Out[290]: Index([u'one', u'two'], dtype='object', name=u'second')

In [291]: index.set_levels(["a", "b"], level=1)
Out[291]: 
MultiIndex(levels=[[0, 1, 2], [u'a', u'b']],
           labels=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]],
           names=[u'first', u'second'])

Set operations on Index objects

警告

在0.15.0. 不建议使用set操作+-,以便为某些索引类型的数字类型操作提供这些操作。+ can be replace by .union() or |, and - by .difference().

两个主要操作是联合 (|)交集 (&amp; / t5>这些可以直接调用为实例方法或通过重载运算符使用。差异通过.difference()方法提供。

In [292]: a = pd.Index(['c', 'b', 'a'])

In [293]: b = pd.Index(['c', 'e', 'd'])

In [294]: a | b
Out[294]: Index([u'a', u'b', u'c', u'd', u'e'], dtype='object')

In [295]: a & b
Out[295]: Index([u'c'], dtype='object')

In [296]: a.difference(b)
Out[296]: Index([u'a', u'b'], dtype='object')

还可以使用symmetric_difference (^)操作,返回出现在idx1idx2,但不能同时包含两者。这相当于由idx1.difference(idx2).union(idx2.difference(idx1))创建的索引,重复项被删除。

In [297]: idx1 = pd.Index([1, 2, 3, 4])

In [298]: idx2 = pd.Index([2, 3, 4, 5])

In [299]: idx1.symmetric_difference(idx2)
Out[299]: Int64Index([1, 5], dtype='int64')

In [300]: idx1 ^ idx2
Out[300]: Int64Index([1, 5], dtype='int64')

Missing values

版本0.17.1中的新功能。

重要

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

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

In [301]: idx1 = pd.Index([1, np.nan, 3, 4])

In [302]: idx1
Out[302]: Float64Index([1.0, nan, 3.0, 4.0], dtype='float64')

In [303]: idx1.fillna(2)
Out[303]: Float64Index([1.0, 2.0, 3.0, 4.0], dtype='float64')

In [304]: idx2 = pd.DatetimeIndex([pd.Timestamp('2011-01-01'), pd.NaT, pd.Timestamp('2011-01-03')])

In [305]: idx2
Out[305]: DatetimeIndex(['2011-01-01', 'NaT', '2011-01-03'], dtype='datetime64[ns]', freq=None)

In [306]: idx2.fillna(pd.Timestamp('2011-01-02'))
Out[306]: DatetimeIndex(['2011-01-01', '2011-01-02', '2011-01-03'], dtype='datetime64[ns]', freq=None)

Set / Reset Index

有时,您将在DataFrame中加载或创建数据集,并且希望在已经这样做之后添加索引。有两种不同的方法。

Set an index

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

In [307]: data
Out[307]: 
     a    b  c    d
0  bar  one  z  1.0
1  bar  two  y  2.0
2  foo  one  x  3.0
3  foo  two  w  4.0

In [308]: indexed1 = data.set_index('c')

In [309]: indexed1
Out[309]: 
     a    b    d
c               
z  bar  one  1.0
y  bar  two  2.0
x  foo  one  3.0
w  foo  two  4.0

In [310]: indexed2 = data.set_index(['a', 'b'])

In [311]: indexed2
Out[311]: 
         c    d
a   b          
bar one  z  1.0
    two  y  2.0
foo one  x  3.0
    two  w  4.0

append关键字选项允许您保留现有索引并将给定列附加到MultiIndex:

In [312]: frame = data.set_index('c', drop=False)

In [313]: frame = frame.set_index(['a', 'b'], append=True)

In [314]: frame
Out[314]: 
           c    d
c a   b          
z bar one  z  1.0
y bar two  y  2.0
x foo one  x  3.0
w foo two  w  4.0

set_index中的其他选项允许您不删除索引列或在现场添加索引(不创建新对象):

In [315]: data.set_index('c', drop=False)
Out[315]: 
     a    b  c    d
c                  
z  bar  one  z  1.0
y  bar  two  y  2.0
x  foo  one  x  3.0
w  foo  two  w  4.0

In [316]: data.set_index(['a', 'b'], inplace=True)

In [317]: data
Out[317]: 
         c    d
a   b          
bar one  z  1.0
    two  y  2.0
foo one  x  3.0
    two  w  4.0

Reset the index

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

In [318]: data
Out[318]: 
         c    d
a   b          
bar one  z  1.0
    two  y  2.0
foo one  x  3.0
    two  w  4.0

In [319]: data.reset_index()
Out[319]: 
     a    b  c    d
0  bar  one  z  1.0
1  bar  two  y  2.0
2  foo  one  x  3.0
3  foo  two  w  4.0

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

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

In [320]: frame
Out[320]: 
           c    d
c a   b          
z bar one  z  1.0
y bar two  y  2.0
x foo one  x  3.0
w foo two  w  4.0

In [321]: frame.reset_index(level=1)
Out[321]: 
         a  c    d
c b               
z one  bar  z  1.0
y two  bar  y  2.0
x one  foo  x  3.0
w two  foo  w  4.0

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

注意

reset_index方法以前称为delevel,现在已被弃用。

Adding an ad hoc index

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

data.index = index

Returning a view versus a copy

在pandas对象中设置值时,必须注意避免使用链接 索引这里是一个例子。

In [322]: dfmi = pd.DataFrame([list('abcd'),
   .....:                      list('efgh'),
   .....:                      list('ijkl'),
   .....:                      list('mnop')],
   .....:                     columns=pd.MultiIndex.from_product([['one','two'],
   .....:                                                         ['first','second']]))
   .....: 

In [323]: dfmi
Out[323]: 
    one          two       
  first second first second
0     a      b     c      d
1     e      f     g      h
2     i      j     k      l
3     m      n     o      p

比较这两种访问方法:

In [324]: dfmi['one']['second']
Out[324]: 
0    b
1    f
2    j
3    n
Name: second, dtype: object
In [325]: dfmi.loc[:,('one','second')]
Out[325]: 
0    b
1    f
2    j
3    n
Name: (one, second), dtype: object

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

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

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

Why does assignment fail when using chained indexing?

上一节中的问题只是一个性能问题。什么是SettingWithCopy警告?我们不会通常在您执行可能需要花费更多毫秒的操作时抛出警告!

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

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

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

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

看到__getitem__在那里?Outside of simple cases, it’s very hard to predict whether it will return a view or a copy (it depends on the memory layout of the array, about which pandas makes no guarantees), and therefore whether the __setitem__ will modify dfmi or a temporary object that gets thrown out immediately afterward. 这是什么SettingWithCopy警告你!

注意

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

有时,当没有明显的链接索引时,会出现SettingWithCopy警告。这些SettingWithCopy旨在捕获的错误!熊猫可能试图警告你,你这样做:

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

Yikes!

Evaluation order matters

此外,在链接表达式中,顺序可以确定是否返回副本。如果一个表达式在一个slice的副本上设置值,那么会出现一个SettingWithCopy异常(这个从0.13.0开始的raise / warn行为是新的)

您可以通过选项mode.chained_assignment控制链接分配的操作,该选项可以取值['raise','warn',None] warning是默认值。

In [326]: dfb = pd.DataFrame({'a' : ['one', 'one', 'two',
   .....:                            'three', 'two', 'one', 'six'],
   .....:                     'c' : np.arange(7)})
   .....: 

# This will show the SettingWithCopyWarning
# but the frame values will be set
In [327]: dfb['c'][dfb.a.str.startswith('o')] = 42

然而,这是操作一个副本,将不工作。

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

链接分配也可以在混合dtype帧中的设置中向上裁剪。

注意

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

这是正确的访问方法

In [328]: dfc = pd.DataFrame({'A':['aaa','bbb','ccc'],'B':[1,2,3]})

In [329]: dfc.loc[0,'A'] = 11

In [330]: dfc
Out[330]: 
     A  B
0   11  1
1  bbb  2
2  ccc  3

可以有时工作,但不能保证,因此应该避免

In [331]: dfc = dfc.copy()

In [332]: dfc['A'][0] = 111

In [333]: dfc
Out[333]: 
     A  B
0  111  1
1  bbb  2
2  ccc  3

这将不是工作,所以应该避免

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

警告

链接的分配警告/异常旨在通知用户可能无效的分配。可能有假阳性;无意中报告了链式分配的情况。