Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/354.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Pandas-使用部分匹配合并两个数据帧_Python_Pandas - Fatal编程技术网

Python Pandas-使用部分匹配合并两个数据帧

Python Pandas-使用部分匹配合并两个数据帧,python,pandas,Python,Pandas,有了下图所示的数据帧,我想先在['A'、'B'、'C']和['X'、'Y'、'Z']上合并,然后逐渐寻找一个少一列的匹配项,即['A'、'B']和['X'、'Y']然后['A']和['X'],而不复制结果行,在下面的示例中,a,y,y,v3被省略,因为a,d,d已经匹配 到目前为止,我的代码在所有3列上都匹配: df1 = pd.DataFrame({"A":['a','b','c'],"B":['d','e','f'],"C":['

有了下图所示的数据帧,我想先在
['A'、'B'、'C']
['X'、'Y'、'Z']
上合并,然后逐渐寻找一个少一列的匹配项,即
['A'、'B']
['X'、'Y']
然后
['A']
['X']
,而不复制结果行,在下面的示例中,
a,y,y,v3
被省略,因为
a,d,d
已经匹配

到目前为止,我的代码在所有3列上都匹配:

df1 = pd.DataFrame({"A":['a','b','c'],"B":['d','e','f'],"C":['d','e','f']})
df2 = pd.DataFrame({"X":['a','b','a','c'],"Y":['d','e','y','z'],"Z":['d','x','y','z'],"V":['v1','v2','v3','v4']})

merged = pd.merge(df1,df2,left_on=['A','B','C'],right_on=['X','Y','Z'], how='left')
merged = merged.drop_duplicates(['A','B','C'])
merged.head()

我怎样才能实现我的目标

更新:预期输出

这个怎么样:

matches = [['A', 'B', 'C'], ['X', 'Y', 'Z']]
df = df1.copy()
for k in range(len(matches[0])):

    #Get your left/right keys right at each iteration :
    left, right = matches
    left = left if k==0 else left[:-k]
    right = right if k==0 else right[:-k]

    #Make sure columns from df2 exist in df
    for col in df2.columns.tolist():
        try:
            df[col]
        except Exception:
            df[col] = np.nan

    #Merge dataframes
    df = df.merge(df2, left_on=left, right_on=right, how='left')

    #Find which row of df's "left" columns (previously initialised) are empty
    ix_left_part = np.all([df[x + "_x"].isnull() for x in right], axis=0)

    #Find which row of df's "right" columns are not empty
    ix_right_part = np.all([df[x + "_y"].notnull() for x in right], axis=0)

    #Combine both to get indexes
    ix = df[ix_left_part & ix_right_part].index

    #Complete values on "left" with those from "right"
    for x in df2.columns.tolist():
        df.loc[ix, x+"_x"] = df.loc[ix, x+'_y']

    #Drop values from "right"
    df.drop([x+"_y" for x  in df2.columns.tolist()], axis=1, inplace=True)

    #Rename "left" columns to stick with original names from df2
    df.rename({x+"_x":x for x  in df2.columns.tolist()}, axis=1, inplace=True)

#drop eventual duplicates
df.drop_duplicates(keep="first", inplace=True)
print(df)

编辑

我纠正了这个循环;这对内存来说应该更容易:

import pandas as pd
import numpy as np

df1 = pd.DataFrame({"A":['a','b','c'],"B":['d','e','f'],"C":['d','e','f']})
df2 = pd.DataFrame({"X":['a','b','a','c'],"Y":['d','e','y','z'],"Z":['d','x','y','z'],"V":['v1','v2','v3','v4']})

matches = [['A', 'B', 'C'], ['X', 'Y', 'Z']]
df = df1.copy()

#Make sure columns of df2 exist in df
for col in df2.columns.tolist():
    df[col] = np.nan

for k in range(len(matches[0])):

    #Get your left/right keys right at each iteration :
    left, right = matches
    left = left if k==0 else left[:-k]
    right = right if k==0 else right[:-k]
    
    #recreate dataframe of (potential) usable datas in df2:
    ix = df[df.V.isnull()].index
    temp = (
            df.loc[ix, left]
            .rename(dict(zip(left, right)), axis=1)
            )
    
    temp=temp.merge(df2, on=right, how="inner")
    
    #Merge dataframes
    df = df.merge(temp, left_on=left, right_on=right, how='left')
    
    
    #Combine both to get indexes
    ix = df[(df['V_x'].isnull()) & (df['V_y'].notnull())].index
    

    #Complete values on "left" with those from "right"
    cols_left = [x+'_x' for x in df2.columns.tolist()]
    cols_right = [x+'_y' for x in df2.columns.tolist()]    
    df.loc[ix, cols_left] = df.loc[ix, cols_right].values.tolist()
        
    #Drop values from "right"
    df.drop(cols_right, axis=1, inplace=True)
    
    #Rename "left" columns to stick with original names from df2
    rename = {x+"_x":x for x  in df2.columns.tolist()}
    df.rename(rename, axis=1, inplace=True)

print(df)

一个想法与多个
合并
在循环中,第二个
数据帧
应该避免在最终的
数据帧
中重复行:

from functools import reduce

dfs = []
L = [['A', 'B', 'C'], ['X', 'Y', 'Z']]

for i in range(len(L[0]), 0, -1):
    df22 = df2.drop_duplicates(L[1][:i])
    df = pd.merge(df1,df22,left_on=L[0][:i],right_on=L[1][:i], how='left')
    dfs.append(df)

df = reduce(lambda l,r: pd.DataFrame.fillna(l,r), dfs)
print (df)
   A  B  C  X  Y  Z   V
0  a  d  d  a  d  d  v1
1  b  e  e  b  e  x  v2
2  c  f  f  c  z  z  v4
工作方式如下:

merged1 = pd.merge(df1,df2.drop_duplicates(['X','Y','Z']),left_on=['A','B','C'],right_on=['X','Y','Z'], how='left')
merged2 = pd.merge(df1,df2.drop_duplicates(['X','Y']),left_on=['A','B'],right_on=['X','Y'], how='left')
merged3 = pd.merge(df1,df2.drop_duplicates('X'),left_on=['A'],right_on=['X'], how='left')

df = merged1.fillna(merged2).fillna(merged3)
print (df)
   A  B  C  X  Y  Z   V
0  a  d  d  a  d  d  v1
1  b  e  e  b  e  x  v2
2  c  f  f  c  z  z  v4

a,y,y,v3
已被忽略,因为您已经有一行与整个3列匹配?你能不能也加上预期的输出?没错,我会加上预期的输出。我想我把“ix_left_part”搞砸了,你不应该在最后得到重复的。。。我想我现在知道它是什么了,但是纠正它将取决于是否有一个“target”列(在您的实际df2上是“V”的意思)。有一个目标,V列。我将测试代码,让您知道您的代码在我提供的虚拟数据上工作,这是值得称赞的…但是,当我在实际数据上运行它时,它会消耗大量内存并使我的环境崩溃:(数据帧的形状是什么?df1是(10000,3)而df2是(137503,3),在我的实际数据中只有两列需要匹配,但我正在寻找一个通用的答案,就像你提供的答案一样。超级!工作得像个charmcan你可以看看这里:?