4

配列要素のサブセットの積を返す関数を作成しようとしています。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)

そして、結果Vprodsは次のようになります。

Vprods
array([6, 4, 30])

https://stackoverflow.com/a/4387453/1085691に似ているはずの要素の合計について、ここに素晴らしい答えがあり ます。

log最初に、次にsum_by_group、次に、をとってみましexpたが、数値の問題に遭遇しました。

グループごとの要素の最小値と最大値について、他にも同様の回答がいくつかあります: https ://stackoverflow.com/a/8623168/1085691

編集:迅速な回答をありがとう!私はそれらを試しています。できるだけ速くしたいということを付け加えておきます(これが、私が示した例のように、ベクトル化された方法で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)
4

5 に答える 5

2

グループがすでに並べ替えられている場合(そうでない場合はで行うことができます)、sの機能をnp.argsort使用してこれを行うことができます(並べ替えられていない場合は、効率的に行うために最初に並べ替える必要があります)。reduceatufunc

# 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)

または、グループが少ない場合はmgilsonが答えます。ただし、グループが多い場合は、これがはるかに効率的です。すべてのグループの元の配列のすべての要素のブールインデックスを回避するため。さらに、reduceatを使用してPythonループでスライスすることを避けます。

もちろん、パンダはこれらの操作を便利に行います。

編集:申し訳ありませんがprodそこにありました。ufuncはmultiplyです。このメソッドは、任意のバイナリに使用できますufunc。これは、2つの入力配列で要素ごとに機能する基本的にすべてのnumpy関数で機能することを意味します。(つまり、multiplyは通常、2つの配列を要素ごとに乗算し、addはそれらを加算し、最大/最小など)

于 2012-11-16T20:04:18.497 に答える
1

最初に、グループを別の次元で展開するようにグループのマスクを設定します

mask=(groups==unique(groups).reshape(-1,1))
mask
array([[ True,  True,  True, False, False, False],
       [False, False, False,  True, False, False],
       [False, False, False, False,  True,  True]], dtype=bool)

今、私たちはvalを掛けます

mask*val
array([[1, 2, 3, 0, 0, 0],
       [0, 0, 0, 4, 0, 0],
       [0, 0, 0, 0, 5, 6]])

これで、修正が簡単なゼロを除いて、軸1に沿ってすでにprodを実行できます。

prod(where(mask*val,mask*val,1),axis=1)
array([ 6,  4, 30])
于 2012-11-16T20:03:52.467 に答える
1

コメントで示唆されているように、Pandasモジュールを使用することもできます。この関数を使用するgrouby()と、このタスクはワンライナーになります。

import numpy as np
import pandas as pd

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

df = pd.DataFrame({'values': values, 'groups': groups})

したがってdf、次のようになります。

   groups  values
0       1       1
1       1       2
2       1       3
3       2       4
4       3       5
5       3       6

これで、このように各グループに列とnumpyの関数groupby()groups追加applyできますprod()

 df.groupby(groups)['values'].apply(np.prod)

これにより、目的の出力が得られます。

1     6
2     4
3    30
于 2016-06-30T23:11:50.440 に答える
0

まあ、これが素晴らしい答えだとは思えませんが、私が思いつくことができる最高のものです:

np.array([np.product(values[np.flatnonzero(groups == x)]) for x in np.unique(groups)])
于 2012-11-16T20:02:31.340 に答える
0

それは厄介な解決策ではありませんが、かなり読みやすいです(私は時々厄介な解決策がそうではないことがわかります!):

from operator import itemgetter, mul
from itertools import groupby

grouped = groupby(zip(groups, values), itemgetter(0))
groups = [reduce(mul, map(itemgetter(1), vals), 1) for key, vals in grouped]
print groups
# [6, 4, 30]
于 2012-11-16T20:07:44.743 に答える