2016-07-12 21 views
0

Ich habe einen Datenrahmen df, die wie folgt aussieht:Erstellen neue Matrix von Datenrahmen und Matrix in Pandas

id1 id2 weights 
0 a 2a 144.0 
1 a 2b 52.5 
2 a 2c 2.0 
3 a 2d 1.0 
4 a 2e 1.0 
5 b 2a 2.0 
6 b 2e 1.0 
7 b 2f 1.0 
8 b 2b 1.0 
9 b 2c 0.008 

Und eine Ähnlichkeitsmatrix mat zwischen den Elementen der id2 Säule:

2a 2b 2c 2d 2e 2f 
2a 1  0.5 0.7 0.2 0.1 0.3 
2b 0.5 1 0.6 0.4 0.3 0.4 
2c 0.7 0.6 1 0.1 0.4 0.2 
2d 0.2 0.4 0.1 1 0.8 0.7 
2e 0.1 0.3 0.4 0.8 1 0.8 
2f 0.3 0.4 0.2 0.7 0.8 1 

Jetzt Ich möchte eine Ähnlichkeitsmatrix zwischen den Elementen id1 und den Elementen aus id2 erstellen. Dafür betrachte ich die Elemente id1 als Barycentres der entsprechenden Elemente von id2 ind meinen Datenrahmen df (mit der entsprechenden weights).

Mein erster Versuch, das zu tun ist mit Schlaufen (aouch):

ids = df.id1.unique() 
output = pd.DataFrame(columns = mat.columns,index = ids) 
for id in ids: 
    df_slice = df.loc[df.id1 == id] 
    to_normalize = df_slice.weights.sum() 
    temp = mat.loc[df_slice.id2] 
    for art in df_slice.id2: 
     temp.loc[art] *= df_slice.ix[df_slice.id2 == art,'weights'].values[0] 
     temp.loc[art] /= (1.*to_normalize) 
    output.loc[id] = temp.sum() 

Aber natürlich nicht auf diese Weise pythonic ist, und nimmt im Alter (timeit für diese kleine Matrix zeigte 21.3ms nicht berechenbar für ein 10k Reihen df und 3k durch 3k mat). Was wäre ein sauberer/effizienter Weg, dies zu tun?

Ausgaben gewünscht:

2a   2b   2c   2d   2e   2f 
a 0.857606 0.630424 0.672319 0.258354 0.163342 0.329676 
b 0.580192 0.540096 0.520767 0.459425 0.459904 0.559425 

Und gibt es eine Möglichkeit, eine andere Ähnlichkeitsmatrix zwischen den Elementen id1 (aus diesen Daten) zu berechnen?

Vielen Dank im Voraus.

Antwort

2

Die folgenden Uhren in 6 – 7ms (vs. etwa 30ms, dass Ihre Annäherung auf meinem Rechner dauert).

import io 

import pandas as pd 


raw_df = io.StringIO("""\ 
    id1 id2 weights 
0 a 2a 144.0 
1 a 2b 52.5 
2 a 2c 2.0 
3 a 2d 1.0 
4 a 2e 1.0 
5 b 2a 2.0 
6 b 2e 1.0 
7 b 2f 1.0 
8 b 2b 1.0 
9 b 2c 0.008 
""") 
df = pd.read_csv(raw_df, delim_whitespace=True) 

raw_mat = io.StringIO("""\ 
    2a 2b 2c 2d 2e 2f 
2a 1  0.5 0.7 0.2 0.1 0.3 
2b 0.5 1 0.6 0.4 0.3 0.4 
2c 0.7 0.6 1 0.1 0.4 0.2 
2d 0.2 0.4 0.1 1 0.8 0.7 
2e 0.1 0.3 0.4 0.8 1 0.8 
2f 0.3 0.4 0.2 0.7 0.8 1 
""") 
mat = pd.read_csv(raw_mat, delim_whitespace=True) 


df['norm'] = df.groupby('id1')['weights'].transform('sum') 

m = pd.merge(df, mat, left_on='id2', right_index=True) 
m[mat.index] = m[mat.index].multiply(m['weights']/m['norm'], axis=0) 

output = m.groupby('id1')[mat.index].sum() 
output.columns.name = 'id2' 
print(output)  

Ausgang:

id2  2a  2b  2c  2d  2e  2f 
id1                
a 0.857606 0.630424 0.672319 0.258354 0.163342 0.329676 
b 0.580192 0.540096 0.520767 0.459425 0.459904 0.559425 
+0

Du bist ein Genie, jetzt auf meinem ursprünglichen Datenrahmen dauert es weniger als 2 Sekunden ... Es perfekt Waage, upvoted und akzeptiert, danke! – ysearka

+0

Ok mein Fehler, es funktioniert gut in meiner Probe (1% meines Datenrahmens), aber dauert 10 Minuten auf dem großen. Und wenn ich versuche, es erneut anzuwenden, um eine Matrix "id1"/"id1" zu bekommen, bekomme ich einen memorryrerror .. – ysearka