计算一半对称numpy矩阵的更好方法?

问题描述 投票:0回答:3

我的矩阵的每个单元格都需要是由昂贵的函数计算的分数。 矩阵是对称的,这是我能想到的填充每个单元格的最佳方法。

num_cases = len(case_dictionary.keys())  # num_cases = 10
SmallMatrix = np.zeros((num_cases,num_cases))

for CasesX in range(0,num_cases):
    for CasesY in range(CasesX,num_cases):
        SmallMatrix[CasesX,CasesY] = 1

返回:

array([[ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
       [ 0.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
       [ 0.,  0.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  1.,  1.,  1.,  1.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  1.,  1.,  1.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  0.,  1.,  1.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.]])

足够简单...

但是,当矩阵较大且计算量较大时: 嵌套 for 循环是最有效的解决方案吗?

num_cases = len(case_dictionary.keys())  # 100000
BigMatrix = np.zeros((num_cases,num_cases))

for CasesX in range(0,num_cases):
    for CasesY in range(CasesX,num_cases):
        BigMatrix[CasesX,CasesY] = ExpensiveFunction()

慢...由于我的功能或循环?

编辑

继续处理成对数据,所以我回去尝试使用@hpaulj 解决方案。 我知识不够,无法理解为什么 testUpper() 更快?

def testUpper(func):
    num_cases = 100
    BigMatrix = np.zeros((num_cases,num_cases))

    upper = np.triu_indices_from(BigMatrix)

    BigMatrix[upper] = ExpensiveFunction()

基准@unutbu

test
函数从下面,针对numpy版本:

In [8]: %timeit test(ExpensiveFunction)
        1 loops, best of 3: 11.1 s per loop

In [9]: %timeit testUpper(ExpensiveFunction)
        1000 loops, best of 3: 2.03 ms per loop
python numpy optimization matrix
3个回答
6
投票

这是一个简单的实验,表明瓶颈更有可能是

ExpensiveFunction

import time

def SimpleFunction():
    return 1

def ExpensiveFunction():
    time.sleep(0.001)
    return 1

def test(func):
    num_cases = 100
    BigMatrix = np.zeros((num_cases,num_cases))

    for CasesX in range(0,num_cases):
        for CasesY in range(CasesX,num_cases):
            BigMatrix[CasesX,CasesY] = func()

In [84]: %timeit test(ExpensiveFunction)
1 loops, best of 3: 5.48 s per loop

In [85]: %timeit test(SimpleFunction)
1000 loops, best of 3: 890 µs per loop

除了调用的函数之外,两次 timeit 运行是相同的。 当

func
SimpleFunction
时,填充
BigMatrix
所需时间不到 1ms。 但当
func
ExpensiveFunction
时,填充
BigMatrix
需要超过 5 秒。

所以双

for-loop
可能不是瓶颈;
ExpensiveFunction
是。您可以用实际代码尝试一下以确保。如果事实证明
ExpensiveFunction
确实是瓶颈,那么您不需要费心优化双循环,因为即使有更快的方法来填充
BigMatrix
- 即使您可以将时间成本削减到零-- 你最多只能保存(在上述情况下)
890 us
,而整个程序仍然需要 5 秒以上。


5
投票

我建议将“昂贵”的计算应用于矩阵的一半,然后使用

symmetrize()
函数使 numpy 数组对称,该函数应该具有最小的时间成本

def symmetrize(a):
    return a + a.T - numpy.diag(a.diagonal())

0
投票

使用 Numpy 查看以下技术。对于大型数据集最有效。

import numpy as np

matrix = upper_triangular_matrix = np.array([[1.,  2.,  3.,  4.],
                     [0.,  5.,  6.,  7.],
                     [0.,  0.,  8.,  9.],
                     [0.,  0.,  0., 10.]])
print(matrix)
'''
[[ 1.  2.  3.  4.]
 [ 0.  5.  6.  7.]
 [ 0.  0.  8.  9.]
 [ 0.  0.  0. 10.]]
'''
'''
Below code, Effectively duplicates the upper triangular part into the lower triangular part, 
resulting in a matrix that is almost symmetric, except for the diagonal elements.
'''
symmetric_matrix = matrix  + matrix.T 
print(symmetric_matrix)

'''
[[ 2.  2.  3.  4.]
 [ 2. 10.  6.  7.]
 [ 3.  6. 16.  9.]
 [ 4.  7.  9. 20.]]
'''
#change the diagonal to the Original matrix 
np.fill_diagonal(symmetric_matrix,np.diag(matrix))
print(symmetric_matrix)
'''
[[ 1.  2.  3.  4.]
 [ 2.  5.  6.  7.]
 [ 3.  6.  8.  9.]
 [ 4.  7.  9. 10.]]
'''
© www.soinside.com 2019 - 2024. All rights reserved.