使用Pandas对数据框进行索引:整数行,命名列。

110

假设 df 是一个 pandas 数据框。

  • df.loc[] 只接受名称。
  • df.iloc[] 只接受整数(实际位置)。
  • df.ix[] 同时接受名称和整数:

当引用行时,df.ix[row_idx, ] 只想得到名称。例如:

df = pd.DataFrame({'a' : ['one', 'two', 'three','four', 'five', 'six'],
                   '1' : np.arange(6)})
df = df.ix[2:6]
print(df)

   1      a
2  2  three
3  3   four
4  4   five
5  5    six

df.ix[0, 'a']

抛出错误,不会返回'two'。

在引用列时,iloc 更喜欢整数而非名称。例如:

df.ix[2, 1]

返回的是"three",而不是2(虽然df.idx[2, '1']确实返回了2)。

奇怪的是,我想要完全相反的功能。通常我的列名非常有意义,所以在我的代码中直接引用它们。但由于对观察数据进行了大量清理,我的Pandas数据框的行名称通常不对应于range(len(df))

我意识到我可以使用:

df.iloc[0].loc['a'] # returns three

但这看起来很丑!有没有人知道更好的方法来做到这一点,使得代码看起来像这样?

df.foo[0, 'a'] # returns three
事实上,我能否在pandas.core.frame.DataFrame中添加自己的新方法,例如df.idx(rows, cols)实际上是df.iloc[rows].loc[cols]吗?

21
你可以使用 df['a'].iloc[0] - unutbu
15
参见GH 9213, 建议使用df.loc[df.index[0], 'a']。这种方法的优点在于不使用链式索引,因此可以在进行赋值操作时正常工作,而df[['a','b']].iloc[0] = val则不行。 - unutbu
1
这里有一个非常好的答案,虽然不能真正解决你的问题,但对于Pandas中iloc、ix和loc的解释非常好:https://dev59.com/31wZ5IYBdhLWcg3wVO5U - JohnE
5
也可以反过来写:df.iloc[0, df.columns.get_loc("a")]。这行代码的意思是选取DataFrame中第一行和"a"列对应的元素。 - Landmaster
熊猫应该被设计成易于使用的,人们根本不应该再去谷歌这个问题。 - undefined
7个回答

79

虽然回答有些晚了,但是@unutbu的评论仍然有效,是解决这个问题的好方法。

若要使用整数行和命名列(标记列)索引DataFrame:

df.loc[df.index[#], 'NAME'] 其中#是有效的整数索引,NAME是列的名称。


1
在处理长数据框时似乎非常缓慢。 - ConanG
1
但它运行得非常出色。昨天我偶然发现了这个,它是我需要更新数据框副本的确切语法,通过索引和列名与原始数据框进行链接。 - horcle_buzz
7
该方法要求索引值唯一,否则将返回一个所有匹配索引值为“#”的Series。 - Yingbo Miao

47

我认为现有的答案对我来说是短视的。

问题解决方案

  1. df.loc[df.index[0], 'a']
    这里的策略是获取第0行的行标签,然后像平常一样使用 .loc。我看到了两个问题。

    1. 如果 df 有重复的行标签,则 df.loc[df.index[0], 'a'] 可能会返回多行。
    2. .loc.iloc 更慢,因此在这里你会牺牲速度。
  2. df.reset_index(drop=True).loc[0, 'a']
    这里的策略是重置索引,使行标签变为 0、1、2、...,因此 .loc[0].iloc[0] 得到相同的结果。但是,这里的问题是运行时间,因为 .loc.iloc 更慢,而且重置索引会产生成本。

更好的解决方案

我建议遵循 @Landmaster's comment 的建议:

df.iloc[0, df.columns.get_loc("a")]

基本上,这与df.iloc [0,0]相同,只是我们使用 df.columns.get_loc(“a”)动态地获取列索引。

要索引多个列,如 ['a','b','c'] ,请使用:

df.iloc[0, [df.columns.get_loc(c) for c in ['a', 'b', 'c']]]

更新

这是我在Pandas课程中讨论的一部分,具体内容可以参考此处


3
您的首选解决方案df.iloc[0, df.columns.get_loc("a")]并不能避免重复标签,因为列标签也可以是重复的。 因此,您不会获得任何好处,但它比df.loc[df.index[0],'a']更冗长和更慢。 对于单个值的访问,您都不应该使用它们。建议使用其他方式来实现。 - Darkonaut
@Darkonaut 重复列名比重复行标签发生的可能性要小得多。此外,除非df有数千列,否则df.iloc [0,df.columns.get_loc(“a”)]df.loc [df.index [0],“a”]在运行时几乎相同,但即使如此,差异也应该微不足道。 - Ben

14

虽然回答晚了,但令我惊讶的是,经过这么多年,pandas仍然没有这样的函数。如果这让你非常不爽,你可以将一个自定义索引器monkey-patch到DataFrame中:

class XLocIndexer:
    def __init__(self, frame):
        self.frame = frame
    
    def __getitem__(self, key):
        row, col = key
        return self.frame.iloc[row][col]

pd.core.indexing.IndexingMixin.xloc = property(lambda frame: XLocIndexer(frame))

# Usage
df.xloc[0, 'a'] # one

只能作为获取器,不适合作为设置器:TypeError: 'XLocIndexer' 对象不支持项目赋值。 - undefined

9

要通过行/列标签获取或设置DataFrame中的单个值,最好使用DataFrame.at而不是DataFrame.loc,因为它...

  1. 更快速
  2. 您更明确地想要访问单个值。

正如其他人已经展示的那样,如果您从行的整数位置开始,则仍然必须使用DataFrame.index找到行标签,因为DataFrame.at只接受标签:

df.at[df.index[0], 'a']
# Out: 'three'

基准测试:

%timeit df.at[df.index[0], 'a']
# 7.57 µs ± 30.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit df.loc[df.index[0], 'a']
# 10.9 µs ± 53.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit df.iloc[0, df.columns.get_loc("a")]
# 13.3 µs ± 24 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

为了完整性:

DataFrame.iat用于通过整数位置访问行/列对的单个值。


数据帧有多大?对于不仅是有序整数的索引,我假设 df.index 需要进行反向查找,这可能需要在 n 行上进行 O(n) 迭代。它如何处理重复项?iat 是否是所有解决方案中最快的,并且也是 O(1) - Mateen Ulhaq
@MateenUlhaq 必须是 OP 给出的示例中相同的 dfdf.index 是哈希的,因此是 O(1)。重复项不会被忽略,因此请始终确保在过滤重复项之前进行过滤。我不记得 iat 的时间,但通常位置查找并不总是一个选项。 - Darkonaut

6
我们可以重置索引,然后使用从0开始的索引,像这样:
df.reset_index(drop=True).loc[0,'a']
编辑:从列名索引'a'中删除[],以便只输出值。

这将不会返回有效的结果,因为索引中没有'0'。 - Hillary Sanders
现在明白问题了,谢谢!请看一下修改后的代码是否足够简洁... - Krishna
1
@KrishnaBandhakavi,但是如果你从“a”中删除[],它将返回更准确。=> df.reset_index().loc[0,'a'] - ipramusinto
这是唯一一个适用于在索引非唯一的情况下进行分配的答案。虽然,在这种情况下,您需要保留原始索引并在之后重新放置它。 - user2561747

0

-2

类似 df["a"][0] 这样的写法对我来说很有效。你可以试一下!


1
如果您能解释为什么这对您有效,以及为什么它将对作者有效,那么这将是一个更好的答案。 - flppv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接