Numpy 加速马氏距离计算

Numpy 加速马氏距离计算,numpy,vectorization,mahalanobis,Numpy,Vectorization,Mahalanobis,背景: 我正在实现一个顺序反向选择算法,从数据集中选择特征。所讨论的数据集是MNIST。我有60000个向量,长度784 该算法要求我从784个特征中去掉一个特征fi,然后选择剩余的783个特征,在下面的代码中称为selection。然后,我必须计算每一个向量的马氏体到它的平均值。一旦这个迭代完成,我就省去了两个特性,然后是三个,以此类推。每个迭代都需要3分钟 我必须选择500个特征,这样上面重复500次,所以总的来说,马氏距离计算为500 x 784=392000次。这需要我计算协方差矩阵的逆

背景:

我正在实现一个顺序反向选择算法,从数据集中选择特征。所讨论的数据集是MNIST。我有60000个向量,长度784

该算法要求我从784个特征中去掉一个特征fi,然后选择剩余的783个特征,在下面的代码中称为selection。然后,我必须计算每一个向量的马氏体到它的平均值。一旦这个迭代完成,我就省去了两个特性,然后是三个,以此类推。每个迭代都需要3分钟

我必须选择500个特征,这样上面重复500次,所以总的来说,马氏距离计算为500 x 784=392000次。这需要我计算协方差矩阵的逆。这个协方差矩阵的逆不存在,因为它是奇异的,所以我使用numpy的伪逆

问题

正如你可以想象的那样,上面的过程非常缓慢。计算伪逆是一个最慢的过程。我想我可以通过预先计算伪逆,然后删除与fi相关联的相应列和行。然而,事实证明,这个伪逆矩阵并不等于直接从向量计算的伪逆矩阵,我已经删除了fi

我试过的

我曾尝试在很大程度上对此进行矢量化,并处理数组堆栈,结果发现分解方法的速度较慢。我试过np.einsum、cdist甚至numexpr。没有什么真正的帮助

这让我相信加速的最好机会就是将协方差和伪逆计算移出这个循环。这是我当前的代码:

def mahalanobis(self, data, lbls, selection):
    subset data[:,tuple(selection)]

    for n in range(10):
        class_rows = subset[np.where(y == n)]
        mean = np.mean(class_rows, axis = )
        pseudoInverse = pinv(covariance(class_rows))
        delta = C - u
        d[n] = np.mean(np.sum(((delta @ pseudoInverse) * delta), axis = -1))
    return np.mean(d)
问题:


如何加快计算速度?从我在过去一周所做的测试来看,这个计算中最慢的部分似乎是pseudoInverse=pinvCovenanceClass_行。

现在,您的代码基本上是:

def马哈拉诺比斯德尔塔,cov: ci=np.linalg.pinvcov 返回np.sumdelta@ci*delta,轴=-1 您可以通过以下方式稍微加快速度:

直接使用svd而不是pinv,并消除不使用的共轭。 使用eigh代替svd,svd利用协方差矩阵的对称性 def马哈拉诺比斯埃格德尔塔,cov: s、 u=np.linalg.eighcov 注意:缺少小S的过滤,你可能需要考虑添加-pvv已经为你做到了这一点。 ic=u@1/s[…,无]*u.T 返回np.sumdelta@ci*delta,轴=-1
值得注意的是,对于复杂值,此函数和您的函数都不能正常工作。

现在,您的代码基本上是:

def马哈拉诺比斯德尔塔,cov: ci=np.linalg.pinvcov 返回np.sumdelta@ci*delta,轴=-1 您可以通过以下方式稍微加快速度:

直接使用svd而不是pinv,并消除不使用的共轭。 使用eigh代替svd,svd利用协方差矩阵的对称性 def马哈拉诺比斯埃格德尔塔,cov: s、 u=np.linalg.eighcov 注意:缺少小S的过滤,你可能需要考虑添加-pvv已经为你做到了这一点。 ic=u@1/s[…,无]*u.T 返回np.sumdelta@ci*delta,轴=-1
值得注意的是,对于复杂值,此函数和您的函数都不能正常工作。

您知道吗?编辑:没关系,它不会比你拥有的更快。是的。它非常有限,因为它只能接受1D数组。在numpy 1.16中,您可以将hermitian=true传递给pinv,这可能会加快速度up@Eric我安装了1.16,但传递了关键字arg。给了我一个错误。医生也没有提到任何关于赫米特人的争论。哎呀,那要到1点17分,对不起。不管怎样,我的答案与之相当。你知道吗?编辑:没关系,它不会比你拥有的更快。是的。它非常有限,因为它只能接受1D数组。在numpy 1.16中,您可以将hermitian=true传递给pinv,这可能会加快速度up@Eric我安装了1.16,但传递了关键字arg。给了我一个错误。医生也没有提到任何关于赫米特人的争论。哎呀,那要到1点17分,对不起。无论如何,我的答案与之相当。