Python 对DataFrame元素的访问速度惊人地慢

Python 对DataFrame元素的访问速度惊人地慢,python,pandas,Python,Pandas,考虑下面的例子 x={f“b{k}:10000*[None]表示范围(10)内的k} 对于x.keys()中的列: 对于范围(10000)内的i: x[列][i]=i%4#这里有一些小的计算 x=pd.DataFrame(x) 在我的电脑上大约60毫秒就完成了。类似的事情可以直接在熊猫的数据框上完成: x=pd.DataFrame(索引=范围(10000),列=[f“b{i}”表示范围(10)中的i),dtype=np.int32) 对于x.columns中的列: 对于范围(10000)内的i

考虑下面的例子

x={f“b{k}:10000*[None]表示范围(10)内的k}
对于x.keys()中的列:
对于范围(10000)内的i:
x[列][i]=i%4#这里有一些小的计算
x=pd.DataFrame(x)
在我的电脑上大约60毫秒就完成了。类似的事情可以直接在熊猫的数据框上完成:

x=pd.DataFrame(索引=范围(10000),列=[f“b{i}”表示范围(10)中的i),dtype=np.int32)
对于x.columns中的列:
对于范围(10000)内的i:
x、 loc[i,column]=i%4#这里有一些小的计算
这个片段大约在11.8秒后结束。这种操作是否可以直接在数据帧上执行而不会对性能造成重大影响

更新

使用
.at
而不是
.loc
可以显著提高性能,但与Python的dict相比仍然要慢得多

x = pd.DataFrame(index=range(10000), columns=[f"b{i}" for i in range(10)], dtype=np.int32)
for column in x.columns:
    for i in range(10000):
        x.at[i, column] = i % 4

这将在大约1.2秒内完成。

这是熊猫的预期。在pandas中执行这样的单个操作肯定会很慢,甚至要开始执行实际的“工作”,还需要几个Python层,例如几个Python级别的函数。这是我的建议

请注意,这是mixin的一部分,它已经可以减慢速度了。但更重要的是,它返回
\u AtIndexer
的一个实例,即

这时,您终于找到了一个
\uuu getitem\uuu
方法,但即便如此,还是要看看它需要做什么:

def __getitem__(self, key):

    if self.ndim == 2 and not self._axes_are_unique:
        # GH#33041 fall back to .loc
        if not isinstance(key, tuple) or not all(is_scalar(x) for x in key):
            raise ValueError("Invalid call for scalar access (getting)!")
        return self.obj.loc[key]

    return super().__getitem__(key)
所以它是Python级别的条件,但标准情况实际上只是

return super().__getitem__(key)
因此,另一个Python级别的函数调用。它有什么作用

所以更多的Python级条件,一些其他Python级方法调用

我们可以继续挖掘,看看
self.obj.\u get\u value
做了什么,这是在其他一些基类中实现的,但我认为您现在已经理解了这一点

在list/dict中,一旦通过了初始方法解析,就进入了C层,它在那里完成了所有的工作。在pandas中,在Python层中执行了大量的开销,在它被推到
numpy
之前,希望最终能够实现批量操作的速度。不过,它没有希望击败在内置python数据结构上完成的操作,而内置python数据结构是围绕编译代码的更薄的包装。pandas的性能因各种方法调用的上千次削减、Python内部簿记逻辑、


编辑:我注意到,我实际上经历了
\uuuuuGetItem\uuuuuuuuuu
逻辑,但要点仍然代表
\uuuuuuuSetItem\uuuuuuuuuu
,事实上,中间步骤似乎涉及更多的工作。

您是否尝试执行
x%4
?您可以在这里阅读coldspeed的答案,它的经验法则很好:数据帧上的循环通常很慢,如果可能,请使用矢量化函数。@Bharath
i%4
只是一个虚拟操作,以证明计算不是问题。链接似乎回答了计算价值本身的问题。此问题中的问题似乎与单个项目访问相关@广宏,这不是太慢了吗?
return super().__getitem__(key)
def __getitem__(self, key):
    if not isinstance(key, tuple):

        # we could have a convertible item here (e.g. Timestamp)
        if not is_list_like_indexer(key):
            key = (key,)
        else:
            raise ValueError("Invalid call for scalar access (getting)!")

    key = self._convert_key(key)
    return self.obj._get_value(*key, takeable=self._takeable)