generar secuencia por índices / encoding one-hot

Tengo una secuencia s = [4,3,1,0,5] y num_classes = 6 y quiero generar una matriz Numpy m de forma (len(s), num_classes) donde m[i,j] = 1 if s[i] == j else 0 .

¿Existe tal función en Numpy, donde puedo pasar s y num_classes ?

Esto también se denomina encoding 1-of-k o one-hot.


resultados de timeit :

 def b(): m = np.zeros((len(s), num_classes)) m[np.arange(len(s)), s] = 1 return m In [57]: timeit.timeit(lambda: b(), number=1000) Out[57]: 0.012787103652954102 In [61]: timeit.timeit(lambda: (np.array(s)[:,None]==np.arange(num_classes))+0, number=1000) Out[61]: 0.018411874771118164 

Como desea un solo 1 por fila, puede hacer un índice de lujo utilizando arange(len(s)) largo del primer eje, y usando s largo del segundo:

 s = [4,3,1,0,5] n = len(s) k = 6 m = np.zeros((n, k)) m[np.arange(n), s] = 1 m => array([[ 0., 0., 0., 0., 1., 0.], [ 0., 0., 0., 1., 0., 0.], [ 0., 1., 0., 0., 0., 0.], [ 1., 0., 0., 0., 0., 0.], [ 0., 0., 0., 0., 0., 1.]]) m.nonzero() => (array([0, 1, 2, 3, 4]), array([4, 3, 1, 0, 5])) 

Se puede pensar que esto usa el índice (0,4), luego (1,3), luego (2,1), (3,0), (4,5).

Puedes usar la broadcasting

 (np.array(s)[:,None]==np.arange(num_classes))+0 

Ejecución de la muestra

 In [439]: s Out[439]: [4, 3, 1, 0, 5] In [440]: num_classes = 9 In [441]: (np.array(s)[:,None]==np.arange(num_classes))+0 Out[441]: array([[0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0]]) 

Brocasting todavía funciona solo hacer

$ (tags [:,:,:, Ninguna] == np.arange (num_classes)) + 0

La respuesta aceptada no funcionará si su encoding instantánea agrega una dimensión adicional a una matriz multidimensional. El uso de la difusión le dará resultados inesperados – https://scipy.github.io/old-wiki/pages/Cookbook/Indexing . Esta solución es elegante pero no muy eficiente.

 labels.shape # (80, 256, 10) def b(labels): onehot = np.zeros((a,b,c,num_classes), dtype=float) # This is the slow, dumb line: (onehot_i, onehot_j, onehot_k) = np.ones(labels.shape).nonzero() thehotone = labels[onehot_i, onehot_j, onehot_k] onehot[onehot_i, onehot_j, onehot_k, thehotone] = 1 return onehot