Como manter o índice ao usar a mesclagem de pandas

126

Gostaria de mesclar dois DataFramese manter o índice do primeiro quadro como o índice no conjunto de dados mesclado. No entanto, quando faço a mesclagem, o DataFrame resultante possui um índice inteiro. Como posso especificar que quero manter o índice do quadro de dados esquerdo?

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

EDIT: Mudou para o código de exemplo que pode ser facilmente reproduzido

DanB
fonte
2
se você mesclar em uma coluna específica, não está claro quais índices usar (caso ambos sejam diferentes).
Bonobo

Respostas:

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 algumas operações de mesclagem à esquerda, você pode acabar com mais linhas se houver várias correspondências entre ae bserá necessário deduplicar ( documentação para deduplicação ). É por isso que os pandas não mantêm o índice para você.

Wouter Overmeire
fonte
4
Muito esperto. a.merge (b, how = "left"). set_index (a.index) também funciona, mas parece menos robusto (uma vez que a primeira parte perde os valores do índice para a antes de redefini-los.)
DanB
11
Para este caso em particular, esses são equivalentes. Porém, para muitas operações de mesclagem, o quadro resultante não possui o mesmo número de linhas que o aquadro original . reset_index move o índice para uma coluna regular e set_index dessa coluna após a mesclagem também cuida quando as linhas de uma são duplicadas / removidas devido à operação de mesclagem.
Wouter Overmeire
1
@ Wouter Gostaria de saber por que uma mesclagem esquerda será reindexada por padrão. Onde posso aprender mais?
Matthew
7
Agradável! Para evitar especificar explicitamente o nome do índice que eu uso a.reset_index().merge(b, how="left").set_index(a.index.names).
quer
3
Os pandas pensaram mal que a API ataca novamente.
Henry Henrinson
7

Você pode fazer uma cópia do índice no quadro de dados esquerdo e mesclar.

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

Achei esse método simples muito útil ao trabalhar com um dataframe grande e usando pd.merge_asof()(ou dd.merge_asof()).

Essa abordagem seria superior quando a redefinição do índice for cara (dataframe grande).

Matthew Son
fonte
1
Esta é a melhor resposta. Há muitas razões pelas quais você deseja preservar seus índices antigos durante uma mesclagem (e a resposta aceita não preserva os índices, apenas os redefine). Ela ajuda quando você está tentando mesclar mais de 2 dataframes, e assim por diante ...
Marses
2
Solução superior, uma vez que preserva o nome do índice (original)
Martien Lubberink
upvoted mas apenas ter cuidado com uma ressalva, ao usar multi-índice, os índices serão armazenados como uma tupla em uma única coluna chamada [copy_index]
geekidharsh
6

Existe uma solução não-pd.merge. Usando mapeset_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

E, não introduz um indexnome fictício para o índice.

Zero
fonte
1
Isso parece superior à resposta aceita, pois provavelmente funcionará melhor com casos extremos como multi-índices. Alguém pode comentar sobre isso?
usar o seguinte
1
pergunta, e se você precisar atribuir várias colunas, essa abordagem funcionaria ou está limitada a apenas um campo?
Yuca
@Yuca: Isso possivelmente não funcionará com várias colunas, pois quando você define subconjuntos de várias colunas, termina com a pd.Dataframee não a pd.Series. O .map()método é definido apenas para o pd.Series. Isso significa que: a[['to_merge_on_1', 'to_merge_on_2']].map(...)não funcionará.
Dataman
4
df1 = df1.merge(
        df2, how="inner", left_index=True, right_index=True
    )

Isso permite preservar o índice de df1

Supratik Majumdar
fonte
Parece que funciona, mas quando eu usá-lo com on=list_of_cols], ela contradiz a documentação: If joining columns on columns, the DataFrame indexes *will be ignored*. Um dos índices ou colunas tem precedência?
Itamar Katz
0

Acho que criei uma solução diferente. Eu estava ingressando na tabela esquerda no valor do índice e na tabela direita em um valor da coluna com base no índice da tabela esquerda. O que eu fiz foi uma mesclagem normal:

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

Em seguida, recuperei os novos números de índice da tabela mesclada e os coloquei em uma nova coluna denominada Número da linha de sentimento:

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

Em seguida, defino manualmente o índice de volta ao índice original da tabela esquerda, com base na coluna preexistente chamada Número da linha (o valor da coluna em que ingressei no índice da tabela esquerda):

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

Em seguida, remova o nome do índice do número da linha para que permaneça em branco:

First10ReviewsJoined.index.name = None

Talvez um pouco de hack, mas parece funcionar bem e relativamente simples. Além disso, acho que reduz o risco de duplicar / atrapalhar seus dados. Espero que tudo faça sentido.

o desenvolvedor
fonte
0

Outra opção simples é renomear o índice para o que era antes:

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

A mesclagem preserva a ordem no dataframe 'a', mas apenas redefine o índice para que seja salvo o uso de set_axis

lisrael1
fonte