71650


現在、Pythonで重複する値の平均を出そうとしています。  
具体的には、

[code]

    x = np.array([0, 0, 1, 1, 1])
    y = np.array([0, 0, 1, 0, 0])
    z = np.array([2, 3, 4, 3, 6])
    
[/code]

という配列から、

[code]

    new_x = np.array([0, 1, 1])
    new_y = np.array([0, 1, 0])
    new_z = np.array([2.5, 5., 3.])
    
[/code]

もしくは

[code]

    new_x = np.array([0, 0, 1, 1, 1])
    new_y = np.array([0, 0, 1, 0, 0])
    new_z = np.array([2.5, 2.5, 5., 3., 5.])
    
[/code]

という値が欲しいです。  
`x`と`y`はインデックスの値、`z[i]`は(`x[i]`, `y[i]`)のときの値で  
`x[0] == x[1], y[0] == y[1]`なので、`new_z`の要素に`z[0]`と`z[1]`の平均を入るという処理がしたいです。  
なにかいい案はないでしょうか？


CC BY-SA 4.0
2020-09-28T10:02:52.393
70782
2020-11-30T01:59:34.427
42083
question
python numpy
PythonのNumPyの値が重複しているときの平均値を求めたい


NumPyを使った方法ではありませんが、いかがでしょうか。700～800個程度のデータでしたらパフォーマンス的には問題ないかと思います。

[code]

    x = [0, 0, 1, 1, 1]
    y = [0, 0, 1, 0, 1]
    z = [2, 3, 4, 3, 6]
    
    from collections import defaultdict, Counter
    z_total = defaultdict(lambda: 0)
    z_count = Counter()
    
    for xi, yi, zi in zip(x, y, z):
        z_total[(xi, yi)] += zi
        z_count[(xi, yi)] += 1
    
    indexes = set((xi, yi) for xi, yi in zip(x, y))
    z_average = {k: z_total[k] / z_count[k] for k in indexes}
    
    new_x = [0, 0, 1, 1, 1]
    new_y = [0, 0, 1, 0, 0]
    new_z = [z_average[k] for k in zip(new_x, new_y)]
    
    new_z
    # [2.5, 2.5, 5.0, 3.0, 3.0]
    
[/code]


CC BY-SA 4.0
2020-09-28T18:20:49.813
70787
2020-09-29T01:58:15.260
2020-09-29T01:58:15.260
36398
36398
70782
answer


[`np.ravel_multi_index()`](https://numpy.org/doc/stable/reference/generated/numpy.ravel_multi_index.html)（あるいは[`np.unique()`](https://numpy.org/doc/stable/reference/generated/numpy.unique.html)等でも可能）を用いて、（x,
y）の二次元座標を一次元座標に変換した後、[`np.bincount()`](https://numpy.org/doc/stable/reference/generated/numpy.bincount.html)を用いて各座標の合計と総数を計算します。

例：

[code]

    def pos_means1(x, y, z):
        xy = np.ravel_multi_index([x, y], (x.max()+1, y.max()+1))
        means = np.bincount(xy, z) / np.bincount(xy)
        return means[xy]
    
    
    def pos_means2(x, y, z):
        unq, xy, cnt = np.unique([x, y], axis=1,
                                 return_inverse=True, return_counts=True)
        means = np.bincount(xy, z) / cnt
        return unq[0], unq[1], means
    
[/code]

動作：

[code]

    In [4]: x = np.array([0, 0, 1, 1, 1])
       ...: y = np.array([0, 0, 1, 0, 1])
       ...: z = np.array([2, 3, 4, 3, 6])
    
    In [5]: pos_means1(x, y, z)
    Out[5]: array([2.5, 2.5, 5. , 3. , 5. ])
    
    In [6]: pos_means2(x, y, z)
    Out[6]: (array([0, 1, 1]),
             array([0, 0, 1]),
             array([2.5, 3. , 5. ]))
    
[/code]


CC BY-SA 4.0
2020-11-02T01:42:19.137
71650
2020-11-30T01:59:34.427
2020-11-30T01:59:34.427
37167
37167
70782
answer


シンプルに。。。

[code]

    x = [0, 0, 1, 1, 1]
    y = [0, 0, 1, 0, 1]
    z = [2, 3, 4, 3, 6]
    
    lst = [[(xi, yi), zi] for xi, yi, zi in zip(x, y, z)]
    dic = {k:sum(map(lambda x:x[1] if x[0]==k else 0, lst))/
             sum(map(lambda x:x[0]==k, lst)) for k, v in lst}
    
    new_x = [0, 0, 1, 1, 1]
    new_y = [0, 0, 1, 0, 0]
    new_z = [dic[k] for k in zip(new_x, new_y)]
    print(new_z)  # [2.5, 2.5, 5.0, 3.0, 3.0]
    
[/code]

numpy の array も同じパターンで

[code]

    import numpy as np
    
    x = np.array([0, 0, 1, 1, 1])
    y = np.array([0, 0, 1, 0, 1])
    z = np.array([2, 3, 4, 3, 6])
    
    lst = [[(xi, yi), zi] for xi, yi, zi in zip(x, y, z)]
    dic = {k:sum(map(lambda x:x[1] if x[0]==k else 0, lst))/
             sum(map(lambda x:x[0]==k, lst)) for k, v in lst}
    
    new_x = np.array([0, 0, 1, 1, 1])
    new_y = np.array([0, 0, 1, 0, 0])
    new_z = np.array([dic[k] for k in zip(new_x, new_y)])
    print(new_z) # [2.5 2.5 5.  3.  3. ]
    
[/code]


CC BY-SA 4.0
2020-11-02T09:32:36.590
71667
2020-11-02T09:32:36.590
41756
70782
answer