Cómo mantener el índice al usar pandas merge

126

Me gustaría fusionar dos DataFramesy mantener el índice del primer fotograma como índice en el conjunto de datos combinado. Sin embargo, cuando hago la fusión, el DataFrame resultante tiene un índice entero. ¿Cómo puedo especificar que quiero mantener el índice del marco de datos izquierdo?

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')

EDITAR: se cambió al código de ejemplo que se puede reproducir fácilmente

DanB
fuente
2
si se fusiona en una columna específica, no está claro qué índices usar (en caso de que ambos sean diferentes).
bonobo

Respuestas:

161
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

Nota: para algunas operaciones de combinación izquierda, puede terminar con más filas si hay varias coincidencias entre ay, by deberá deduplicar ( documentación para la deduplicación ). Es por eso que pandas no guarda el índice por ti.

Wouter Overmeire
fuente
4
Muy inteligente. a.merge (b, how = "left"). set_index (a.index) también funciona, pero parece menos robusto (ya que la primera parte pierde los valores del índice en a antes de restablecerlos)
DanB
11
Para este caso particular, esos son equivalentes. Pero para muchas operaciones de combinación, el marco resultante no tiene el mismo número de filas que el amarco original . reset_index mueve el índice a una columna normal y set_index de esta columna después de la fusión también se ocupa cuando las filas de a se duplican / eliminan debido a la operación de fusión.
Wouter Overmeire
1
@Wouter Me encantaría saber por qué una combinación a la izquierda se reindexará de forma predeterminada. ¿Dónde puedo aprender más?
Mateo
7
¡Agradable! Para evitar especificar explícitamente el nombre de índice que uso a.reset_index().merge(b, how="left").set_index(a.index.names).
Truls
3
Pandas pensó mal que API ataca nuevamente.
Henry Henrinson
7

Puede hacer una copia del índice en el marco de datos izquierdo y fusionar.

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

Encontré este método simple muy útil al trabajar con marcos de datos grandes y usar pd.merge_asof()(odd.merge_asof() ).

Este enfoque sería superior cuando restablecer el índice es costoso (marco de datos grande).

Mateo hijo
fuente
1
Esta es la mejor respuesta. Hay muchas razones por las que querría conservar sus índices antiguos durante una fusión (y la respuesta aceptada no conserva los índices, simplemente los restablece). Ayuda cuando intentas fusionar más de 2 marcos de datos, y así sucesivamente ...
Marses
2
Solución superior ya que conserva el nombre de índice (original)
Martien Lubberink
votó a favor, pero tenga cuidado con una advertencia, cuando utilice múltiples índices, sus índices se almacenarán como una tupla en una sola columna llamada [copy_index]
geekidharsh
6

Hay una solución que no es pd.merge. Usando mapyset_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

Y no introduce un indexnombre ficticio para el índice.

Cero
fuente
1
Esto parece superior a la respuesta aceptada, ya que probablemente funcionará mejor con casos extremos como índices múltiples. ¿Alguien puede comentar sobre esto?
BallpointBen
1
pregunta, ¿qué pasa si necesita asignar varias columnas, este enfoque funcionaría o está limitado a solo 1 campo?
Yuca
@Yuca: Esto posiblemente no funcione con varias columnas, ya que cuando subestableces varias columnas terminas con un pd.Dataframey no un pd.Series. El .map()método solo está definido para pd.Series. Esto significa que: a[['to_merge_on_1', 'to_merge_on_2']].map(...)no funcionará.
Dataman
4
df1 = df1.merge(
        df2, how="inner", left_index=True, right_index=True
    )

Esto permite preservar el índice de df1

Supratik Majumdar
fuente
Parece que funciona, pero cuando lo uso con on=list_of_cols], contradice la documentación: If joining columns on columns, the DataFrame indexes *will be ignored*. ¿Tiene prioridad el uso de índices frente a columnas?
Itamar Katz
0

Creo que se me ocurrió una solución diferente. Me estaba uniendo a la tabla de la izquierda en el valor del índice y la tabla de la derecha en un valor de columna basado en el índice de la tabla de la izquierda. Lo que hice fue una fusión normal:

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

Luego recuperé los nuevos números de índice de la tabla combinada y los puse en una nueva columna llamada Número de línea de opinión:

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

Luego, volví a establecer manualmente el índice en el índice de la tabla izquierda original en función de la columna preexistente llamada Número de línea (el valor de columna al que me uní desde el índice de la tabla izquierda):

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

Luego eliminó el nombre de índice del Número de línea para que quede en blanco:

First10ReviewsJoined.index.name = None

Tal vez sea un truco, pero parece funcionar bien y relativamente simple. Además, suponga que reduce el riesgo de duplicados / alterar sus datos. Ojalá todo tenga sentido.

El desarrollador
fuente
0

otra opción simple es cambiar el nombre del índice a lo que era antes:

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

fusionar conserva el orden en el marco de datos 'a', pero simplemente restablece el índice para que se guarde para usar set_axis

lisrael1
fuente