Как изменить значение некоторых подматриц m x m из матрицы NxN с помощью numpy?

#python #numpy #matrix

#питон #тупица #матрица

Вопрос:

Общую проблему, с которой я сталкиваюсь, можно перевести следующим образом:

Кодируйте матрицу NxN, в которой регулярно чередуются подматрицы mxm значений x или y.

Например, допустим, мне нужно сделать матрицу 6×6 с 2×2 подматрицами 0 или 1, чередующимися, результатом должна быть матрица ниже:

 0 0 1 1 0 0  0 0 1 1 0 0 1 1 0 0 1 1 1 1 0 0 1 1 0 0 1 1 0 0 0 0 1 1 0 0  

На данный момент мне удалось получить только это:

 0 0 1 0 0 0  0 0 1 0 0 0  1 1 0 0 0 0  0 0 0 0 0 0 0 0 0 0 0 0  0 0 0 0 0 0   

с помощью кода :

 b = numpy.zeros((6, 6)) b[:2, 2:6:4] = 1 b[2:6:4, :2] = 1 print(b)  

Мне удалось найти решение, но оно имеет четыре цикла, поэтому его трудно прочитать и занимает немного времени. Код для этого возможного ответа таков:

 c = np.array([])  for k in range(3):  for l in range (2):  for i in range(3):  for j in range (2):    if (k i)%2 == 0:  c = np.append(c, 0)  else:  c = np.append(c, 1) print("c = ", np.reshape(c, (6, 6)))  

Разве нет лучшего способа получить ожидаемый результат без использования циклов или с максимальным количеством циклов 1 или 2 ?

Ответ №1:

 import numpy as np m = 8  n = 4  c = np.zeros(shape=(m,m))  assert not m%n #m must be divisible by n for row_i in range(m):  for col_i in range(m):  if (row_i//n   col_i//n)%2:  c[row_i][col_i] = 1  print(c)  
 [[0. 0. 0. 0. 1. 1. 1. 1.]  [0. 0. 0. 0. 1. 1. 1. 1.]  [0. 0. 0. 0. 1. 1. 1. 1.]  [0. 0. 0. 0. 1. 1. 1. 1.]  [1. 1. 1. 1. 0. 0. 0. 0.]  [1. 1. 1. 1. 0. 0. 0. 0.]  [1. 1. 1. 1. 0. 0. 0. 0.]  [1. 1. 1. 1. 0. 0. 0. 0.]]  

Ответ №2:

Я думаю, что вы на правильном пути с использованием нарезки массивов python. Вот пример для подматриц 2×2 (работает с любой матрицей b четного квадратного размера).

 # first block for submatrices starting at column and row index 0  # 0::4 - every 4th column/row starting from column 0 # so this results in 1 0 0 0 1 0 and so on b[0::4, 0::4] = 1  # 1::4 - every 4th column starting from column 1 # so this results in 0 1 0 0 0 1 and so on b[0::4, 1::4] = 1  b[1::4, 0::4] = 1 b[1::4, 1::4] = 1  # second block for submatrices starting from column and row index 2  b[2::4, 2::4] = 1 b[2::4, 3::4] = 1 b[3::4, 2::4] = 1 b[3::4, 3::4] = 1  

Теперь для больших подматриц вам нужно просто увеличить расстояние между записями. Для подматриц размера n расстояние должно быть 2 * n таким , потому что это схема для повторения 1 в матрице. Затем каждый блок имеет размер n . Попробуйте написать процедуру. Если у вас не получится, я буду помогать и дальше.

Ответ №3:

Я сократил ваш цикл до 2:

 def create_mxm_from_NxN(N,m):  """N has to be divisible by m"""  b = np.zeros((N,N))  skip = N // m  for i in range(0,N 1,m):  for s in range(1,skip 1,2):  b[i:i m, i s*m:i (s 1)*m] = 1  b[i s*m:i (s 1)*m, i:i m] = 1  return b.astype(int)  

Выход:

 create_mxm_from_NxN(6,2)  [[0 0 1 1 0 0]  [0 0 1 1 0 0]  [1 1 0 0 1 1]  [1 1 0 0 1 1]  [0 0 1 1 0 0]  [0 0 1 1 0 0]]   create_mxm_from_NxN(9,3)  [[0 0 0 1 1 1 0 0 0]  [0 0 0 1 1 1 0 0 0]  [0 0 0 1 1 1 0 0 0]  [1 1 1 0 0 0 1 1 1]  [1 1 1 0 0 0 1 1 1]  [1 1 1 0 0 0 1 1 1]  [0 0 0 1 1 1 0 0 0]  [0 0 0 1 1 1 0 0 0]  [0 0 0 1 1 1 0 0 0]]  

Ответ №4:

Вот один из вариантов использования np.repeat и np.tile :

 import numpy as np  def tiled_matrix(n, m):  row = np.tile(np.repeat([1, 0], m), (n // m) // 2   1)[:n]  row_block = np.tile(row, (m,1))  two_rows_block = np.vstack((row_block, 1 - row_block))  arr = np.tile(two_rows_block, ((n // m) // 2   1, 1))[:n]  return arr  print(tiled_matrix(10, 4)) # [[1 1 1 1 0 0 0 0 1 1] # [1 1 1 1 0 0 0 0 1 1] # [1 1 1 1 0 0 0 0 1 1] # [1 1 1 1 0 0 0 0 1 1] # [0 0 0 0 1 1 1 1 0 0] # [0 0 0 0 1 1 1 1 0 0] # [0 0 0 0 1 1 1 1 0 0] # [0 0 0 0 1 1 1 1 0 0] # [1 1 1 1 0 0 0 0 1 1] # [1 1 1 1 0 0 0 0 1 1]]  

Вот еще один дубль с np.meshgrid и xor :

 def meshgrid_mod(n, m):  ix = np.arange(n, dtype=np.uint8)  xs, ys = np.meshgrid(ix, ix)  arr = ((xs % (2*m)) lt; m) ^ ((ys % (2*m)) lt; m)  return arr.astype(np.int)  

Ответ №5:

Самое простое решение, вероятно, состоит в том, чтобы использовать skimage.util.view_as_blocks() :

 import numpy as np import skimage.util  a = np.zeros((6, 6)) b = skimage.util.view_as_blocks(a, (2, 2)) # b is a view of a, so changing values in b will also change values in a b[::2, ::2, ...] = 1 b[1::2, 1::2, ...] = 1  a # array([[1., 1., 0., 0., 1., 1.], # [1., 1., 0., 0., 1., 1.], # [0., 0., 1., 1., 0., 0.], # [0., 0., 1., 1., 0., 0.], # [1., 1., 0., 0., 1., 1.], # [1., 1., 0., 0., 1., 1.]])