2017-08-31 2 views
0

Ich möchte zwei Pandas DataFrames zusammenführen. Wenn der Code item (z. B. A, B, C, D) derselbe ist, müssen ihre Attribute a, b gleich sein, aber b ist ein Nummernfeld oder eine Liste, die unhashable ist.Zusammenführen von Datenrahmen mit nicht abspeichernden Spalten

Foo:

item a  b    
A  1  [2,0] 
B  1  [3,0]   
C  0  [4,0]   

Bar:

item a  b 
A  1  [2,0] 
D  0  [6,1] 

Das ist, was ich will

code a  b  Foo Bar 
A  1  [2,0] 1  1 
B  1  [3,0] 1  0 
C  0  [4,0] 1  0 
D  0  [6,1] 0  1 

Antwort

4

Sie df.merge und df.fillna verwenden:

out = foo.assign(Foo=1).merge(bar.assign(Bar=1), 'outer').fillna(0) 
print(out) 

    item a  b Foo Bar 
0 A 1 (2, 0) 1.0 1.0 
1 B 1 (3, 0) 1.0 0.0 
2 C 0 (4, 0) 1.0 0.0 
3 D 0 (6, 1) 0.0 1.0 

Wenn b ein Listentyp ist, können Sie ihn zuerst in ein Tupel konvertieren und dann zusammenführen.

foo.b = foo.b.apply(tuple) 
bar.b = bar.b.apply(tuple) 
out = foo.assign(Foo=1).merge(bar.assign(Bar=1), 'outer').fillna(0) 
out.b = out.b.apply(list) 

print(out) 

    item a  b Foo Bar 
0 A 1 [2, 0] 1.0 1.0 
1 B 1 [3, 0] 1.0 0.0 
2 C 0 [4, 0] 1.0 0.0 
3 D 0 [6, 1] 0.0 1.0 
+0

wenn ich fusionieren, es gibt mir einen Fehler, b sagt, ist eine unhashable Typ numpy.ndarray – niukasu

+0

@niukasu Okay, also Ihre Frage zu Tupeln ist. Aber Sie arbeiten mit numpy Arrays :) –

+0

@niukasu Bearbeitet, sollte die zweite Lösung helfen. –

4

Hier ist eine Möglichkeit zum Zusammenführen, ohne die Unhashables in Tupel zu konvertieren.

Da der item Code eine 1-zu-1-Entsprechung mit den Werten in den a und b Spalten hat, genügt es, auf item allein zu verschmelzen. Da die Werte in der Spalte item hashable sind, ist es kein Problem verschmelzenden:

import pandas as pd 

foo = pd.DataFrame({'item': list('ABC'), 'a':[1,1,0], 'b':[[2,0], [3,0], [4,0]]}) 
bar = pd.DataFrame({'item': list('AD'), 'a':[1,0], 'b':[[2,0], [6,1]]}) 

result = pd.merge(foo.assign(Foo=1), bar.assign(Bar=1), on='item', how='outer', 
        suffixes=['', '_y']) 
for col in ['a','b']: 
    result[col].update(result[col+'_y']) 

for col in ['Foo', 'Bar']: 
    result[col] = result[col].fillna(0) 
result = result.drop(['a_y', 'b_y'], axis=1) 
print(result) 

ergibt

 a  b item Foo Bar 
0 1.0 [2, 0] A 1.0 1.0 
1 1.0 [3, 0] B 1.0 0.0 
2 0.0 [4, 0] C 1.0 0.0 
3 0.0 [6, 1] D 0.0 1.0 

Es ist ein bisschen von Ausbesserungsarbeiten nach der Zusammenführung benötigt, jedoch. Da wir nur auf item verschmelzen, wird result zwei Spalten von a und b - diejenigen von bar sind a_y genannt, und b_y. Die update Methode wird verwendet, um NaN Werte von a mit entsprechenden Werten von a_y, und dann das gleiche ist auch für b getan.

Die clevere Idee foo.assign(Foo=1), bar.assign(Bar=1) zu verwenden, um die Foo und Bar Spalten von cᴏʟᴅsᴘᴇᴇᴅ's solution genommen zu erhalten.

+0

Ich wusste, es gab einen Weg. Ich wusste nicht, es war so einfach wie eine Zusammenführung auf 'item'. Schöne. –

2

Oder Sie können versuchen, diese

foo.b = foo.b.apply(tuple) 
bar.b = bar.b.apply(tuple) 
df=pd.concat([foo,bar],axis=0).drop_duplicates() 
df['foo']=df.isin(foo).a.astype(int) 
df['bar']=df.isin(bar).a.astype(int) 
df.b=df.b.apply(list) 
df 
Out[60]: 
    a  b item foo bar 
0 1 [2, 0] A 1 1 
1 1 [3, 0] B 1 0 
2 0 [4, 0] C 1 0 
1 0 [6, 1] D 0 1 
1
cols = ['a', 'b', 'item'] 
pd.concat([Foo, Bar], keys=['Foo', 'Bar']) \ 
    .assign(c=1).pipe(lambda d: d.assign(b=d.b.apply(tuple))) \ 
    .set_index(cols, append=True) \ 
    .c.unstack(0, fill_value=0).reset_index(cols) \ 
    .pipe(lambda d: d.assign(b=d.b.apply(list))) 

    a  b item Bar Foo 
0 1 [2, 0] A 1 1 
1 0 [6, 1] D 1 0 
1 1 [3, 0] B 0 1 
2 0 [4, 0] C 0 1 
Verwandte Themen