在PandasDataFrame中查找值的更快方法?

我正在尝试将我的一些 R 脚本“翻译”到 Python,但我注意到,在 Python 中处理数据帧比在 R 中处理要慢得多,例如根据某些条件提取单元格。

我做了一些调查,这是在 Python 中查找特定值所需的时间:

import pandas as pd
from timeit import default_timer as timer

code = 145896

# real df is way bigger
df = pd.DataFrame(data={
    'code1': [145896, 800175, 633974, 774521, 416109],
    'code2': [100, 800, 600, 700, 400],
    'code3': [1, 8, 6, 7, 4]}
    )

start = timer()
for _ in range(100000):
    desired = df.loc[df['code1']==code, 'code2'][0]
print(timer() - start) # 19.866242500000226 (sec)

在 R 中:

code <- 145896

df <- data.frame("code1" = c(145896, 800175, 633974, 774521, 416109),
           "code2" = c(100, 800, 600, 700, 400),
           "code3" = c(1, 8, 6, 7, 4))

start <- Sys.time()
for (i in 1:100000) {
  desired <- df[df$code1 == code, "code2"]
}
print(Sys.time() - start) # Time difference of 1.140949 secs

我对 Python 比较陌生,我可能遗漏了一些东西。有什么方法可以加快这个过程吗?也许将这个脚本转移到 Python 的整个想法毫无意义?在其他操作中,Python 更快(即处理字符串),并且一旦需要处理数据帧,在两个或多个脚本之间跳转将非常不方便。请问这有什么帮助吗?

UPDATE
Real 脚本块迭代初始数据框的行(相当大,500-1500k 行)并创建一个新的行,其中包含来自原始列“code1”的值和来自另一个数据框的与其对应的代码,以及许多其他新创建的值。我相信,我可以用图片澄清它:

在脚本的后面,我还需要根据不同的条件在循环中搜索特定的值。所以搜索的速度是必不可少的。

回答

由于您希望从 DataFrame 中选择单个值,因此您可以采取一些措施来提高性能。

  1. 使用.item()代替[0],它有一个很小但不错的改进,尤其是对于较小的数据帧。
  2. 仅仅为了选择一个已知的系列而屏蔽整个 DataFrame是很浪费的。而是仅屏蔽系列并选择值。虽然你可能会想“哦,这是被锁住了——被禁止的][”,但它只是被锁住了令人担忧分配,而不是链接选择。
  3. 使用 numpy。由于索引和调整,Pandas 有很多开销。但是您只想从矩形数据结构中选择一个值,因此下拉到numpy会更快。

下面是选择数据的不同方法的时间说明[下面每种方法都有自己的方法]。使用numpy是迄今为止最快的,尤其是对于像您的示例中的较小的 DataFrame。对于那些,它将比您选择数据的原始方式快 20 倍以上,查看您与 R 的初始比较应该使其比在 R 中选择数据略快。随着 DataFrames 变得更大,numpy 解决方案的相对性能是不是很好,但它仍然是最快的方法(如图所示)。

import perfplot
import pandas as pd
import numpy as np

def DataFrame_Slice(df, code=0):
    return df.loc[df['code1'] == code, 'code2'][0]

def DataFrame_Slice_Item(df, code=0):
    return df.loc[df['code1'] == code, 'code2'].item()

def Series_Slice_Item(df, code=0):
    return df['code2'][df['code1'] == code].item()

def with_numpy(df, code=0):
    return df['code2'].to_numpy()[df['code1'].to_numpy() == code].item()


perfplot.show(
    setup=lambda N: pd.DataFrame({'code1': range(N),
                                  'code2': range(50, N+50),
                                  'code3': range(100, N+100)}),
    kernels=[
        lambda df: DataFrame_Slice(df),
        lambda df: DataFrame_Slice_Item(df),
        lambda df: Series_Slice_Item(df),
        lambda df: with_numpy(df)
    ],
    labels=['DataFrame_Slice', 'DataFrame_Slice_Item', 'Series_Slice_Item', 'with_numpy'],
    n_range=[2 ** k for k in range(1, 21)],
    equality_check=np.allclose,  
    relative_to=3,
    xlabel='len(df)'
)


以上是在PandasDataFrame中查找值的更快方法?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>