Use dados nos quadros de dados do pandas para combinar as colunas

18

Eu tenho dois pandasquadros de dados ae b:

a1   a2   a3   a4   a5   a6   a7
1    3    4    5    3    4    5
0    2    0    3    0    2    1
2    5    6    5    2    1    2

e

b1   b2   b3   b4   b5   b6   b7
3    5    4    5    1    4    3
0    1    2    3    0    0    2
2    2    1    5    2    6    5

Os dois quadros de dados contêm exatamente os mesmos dados, mas em uma ordem diferente e com nomes de colunas diferentes. Com base nos números nos dois quadros de dados, eu gostaria de poder corresponder cada nome de coluna aa cada nome de coluna b.

Não é tão fácil quanto simplesmente comparar a primeira linha de acom a primeira linha de, bpois existem valores duplicados, por exemplo, ambos a4e a7possuem o valor, de 5modo que não é possível correspondê-los imediatamente a um b2ou a outro b4.

Qual é a melhor maneira de fazer isso?

OD1995
fonte

Respostas:

16

Aqui está uma maneira de usar sort_values:

m=df1.T.sort_values(by=[*df1.index]).index
n=df2.T.sort_values(by=[*df2.index]).index
d=dict(zip(m,n))
print(d)

{'a1': 'b5', 'a5': 'b1', 'a2': 'b7', 'a3': 'b6', 'a6': 'b3', 'a7': 'b2', 'a4': 'b4'}
anky
fonte
Obrigado por compartilhar o agradável comando Anky, você poderia explicar mais por [*df1.index]favor? Será grato a você, felicidades.
RavinderSingh13
11
@ RavinderSingh13 Claro, sort_values(by=..)pega uma lista como parâmetro, por isso estou desembalar o índice para uma lista aqui, você também pode fazer list(df1.index)em vez de [*df1.index]:)
anky
16

Aqui está uma maneira de aproveitar o numpy broadcasting:

b_cols = b.columns[(a.values == b.T.values[...,None]).all(1).argmax(1)]
dict(zip(a, b_cols))

{'a1': 'b5',
 'a2': 'b7',
 'a3': 'b6',
 'a4': 'b4',
 'a5': 'b1',
 'a6': 'b3',
 'a7': 'b2'}

Outra abordagem semelhante (por @piR):

a_ = a.to_numpy()
b_ = b.to_numpy()
i, j = np.where((a_[:, None, :] == b_[:, :, None]).all(axis=0))
dict(zip(a.columns[j], b.columns[i]))

{'a1': 'b5',
 'a2': 'b7',
 'a3': 'b6',
 'a4': 'b4',
 'a5': 'b1',
 'a6': 'b3',
 'a7': 'b2'}
yatu
fonte
11
Enfiei o nariz no seu post. Felizmente, você não se importa. Por favor, mude para o seu gosto.
piRSquared
Ah, pelo contrário :) Boa abordagem, e verificar grandes quadros de dados melhora ligeiramente o desempenho @piRSquared
yatu 13/01
12

Uma maneira de merge

s=df1.T.reset_index().merge(df2.T.assign(match=lambda x : x.index))
dict(zip(s['index'],s['match']))
{'a1': 'b5', 'a2': 'b7', 'a3': 'b6', 'a4': 'b4', 'a5': 'b1', 'a6': 'b3', 'a7': 'b2'}
YOBEN_S
fonte
Eu pensei em adicionar outra solução inteligente, apenas para ver que era a mesma que a sua (-: whoops.
piRSquared
8

compreensões de dicionário

Use um tupledos valores da coluna como chave hash em um dicionário

d = {(*t,): c for c, t in df2.items()}
{c: d[(*t,)] for c, t in df1.items()}

{'a1': 'b5',
 'a2': 'b7',
 'a3': 'b6',
 'a4': 'b4',
 'a5': 'b1',
 'a6': 'b3',
 'a7': 'b2'}

Para o caso de não termos uma representação perfeita, produzi apenas o dicionário para colunas em que há correspondência.

d2 = {(*t,): c for c, t in df2.items()}
d1 = {(*t,): c for c, t in df1.items()}

{d1[c]: d2[c] for c in {*d1} & {*d2}}

{'a5': 'b1',
 'a2': 'b7',
 'a7': 'b2',
 'a6': 'b3',
 'a3': 'b6',
 'a1': 'b5',
 'a4': 'b4'}

idxmax

Isso beira o absurdo ... Na verdade, não faça isso.

{c: df2.T.eq(df1[c]).sum(1).idxmax() for c in df1}

{'a1': 'b5',
 'a2': 'b7',
 'a3': 'b6',
 'a4': 'b4',
 'a5': 'b1',
 'a6': 'b3',
 'a7': 'b2'}
piRSquared
fonte
11
Como é que eu consigo entender cada expressão dessas afirmações, mas não ver completamente na minha cabeça o que realmente está acontecendo aqui? Meio que como xadrez, eu sei como mover toda a peça no tabuleiro, mas não consigo ver mais que 2 avançam.
Scott Boston
Ok ... Eu digeri isso agora e é absolutamente simplesmente ainda, brilhante. +1
Scott Boston