簡體   English   中英

基於多列值的重復鍵條件合並/連接兩個大型 Pandas DataFrame - Python

[英]Conditional merge / join of two large Pandas DataFrames with duplicated keys based on values of multiple columns - Python

我來自 R 老實說,這是使用 R data.tables 在一行中做的最簡單的事情,而且對於大型數據表操作也相當快。 Bu 我真的很難在 Python 中實現它。前面提到的用例都不適合我的應用程序。 手頭的主要問題是 Python 解決方案中的 memory 用法,我將在下面解釋。

問題:我有兩個大數據幀 df1 和 df2(每個大約 50M-100M 行),我需要根據兩個條件將 df2 的兩列(或 n 列)合並到 df1:

1)df1.id = df2.id(合並的通常情況)

2) df2.value_2A <= df1.value_1 <= df2.value_2B

import numpy as np
import pandas as pd

df1 = pd.DataFrame({'id': [1,1,1,2,2,3], 'value_1': [2,5,7,1,3,4]})
df2 = pd.DataFrame({'id': [1,1,1,1,2,2,2,3], 'value_2A': [0,3,7,12,0,2,3,1], 'value_2B': [1,5,9,15,1,4,6,3]})

df1
Out[13]: 
   id  value_1
0   1        2
1   1        5
2   1        7
3   2        1
4   2        3
5   3        4

df2
Out[14]: 
   id  value_2A  value_2B
0   1         0         1
1   1         3         5
2   1         7         9
3   1        12        15
4   2         0         1
5   2         2         4
6   2         3         6
7   3         1         3

desired_output
Out[15]: 
   id  value_1  value_2A  value_2B
0   1        2       NaN       NaN
1   1        5       3.0       5.0
2   1        7       7.0       9.0
3   2        1       0.0       1.0
4   2        3       2.0       4.0
5   2        3       3.0       6.0
6   3        4       NaN       NaN

現在,我知道這可以通過首先以“左”方式合並 df1 和 df2 然后過濾數據來完成。 但就擴展性而言,這是一個可怕的解決方案。 我有 50M x 50M 行,其中包含多個重復的 id。 這將創建一些巨大的 dataframe,我必須對其進行過濾。

## This is NOT a solution because memory usage is just too large and 
## too many oprations deeming it extremely inefficient and slow at large scale

output = pd.merge(df1, df2, on='id', how='left')  ## output becomes very large in my case
output.loc[~((output['value_1'] >= output['value_2A']) & (output['value_1'] <= output['value_2B'])), ['value_2A', 'value_2B']] = np.nan
output = output.loc[~ output['value_2A'].isnull()]
output = pd.merge(df1, output, on=['id', 'value_1'], how='left')

這太低效了。 我正在合並一個大型數據集兩次以獲得所需的 output 並在這樣做的同時創建大量數據幀。 呸!

將其視為兩個事件數據幀,我試圖將它們匹配在一起。 也就是說,標記 df1 的事件是否在 df2 的事件中發生。 df1 和 df2 中的每個 id 都有多個事件。 df2 的事件不是相互排斥的。 條件連接確實需要在連接時發生,而不是之后。 這在 R 中很容易完成:

## in R realm ##
require(data.table)
desired_output <- df2[df1, on=.(id, value_2A <= value_1, value_2B >= value_1)] #fast and easy operation

在 Python 中有什么辦法可以做到這一點嗎?

是的。 這是一個煩人的問題。 我通過將左邊的 DataFrame 分成塊來處理這個問題。

def merge_by_chunks(left, right, condition=None, **kwargs):   
    chunk_size = 1000
    merged_chunks = []
    for chunk_start in range(0, len(left), chunk_size):
        print(f"Merged {chunk_start}            ", end="\r")
        merged_chunk = pd.merge(left=left[chunk_start: chunk_start+chunk_size], right=right, **kwargs)
        if condition is not None:
            merged_chunk = merged_chunk[condition(merged_chunk)]
        merged_chunks.append(merged_chunk)
    return pd.concat(merged_chunks)

然后您可以將條件提供為 function。

df1 = pd.DataFrame({'id': [1,1,1,2,2,3], 'value_1': [2,5,7,1,3,4]})
df2 = pd.DataFrame({'id': [1,1,1,1,2,2,2,3], 'value_2A': [0,3,7,12,0,2,3,1], 'value_2B': [1,5,9,15,1,4,6,3]})

def condition_func(output):
    return (((output['value_1'] >= output['value_2A']) & (output['value_1'] <= output['value_2B'])))

output = merge_by_chunks(df1, df2, condition=condition_func, on='id', how='left')
merge_by_chunks(df1, output, on=['id', 'value_1'], how='left')

根據 DataFrame 的大小,它可能會非常慢,但不會用完 memory。

有趣的問題!

看起來 pandasql 可能會做你想做的事。 請參閱: 如何在 python Pandas 中進行條件連接?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM