numpy (Python) 中按组计算数组元素的乘积

Nat*_*ate 5 python numpy

我正在尝试构建一个返回数组元素子集的乘积的函数。基本上我想构建一个prod_by_group执行此操作的函数:

values = np.array([1, 2, 3, 4, 5, 6])
groups = np.array([1, 1, 1, 2, 3, 3])

Vprods = prod_by_group(values, groups)
Run Code Online (Sandbox Code Playgroud)

结果Vprods应该是:

Vprods
array([6, 4, 30])
Run Code Online (Sandbox Code Playgroud)

对于元素之和,这里有一个很好的答案,我认为它应该类似于: /sf/answers/307121741/

我尝试采取log第一个,然后sum_by_group,然后exp,但遇到了数字问题。

对于按组排列的元素的最小和最大数量,这里还有一些其他类似的答案: /sf/answers/603621791/

编辑:感谢您的快速解答!我正在尝试它们。我应该补充一点,我希望它尽可能快(这就是我试图以某种矢量化方式将其放入 numpy 的原因,就像我给出的示例一样)。

编辑:我评估了迄今为止给出的所有答案,最好的答案由下面的 @seberg 给出。这是我最终使用的完整功能:

def prod_by_group(values, groups):
    order = np.argsort(groups)
    groups = groups[order]
    values = values[order]
    group_changes = np.concatenate(([0], np.where(groups[:-1] != groups[1:])[0] + 1))
    return np.multiply.reduceat(values, group_changes)
Run Code Online (Sandbox Code Playgroud)

seb*_*erg 3

如果您的组已经排序(如果没有排序,则可以使用 进行排序np.argsort),您可以使用s 的reduceat功能来执行此ufunc操作(如果它们未排序,则必须先对它们进行排序才能有效地进行排序):

# you could do the group_changes somewhat faster if you care a lot
group_changes = np.concatenate(([0], np.where(groups[:-1] != groups[1:])[0] + 1))
Vprods = np.multiply.reduceat(values, group_changes)
Run Code Online (Sandbox Code Playgroud)

如果你有几个小组,或者 mgilson 回答。但如果你有很多组,那么这会更有效率。因为您避免为每个组的原始数组中的每个元素使用布尔索引。另外,您可以避免使用reduceat 在Python 循环中进行切片。

当然,pandas 很方便地完成这些操作。

编辑:抱歉prod在那里。ufunc 是multiply. 您可以对任何二进制文件使用此方法ufunc。这意味着它基本上适用于所有可以在两个输入数组上按元素工作的 numpy 函数。(即,乘法通常将两个数组按元素相乘,加法将它们相加,最大值/最小值等等)