【问题标题】:Conditional merge on 2 huge pandas datasets2 个大熊猫数据集的条件合并
【发布时间】:2021-01-13 18:56:24
【问题描述】:

我有 2 个数据框如下:

A = pd.DataFrame({'UserId':['U1','U1','U1','U2','U2','U3'],'End_Week':['1/6/2020','15/6/2020','6/7/2020','4/5/2020','18/5/2020','20/4/2020'],'Start_Week':['1/6/2019','15/6/2019','6/7/2019','4/5/2019','18/5/2019','20/4/2019']})

B = pd.DataFrame({'UserId':['U1','U1','U1','U1','U2','U2','U3'],'Action':['U','V','U','U','V','V','U'],'Date':['5/3/2019','4/6/2019','1/7/2019','12/6/2020','4/4/2019','12/5/2019','19/3/2019'],'V1':[2,3,1,2,4,1,1],'V2':[0,1,0,0,1,2,1]})

我想做以下步骤:

对于“A”的每一行,从数据帧“B”中找到位于 A 中的 Start_Week 和 End_Week 列之间的所有对应行。例如 - “A”的第一行 -> Start_Week 是 '1/6/2019 ' 并且 End_Week 是 '1/6/2020'。位于这些日期之间的数据框“B”中的所有行都是第 2 行和第 3 行,即日期 4/06/2019 和 1/7/2019(对于用户 U1)。必须对数据框 A 的所有行进行类似的操作。

我有以下解决方案,它适用于小数据,但无法为我正在使用的整个数据分配内存。

a = A.Date.values
a1 = A.UserId.values
b1 = B.UserId.values
bh = B.End_Week.values
bl = B.Start_Week.values

i, j = np.where((a1[:, None]==b1) & (a[:, None] >= bl) & (a[:, None] <= bh))
final_df = pd.DataFrame(np.column_stack([A.values[i], B.values[j]]),columns=A.columns.append(B.columns))

我收到以下错误消息:

MemoryError: Unable to allocate 514. GiB for an array with shape (662195, 834051) and data type bool

在我的数据集中,A 包含 662195 行,B 包含 834051。

有人可以为这个问题提供更优化的解决方案吗?

【问题讨论】:

    标签: python pandas dataframe numpy


    【解决方案1】:

    首先将日期转换为日期时间(如果日期已经是日期时间数据类型,则忽略此块

    A[['End_Week','Start_Week']] = A[['End_Week','Start_Week']].apply(pd.to_datetime,
                                                                    dayfirst=True)
    B['Date']  = pd.to_datetime(B['Date'],dayfirst=True)
    

    然后merge 并使用series.between

    out = B.merge(A,on='UserId',how='left')
    out = out[out['Date'].between(u['Start_Week'],u['End_Week'])]
    

    print(out)
    
       UserId Action       Date  V1  V2   End_Week Start_Week
    3      U1      V 2019-06-04   3   1 2020-06-01 2019-06-01
    6      U1      U 2019-07-01   1   0 2020-06-01 2019-06-01
    7      U1      U 2019-07-01   1   0 2020-06-15 2019-06-15
    10     U1      U 2020-06-12   2   0 2020-06-15 2019-06-15
    11     U1      U 2020-06-12   2   0 2020-07-06 2019-07-06
    14     U2      V 2019-05-12   1   2 2020-05-04 2019-05-04
    

    如果您只需要 B 中的列,则可以过滤输出以仅保留 B 中的列;

    out = out[out['Date'].between(u['Start_Week'],u['End_Week'])].loc[:,B.columns]
    print(out)
    
       UserId Action       Date  V1  V2
    3      U1      V 2019-06-04   3   1
    6      U1      U 2019-07-01   1   0
    7      U1      U 2019-07-01   1   0
    10     U1      U 2020-06-12   2   0
    11     U1      U 2020-06-12   2   0
    14     U2      V 2019-05-12   1   2
    

    【讨论】:

    • 我也面临类似的问题。我尝试了合并操作(您也建议这样做),但由于内存大小问题,它会杀死内核。我有 128 GB RAM 可用。
    • @Prateek 你的数据集有多大?
    • 大约 2000 万行 15 列。它是日期级别的用户交易数据。
    猜你喜欢
    • 1970-01-01
    • 2018-11-04
    • 2018-09-16
    • 2017-12-27
    • 1970-01-01
    • 2022-11-28
    • 1970-01-01
    • 2018-07-05
    • 1970-01-01
    相关资源
    最近更新 更多