9

私は複数の列を持つpandasデータフレームを持っています。 「私は機能sum(axis=1)を見つけたが、それはdoesnのパンダの行のすべての要素の加重和の計算方法は?

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

:私は、行の値から新しい列weighted_sumを作成したいと別の列ベクトルデータフレームweight

weighted_sum次の値を持つ必要があります私にweightを乗せさせてください。

編集: 私は少し変わった。

weightは次のようになります。

 0 
col1 0.5 
col2 0.3 
col3 0.2 

dfは次のようになります。

col1 col2 col3 
1.0 2.2 3.5 
6.1 0.4 1.2 

df*weightNan値の全データフレームを返します。重みを仮定

+0

あなたの 'DataFrame'と' weights'のいくつかを表示できますか?なぜこれを行うのに問題があるのか​​は明らかではありません。行の値のドット積を 'weights'で求めたい場合、' ndarray.dot'メソッド 'row.values.dot(weights.values)'を使います。 –

答えて

9

異なるフレームのフレームに異なる行インデックスを掛けているのが問題です。ここでは解決策があります:

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 

あなたが列にアクセスすることができ、次のいずれか

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 

または一緒にそれをすべて持って来るために別のDataFrame

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

を取り戻すためにdotを使用します。

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 

各メソッドのtimeitがあります。大きい方はDataFrameです。広い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 

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 

ので、dotはより速く、より読みやすいです。

注:あなたのデータのいずれかがNaN Sが含まれている場合は、乗算及び加算方式を使用する必要があり、あなたがdotを使用しないでください。 (これはNaNを処理しません)の周りの単なる薄いラッパーなので、dotNaNを処理できません。

+0

私はこのスピードブーストによってかなり驚いていましたが、実際にはドットが同じ結果を生み出すかどうかはわかりません。 'df.mul(weight).sum(1)'はほぼ同じように見えます(少し遅い場合)。 –

+0

'df.dot(weight)'は 'df'と' weight'が 'DataFrames'の両方であれば' DataFrame'を生成し、 'Series'が' Series'であれば 'Series'を、' Series'であればスカラーを生成します。数値的には同等です。 –

+0

スピードアップはおそらく '*'操作で一時的に作成されたためです。 'dot'はそのような一時的なものを必要としません:) –

6

はあなただけ掛けることができ、その合計を行い、各列の重みのシリーズです:

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 

このアプローチの利点は、それはあなたが重量を量るしたくない列の世話をしています:

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