mins
mins

Reputation: 7524

Vectorization of lookup

I've an array of values and want to map each value with one from another array. The mapped value is the largest found which is lower or equal (I make the assumption it always exists).

For example from the values [6, 15, 4, 12, 10, 5] and the lookup table [4, 6, 7, 8, 10, 12] I would print:

6 is between 6 and 7
15 is between 12 and None
4 is between 4 and 6
12 is between 12 and None
10 is between 10 and 12
5 is between 4 and 6

I do this like this:

import numpy as np

def last_smallest(values, limits):
    count = values.shape[0]
    value = np.zeros(count, dtype='int')
    for i in range(count):
        found = np.where(limits <= values[i])
        value[i] = found[-1][-1]
    return value

lookup_table = np.array([4, 6, 7, 8, 10, 12])
samples = np.array([6, 15, 4, 12, 10, 5])
result = last_smallest(samples, lookup_table)
for i, value in enumerate(samples):
    index = result[i]
    high = lookup_table[index+1] if index < lookup_table.shape[0] - 1 else None
    print(f'{value} is between {lookup_table[index]} and {high}')

This works, however last_smallest function is really not elegant. I've tried to vectorize it, but I can't.

Is it possible to replace result = last_smallest(samples, lookup_table) by pure numpy array operations?

Upvotes: 0

Views: 117

Answers (1)

Kevin
Kevin

Reputation: 3368

np.digitize can be used here:

lookup_table = np.array([4, 6, 7, 8, 10, 12])
samples = np.array([6, 15, 4, 12, 10, 5])
res = np.digitize(samples, lookup_table)

lookup_table = np.append(lookup_table, None) # you might want to change this line

for sample, idx in zip(samples, res):
    print(f'{sample} is between {lookup_table[idx-1]} and {lookup_table[idx]}')

Output:

6 is between 6 and 7
15 is between 12 and None
4 is between 4 and 6
12 is between 12 and None
10 is between 10 and 12
5 is between 4 and 6

Upvotes: 1

Related Questions