9

У меня есть кадр данных pandas с несколькими столбцами. Я хочу, чтобы создать новый столбец weighted_sum из значений в строке, а другой вектор-столбец dataframe weightКак вычислить взвешенную сумму всех элементов в строке в пандах?

weighted_sum должен иметь следующее значение:

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

Я нашел функцию sum(axis=1), но это Безразлично» t позвольте мне размножаться с 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*weight возвращает dataframe полный Nan значений.

+0

Можете ли вы показать некоторые из ваших 'DataFrame' и' весов'? Непонятно, почему у вас проблемы с этим. Если вы просто хотите, чтобы точечный продукт значений строк с помощью «веса», используйте метод '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 

Или использовать dot, чтобы вернуться другой DataFrame

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

Свести все это вместе:

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 s каждого метода, используя более крупный 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 

Для широкого 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 

Так, dot быстрее и более удобным для чтения.

ПРИМЕЧАНИЕ: Если какой-либо из ваших данных содержат NaN сек, то вы не должны использовать dot вы должны использовать метод умножения-и-сумму. dot не может обрабатывать NaN s, поскольку это всего лишь тонкая обертка вокруг numpy.dot() (которая не обрабатывает NaN).

+0

Я был очень удивлен этим ускорением, но на самом деле я не уверен, что точка дает тот же результат. И 'df.mul (weight) .sum (1)' кажется примерно одинаковым (если немного медленнее). –

+0

'df.dot (weight)' будет генерировать 'DataFrame', если' df' и 'weight' являются' 'DataFrames''' '' '' 'если' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '. Численно они эквивалентны. –

+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 

 Смежные вопросы

  • Нет связанных вопросов^_^