【问题标题】:Looking for a way to speed up a pandas merge (or potentially another method)寻找一种加快熊猫合并的方法(或可能是另一种方法)
【发布时间】:2020-01-07 03:17:51
【问题描述】:

您好,我最近发布了一个关于执行合并以获取 pandas 数据框并返回满足条件的列的问题。

完整的细节可以在这里找到:

How to add a new column to a pandas df that returns the smallest value that is greater in the same group from another dataframe

(不确定我是否应该发布整个问题以保持这篇文章的独立性,所以我现在只留下一个链接)。

给出的解决方案效果很好,因为我需要较小的数据集,所以考虑不到一千行。

这是建议的答案:

m=(df1.assign(key=1).merge(df2.assign(key=1),on='key',suffixes=('','_y')).drop('key', 1)
                                            .query("(Code==Code_y)&(Price<=Price_y)"))
m.groupby(['Code','Price'],sort=False)['Price_y'].first().reset_index(name='New Price'

但是,当我开始在更大的数据集(这是我的要求)上使用它时,它开始减慢到几乎无法使用的水平,想想 5 分钟 + 数千行,一旦我因为内存错误而完全崩溃尝试进一步增加数据框中的行数。

我不禁想到,一定有更好的方法在更高效的时间内执行此操作。

有人有什么建议吗?

【问题讨论】:

  • 确保正确配置数据类型,仅从 Dataframe 中获取必要的字段并随时清理未使用的 Dataframe。

标签: python python-3.x pandas dataframe pandas-groupby


【解决方案1】:

请尝试:

m=df1.set_index('Code').join(df2.set_index('Code'),rsuffix='_New')
df1.join(m[m.Price<=m.Price_New].groupby('Price',sort=False)['Price_New']
         .first().reset_index(drop=True))

  Code  Price  Price_New
0    X   4.30        4.5
1    X   2.50        2.5
2    X   4.00        4.0
3    X   1.50        1.5
4    X   0.24        0.5
5    X   1.00        1.0
6    X   1.30        1.5
7    Y   3.90        4.0
8    Y   2.60        3.0

样本df的性能:

【讨论】:

    【解决方案2】:

    考虑以下问题的替代解决方案。在这里,我们迭代不同的Code 值并为每个Price 搜索适当的New Price。应该比原来的方式在时间和记忆上效率更高。还可以通过优化和/或numba 来提高效率。

    import numpy as np
    import pandas as pd
    
    def get_all_new(pd_series, result):
        result[pd_series.name] = np.sort(pd_series.unique())
    
    def find_new_group(pd_series, sorted_arrays):
        return pd_series.apply(lambda x: find_new(x, sorted_arrays[pd_series.name]))
    
    def find_new(value, sorted_array):
        pos = np.searchsorted(sorted_array, value)
        return sorted_array[pos] if pos < sorted_array.size else None  # None OR value ???
    
    if __name__ == '__main__':
    
        N1, N2, M1, M2 = 5, 5, 5, 5
        df1 = pd.DataFrame(
            {'Code': ['X'] * N1 + ['Y'] * N2,
             'Price': np.random.randint(1, 100, N1 + N2) / 10})
        df2 = pd.DataFrame(
            {'Code': ['X'] * M1 + ['Y'] * M2,
             'Price': np.random.randint(1, 100, M1 + M2) / 10})
        print(df1)
        print(df2)
    
        all_new = dict()
        # collect all new prices for every Code
        df2.groupby('Code')['Price'].apply(lambda x: get_all_new(x, all_new))
        # find appropriate new price for every old price
        df1['New Price'] = df1.groupby('Code')['Price'].apply(lambda x: find_new_group(x, all_new))
    
        print(df1)
    

    输出:

      Code  Price
    0    X    7.8
    1    X    6.6
    2    X    3.2
    3    X    0.3
    4    X    4.7
    5    Y    0.5
    6    Y    1.1
    7    Y    8.9
    8    Y    6.7
    9    Y    0.5
      Code  Price
    0    X    6.9
    1    X    4.6
    2    X    2.3
    3    X    7.6
    4    X    2.4
    5    Y    0.8
    6    Y    3.4
    7    Y    0.4
    8    Y    4.2
    9    Y    9.6
      Code  Price  New Price
    0    X    7.8        NaN
    1    X    6.6        6.9
    2    X    3.2        4.6
    3    X    0.3        2.3
    4    X    4.7        6.9
    5    Y    0.5        0.8
    6    Y    1.1        3.4
    7    Y    8.9        9.6
    8    Y    6.7        9.6
    9    Y    0.5        0.8
    

    N1, N2, M1, M2 = ...测试代码

    100_000 - 518 ms ± 2.25 ms per loop (mean ± std. dev. of 7 runs, 1 loop each),

    1_000_000 - 5.29 s ± 72.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each).

    【讨论】:

      猜你喜欢
      • 2021-12-25
      • 2014-12-13
      • 2014-01-09
      • 1970-01-01
      • 2018-06-25
      • 2016-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多