Python:Pandas系列-为什么使用loc?


71

为什么我们对熊猫数据框使用“ loc”?似乎以下代码无论是否使用loc都以模拟速度运行

%timeit df_user1 = df.loc[df.user_id=='5561']

100 loops, best of 3: 11.9 ms per loop

要么

%timeit df_user1_noloc = df[df.user_id=='5561']

100 loops, best of 3: 12 ms per loop

那为什么要使用loc?

编辑:这已被标记为重复问题。但是,尽管熊猫iloc vs ix vs loc的解释?确实提到*

您可以只使用数据框的getitem进行列检索 :

*

df['time']    # equivalent to df.loc[:, 'time']

尽管它确实解释了loc的许多功能,但它并没有说明我们为什么使用loc,但我的特定问题是“为什么不完全省略loc”?为此,我在下面接受了非常详细的答案。

另外,其他帖子的答案(我认为不是答案)在讨论中非常隐蔽,任何搜索我正在寻找的人的人都会发现很难找到信息,并且提供的答案会更好地为您服务我的问题。



4
@JGreenwell-并非如此,他们正在讨论.loc,.iloc和.ix之间的区别,但在这里我只是在问为什么完全使用.loc,而不是为什么要在.iloc或.ix上使用它,我对iloc不感兴趣或ix,我试图首先了解loc以及我们为什么使用它,而不是仅仅忽略它。
Runner Bean

请参见ajcr答案的结尾,其中包括对.locand和.ilocvs的一般用法.ix:或相对部分:“如果仅使用标签建立索引,或仅使用整数位置建立索引,请使用loc或iloc以避免意外结果。”
LinkBerest

1
本质上,当您不指定索引技术时,会有熊猫的后援和最佳猜测。因此,它贯穿了每个人。在DataFrame上,默认设置是.loc在列上使用。在Series上,默认设置是.loc在行上使用,因为没有列。
卡蒂克

4
JGreenwell和Kartik-我不明白。我不是,我重复一遍,我对与.iloc无关的任何内容都不感兴趣,只是假装.iloc不存在,而假装.ix不存在。我只是想知道为什么我应该使用.loc而不是像问题代码中那样将其全部遗漏。
Runner Bean

Answers:


73
  • 显式胜于隐式。

    df[boolean_mask]选择行为boolean_maskTrue的行,但在某些情况下可能不希望出现以下情况:当df具有布尔值的列标签时:

    In [229]: df = pd.DataFrame({True:[1,2,3],False:[3,4,5]}); df
    Out[229]: 
       False  True 
    0      3      1
    1      4      2
    2      5      3
    

    您可能要使用df[[True]]选择True列。相反,它引发一个ValueError

    In [230]: df[[True]]
    ValueError: Item wrong length 1 instead of 3.
    

    与使用loc

    In [231]: df.loc[[True]]
    Out[231]: 
       False  True 
    0      3      1
    

    相反,ValueError即使的结构df2几乎与df1上述相同,也不会出现以下情况:

    In [258]: df2 = pd.DataFrame({'A':[1,2,3],'B':[3,4,5]}); df2
    Out[258]: 
       A  B
    0  1  3
    1  2  4
    2  3  5
    
    In [259]: df2[['B']]
    Out[259]: 
       B
    0  3
    1  4
    2  5
    

    因此,df[boolean_mask]并不总是与相同df.loc[boolean_mask]。即使这可以说是不太可能的用例,但我还是建议您始终使用df.loc[boolean_mask]而不是,df[boolean_mask]因为df.loc的语法含义很明确。随着df.loc[indexer]您自动知道,df.loc被选择行。相反,不清楚是否df[indexer]ValueError在不了解indexer和的细节的情况下选择行或列(或引发)df

  • df.loc[row_indexer, column_index]可以选择行列。df[indexer]只能根据中的值类型和列值的类型选择行列(再次,它们是布尔值吗?)。indexerdf

    In [237]: df2.loc[[True,False,True], 'B']
    Out[237]: 
    0    3
    2    5
    Name: B, dtype: int64
    
  • 将切片传递给df.loc端点时,端点将包含在范围内。将切片传递给时df[...],该切片将被解释为半开间隔:

    In [239]: df2.loc[1:2]
    Out[239]: 
       A  B
    1  2  4
    2  3  5
    
    In [271]: df2[1:2]
    Out[271]: 
       A  B
    1  2  4
    

4
您为什么不在列名周围使用引号?无法df[['True']]正常工作?
Lance E Sloan先生

df[['True']]在示例中,@ LS 似乎无法正常工作。列名不是字符串,它们是布尔对象。看起来熊猫不需要列名称为字符串(不同于R,其中name(df)为字符,[[]
强制

4
我要说的最后一点是最重要的,并将其推到最高点,实际上是完全不同的行为
kilgoretrout

2
切片的一个重要区别是loc [1:2]适用于索引,而df2 [1:2]适用于简单的行顺序,而与索引无关。这是在上面的最后一个例子,如果指数与[3,4],组委会[1:2]开始不会返回任何东西,而DF2 [1:2]将仍然指数3返回第一行
NeverStopLearning

0

除了已经说过的话(在不使用loc的情况下将列名设为True,False的问题,以及具有loc的能力来选择行和列的能力,以及能够对行和列的选择进行切片的问题),另一个很大的不同是您可以定位以将值分配给特定的行和列。如果尝试使用布尔序列选择数据框的子集并尝试更改该子集选择的值,则可能会收到SettingWithCopy警告。

假设您要更改所有薪水大于60000的行的“高级管理”列。

这个:

mask = df["salary"] > 60000
df[mask]["upper management"] = True

引发警告“正在尝试在数据框的切片副本上设置一个值”并且将不起作用,因为df [mask]创建了一个副本,并且尝试更新该副本的“高级管理”无效在原始df上。

但这成功了:

mask = df["salary"] > 60000
df.loc[mask,"upper management"] = True

请注意,在两种情况下都可以执行df[df["salary"] > 60000]df.loc[df["salary"] > 60000],但是我认为先将布尔条件存储在变量中会更干净。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.