9

Mam ramkę danych pandy z wieloma kolumnami. Chcę utworzyć nową kolumnę weighted_sum od wartości w wierszu i inny dataframe kolumna wektor weightJak obliczyć ważoną sumę wszystkich elementów z rzędu w pandach?

weighted_sum powinna mieć następujące wartości:

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

Znalazłem funkcję sum(axis=1), ale nie robi” t pozwól mi pomnożyć z weight.

Edytuj: Zmieniłem trochę.

weight wygląda następująco:

 0 
col1 0.5 
col2 0.3 
col3 0.2 

df wygląda następująco:

col1 col2 col3 
1.0 2.2 3.5 
6.1 0.4 1.2 

df*weight zwraca dataframe pełen Nan wartości.

+0

Czy możesz pokazać niektóre z twoich 'DataFrame' i' wag "? Nie jest jasne, dlaczego masz problem z tym. Jeśli chcesz tylko użyć iloczynu wierszy wartości wierszy za pomocą 'wag", użyj metody 'ndarray.dot': row.values.dot (wag. Wartości)'. –

Odpowiedz

9

Problem polega na tym, że mnożysz ramkę z ramką o innym rozmiarze z innym indeksem wiersza. Oto rozwiązanie:

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 

Można też uzyskać dostęp do kolumny:

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 

Albo użyć dot wrócić inny DataFrame

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

Aby doprowadzić to wszystko razem:

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 

Oto timeit s każdej metody, używając większego 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 

Dla szerokiej 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 

Więc dot jest szybsza i bardziej czytelny.

UWAGA: Jeśli jakiekolwiek dane zawierają NaN s wówczas nie należy używać dot należy użyć metody pomnożyć-a-sum. dot nie może obsłużyć NaN s, ponieważ jest tylko cienką osłoną wokół numpy.dot() (która nie obsługuje NaN s).

+0

Byłem bardzo zaskoczony tym zwiększeniem prędkości, ale w rzeczywistości nie jestem pewien, czy kropka daje taki sam wynik. A 'df.mul (weight) .sum (1)' wydaje się mniej więcej taki sam (jeśli trochę wolniej). –

+0

'df.dot (waga)' spowoduje utworzenie 'DataFrame', jeśli' df' i 'weight' są zarówno' DataFrames', 'Series' jeśli albo jest' Series' i skalar jeśli oba są 'Series'. Numerycznie są one równoważne. –

+0

Przyspieszenie jest prawdopodobnie spowodowane tymczasowym utworzeniem przez operację '*'. 'kropka' nie potrzebuje takiego tymczasowego :) –

6

Zakładając ciężarów to seria wag dla poszczególnych kolumn, można tylko mnożyć i zrobić sumę:

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 

Zaletą tego podejścia jest to dba kolumn, które nie chcą ważyć :

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 
Powiązane problemy