Самый эффективный способ заменить все значения в 2D целочисленном массиве numpy на трехэлементный подмассив?

#python #numpy #numpy-ndarray

#python #numpy #numpy-ndarray

Вопрос:

У меня есть большой 2D (N x N) массив numpy, содержащий целочисленные значения. Я хочу создать из него 3D-массив, который равен (N x N x 3), где — по сути — каждое целое число в исходном массиве заменяется трехэлементным массивом, содержащим триплет RGB, на основе определенного отображения из integer в RGB triplet .

В качестве уменьшенного примера рассмотрим входной массив

 ints = np.array([[0, 1, 0, 2, 2],
                 [1, 1, 0, 2, 0],
                 [0, 0, 3, 0, 4],
                 [5, 0, 3, 0, 4],
                 [0, 3, 3, 0, 0]])
  

и сопоставление целых чисел с цветами RGB, указанными

 mapping = {0: [0, 0, 0],
           1: [255, 0, 0],
           2: [0, 255, 0],
           3: [0, 0, 255],
           4: [127, 127, 0],
           5: [127, 0, 127],
           6: [0, 127, 127]}
  

Я хотел бы эффективный (и, желательно, простой для чтения) метод, который принимал ints бы и mapping и создавал выходной массив

 colors = np.array([[[0,0,0], [255,0,0], [0,0,0], [0,255,0], [0,255,0],],
                  [[255,0,0], [255,0,0], [0,0,0], [0,255,0], [0,0,0],],
                  [[0,0,0], [0,0,0], [0,0,255], [0,0,0], [127,127,0],],
                  [[127,0,127], [0,0,0], [0,0,255], [0,0,0], [127,127,0],],
                  [[0,0,0], [0,0,255], [0,0,255], [0,0,0], [0,0,0],]])
  

Я знаю, что мог бы выделить colors как пустой 3D массив соответствующих размеров, а затем перебрать строки и столбцы ints и соответствующим образом установить соответствующий фрагмент colors … Но это кажется сверхэффективным, и мои реальные массивы будут больше похожи на 1000 x 1000. Есть ли у кого-нибудь предложения по более быстрым, более элегантным, более идиоматичным подходам?

(К вашему сведению, моя мотивация — использовать imshow метод plotly для создания визуализации матрицы, подобной тепловой карте, но с оптимально различными цветами для разных чисел, а не с каким-либо континуумом, как предполагают стандартные параметры окраски.)

Ответ №1:

Поскольку ваш ключ map может быть целыми числами, сопоставление может быть таким же, как индексация, а значения RGB могут быть просто массивом Nx3.

Что-то вроде этого:

 x =  np.arange(30).reshape((10,3))  # the map

keys = np.array([1, 4, 7, 3])

x[keys] # the mapping

# which gives
array([[ 3,  4,  5],
       [12, 13, 14],
       [21, 22, 23],
       [ 9, 10, 11]])
  

Комментарии:

1. Интересно… Я только что попробовал это с 2D-массивом для keys , и, похоже, это работает!

Ответ №2:

Создайте массив (7,3) с

 arr = np.array(list(mapping.values()))
  

проиндексируйте его с помощью

 arr[idx,:]
  

Это зависит от mapping упорядоченности и полноты.