12 votes

Comment calculer la somme pondérée de tous les éléments d'une ligne dans pandas ?

J'ai un cadre de données pandas avec plusieurs colonnes. Je veux créer une nouvelle colonne weighted_sum à partir des valeurs de la ligne et d'un autre vecteur colonne du dataframe weight

weighted_sum doit avoir la valeur suivante :

row[weighted_sum] = row[col0]*weight[0] + row[col1]*weight[1] + row[col2]*weight[2] + ...

J'ai trouvé la fonction sum(axis=1) mais il ne me permet pas de multiplier avec weight .

Modifier : J'ai changé un peu les choses.

weight ressemble à ça :

     0
col1 0.5
col2 0.3
col3 0.2

df ressemble à ça :

col1 col2 col3
1.0  2.2  3.5
6.1  0.4  1.2

df*weight renvoie un cadre de données rempli de Nan valeurs.

14voto

Phillip Cloud Points 6685

Le problème est que vous multipliez un cadre avec un cadre d'une taille différente avec un indice de ligne différent. Voici la solution :

In [121]: df = DataFrame([[1,2.2,3.5],[6.1,0.4,1.2]], columns=list('abc'))

In [122]: weight = DataFrame(Series([0.5, 0.3, 0.2], index=list('abc'), name=0))

In [123]: df
Out[123]:
           a          b          c
0       1.00       2.20       3.50
1       6.10       0.40       1.20

In [124]: weight
Out[124]:
           0
a       0.50
b       0.30
c       0.20

In [125]: df * weight
Out[125]:
           0          a          b          c
0        nan        nan        nan        nan
1        nan        nan        nan        nan
a        nan        nan        nan        nan
b        nan        nan        nan        nan
c        nan        nan        nan        nan

Vous pouvez soit accéder à la colonne :

In [126]: df * weight[0]
Out[126]:
           a          b          c
0       0.50       0.66       0.70
1       3.05       0.12       0.24

In [128]: (df * weight[0]).sum(1)
Out[128]:
0         1.86
1         3.41
dtype: float64

Ou utilisez dot pour récupérer un autre DataFrame

In [127]: df.dot(weight)
Out[127]:
           0
0       1.86
1       3.41

Pour rassembler tout ça :

In [130]: df['weighted_sum'] = df.dot(weight)

In [131]: df
Out[131]:
           a          b          c  weighted_sum
0       1.00       2.20       3.50          1.86
1       6.10       0.40       1.20          3.41

Voici les timeit de chaque méthode, en utilisant une plus grande DataFrame .

In [145]: df = DataFrame(randn(10000000, 3), columns=list('abc'))
weight
In [146]: weight = DataFrame(Series([0.5, 0.3, 0.2], index=list('abc'), name=0))

In [147]: timeit df.dot(weight)
10 loops, best of 3: 57.5 ms per loop

In [148]: timeit (df * weight[0]).sum(1)
10 loops, best of 3: 125 ms per loop

Pour un large DataFrame :

In [162]: df = DataFrame(randn(10000, 1000))

In [163]: weight = DataFrame(randn(1000, 1))

In [164]: timeit df.dot(weight)
100 loops, best of 3: 5.14 ms per loop

In [165]: timeit (df * weight[0]).sum(1)
10 loops, best of 3: 41.8 ms per loop

Donc, dot est plus rapide et plus lisible.

NOTE : Si l'une de vos données contient NaN alors vous ne devez pas utiliser dot vous devez utiliser la méthode de multiplication et de sommation. dot ne peut pas gérer NaN puisqu'il ne s'agit que d'une enveloppe fine autour de l'outil numpy.dot() (qui ne gère pas NaN s).

10voto

Andy Hayden Points 38010

En supposant que les poids sont une série de poids pour chaque colonne, vous pouvez simplement multiplier et faire la somme :

In [11]: df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=['a', 'b', 'c'])

In [12]: weights = pd.Series([7, 8, 9], index=['a', 'b', 'c'])

In [13]: (df * weights)
Out[13]: 
    a   b   c
0   7  16  27
1  28  40  54

In [14]: (df * weights).sum(1)
Out[14]: 
0     50
1    122
dtype: int64

L'avantage de cette approche est qu'elle prend en charge les colonnes que vous ne voulez pas peser :

In [21]: weights = pd.Series([7, 8], index=['a', 'b'])

In [22]: (df * weights)
Out[22]: 
    a   b   c
0   7  16 NaN
1  28  40 NaN

In [23]: (df * weights).sum(1)
Out[23]: 
0    23
1    68
dtype: float64

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X