python - 对巨大的矩阵进行排序,然后在列表中找到最小的元素及其索引

标签 python sorting numpy scipy scikit-learn

我有一个相当大的矩阵M。我正在尝试找到前 5 个最接近的距离及其索引。

M = csr_matrix(M)
dst = pairwise_distances(M,Y=None,metric='euclidean')

dst 变成了一个巨大的矩阵,我正在尝试对其进行有效排序或使用 scipy 或 sklearn 找到最近的 5 个距离。

这是我正在尝试做的一个例子:

X = np.array([[2, 3, 5], [2, 3, 6], [2, 3, 8], [2, 3, 3], [2, 3, 4]]) 

然后我将 dst 计算为:

[[ 0.  1.  3.  2.  1.]
 [ 1.  0.  2.  3.  2.]
 [ 3.  2.  0.  5.  4.]
 [ 2.  3.  5.  0.  1.]
 [ 1.  2.  4.  1.  0.]]

因此,第 0 行到自身的距离为 0.,第 0 行到第 1 行的距离为 1.,...第 2 行到第 3 行有5. 的距离,依此类推。我想找到这 5 个最接近的距离并将它们放入具有相应行的列表中,可能像 [distance, row, row]。我不想要任何对角线元素或重复元素,所以我采用上三角矩阵如下:

[[ inf   1.   3.   2.   1.]
 [ nan  inf   2.   3.   2.]
 [ nan  nan  inf   5.   4.]
 [ nan  nan  nan  inf   1.]
 [ nan  nan  nan  nan  inf]]

现在,从最小到最大的前 5 个距离是:

[1, 0, 1], [1, 0, 4], [1, 3, 4], [2, 1, 2], [2, 0, 3], [2, 1, 4] 

如您所见,三个元素的距离为 2,三个元素的距离为 1。我想从这些元素中随机选择一个距离为 2 的元素来保留,因为我只想要顶部 f 元素,其中 f=5这个案例。

这只是一个样本,因为这个矩阵可能非常大。除了使用基本的排序函数之外,是否有一种有效的方法来执行上述操作?我找不到任何 sklearn 或 scipy 来帮助我解决这个问题。

最佳答案

这是针对您的问题的完全矢量化解决方案:

import numpy as np
from scipy.spatial.distance import pdist

def smallest(M, f):
    # compute the condensed distance matrix
    dst = pdist(M, 'euclidean')
    # indices of the upper triangular matrix
    rows, cols = np.triu_indices(M.shape[0], k=1)
    # indices of the f smallest distances
    idx = np.argsort(dst)[:f]
    # gather results in the specified format: distance, row, column
    return np.vstack((dst[idx], rows[idx], cols[idx])).T

请注意,np.argsort(dst)[:f] 会生成压缩距离矩阵 dst 的最小 f 元素的索引升序排列。

以下演示重现了您的玩具示例的结果,并展示了函数 smallest 如何处理相当大的 10000*2000 矩阵。整数:

In [59]: X = np.array([[2, 3, 5], [2, 3, 6], [2, 3, 8], [2, 3, 3], [2, 3, 4]])

In [60]: smallest(X, 5)
Out[60]: 
array([[ 1.,  0.,  1.],
       [ 1.,  0.,  4.],
       [ 1.,  3.,  4.],
       [ 2.,  0.,  3.],
       [ 2.,  1.,  2.]])

In [61]: large_X = np.random.randint(100, size=(10000, 2000))

In [62]: large_X
Out[62]: 
array([[ 8, 78, 97, ..., 23, 93, 90],
       [42,  2, 21, ..., 68, 45, 62],
       [28, 45, 30, ...,  0, 75, 48],
       ..., 
       [26, 88, 78, ...,  0, 88, 43],
       [91, 53, 94, ..., 85, 44, 37],
       [39,  8, 10, ..., 46, 15, 67]])

In [63]: %time smallest(large_X, 5)
Wall time: 1min 32s
Out[63]: 
array([[ 1676.12529365,  4815.        ,  5863.        ],
       [ 1692.97253374,  1628.        ,  2950.        ],
       [ 1693.558384  ,  5742.        ,  8240.        ],
       [ 1695.86408654,  2140.        ,  6969.        ],
       [ 1696.68853948,  5477.        ,  6641.        ]])

关于python - 对巨大的矩阵进行排序,然后在列表中找到最小的元素及其索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41962084/

相关文章:

ruby - 从 key 小于特定值的哈希中获取所有值的有效方法

javascript - 如何在排序比较过程中忽略值中的 "-"和 "."字符?

python - 在 python 中更新 json 行文件的快速方法

Python 语音识别库 - 总是在听?

php - 如何从php中的另一个键排序和更新唯一键

python - 快速查找二维数组中的多个最大值

python - 防止 numpy 创建多维数组

python - Python + scipy 中 sigmoid 回归的参数

python - 无效版本规范错误 : Invalid version spec: =2. 7

python - 异常处理在 python 程序中不起作用