Python 17000×300矩阵行的每个组合之间的平方差之和

Python 17000×300矩阵行的每个组合之间的平方差之和,python,numpy,optimization,matrix,Python,Numpy,Optimization,Matrix,好的,我有一个17000行(示例)和300列(特征)的矩阵。我想基本上计算每个可能的行组合之间的欧几里德距离,所以每个可能的行对的平方差之和。 很明显,这是一个很大的问题,iPython在没有完全弄坏我的笔记本电脑的情况下,说了一会儿“忙”,然后我再也不能运行任何东西了,它似乎已经放弃了,尽管我可以移动我的鼠标和所有东西 有什么办法可以让这一切顺利进行吗?这是我写的函数。我在任何地方都用numpy。 我所做的是将每个可能的组合的差异存储在差异矩阵中。我知道矩阵的下对角线部分=上对角线,但这只会节

好的,我有一个17000行(示例)和300列(特征)的矩阵。我想基本上计算每个可能的行组合之间的欧几里德距离,所以每个可能的行对的平方差之和。 很明显,这是一个很大的问题,iPython在没有完全弄坏我的笔记本电脑的情况下,说了一会儿“忙”,然后我再也不能运行任何东西了,它似乎已经放弃了,尽管我可以移动我的鼠标和所有东西

有什么办法可以让这一切顺利进行吗?这是我写的函数。我在任何地方都用numpy。 我所做的是将每个可能的组合的差异存储在差异矩阵中。我知道矩阵的下对角线部分=上对角线,但这只会节省1/2的计算时间(总比什么都没有好,但我认为这不是游戏规则改变者)

编辑:我刚刚尝试使用了
scipy.spatial.distance.pdist
,但它已经运行了一分钟,看不到尽头,有没有更好的方法?我还应该提到,我有NaN值…但这显然不是numpy的问题

features = np.array(dataframe)
distances = np.zeros((17000, 17000))


def sum_diff():
    for i in range(17000):
        for j in range(17000):
            diff = np.array(features[i] - features[j])
            diff = np.square(diff)
            sumsquares = np.sum(diff)
            distances[i][j] = sumsquares

您可以将计算时间除以2,注意d(i,i)=0和d(i,j)=d(j,i)

但是你有没有看过
sklearn.metrics.pairwise.pairwise_distance()
(在V0.18中,请参见)

您可以将其用作:

from sklearn.metrics import pairwise
import numpy as np

a = np.array([[0, 0, 0], [1, 1, 1], [3, 3, 3]])
pairwise.pairwise_distances(a)

numpy最大的优点是避免使用循环,让它在矢量化操作中发挥神奇的作用,因此有一些基本的改进可以节省一些计算时间:

import numpy as np
import timeit

#I reduced the problem size to 1000*300 to keep the timing in reasonable range
n=1000
features = np.random.rand(n,300)
distances = np.zeros((n,n))


def sum_diff():
    for i in range(n):
        for j in range(n):
            diff = np.array(features[i] - features[j])
            diff = np.square(diff)
            sumsquares = np.sum(diff)
            distances[i][j] = sumsquares

#Here I removed the unnecessary copy induced by calling np.array
# -> some improvement
def sum_diff_v0():
    for i in range(n):
        for j in range(n):
            diff = features[i] - features[j]
            diff = np.square(diff)
            sumsquares = np.sum(diff)
            distances[i][j] = sumsquares

#Collapsing of the statements -> no improvement
def sum_diff_v1():
    for i in range(n):
        for j in range(n):
            distances[i][j] = np.sum(np.square(features[i] - features[j]))

# Using brodcasting and vetorized operations -> big improvement
def sum_diff_v2():
    for i in range(n):
        distances[i] = np.sum(np.square(features[i] - features),axis=1)

# Computing only half the distance -> 1/2 computation time
def sum_diff_v3():
    for i in range(n):
        distances[i][i+1:] = np.sum(np.square(features[i] - features[i+1:]),axis=1)
    distances[:] = distances + distances.T

print("original :",timeit.timeit(sum_diff, number=10))
print("v0 :",timeit.timeit(sum_diff_v0, number=10))
print("v1 :",timeit.timeit(sum_diff_v1, number=10))
print("v2 :",timeit.timeit(sum_diff_v2, number=10))
print("v3 :",timeit.timeit(sum_diff_v3, number=10))
编辑:为了完整性,我还对卡米莱里的解决方案进行了计时,该解决方案的速度要快得多

from sklearn.metrics import pairwise

def Camilleri_solution():
    distances=pairwise.pairwise_distances(features)
计时结果(以秒为单位,使用1000*300输入运行10次函数):


正如您所看到的,通过使用适当的numpy语法,我们可以很容易地获得一个数量级。请注意,由于只有1/20的数据,函数在大约1秒内运行,因此我预计整个过程将在数十分钟内运行,因为scipt在N^2内运行。

@TimPietzcker,嗯,我非常确定每个循环的值应该是17000,因为我计算的是每行(对)组合之间的距离,其中有17k行。然而,我刚刚意识到我对这两个循环变量都有
I
…太棒了,这比scipy的pdist工作得更好,非常感谢!感谢您花时间键入所有这些内容。我希望我能选择你的答案,因为它教会了我一些关于numpy的东西,我不知道,但P.Camilleri的答案让这一切运行得非常快,所以我必须选择他的答案。没问题,这是正确的选择。我将为Camilleri的解决方案添加计时,以显示它的速度有多快。
original : 138.36921879299916
v0 : 111.39915344800102
v1 : 117.7582511530054
v2 : 23.702392491002684
v3 : 9.712442981006461
Camilleri's : 0.6131987979897531