2016-07-12 1 views
0

J'ai un dataframe df qui ressemble à ceci:Création d'une nouvelle matrice à partir dataframe et de la matrice en pandas géants

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 

Et une matrice similitude mat entre les éléments de la colonne id2:

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 

maintenant Je voudrais créer une matrice de similarité entre les éléments de id1 et les éléments de id2. Pour cela je considère les éléments de id1 comme des barycentres des éléments correspondants de id2 ind dans mon dataframe df (avec le weights correspondant).

Ma première tentative de le faire est avec des boucles (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() 

Mais bien sûr, c'est pas ainsi pythonique, et prend les âges (timeit pour ces petits matrice a montré 21.3ms pas calculable pour un 10k- rangées df et 3k par 3k mat). Quelle serait une façon plus propre/efficace de le faire?

débit désiré:

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 

Et il est un moyen pour calculer une matrice de similarité entre les éléments de id1 (à partir de ces données)?

Merci d'avance.

Répondre

2

Les horloges suivantes à 6 – 7ms (contre environ 30ms que votre approche prend sur ma machine).

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)  

Sortie:

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

Vous êtes un génie, maintenant sur mon dataframe d'origine, il prend moins de 2 secondes ... Il évolue parfaitement, upvoted et accepté, merci! – ysearka

+0

Ok mon diable, ça marche bien dans mon échantillon (1% de mon dataframe), mais ça prend 10 minutes sur le gros. Et quand j'essaie de le réappliquer pour obtenir une matrice «id1»/«id1», je reçois un message d'erreur. – ysearka