У меня есть два списка.
a_num = [1, 3, 2, 4]
b_num = [1, 2, 3, 4]
Я хочу найти матрицу перестановок для преобразования a
в b
. Математически матрица перестановок - это квадратная матрица, элементы которой равны 1 или 0. Она может изменять последовательность элементов в векторе, умножая ее.
В этом конкретном примере матрица перестановок:
p = [[1,0,0,0],
[0,0,1,0],
[0,1,0,0],
[0,0,0,1]]
# check whether p is correct.
b_num == np.dot(np.array(p), np.array(a_num).reshape(4,1))
Не могли бы вы показать мне, как сделать эту матрицу p
? В моем реальном приложении в списках могут быть десятки элементов с произвольной последовательностью. И два списка всегда содержат str
вместо int
.
А как сделать p
, когда a
и b
- это списки str
?
a_str = ['c1', 'c2', 's1', 's2']
b_str = ['c1', 's1', 'c2', 's2']
В чистом Python вы можете:
a_str = ['c1', 'c2', 's1', 's2']
b_str = ['c1', 's1', 'c2', 's2']
from collections import defaultdict
dd = defaultdict(lambda: [0, []])
for i, x in enumerate(b_str): # collect indexes of target chars
dd[x][1].append(i)
matrix = [[0]*len(a_str) for x in b_str]
for i, a in enumerate(a_str):
# set cell at row (src index) and col (next tgt index) to 1
matrix[i][dd[a][1][dd[a][0]]] = 1
# increment index for looking up next tgt index
dd[a][0] += 1
matrix
# [[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]
Это предполагает, что a_str
и b_str
на самом деле являются соответствующими перестановками.
Обновлено: работает только с числами.
Для массивов одинаковой длины с использованием NumPy
:
import numpy as np
a_num = [1, 3, 2, 4]
b_num = [4, 2, 3, 1]
a = np.array(a_num)
b = np.array(b_num)
len_v = len(a) # = len(b)
A = np.zeros((len_v, len_v))
A[np.argsort(a), np.arange(len_v)] = 1
B = np.zeros((len_v, len_v))
B[np.argsort(b), np.arange(len_v)] = 1
np.dot(np.linalg.inv(B), np.dot(A, a)) # array([4., 2., 3., 1.])