寻找加快熊猫合并的方法(或可能是另一种方法)

时间:2019-09-04 08:52:21

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

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

完整的详细信息可以在这里找到:

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分钟+数千行的行数,并由于内存错误而彻底崩溃。尝试进一步增加数据框中的行。

我忍不住想,必须有一种更好的方法来更有效地执行此操作。

有人有什么建议吗?

2 个答案:

答案 0 :(得分:0)

请尝试:

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的性能:

enter image description here

答案 1 :(得分:0)

请考虑以下替代解决方案。在这里,我们遍历不同的Code值,并为每个New Price搜索适当的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)