Numpy:与唯一坐标位置对应的值的平均值

qybjjes1  于 2022-11-29  发布在  其他
关注(0)|答案(5)|浏览(129)

所以,我已经浏览stackoverflow很长一段时间了,但我似乎找不到解决我的问题的方法
考虑一下

import numpy as np
coo = np.array([[1, 2], [2, 3], [3, 4], [3, 4], [1, 2], [5, 6], [1, 2]])
values = np.array([1, 2, 4, 2, 1, 6, 1])

coo数组包含(x,y)坐标位置x =(1,2,3,3,1,5,1)y =(2,3,4,4,2,6,2)
而值数组是这个网格点的某种数据。
现在我想得到每个唯一网格点的所有值的平均值。例如,坐标(1,2)出现在位置(0,4,6),所以对于这个点,我想得到values[[0, 4, 6]]
如何为所有唯一的网格点获取此信息?

k97glaaz

k97glaaz1#

可以用np.lexsortcoo进行排序,将重复的XY连续排列起来。然后沿着行运行np.diff,得到排序版本中唯一XY的开始掩码。使用该掩码,您可以创建一个ID数组,使重复项具有相同的ID。然后,ID数组可以与np.bincount一起使用,以获得具有相同ID的所有值的总和以及它们的计数,从而获得平均值,作为最终输出。

# Use lexsort to bring duplicate coo XY's in succession
sortidx = np.lexsort(coo.T)
sorted_coo =  coo[sortidx]

# Get mask of start of each unique coo XY
unqID_mask = np.append(True,np.any(np.diff(sorted_coo,axis=0),axis=1))

# Tag/ID each coo XY based on their uniqueness among others
ID = unqID_mask.cumsum()-1

# Get unique coo XY's
unq_coo = sorted_coo[unqID_mask]

# Finally use bincount to get the summation of all coo within same IDs 
# and their counts and thus the average values
average_values = np.bincount(ID,values[sortidx])/np.bincount(ID)

样品运行-

In [65]: coo
Out[65]: 
array([[1, 2],
       [2, 3],
       [3, 4],
       [3, 4],
       [1, 2],
       [5, 6],
       [1, 2]])

In [66]: values
Out[66]: array([1, 2, 4, 2, 1, 6, 1])

In [67]: unq_coo
Out[67]: 
array([[1, 2],
       [2, 3],
       [3, 4],
       [5, 6]])

In [68]: average_values
Out[68]: array([ 1.,  2.,  3.,  6.])
1qczuiv0

1qczuiv02#

您可以使用where

>>> values[np.where((coo == [1, 2]).all(1))].mean()
1.0
piok6c0g

piok6c0g3#

它很可能会更快地拉平你的指数,即:

flat_index = coo[:, 0] * np.max(coo[:, 1]) + coo[:, 1]

然后对其使用np.unique

unq, unq_idx, unq_inv, unq_cnt = np.unique(flat_index,
                                           return_index=True,
                                           return_inverse=True,
                                           return_counts=True)
unique_coo = coo[unq_idx]
unique_mean = np.bincount(unq_inv, values) / unq_cnt

比使用lexsort的类似方法更有效。
但在引擎盖下的方法实际上是相同的。

wd2eg0qa

wd2eg0qa4#

这是一个使用numpy_indexed软件包的简单一行代码(免责声明:我是它的作者):

import numpy_indexed as npi
unique, mean = npi.group_by(coo).mean(values)

应该在性能上与目前公认的答案相媲美,就像它在引擎盖下所做的类似事情一样;但是所有这些都包含在一个经过良好测试的软件包中,并且有一个很好的界面。

8gsdolmq

8gsdolmq5#

另一种方法是使用JAX uniquegrad。这种方法可能特别快,因为它允许在加速器(CPU、GPU或TPU)上运行。

import functools
import jax
import jax.numpy as jnp

@jax.grad
def _unique_sum(unique_values: jnp.ndarray, unique_inverses: jnp.ndarray, values: jnp.ndarray):
    errors = unique_values[unique_inverses] - values
    return -0.5*jnp.dot(errors, errors)

@functools.partial(jax.jit, static_argnames=['size'])
def unique_mean(indices, values, size):
    unique_indices, unique_inverses, unique_counts = jnp.unique(indices, axis=0, return_inverse=True, return_counts=True, size=size)
    unique_values = jnp.zeros(unique_indices.shape[0], dtype=float)
    return unique_indices, _unique_sum(unique_values, unique_inverses, values) / unique_counts

coo = jnp.array([[1, 2], [2, 3], [3, 4], [3, 4], [1, 2], [5, 6], [1, 2]])
values = jnp.array([1, 2, 4, 2, 1, 6, 1])
unique_coo, unique_mean = unique_mean(coo, values, size=4)
print(unique_mean.block_until_ready())

唯一奇怪的是size参数,因为JAX要求所有数组的大小都是固定的,如果你把size设置得太小,它会给出好的结果,太大,它会返回nan的。

相关问题