Присоединиться к фрагменту фрейма данных

Я пытаюсь соединить фрагмент фрейма данных с другим. Структура присоединяемого фрейма данных упрощена ниже:

left:
ID    f1   TIME
1     10     1
3     10     1
7     10     1
9     10     2
2     10     2
1     10     2
3     10     2

right:
ID    f2    f3
1      0    11
7      9    11

Мне нужно выбрать левый набор данных по времени, и мне нужно прикрепить правый, результат, который я хотел бы получить, будет следующим:

left:
ID    f1   TIME  f2     f3
1     10     1    0     11
3     10     1  nan    nan
7     10     1    9     11
9     10     2  nan    nan
2     10     2  nan    nan
1     10     2  nan    nan
3     10     2  nan    nan

В настоящее время я обычно присоединяюсь к фреймам данных следующим образом:

left = left.join(right.set_index('ID'), on='ID')

В этом случае я использую:

left[left.TIME == 1] = left[left.TIME == 1].join(right.set_index('ID'), on='ID')

Я также пробовал слияние, но результат - левый фрейм данных без каких-либо других столбцов. Наконец, структура моего скрипта должна делать это для каждого уникального ВРЕМЕНИ в фрейме данных, таким образом:

 for t in numpy.unique(left.TIME):
     #do join on the fragment left.TIME == t

Если я сохраню возвращаемое значение из функции соединения в новом фрейме данных, все будет работать нормально, но попытка добавить значение в левый фрейм данных не сработает.

Обновлено: идентификаторы левого набора данных могут присутствовать несколько раз, но не внутри одного и того же значения TIME.

🤔 А знаете ли вы, что...
Python популярен в анализе данных и машинном обучении с помощью библиотеки scikit-learn.


2
130
2

Ответы:

Это один способ:

res = left.drop_duplicates('ID')\
          .merge(right, how='left')\
          .append(left[left.duplicated(subset=['ID'])])

#    ID  TIME  f1   f2    f3
# 0   1     1  10  0.0  11.0
# 1   3     1  10  NaN   NaN
# 2   7     1  10  9.0  11.0
# 3   9     2  10  NaN   NaN
# 4   2     2  10  NaN   NaN
# 5   1     2  10  NaN   NaN
# 6   3     2  10  NaN   NaN

Обратите внимание, что столбцы f2 и f3 становятся float, поскольку NaN считается плавающим.


Решено

Вы можете фильтровать сначала по boolean indexing, merge и concat в последнюю очередь:

df1 = left[left['TIME']==1]
#alternative
#df1 = left.query('TIME == 1')
df2 = left[left['TIME']!=1]
#alternative
#df2 = left.query('TIME != 1')

df = pd.concat([df1.merge(right, how='left'), df2])
print (df)
   ID  TIME  f1   f2    f3
0   1     1  10  0.0  11.0
1   3     1  10  NaN   NaN
2   7     1  10  9.0  11.0
3   9     2  10  NaN   NaN
4   2     2  10  NaN   NaN
5   1     2  10  NaN   NaN
6   3     2  10  NaN   NaN

Обновлено: merge создает индексы по умолчанию, поэтому возможное решение - сначала создать столбец, а затем установить индекс:

print (left)
    ID  f1  TIME
10   1  10     1
11   3  10     1
12   7  10     1
13   9  10     2
14   2  10     2
15   1  10     2
16   3  10     2

#df = left.merge(right, how='left')
df1 = left[left['TIME']==1]

df2 = left[left['TIME']!=1]
df = pd.concat([df1.reset_index().merge(right, how='left').set_index('index'), df2])
print (df)
    ID  TIME  f1   f2    f3
10   1     1  10  0.0  11.0
11   3     1  10  NaN   NaN
12   7     1  10  9.0  11.0
13   9     2  10  NaN   NaN
14   2     2  10  NaN   NaN
15   1     2  10  NaN   NaN
16   3     2  10  NaN   NaN

Обновлено:

После обсуждения после изменения входных данных возможно использование:

df = left.merge(right, how='left', on=['ID','TIME'])