Как сохранить индекс при использовании pandas merge


126

Я хотел бы объединить два DataFramesи сохранить индекс из первого кадра в качестве индекса в объединенном наборе данных. Однако, когда я выполняю слияние, полученный DataFrame имеет целочисленный индекс. Как я могу указать, что хочу сохранить индекс из левого фрейма данных?

In [4]: a = pd.DataFrame({'col1': {'a': 1, 'b': 2, 'c': 3}, 
                          'to_merge_on': {'a': 1, 'b': 3, 'c': 4}})

In [5]: b = pd.DataFrame({'col2': {0: 1, 1: 2, 2: 3}, 
                          'to_merge_on': {0: 1, 1: 3, 2: 5}})

In [6]: a
Out[6]:
   col1  to_merge_on
a     1            1
b     2            3
c     3            4

In [7]: b
Out[7]:
   col2  to_merge_on
0     1            1
1     2            3
2     3            5

In [8]: a.merge(b, how='left')
Out[8]:
   col1  to_merge_on  col2
0     1            1   1.0
1     2            3   2.0
2     3            4   NaN

In [9]: _.index
Out[9]: Int64Index([0, 1, 2], dtype='int64')

РЕДАКТИРОВАТЬ: переключился на пример кода, который можно легко воспроизвести


2
при объединении по определенному столбцу неясно, какие индексы использовать (если они оба разные).
бонобо

Ответы:


162
In [5]: a.reset_index().merge(b, how="left").set_index('index')
Out[5]:
       col1  to_merge_on  col2
index
a         1            1     1
b         2            3     2
c         3            4   NaN

Примечание: для некоторых операций слияния слева вы можете получить больше строк, если есть несколько совпадений между aи, bи вам потребуется выполнить дедупликацию ( документация по дедупликации ). Вот почему pandas не хранит для вас индекс.


4
Очень умный. a.merge (b, how = "left"). set_index (a.index) также работает, но кажется менее надежным (поскольку первая часть теряет значения индекса до a до того, как сбрасывает их.)
DanB,

11
В данном конкретном случае они эквивалентны. Но для многих операций слияния результирующий фрейм не имеет того же количества строк, что и исходный aфрейм. reset_index перемещает индекс в обычный столбец, а set_index из этого столбца после слияния также заботится о том, когда строки a дублируются / удаляются из-за операции слияния.
Воутер Овермайр

1
@Wouter Мне бы хотелось знать, почему левое слияние по умолчанию переиндексируется. Где я могу узнать больше?
Мэтью

7
Ницца! Чтобы избежать явного указания имени индекса, я использую a.reset_index().merge(b, how="left").set_index(a.index.names).
Truls

3
Панды плохо думали, что API снова бьет.
Генри Хенринсон

7

Вы можете сделать копию индекса на левом фрейме данных и выполнить слияние.

a['copy_index'] = a.index
a.merge(b, how='left')

Я нашел этот простой метод очень полезным при работе с большими фреймами данных и использованием pd.merge_asof()(или dd.merge_asof()).

Этот подход будет лучше, если сброс индекса стоит дорого (большой фрейм данных).


1
Это лучший ответ. Есть много причин, по которым вы хотели бы сохранить свои старые индексы во время слияния (и принятый ответ не сохраняет индексы, он просто сбрасывает их). Это помогает, когда вы пытаетесь объединить более двух фреймов данных и так далее ...
Марсес

2
Превосходное решение, поскольку оно сохраняет (исходное) индексное название
Мартьен Любберинк,

проголосовали за, но будьте осторожны с предостережением, при использовании мультииндекса ваши индексы будут храниться в виде кортежа в единственном столбце, который называется [copy_index]
geekidharsh

6

Есть решение, отличное от pd.merge. Использование mapиset_index

In [1744]: a.assign(col2=a['to_merge_on'].map(b.set_index('to_merge_on')['col2']))
Out[1744]:
   col1  to_merge_on  col2
a     1            1   1.0
b     2            3   2.0
c     3            4   NaN

И не вводит фиктивное indexимя для индекса.


1
Это кажется лучше принятого ответа, поскольку он, вероятно, будет лучше работать с крайними случаями, такими как несколько индексов. Кто-нибудь может это прокомментировать?
BallpointBen

1
вопрос: что, если вам нужно назначить несколько столбцов, будет ли этот подход работать или он ограничен только одним полем?
Юка

@Yuca: Возможно, это не будет работать с несколькими столбцами, поскольку при подгруппе нескольких столбцов вы получаете a, pd.Dataframeа не a pd.Series. .map()Метод определен только для pd.Series. Это значит, что: a[['to_merge_on_1', 'to_merge_on_2']].map(...)не сработает.
Dataman

4
df1 = df1.merge(
        df2, how="inner", left_index=True, right_index=True
    )

Это позволяет сохранить индекс df1


Это похоже на работу, но когда я использую его on=list_of_cols], это противоречит документации: If joining columns on columns, the DataFrame indexes *will be ignored*. Имеет ли приоритет использование индексов или столбцов?
Итамар Кац,

0

Думаю, я придумал другое решение. Я присоединялся к левой таблице по значению индекса и правой таблице по значению столбца на основе индекса левой таблицы. Я сделал обычное слияние:

First10ReviewsJoined = pd.merge(First10Reviews, df, left_index=True, right_on='Line Number')

Затем я извлек новые номера индексов из объединенной таблицы и поместил их в новый столбец с именем Номер строки настроения:

First10ReviewsJoined['Sentiment Line Number']= First10ReviewsJoined.index.tolist()

Затем я вручную установил индекс обратно к исходному, левому индексу таблицы на основе ранее существовавшего столбца с именем Line Number (значение столбца, к которому я присоединился из индекса левой таблицы):

First10ReviewsJoined.set_index('Line Number', inplace=True)

Затем удалили индексное имя номера строки, чтобы оно оставалось пустым:

First10ReviewsJoined.index.name = None

Может быть, это немного взлом, но, похоже, работает хорошо и относительно просто. Кроме того, думаю, это снижает риск дублирования / испортить ваши данные. Надеюсь, все это имеет смысл.


0

другой простой вариант - переименовать индекс в то, что было раньше:

a.merge(b, how="left").set_axis(a.index)

merge сохраняет порядок в фрейме данных 'a', но просто сбрасывает индекс, чтобы сохранить его для использования set_axis

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.