Python или Pandas левое внешнее объединение или объединение с одним ключом в виде списка - PullRequest
2 голосов
/ 11 февраля 2020

Я пытаюсь сделать left outer join для двух Data.Frames, используя Python. Цель состоит в том, чтобы получить столбец справа налево, основываясь на том, существует ли слева в списке ключ слева.

Сначала я решил использовать Pandas, поэтому я написал что-то вроде этого:

import pandas as pd

left = pd.DataFrame({'name':['spam', 'ham', 'eggs'], 'leftkey':[11, 22, 33]})
right = pd.DataFrame({'var':['foo', 'bar'], 'rightkey':[[1, 2, 5], [2, 33, 100]]})

merged = pandas.merge(left, right, left_on='keyleft', right_on='keyright', how='left')

Как мы видим, left_on - это одна переменная, а right_on - это list.

Я бы ожидал, что merged будет выглядеть примерно так:

|   | name | leftkey | var | rightkey   |
|---|------|---------|-----|------------|
| 0 | spam | 11      | NaN | NaN        |
| 1 | ham  | 22      | NaN | NaN        |
| 2 | eggs | 33      | bar | [2,33,100] |

Однако все var и rightkey в конечном итоге становятся NaN.

Я понимаю, что могу просто поместить все в R и сделать это. Возможно, я обдумываю вещи, и это даже не требует Pandas. Однако я надеюсь сохранить конвейер в Python как можно дольше.

Есть предложения?

1 Ответ

1 голос
/ 11 февраля 2020

Вы можете использовать метод explode для создания нового столбца, который можно использовать в качестве аргумента right_on в merge:

right = right.assign(rightkey_x = right['rightkey']).explode('rightkey_x')

Вывод:

   var      rightkey rightkey_x
0  foo     [1, 2, 5]          1
0  foo     [1, 2, 5]          2
0  foo     [1, 2, 5]          5
1  bar  [2, 33, 100]          2
1  bar  [2, 33, 100]         33
1  bar  [2, 33, 100]        100

Затем вы можете объединить оба кадра данных и удалить столбец помощника:

pd.merge(left, right, left_on='leftkey', right_on='rightkey_x', how='left')\
.drop('rightkey_x', axis=1)

Вывод:

   name leftkey  var      rightkey
0  spam      11  NaN           NaN
1   ham      22  NaN           NaN
2  eggs      33  bar  [2, 33, 100]
...