Gunakan data dalam bingkai data panda untuk mencocokkan kolom bersama

18

Saya memiliki dua pandasbingkai data, adan 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

dan

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

Dua frame data berisi data yang persis sama, tetapi dalam urutan yang berbeda dan dengan nama kolom yang berbeda. Berdasarkan angka dalam dua frame data, saya ingin dapat mencocokkan setiap nama kolom adengan setiap nama kolom di b.

Tidak semudah membandingkan baris pertama adengan baris pertama bkarena ada nilai duplikat, misalnya keduanya a4dan a7memiliki nilai 5sehingga tidak mungkin untuk segera mencocokkannya dengan salah satu b2atau b4.

Apa cara terbaik untuk melakukan ini?

OD1995
sumber

Jawaban:

16

Berikut cara menggunakan 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
sumber
Terima kasih telah berbagi perintah yang bagus, Anky, bisakah Anda menjelaskan lebih lanjut [*df1.index]? Akan berterima kasih padamu, tepuk tangan.
RavinderSingh13
1
@ RavinderSingh13 Tentu, sort_values(by=..)mengambil daftar sebagai parameter jadi saya membongkar indeks ke daftar di sini, Anda juga bisa melakukan list(df1.index)alih - alih [*df1.index]:)
anky
16

Ini salah satu cara meningkatkan 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'}

Pendekatan serupa lainnya (oleh @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
sumber
1
Aku menancapkan hidungku di posmu. Semoga Anda tidak keberatan. Harap ubah sesuai keinginan Anda.
piRSquared
Ah sebaliknya: Pendekatan yang bagus, dan memeriksa dataframe besar itu sedikit meningkatkan kinerja @piRSquared
yatu
12

Salah satu caranya 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
sumber
Saya pikir saya akan menambahkan solusi cerdas lain hanya untuk melihat bahwa itu sama dengan Anda (-: whoops.
piRSquared
8

pemahaman kamus

Gunakan tuplenilai kolom sebagai kunci hashable dalam kamus

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

Kalau-kalau kita tidak memiliki representasi yang sempurna, saya hanya menghasilkan kamus untuk kolom di mana ada kecocokan.

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

Ini berbatasan dengan absurd ... Jangan benar-benar melakukan ini.

{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'}
piRquared
sumber
1
Bagaimana mungkin, saya dapat memahami setiap ungkapan dalam pernyataan ini, namun tidak sepenuhnya melihat di kepala saya apa yang sebenarnya terjadi di sini? Agak suka catur, saya tahu cara menggerakkan semua bagian di papan tulis, tetapi tidak bisa melihat lebih banyak daripada yang bergerak maju.
Scott Boston
Oke ... Saya telah mencerna ini sekarang dan itu benar-benar sederhana, brilian. +1
Scott Boston