У меня есть матрица, которая содержит числа между [0, 5]. Матрица очень разреженная, большинство элементов равно нулю. Я хочу применить масштабирование min-max к каждой строке отдельно, чтобы все элементы находились между [-1, 1]. Однако я хочу учитывать только ненулевые элементы. Например, рассмотрим следующую матрицу:
[[0.5 3. 0. 2. 0. ]
[0. 4. 5. 0. 0. ]
[3. 0. 0. 2.5 4. ]]
После преобразования он будет выглядеть так: (Как видите, 0 элементов нетронутыми)
[[-1. 1. 0. 0.2 0. ]
[ 0. -1. 1. 0. 0. ]
[-0.33333333 0. 0. -1. 1. ]]
Я могу сделать это на обычных массивах numpy со следующим кодом:
max_arr = A.max(axis=1)
min_arr = np.where(A == 0, A.max(), A).min(axis=1)
row_idx, col_idx = A.nonzero()
A_scaled = np.zeros_like(A)
for row, col in zip(row_idx, col_idx):
element = A[row, col]
A_scaled[row, col] = 2 * ((element - min_arr[row]) / (max_arr[row] - min_arr[row])) - 1
Здесь есть пара вопросов. Во-первых, он медленный (из-за цикла for может быть?). Другое дело, что моя матрица разрежена, поэтому я хочу использовать разреженный формат csr_matrix
. Этот код не работает, если матрица A
является csr_matrix
. Он дает ошибку в строке 2, говорящей ValueError: setting an array element with a sequence.
Как я могу достичь этого быстро и эффективно? Я посмотрел на sklearn.preprocessing.MinMaxScaler
но он не поддерживает масштабирование, исключая нули.
Здесь один векторный метод для матриц csr_matrix
-
def scale_sparse_matrix_rows(s, lowval=0, highval=1):
d = s.data
lens = s.getnnz(axis=1)
idx = np.r_[0,lens[:-1].cumsum()]
maxs = np.maximum.reduceat(d, idx)
mins = np.minimum.reduceat(d, idx)
minsr = np.repeat(mins, lens)
maxsr = np.repeat(maxs, lens)
D = highval - lowval
scaled_01_vals = (d - minsr)/(maxsr - minsr)
d[:] = scaled_01_vals*D + lowval
Пример прогона -
1) Ввод установки csr_matrix:
In [153]: a
Out[153]:
array([[0.5, 3. , 0. , 2. , 0. ],
[0. , 4. , 5. , 0. , 0. ],
[3. , 0. , 0. , 2.5, 4. ]])
In [154]: from scipy.sparse import csr_matrix
In [155]: s = csr_matrix(a)
2) Запустите предложенный метод и проверьте результаты:
In [156]: scale_sparse_matrix_rows(s, lowval=-1, highval=1)
In [157]: s.toarray()
Out[157]:
array([[-1. , 1. , 0. , 0.2 , 0. ],
[ 0. , -1. , 1. , 0. , 0. ],
[-0.33333333, 0. , 0. , -1. , 1. ]])