Numpy: Replacing values in a 2D array efficiently using a dictionary as a map Numpy: Replacing values in a 2D array efficiently using a dictionary as a map numpy numpy

Numpy: Replacing values in a 2D array efficiently using a dictionary as a map


Here's one way, provided you have a small dictionary/min and max values, this may be more efficient, you work around the negative index by adding the array min:

In [11]: indexer = np.array([d.get(i, -1) for i in range(a.min(), a.max() + 1)])In [12]: indexer[(a - a.min())]Out[12]:array([[4, 1, 3, 0],       [2, 0, 2, 3],       [1, 4, 3, 3]])

Note: This moves the for loop to the lookup table, but if this is significantly smaller than the actual array this could be a lot faster.


Make a copy of the array then iterate over the dictionary items then use boolean indexing to assign the new values to the copy.

import numpy as npb = np.copy(a)for old, new in d.items():    b[a == old] = new


This post solves for one-to-one mapping case between array and dictionary keys. The idea would be similar to proposed in @Andy Hayden's smart solution, but we will create a bigger array that incorporates Python's negative indexing thereby giving us the efficiency of simply indexing without any offsetting needed for incoming input arrays, which should be the noticeable improvement here.

To get the indexer, which would be a one-time usage as the dictionary stays the same, use this -

def getval_array(d):    v = np.array(list(d.values()))    k = np.array(list(d.keys()))    maxv = k.max()    minv = k.min()    n = maxv - minv + 1    val = np.empty(n,dtype=v.dtype)    val[k] = v    return valval_arr = getval_array(d)

To get the final replacements, simply index. So, for an input array a, do -

out = val_arr[a]

Sample run -

In [8]: a = np.array([[  3,   0,   2,  -1],   ...:               [  1, 255,   1, -16],   ...:               [  0,   3,   2,   2]])   ...:    ...: d = {0: 1, 1: 2, 2: 3, 3: 4, -1: 0, 255: 0, -16:5}   ...: In [9]: val_arr = getval_array(d) # one-time operationIn [10]: val_arr[a]Out[10]: array([[4, 1, 3, 0],       [2, 0, 2, 5],       [1, 4, 3, 3]])

Runtime test on tiled sample data -

In [141]: a = np.array([[  3,   0,   2,  -1],     ...:               [  1, 255,   1, -16],     ...:               [  0,   3,   2,   2]])     ...:      ...: d = {0: 1, 1: 2, 2: 3, 3: 4, -1: 10, 255: 89, -16:5}     ...: In [142]: a = np.random.choice(a.ravel(), 1024*2048).reshape(1024,2048)# @Andy Hayden's solnIn [143]: indexer = np.array([d.get(i, -1) for i in range(a.min(), a.max() + 1)])In [144]: %timeit indexer[(a - a.min())]100 loops, best of 3: 8.34 ms per loop# Proposed in this postIn [145]: val_arr = getval_array(d)In [146]: %timeit val_arr[a]100 loops, best of 3: 2.69 ms per loop