【问题标题】:Python: How to create a complete distance matrix from a row of values?Python:如何从一行值创建一个完整的距离矩阵?
【发布时间】:2015-04-23 03:29:47
【问题描述】:

您好,我想构建一个大小为 10 x 10 的距离矩阵,并生成了一个包含 45 个实数的值列表来填充 10 x 10 矩阵。距离矩阵也称为对称矩阵,它是矩阵另一侧的镜像。我目前的情况是我有 45 个值我想知道如何创建距离矩阵并在矩阵的对角线部分填充 0 并创建镜像矩阵以形成一个完整的远距离矩阵。

例如,
1、2、4、3、5、6

输出:
0、1、2、4
1、0、3、5
2、3、0、6
4、5、6、0

谢谢。

【问题讨论】:

  • 我对示例中的输入如何映射到输出感到困惑。如何从六个值中得到一个 4 X 4 矩阵?

标签: python python-2.7 python-3.x matrix distance


【解决方案1】:

如果您使用的是 NumPy,这对于 numpy.triu_indices 来说将是一个完美的工作,它返回一对索引数组,适合选择矩阵的上三角形。第一个参数是矩阵的边长,第二个参数是从哪个对角线开始:

In [1]: import numpy

In [2]: x = numpy.zeros([4, 4]) # 4x4 array of zeros

In [3]: x[numpy.triu_indices(4, 1)] = [1, 2, 4, 3, 5, 6]

In [4]: x
Out[4]: 
array([[ 0.,  1.,  2.,  4.],
       [ 0.,  0.,  3.,  5.],
       [ 0.,  0.,  0.,  6.],
       [ 0.,  0.,  0.,  0.]])

In [5]: x += x.T

In [6]: x
Out[6]: 
array([[ 0.,  1.,  2.,  4.],
       [ 1.,  0.,  3.,  5.],
       [ 2.,  3.,  0.,  6.],
       [ 4.,  5.,  6.,  0.]])

【讨论】:

  • 哈!我知道这必须已经在 numpy 中实现了。
【解决方案2】:

假设您要创建任意大小的距离矩阵:

import math

def distance_matrix(pattern):
    # to get the side length, solve for n where len(pattern) = n*(n + 1)/2 (triangular number formula)
    side_length = (int(math.sqrt(1 + 8 * len(pattern))) - 1) // 2 + 1
    assert (side_length * (side_length - 1)) // 2 == len(pattern), "Pattern length must be a triangular number."

    # create the grid
    grid = [[0] * side_length for i in range(side_length)]

    # fill in the grid
    position = 0
    for i in range(0, side_length - 1):
        for j in range(0, side_length - 1 - i):
            element = pattern[position]; position += 1
            grid[i][i + j + 1] = element # fill in the upper triangle
            grid[i + j + 1][i] = element # fill in the lower triangle

    return grid

def matrix_to_string(matrix): return "\n".join("\t".join(str(x) for x in row) for row in distance_matrix([1, 2, 4, 3, 5, 6]))

if __name__ == "__main__":
    print(matrix_to_string(distance_matrix([1, 2, 4, 3, 5, 6])))

编辑:边长必须是整数。否则你会得到这个错误:'float' 对象不能被解释为一个整数。解决方法是添加楼层除法运算符 \。

【讨论】:

    【解决方案3】:

    这样的事情怎么样?

    # Create a zero matrix of w x h
    w, h = 10, 10
    matrix = [[0] * w for i in range(h)] 
    
    # List of your numbers
    numbers = range(1,46)
    
    # Fill your numbers in
    # go one row at a time and fill until you reach the diagonal
    for i in range(10):
        for j in range(0, i):
                matrix[i][j] = matrix[j][i] = numbers.pop(0)
    
    # Print all rows
    for row in matrix:
        print row
    

    你得到的输出是:

    [0, 1, 2, 4, 7, 11, 16, 22, 29, 37]
    [1, 0, 3, 5, 8, 12, 17, 23, 30, 38]
    [2, 3, 0, 6, 9, 13, 18, 24, 31, 39]
    [4, 5, 6, 0, 10, 14, 19, 25, 32, 40]
    [7, 8, 9, 10, 0, 15, 20, 26, 33, 41]
    [11, 12, 13, 14, 15, 0, 21, 27, 34, 42]
    [16, 17, 18, 19, 20, 21, 0, 28, 35, 43]
    [22, 23, 24, 25, 26, 27, 28, 0, 36, 44]
    [29, 30, 31, 32, 33, 34, 35, 36, 0, 45]
    [37, 38, 39, 40, 41, 42, 43, 44, 45, 0]
    

    【讨论】:

      【解决方案4】:

      对于 SciPy,使用 scipy.spatial.distance.squareform:

      >>> scipy.spatial.distance.squareform([1,2,3,4,5,6])
      array([[ 0.,  1.,  2.,  3.],
             [ 1.,  0.,  4.,  5.],
             [ 2.,  4.,  0.,  6.],
             [ 3.,  5.,  6.,  0.]])
      

      【讨论】:

        【解决方案5】:

        所以,听起来你想使用一个 numpy 数组。

        import numpy as np
        yourarray = np.zeros([10,10])
        

        这形成了一个十乘十的数组,用零填充。

        然后,要填充它,您需要跨出一个三角形,并用下一个值填充每个连续的对象。因此,在每个对象只是下一个整数的基本情况下,

        count = 1
        for ii in range(1,10):
            for jj in range(ii):
                yourarray[ii,jj] = yourarray[jj,ii] = count
                count +=1
        

        如果您想要插入一个包含 45 个数字的列表,则可以替换

        yourarray[ii,jj] = yourarray[jj,ii] = count
        

        yourarray[ii,jj] = yourarray[jj,ii] = vallist[count]
        

        其中 vallist 是您的 45 个对象的列表。在这种情况下,请将代码开头的 count = 1 替换为 count = 0(因为 Python 是从 0 开始索引的)。

        详情 为了避免填充对角线,jj 设置为range(ii)。由于 python 中的 range(N) 返回[0, 1, 2, ... N - 2, N -1],所以你永远不可能拥有jj=ii。此外,由于 jj 仅上升到 ii,但不会变得更大(如果 jj 也是 in range(1,10) 也会发生这种情况),这只会处理对角线正确一侧的数组的每一侧。

        【讨论】:

          猜你喜欢
          • 2020-09-11
          • 1970-01-01
          • 1970-01-01
          • 2022-08-17
          • 2015-06-11
          • 1970-01-01
          • 1970-01-01
          • 2019-07-13
          • 2016-10-23
          相关资源
          最近更新 更多