转换 x,y 对的扁平化矩阵

3

我收到了一个包含x和y值的一维十进制数数组。

我需要将给定的一维数组转置,就像它是一个矩阵一样。

我的当前代码可以实现这个功能,但并不完全符合我的要求:

to_transpose = [0.914, 0.639, 0.058, 0.760, 0.926, 0.475,
                0.255, 0.671, 0.195, 0.966, 0.336, 0.841,
                0.279, 0.341, 0.591, 0.638, 0.520, 0.225]
matrix_width = 6
matrix_height = 3
# INITIALIZE AN EMPTY LIST
transposed_list = [None] * matrix_width * matrix_height

for w in range(matrix_width):
    for h in range(matrix_height):
        transposed_list[w * matrix_height + h] = to_transpose[h * matrix_width + w]

这段代码可以正确地转置矩阵,但不符合我的要求格式。
由于这是一个x、y值的数组,所需输出如下:
correct_output=[0.914, 0.639, 0.255, 0.671, 0.279, 0.341,
                0.058, 0.760, 0.195, 0.966, 0.591, 0.638,
                0.926, 0.475, 0.336, 0.841, 0.520, 0.225]

在正确的输出中,转置时每个两位小数都被视为一个小数。

  1. 我想知道是否可以在不使用外部库的情况下通过一次矩阵遍历实现此功能,如上例所示?
  2. 我希望这适用于正方形和非正方形矩阵。

你要求“不使用外部库”,但是 numpy 对此非常完美:np.array(to_transpose).reshape((6,3)).T.ravel() - tobias_k
考虑到每两个值应该配对,因此可能更适合使用 reshape(3, 3, 2)(2, 3, 3) - mkrieger1
@mkrieger1 同意,一开始我也没有看到两个值是成对的这件事。 - tobias_k
@DominickSearle 如果您对列表进行预处理,使其成为[(0.914, 0.639), (0.058, 0.760), ...],那么您的方法将起作用。 - mkrieger1
尝试创建一个列表的列表。 - hpaulj
显示剩余2条评论
5个回答

1

虽然您要求不使用库,但我非常建议在涉及矩阵操作的所有情况下使用numpy,例如重塑或转置,这两种操作您在此处都需要:

>>> import numpy as np
>>> to_transpose = [0.914, 0.639, 0.058, 0.760, 0.926, 0.475,
                    0.255, 0.671, 0.195, 0.966, 0.336, 0.841,
                    0.279, 0.341, 0.591, 0.638, 0.520, 0.225]

>>> np.array(to_transpose).reshape((3,3,2)).transpose(1,0,2).ravel()
array([ 0.914,  0.639,  0.255,  0.671,  0.279,  0.341,
        0.058,  0.76 ,  0.195,  0.966,  0.591,  0.638,
        0.926,  0.475,  0.336,  0.841,  0.52 ,  0.225])

将其分解一下:

  • np.array 将您的列表转换为一个 array...
  • 然后将其 reshape3x3x2,即一个由元组组成的 3x3 矩阵...
  • 然后使用 transpose 进行矩阵转置,交换第一(0)和第二(1)轴,并保持第三(2)轴不变...
  • 最后使用 ravel 再次展平矩阵。

如果最终不能使用 numpy,则仍然可以使用此方法正确地转置索引矩阵以找出应该放在哪里的元素,然后通过循环遍历列表 to_transpose 来重现它。

>>> list(np.array(list(range(w*h))).reshape((3,3,2)).transpose(1,0,2).ravel())
[0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11, 16, 17]

>>> [i%2 + (i//2 * w % (w*h)) + 2 * (i//(h*2)) for i in range(w*h)]
[0, 1, 6, 7, 12, 13, 2, 3, 8, 9, 14, 15, 4, 5, 10, 11, 16, 17]

>>> [to_transpose[i%2 + (i//2 * w % (w*h)) + 2 * (i//(h*2))] for i in range(w*h)]
[0.914, 0.639, 0.255, 0.671, 0.279, 0.341,
 0.058, 0.76, 0.195, 0.966, 0.591, 0.638,
 0.926, 0.475, 0.336, 0.841, 0.52, 0.225]

当然,您也可以使用普通循环而不是列表推导,在其他语言中执行相同的操作。基本上,索引相加中的三个术语分别对应于矩阵的三个维度,老实说,我更多地是通过猜测而不是真正理解发生了什么来解决这个问题。毋庸置疑,使用numpy的解决方案更加简洁。

我会接受这个答案,因为它是正确且快速的。谢谢你。但是你是否知道一种不使用numpy(在for循环内)的方法? - Dominick Searle

1

如果您坚持不使用numpy,我建议要么将x,y值分开,要么先将它们作为元组:

to_transpose = [0.914, 0.639, 0.058, 0.760, 0.926, 0.475,
                0.255, 0.671, 0.195, 0.966, 0.336, 0.841,
                0.279, 0.341, 0.591, 0.638, 0.520, 0.225]
a = to_transpose

rows = 3
cols = 3
tot = rows*cols

# separated
x, y = a[::2], a[1::2]
xt = [x[i+j] for i in range(0, rows) for j in range(0, tot, cols)]
yt = [y[i+j] for i in range(0, rows) for j in range(0, tot, cols)]
transposed = [e for t in zip(xt, yt) for e in t]

# tupled
xy = [(i,j) for i,j in zip(a[::2], a[1::2])]
xyt = [xy[i+j] for i in range(0, rows) for j in range(0, tot, cols)]
transposed = [e for t in xyt for e in t]

很明显,即使这种方法可行,numpy仍然是这种操作的更好工具。


1
#!/bin/python3

to_transpose = [
    0.914, 0.639, 0.058, 0.760, 0.926, 0.475,
    0.255, 0.671, 0.195, 0.966, 0.336, 0.841,
    0.279, 0.341, 0.591, 0.638, 0.520, 0.225
]

matrix_width = 6
matrix_height = 3

to_transpose_with_pairs = [(to_transpose[2 * i], to_transpose[2 * i + 1]) for i in range(len(to_transpose) // 2)]
# [
#     (0.914, 0.639), (0.058, 0.76), (0.926, 0.475),
#     (0.255, 0.671), (0.195, 0.966), (0.336, 0.841),
#     (0.279, 0.341), (0.591, 0.638), (0.52, 0.225)
# ]

to_transpose_as_matrix = [None for _ in range(matrix_height)]

for row in range(matrix_height):
    start = row * matrix_width // 2
    end = start + matrix_width // 2

    to_transpose_as_matrix[row] = to_transpose_with_pairs[start:end]

# [
#     [(0.914, 0.639), (0.058, 0.76), (0.926, 0.475)],
#     [(0.255, 0.671), (0.195, 0.966), (0.336, 0.841)],
#     [(0.279, 0.341), (0.591, 0.638), (0.52, 0.225)]
# ]

transposed_as_matrix = list(map(list, zip(*to_transpose_as_matrix)))
# [
#     [(0.914, 0.639), (0.255, 0.671), (0.279, 0.341)],
#     [(0.058, 0.76), (0.195, 0.966), (0.591, 0.638)],
#     [(0.926, 0.475), (0.336, 0.841), (0.52, 0.225)]
# ]

transposed_with_pairs = [pair for row in transposed_as_matrix for pair in row]
# [
#     (0.914, 0.639), (0.255, 0.671), (0.279, 0.341),
#     (0.058, 0.76), (0.195, 0.966), (0.591, 0.638),
#     (0.926, 0.475), (0.336, 0.841), (0.52, 0.225)
# ]


transposed = [val for pair in transposed_with_pairs for val in pair]
# [
#     0.914, 0.639, 0.255, 0.671, 0.279, 0.341,
#     0.058, 0.76, 0.195, 0.966, 0.591, 0.638,
#     0.926, 0.475, 0.336, 0.841, 0.52, 0.225
# ]

1
我发现这个方法只需通过矩阵一次并且不使用任何库就可以按照您的要求工作。
to_transpose = [0.914, 0.639, 0.058, 0.760, 0.926, 0.475,
                0.255, 0.671, 0.195, 0.966, 0.336, 0.841,
                0.279, 0.341, 0.591, 0.638, 0.520, 0.225]
matrix_width = 6
matrix_height = 3
# INITIALIZE AN EMPTY LIST
transposed_list = [None] * matrix_width * matrix_height

for w in range(0, matrix_width, 2):
    for h in range(matrix_height):
        transposed_list[w * matrix_height + (2 * h)] = to_transpose[h * matrix_width + w]
        transposed_list[(w * matrix_height + (2 * h)) + 1] = to_transpose[(h * matrix_width + w) + 1]
print(transposed_list)

我做了三件事:

  • 通过将步长值设置为2,使w跳过奇数值
  • 添加了一行额外的代码,其中奇数索引元素获取y的值
  • 最后将h的值加倍,以便每个交替元素都获得新值

0

你可以在不使用numpy的情况下,在一行/一次遍历中计算它,但这是可怕的:

m=to_transpose # for easy writing only
[ n for l in zip( *[[(m[i],m[i+1]) for i in range(k,k+6,2)] for k in range(0,len(m),6)] ) for t in l for n in t ]

请使用numpy代替。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接