【问题标题】:What is the fastest way to vectorize a 2 parameter .loc update?向量化 2 参数 .loc 更新的最快方法是什么?
【发布时间】:2019-06-25 03:36:06
【问题描述】:

假设我有以下数据框:

import pandas as pd
df = pd.DataFrame({'n': [1, 2, 3], 'm': [4, 4, 7]})
df.loc[df['m']==4,'n']=1

在相对较小的数据集(约 50,000 个 int32 样本)上运行此 .loc 函数需要 11 毫秒。有什么办法可以加快速度吗?我希望将相同的操作降低到 10-100μs 之间。

更新

我已将上面的示例编辑得更简洁。

测试建议的方法后,最快的是:

df['n'].values[df['m'].values == 4] = 1

将该解决方案应用于约 50,000 个样本数据集后,该解决方案的运行速度比原始代码快 244 倍。

【问题讨论】:

    标签: python pandas performance numpy


    【解决方案1】:

    您可以使用np.where 获得更有效的解决方案:

    df = pd.DataFrame({'numbers': np.random.choice(range(5), 100_000), 
                       'more_numbers': np.random.choice(range(5), 100_000)})
    
    %timeit df.loc[df.more_numbers==4,'numbers']=1
    7.09 ms ± 658 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    %timeit np.where(df.more_numbers == 4, 1, df.numbers)
    547 µs ± 20.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    

    所以你可以这样做:

    df.numbers = np.where(df.more_numbers == 4, 1, df.numbers)
    

    【讨论】:

      【解决方案2】:

      有很多方法。您可能希望考虑修改底层 NumPy 数组。但是,这不是文档化或官方推荐的方法。

      # Python 3.6.5, Pandas 0.19.2, NumPy 1.11.4
      np.random.seed(0)
      df = pd.DataFrame({'n': np.random.randint(0, 10, 10**5),
                         'm': np.random.randint(0, 10, 10**5)})
      
      %timeit df.loc[df['m'] == 4, 'n'] = 1                              # 1.3 ms
      %timeit df['n'].values[df['m'].values == 4] = 1                    # 436 µs
      %timeit df['n'] = np.where(df['m'].values == 4, 1, df['n'])        # 751 µs
      %timeit df.iloc[df['m'].values == 4, df.columns.get_loc('n')] = 1  # 880 µs
      %timeit df.loc[df['m'].values == 4, 'n'] = 1                       # 1.12 ms
      %timeit df['n'] = df['n'].mask(df['m'].values == 4, 1)             # 1.34 ms
      

      【讨论】:

      • 非常感谢jpp的详细解答!最快的方法是%timeit df['n'].values[df['m'].values == 4] = 1
      【解决方案3】:

      所以只需使用values

      %timeit df.values[df['more_numbers']==4,0]=1
      10000 loops, best of 3: 127 µs per loop
      %timeit df.loc[df['more_numbers']==4,'numbers']=1
      1000 loops, best of 3: 692 µs per loop
      

      【讨论】:

      • 这太好了,谢谢!通过将其更改为 df.values[df['more_numbers'].values==4,0]=1,我能够稍微加快您的建议
      【解决方案4】:

      你可以看看np.where()

      df.numbers=np.where(df['more_numbers']==4,1,df.numbers)
      

      【讨论】:

      • 非常感谢
      • 高兴丹尼尔 :)
      猜你喜欢
      • 2014-09-10
      • 1970-01-01
      • 2018-07-08
      • 2020-01-05
      • 2018-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多