如何在 python 中正确复制 excel sumproduct 函数?

How to replicate excel sumproduct function correctly in python?

我有一个像下面这样的数据框,我需要计算平均权重。在 excel 中,如果我使用 sumproduct 函数,我将得到 15.25 的结果。但是,当我使用以下代码时,它给了我 0。如何在代码中更正此问题?

import pandas as pd
df1 = { 'product1':['N/A'],
  'product2':[15.25],
  'p1 weight':[0],
  'p2 weight':[4]}

df1=pd.DataFrame(df1)
df1.fillna(0,inplace=True)


cols_left = [c for c in df1.columns if 'product' in c]
cols_right = [c for c in df1.columns if 'weight' in c]

result = (df1[cols_left] * df1[cols_right]).sum(axis=1) / df1[cols_right].sum(axis=1)
df1['result'] = result

结果如下

请注意,我必须使用 cols_left 和 cols_right 方法,因为在我的实际工作情况下,我有 +100 列需要根据相应的列。

我没有像df1['result1'] = (df1['product1'] * df1['p1 weight'] + df1['product2'] * df1['p2 weight'] )/ df1['p1 weight'] + df1['p2 weight']那样进行硬编码,而是在和积计算之前将cols_left和cols_right中的所有对应列分别分组。

非常感谢任何建议。

Pandas 支持(并强制)数据对齐。当您将一个操作应用于两个数据框时,该操作将应用于具有相同索引(名称)的行和列,而不是在相同的位置。要将操作应用于具有不同名称的一对列,您应该从中提取底层的 numpy 数组:

# Clean the NAs
import numpy as np
df1.replace("N/A", np.nan, inplace=True)

(df1[cols_left].fillna(0).values * df1[cols_right].values).sum() / df1[cols_right].sum(1)
#0    15.25

请注意 nan * 0 仍然是 nan。您必须将 nans 转换为有限数字(例如,转换为 0s)以获得数字结果。

Numpy 方法:

df1 for below examples is defined in the last section of my answer

解决此问题的 numpy 方法是采用 np.nanprod 后跟 .sum()。这个答案的灵感来自 this Whosebug solution.

A = df1.iloc[:,:2].values
B = df1.iloc[:,2:].values

num = np.nanprod(np.dstack((A,B)),2).sum(1)
den = df1.iloc[:,2:].sum(1)

df1['sumproduct'] = num/den
print(df1)
   product1  product2  p1 weight  p2 weight  sumproduct
0       NaN     15.25          0          4       15.25
1      10.0     10.00          2          3       10.00
2       8.0      2.00          5          1        7.00

Pandas方法:

Pandas' 方式可能有点复杂,因为 pandas.DataFrame.dot(这基本上是您想要的 sumproduct)不会给具有不同列名的数据帧带来很大的灵活性。但是,您可以将 pandas.groupby 与自定义石斑鱼一起使用来轻松完成产品。

尝试这种受 -

启发的方法
num_base_cols = 2 #number of columns per group
num_repeat = 2 #number of such groups

col_groups = np.tile(np.arange(num_base_cols), num_repeat) #[0,1,0,1] grouper

num = df1.groupby(col_groups, axis=1).prod().sum(1)
den = df1.iloc[:,2:].sum(1)

df1['sumproduct'] = num/den
print(df1)
   product1  product2  p1 weight  p2 weight  sumproduct
0       NaN     15.25          0          4       15.25
1      10.0     10.00          2          3       10.00
2       8.0      2.00          5          1        7.00

PS - 我使用此数据框和一些添加的行来演示上述解决方案。此外,我使用适当的 np.nan 而不是 NAN 字符串来实现真实的虚拟输入。

import pandas as pd
import numpy as np   #for adding proper Nans instead of strings

## added a few more rows for testing ##
#######################################
df1 = { 'product1':[np.nan,10,8],
        'product2':[15.25,10,2],
        'p1 weight':[0,2,5],
        'p2 weight':[4,3,1]}

df1=pd.DataFrame(df1)
#######################################