【问题标题】:Find most frequent row or mode of a matrix of vectors - Python / NumPy查找向量矩阵的最频繁行或模式 - Python / NumPy
【发布时间】:2017-09-19 04:06:25
【问题描述】:

我有一个形状为 (?,n) 的 numpy 数组,它表示 n 维向量的向量。

我想找到最频繁的行。

到目前为止,最好的方法似乎是遍历所有条目并存储一个计数,但 numpy 或 scipy 没有内置的东西来执行此任务似乎很可笑。

【问题讨论】:

  • 什么意思? scipy.stats.mode 存在。
  • @Blender:我不确定这是否自然地处理找到最常见的 row - 它返回给定 values 的模式轴,我想。
  • @DSM:你是对的。 Counter(map(tuple, a)).most_common()[0] 在大约一秒钟内处理了 600k 3 向量,但我确信存在更有效的解决方案。
  • @Blender:是的,scipy.stats.mode 并不是我想要的。我将使用该 sn-p 作为占位符,现在等待其他响应:)

标签: python numpy scipy


【解决方案1】:

如果你能够使用 Pandas,这里有一种方法,它大量借鉴了 this answer

import numpy as np
import pandas as pd

# generate sample data
ncol = 5
nrow = 20000
matrix = np.random.randint(0,ncol,ncol*nrow).reshape(nrow,ncol)
df = pd.DataFrame(matrix)

df.head()
   0  1  2  3  4
0  3  0  4  4  4
1  4  0  0  2  0
2  3  3  2  0  0
3  0  3  4  3  3
4  1  1  3  3  3

# count duplicated rows
(df.groupby(df.columns.tolist())
   .size()
   .sort_values(ascending=False))

输出:

0  1  2  3  4
4  2  2  1  1    17
2  2  4  2  3    16
3  2  1  2  2    15
   1  2  4  3    15
                 ..
4  1  3  0  1     1
1  2  3  0  4     1

最频繁的行是此输出的顶行。频率计数是最右边的列。

【讨论】:

  • 谢谢,我之前能够找到 pandas 的解决方案,但就我目前的任务而言,我无法使用该库。
【解决方案2】:

这是一种使用NumPy views的方法,应该非常有效-

def mode_rows(a):
    a = np.ascontiguousarray(a)
    void_dt = np.dtype((np.void, a.dtype.itemsize * np.prod(a.shape[1:])))
    _,ids, count = np.unique(a.view(void_dt).ravel(), \
                                return_index=1,return_counts=1)
    largest_count_id = ids[count.argmax()]
    most_frequent_row = a[largest_count_id]
    return most_frequent_row

示例运行 -

In [45]: # Let's have a random arrayb with three rows(2,4,8) and two rows(1,7)
    ...: # being duplicated. Thus, the most freequent row must be 2 here.
    ...: a = np.random.randint(0,9,(9,5))
    ...: a[4] = a[8]
    ...: a[2] = a[4]
    ...: 
    ...: a[1] = a[7]
    ...: 

In [46]: a
Out[46]: 
array([[8, 8, 7, 0, 7],
       [7, 8, 2, 6, 1],
       [2, 2, 5, 7, 6],
       [6, 5, 8, 8, 5],
       [2, 2, 5, 7, 6],
       [5, 7, 3, 6, 3],
       [2, 8, 7, 2, 0],
       [7, 8, 2, 6, 1],
       [2, 2, 5, 7, 6]])

In [47]: mode_rows(a)
Out[47]: array([2, 2, 5, 7, 6])

【讨论】:

  • 太好了,谢谢!我试图弄清楚这到底是如何工作的。 view() 如何将数组强制转换为每个元素实际上都是 numpy 看不到的数组的表示形式?具体来说, np.ravel() 不会导致所有内容都变成一个包含所有值的长数组。
  • @dant 好吧,每一行都被压缩为一个标量,但保持尺寸。所以,(m,n) 数组变成了(m,1) 数组。这是通过a.view(void_dt) 完成的。然后,我们使用ravel() 使其成为(m) 数组,它是一个一维数组,然后可以与np.unique 一起使用。
  • @dant 为了验证这一点,将a.view(void_dt).ravel() 替换为a.view(void_dt)[:,0] 也可以。
【解决方案3】:

numpy_indexed 包(dsiclaimer:我是它的作者)具有完全做到这一点的功能,适用于任意数量的维度:

import numpy_indexed as npi
row = npi.mode(arr)

在引擎盖下,它在算法和复杂性方面就像 Divakar 的解决方案,只是多了一些花里胡哨的东西;查看“权重”和“return_indices”kwargs。

【讨论】:

  • 很高兴看到有人正在开发 numpy 的扩展。希望有一天它会出现在源代码中:)
  • 这是我的初衷;但鉴于近年来python包管理已经成熟了很多,我认为一个单独的迷你包有自己的发布周期真的更有意义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-01
  • 1970-01-01
  • 2013-11-27
  • 1970-01-01
  • 2016-01-16
  • 2017-11-18
相关资源
最近更新 更多