Python Pandas.copy()空间/时间复杂性

Python Pandas.copy()空间/时间复杂性,python,pandas,Python,Pandas,我最近在Pandas中采用了一种新的编程风格,其中我有返回一系列的单责任函数 我发现这样做的好处是,对于大数据帧(100+列),我可以只获取执行计算所需的数据片段。感觉这样效率更高,但我不确定熊猫在引擎盖下是如何工作的 是否有人知道(a)这是否是推荐采用的风格,以及(b)这会对记忆/时间产生什么影响 例如: df = pd.DataFrame({'a': range(0, 10000), 'b': range(0, 10000),

我最近在Pandas中采用了一种新的编程风格,其中我有返回一系列的单责任函数

我发现这样做的好处是,对于大数据帧(100+列),我可以只获取执行计算所需的数据片段。感觉这样效率更高,但我不确定熊猫在引擎盖下是如何工作的

是否有人知道(a)这是否是推荐采用的风格,以及(b)这会对记忆/时间产生什么影响

例如:

df = pd.DataFrame({'a': range(0, 10000),
                   'b': range(0, 10000),
                   # etc
                   'z': range(0, 10000)})

def f(df):
    df = df[['a', 'b']].copy()
    df['New Column'] = df['a'] * df['b']
    return df['New Column'].astype(int)

df['New Column'] = f(df)

按你的方式做比较慢

我使用了以下数据帧

import string
df  = pd.DataFrame({key:range(0, 10000) for key in string.ascii_lowercase})
然后在Jupyter笔记本中,我使用%%timeit cell magic测试运行以下代码所需的时间:

%%timeit

def f(df):
    df = df[['a', 'b']].copy()
    df['New Column'] = df['a'] * df['b']
    return df['New Column'].astype(int)

df['New Column'] = f(df)
每个循环的时间为1.05 ms±20.3µs(平均±标准偏差为7次,每个循环1000次)

鉴于以下代码

%%timeit

df['New Column'] = df['a'] * df['b']
df['New Column'].astype(int)
只带走

%%timeit

df['New Column'] = df['a'] * df['b']
df['New Column'].astype(int)
每个回路340µs±2.46µs(7次运行的平均±标准偏差,每个1000个回路)

大约快3倍

当我们在第二段代码中添加副本时,这两段代码在功能上并不完全相同(第二段代码没有第一段代码的副本),如下所示:

%%timeit
df2 = df[['a','b']].copy()
df['New Column'] = df2['a'] * df2['b']
df['New Column'].astype(int) 
每个回路的运行速度为820µs±1.89µs(平均值±标准偏差为7次,每个回路1000次) 差异不大,但仍比您的方法快。 添加副本使计算时间增加了一倍多

那么,当我们将所用函数的定义移到计时之外时会发生什么情况:

我们首先运行这段代码:

import string
df  = pd.DataFrame({key:range(0, 10000) for key in string.ascii_lowercase})

def f(df):
    df = df[['a', 'b']].copy()
    df['New Column'] = df['a'] * df['b']
    return df['New Column'].astype(int) 
然后这段代码:

%%timeit

df['New Column'] = f(df)
每个回路的运行时间为1.03 ms±2.02µs(平均±标准偏差为7次,每个回路1000次)。仍然比不使用您的函数慢

注意:运行时取决于计算机的规格和运行的其他后台任务。里程可能会有所不同

这是我回答的客观事实部分

至于你的方法是否是首选的问题。我会说不

1) 在示例函数f中执行此操作的方式是非常硬编码的

您的函数f仅适用于a列和b列。如果你想在n列和m列上做呢?目前,您需要编写一个全新的函数来处理这些列。如果您想坚持使用这种通用方法,使代码更通用,那就更好了。TLDR不需要硬编码


2) 复制数据帧不会加快最终计算速度(但它确实需要额外的资源,导致额外的开销)。

我知道复制会影响性能,因为我在内存中复制数据帧。但是,我这样做是为了避免设置CopyWarning的问题。我不想改变dataframe的视图,但复制()可能会带来不必要的负担。就我个人而言,我更喜欢用这个公认的答案来解决CopyWarning的设置问题。总是使用copy(),因为有时您可能会使用copyWarning进行设置,这对我来说效率很低。特别是当你不需要像你的例子中那样担心警告的时候。同意。我想我是想更多地了解熊猫是如何在幕后管理记忆的。我感兴趣的主要领域之一是只获取所需列的列子集,而不是拉入整个100列宽的数据帧。但我想,也许不需要的数据进入函数并不重要。