如何在numpy的ndarray中找到最常见的值?

21

我有一个形状为(30,480,640)的numpy ndarray,其中第1和第2个轴代表地理位置(纬度和经度),第0个轴包含实际数据点。我想在每个位置沿着第0个轴使用最频繁的值,以构建一个新数组,其形状为(1,480,640)。

>>> data
array([[[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]],

       [[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]],

       [[40, 40, 42, 43, 44],
        [45, 46, 47, 48, 49],
        [50, 51, 52, 53, 54],
        [55, 56, 57, 58, 59]]])

(perform calculation)

>>> new_data 
array([[[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]]])

数据点将包含正负浮点数。 我该如何执行这样的计算? 非常感谢!

我尝试使用numpy.unique,但是我收到了“TypeError:unique()获得了意外的关键字参数'return_inverse'”错误消息。 我正在使用在Unix上安装的numpy版本1.2.1,并且它不支持return_inverse..我还尝试过mode,但它需要处理如此大量的数据而花费很长时间...那么有没有替代方法可以获取最频繁出现的值? 再次感谢。


2
什么是主导值?我不理解这个问题。 - Henry Gomersall
我也支持@HenryGomersall的评论 - 我也不知道你的问题是什么... - Jon Clements
抱歉让您感到困惑...我的意思是最常见的值。 - oops
这个回答解决了你的问题吗?在numpy数组中找到众数的最有效方法 - mpx
5个回答

27

要找到平坦数组中出现最频繁的值,请使用 uniquebincountargmax

arr = np.array([5, 4, -2, 1, -2, 0, 4, 4, -6, -1])
u, indices = np.unique(arr, return_inverse=True)
u[np.argmax(np.bincount(indices))]

要使用多维数组,我们不需要担心unique,但是我们需要在bincount上使用apply_along_axis

arr = np.array([[5, 4, -2, 1, -2, 0, 4, 4, -6, -1],
                [0, 1,  2, 2,  3, 4, 5, 6,  7,  8]])
axis = 1
u, indices = np.unique(arr, return_inverse=True)
u[np.argmax(np.apply_along_axis(np.bincount, axis, indices.reshape(arr.shape),
                                None, np.max(indices) + 1), axis=axis)]

使用您的数据:

data = np.array([
   [[ 0,  1,  2,  3,  4],
    [ 5,  6,  7,  8,  9],
    [10, 11, 12, 13, 14],
    [15, 16, 17, 18, 19]],

   [[ 0,  1,  2,  3,  4],
    [ 5,  6,  7,  8,  9],
    [10, 11, 12, 13, 14],
    [15, 16, 17, 18, 19]],

   [[40, 40, 42, 43, 44],
    [45, 46, 47, 48, 49],
    [50, 51, 52, 53, 54],
    [55, 56, 57, 58, 59]]])
axis = 0
u, indices = np.unique(arr, return_inverse=True)
u[np.argmax(np.apply_along_axis(np.bincount, axis, indices.reshape(arr.shape),
                                None, np.max(indices) + 1), axis=axis)]
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19]])
NumPy 1.2,真的吗?您可以使用np.searchsorted相对高效地近似实现np.unique(return_inverse=True)(它会增加一个O(n log n),因此不应显着改变性能):
u = np.unique(arr)
indices = np.searchsorted(u, arr.flat)

@ ecatmur,我正在使用numpy版本1.2.1,它不支持np.unique(return_inverse)。有什么建议吗? - oops
1
@oops 请参考上面的内容,因为我甚至不知道在哪里找到这么旧的numpy版本,所以你需要自己测试一下。 - ecatmur
对于更多维度的大型ndarray,这种方法并不是很适合,因为它会分配一个大小为(N_dim1,N_dim2,...,N_unique)的数组,而这个大小会非常快地失控。 - CheshireCat

9
使用SciPy的mode函数:
import numpy as np
from scipy.stats import mode

data = np.array([[[ 0,  1,  2,  3,  4],
                  [ 5,  6,  7,  8,  9],
                  [10, 11, 12, 13, 14],
                  [15, 16, 17, 18, 19]],

                 [[ 0,  1,  2,  3,  4],
                  [ 5,  6,  7,  8,  9],
                  [10, 11, 12, 13, 14],
                  [15, 16, 17, 18, 19]],

                 [[40, 40, 42, 43, 44],
                  [45, 46, 47, 48, 49],
                  [50, 51, 52, 53, 54],
                  [55, 56, 57, 58, 59]]])

print data

# find mode along the zero-th axis; the return value is a tuple of the
# modes and their counts.
print mode(data, axis=0)

谢谢佐藤太郎,但是处理大型数组需要非常长的时间..有什么建议可以加速吗? - oops
好的,我注意到你想使用浮点数来完成这个任务。为了做到这一点,我认为你需要采用稍微不同的方法,因为询问最频繁的浮点数并没有太多意义,因为从重复实验中两个浮点数相等的概率很小。你真的需要找到这样奇怪的东西吗?如果你大致知道样本的分布,那么有更好的度量方法可以计算,例如平均值和中位数,以找出样本中最可能的数字。 - Taro Sato
人们是否仍然广泛使用scipy包?我在某处看到scipy中的mean函数已被弃用。只是好奇想知道 :) - Mona Jalal
这个答案写了一段时间,所以如果该函数已被弃用(例如支持np.mean)我不会感到惊讶...但我认为我是在评论一般方法,而不是包的特定功能。 - Taro Sato

1
我个人认为稍微更好的解决方案如下:
tmpL = np.array([3, 2, 3, 2, 5, 2, 2, 3, 3, 2, 2, 2, 3, 3, 2, 2, 3, 2, 3, 2])
unique, counts = np.unique(tmpL, return_counts=True)
return unique[np.argmax(counts)]

使用 np.unique 我们可以获取每个唯一元素的计数。在 counts 中最大元素的索引将是 unique 中相应的元素。

0
解释 @ecatmurs 部分
u[np.argmax(np.apply_along_axis(np.bincount, axis, indices.reshape(arr.shape),
                                None, np.max(indices) + 1), axis=axis)]

稍微修改一下,使其更加简洁易读(因为我使用了这个解决方案后,几周后我想知道在这个函数中发生了什么):
axis = 0
uniques, indices = np.unique(arr, return_inverse=True)

args_for_bincount_fn = None, np.max(indices) + 1
binned_indices = np.apply_along_axis(np.bincount,
                            last_axis, 
                            indices.reshape(arr.shape),
                            *args_for_bincount_fn)

most_common = uniques[np.argmax(binned_indices,axis=axis)]

0

flatten你的数组,然后从中构建一个collections.Counter。像往常一样,在比较浮点数时要特别小心。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接