Python: как объединить два кадра данных, используя несколько столбцов в качестве ключей - PullRequest
0 голосов
/ 17 июня 2019

Я ищу что-то эквивалентное слиянию SQL, используя где "t1.A = t2.A ИЛИ t1.B = t2.A" ИЛИ t1.C = t2.A.У меня есть два фрейма данных, скажем, D1 с A, B, C, D, E в качестве столбцов и D2, где несколько записей D2 могут быть извлечены столбцом A D1, немногие из его псевдонимов B, C, D и E столбцов.

Я пытался, как показано ниже, но он выдавал неправильный вывод.

sample = D1.merge(D2,left_on=[ 'A' or'B' or'C'or 'D' or E], 
right_on=['A'], how='left')

Затем я попытался

sample = pd.concat([D1.merge(D2,left_on='A', right_on= 'A', how='left'), 
D1.merge(D2,left_on='B', right_on='A', how='left'), D1.merge(D2, 
left_on='C',right_on='A', how='left'),D1.merge(D2,left_on='D', 
right_on='A', how='left'),D1.merge(D2,left_on='E', right_on='A', 
how='left')])

Это дает мне много дубликатов, которые я пыталсяудалить дубликаты, но, к сожалению, это не сработало.

dupes = (sample['A'] == sample['B']) == (sample['C'] == sample['D']) == 
sample['E']   
sample=sample.loc[~dupes]



ValueError: The truth value of a Series is ambiguous. Use a.empty, 
 a.bool(), a.item(), a.any() or a.all().

Мне нужно, чтобы выходные или «выборочные» записи были такими же, как записи фрейма данных D1.

1 Ответ

0 голосов
/ 17 июня 2019

Давайте начнем с import itertools (мы будем использовать его).

Я создал тестовые фреймы данных следующим образом:

D1 = pd.DataFrame(data=[
    [ 1, 0, 0, 0, 0, 91 ],
    [ 0, 2, 0, 0, 0, 92 ],
    [ 0, 0, 3, 0, 0, 93 ],
    [ 0, 0, 0, 4, 0, 94 ],
    [ 0, 0, 0, 0, 5, 95 ],
    [ 0, 6, 0, 0, 0, 96 ],
    [ 0, 0, 7, 0, 0, 97 ]], columns=list('ABCDEF'))

D2 = pd.DataFrame(data=[
    [ 1, 71, 89 ],
    [ 2, 72, 88 ],
    [ 3, 73, 87 ],
    [ 4, 74, 86 ],
    [ 5, 75, 85 ],
    [ 8, 76, 84 ]], columns=list('AXY'))

Как видите:

  • D1 содержит столбцы «кандидатов на присоединение» A - E и один дополнительный столбец ( F ),
  • D2 содержит один столбец объединения A и два дополнительных столбца ( X и Y ).

Тогда давайте определим функцию соединения:

def myJoin(df1, df2):
    rows = itertools.product(df1.iterrows(), df2.iterrows())
    df = pd.DataFrame(left.append(right.iloc[1:])
        for (_, left), (_, right) in rows
            if right.A in left.loc['A':'E'].tolist())
    return df.reset_index(drop=True)

И единственное, что нужно сделать, это вызвать ее:

myJoin(D1, D2)

Результат:

   A  B  C  D  E   F   X   Y
0  1  0  0  0  0  91  71  89
1  0  2  0  0  0  92  72  88
2  0  0  3  0  0  93  73  87
3  0  0  0  4  0  94  74  86
4  0  0  0  0  5  95  75  85

Обратите внимание, что имена столбцов, взятые из обоих фреймов данных, должны быть уникальными , поэтому я исключил столбец A из D2 ( right.iloc [1:] ).

Редактировать

Представленная выше функция фактически внутренняя объединяет.Если вы хотите left join, тогда определите другую функцию join как:

def myJoin2(df1, df2):
    res = []
    for (_, left) in df1.iterrows():
        found = False
        for (_, right) in df2.iterrows():
            if right.A in left.loc['A':'E'].tolist():
                res.append(left.append(right.iloc[1:]))
                found = True
        if not found:
            res.append(left)
    df = pd.DataFrame(res)
    return df.reset_index(drop=True)

и вызовите ее:

myJoin2(D1, D2)

, получив результат:

     A    B    C    D    E     F     X     Y
0  1.0  0.0  0.0  0.0  0.0  91.0  71.0  89.0
1  0.0  2.0  0.0  0.0  0.0  92.0  72.0  88.0
2  0.0  0.0  3.0  0.0  0.0  93.0  73.0  87.0
3  0.0  0.0  0.0  4.0  0.0  94.0  74.0  86.0
4  0.0  0.0  0.0  0.0  5.0  95.0  75.0  85.0
5  0.0  0.0  0.0  0.0  5.0  95.0  76.0  84.0
6  0.0  6.0  0.0  0.0  0.0  96.0   NaN   NaN
7  0.0  0.0  7.0  0.0  0.0  97.0   NaN   NaN

Недостатком является то, что значения int преобразуются в float , но NaN также является частным случаем float ,этого нельзя избежать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...