Disons que j'ai un tableau 1p numpy
a = array([1,0,3])
Je voudrais encoder ceci comme un tableau 2d 1-hot
b = array([[0,1,0,0], [1,0,0,0], [0,0,0,1]])
Y at-il un moyen rapide de faire cela? Plus rapide que de simplement parcourir a
pour définir les éléments de b
, c’est-à-dire.
Votre tableau a
définit les colonnes des éléments non nuls du tableau en sortie. Vous devez également définir les lignes, puis utiliser une indexation sophistiquée:
>>> a = np.array([1, 0, 3])
>>> b = np.zeros((3, 4))
>>> b[np.arange(3), a] = 1
>>> b
array([[ 0., 1., 0., 0.],
[ 1., 0., 0., 0.],
[ 0., 0., 0., 1.]])
>>> values = [1, 0, 3]
>>> n_values = np.max(values) + 1
>>> np.eye(n_values)[values]
array([[ 0., 1., 0., 0.],
[ 1., 0., 0., 0.],
[ 0., 0., 0., 1.]])
Vous pouvez utiliser sklearn.preprocessing.LabelBinarizer
:
Exemple:
import sklearn.preprocessing
a = [1,0,3]
label_binarizer = sklearn.preprocessing.LabelBinarizer()
label_binarizer.fit(range(max(a)+1))
b = label_binarizer.transform(a)
print('{0}'.format(b))
sortie:
[[0 1 0 0]
[1 0 0 0]
[0 0 0 1]]
Entre autres choses, vous pouvez initialiser sklearn.preprocessing.LabelBinarizer()
afin que la sortie de transform
soit rare.
Voici ce que je trouve utile:
def one_hot(a, num_classes):
return np.squeeze(np.eye(num_classes)[a.reshape(-1)])
Ici, num_classes
représente le nombre de classes que vous avez. Donc, si vous avez un vecteur a
de forme (10000,), cette fonction le transforme en (10000, C). Notez que a
est indexé à zéro, c'est-à-dire que one_hot(np.array([0, 1]), 2)
donnera [[1, 0], [0, 1]]
.
Je crois que c'est exactement ce que tu voulais avoir.
PS: la source est Modèles de séquence - deeplearning.ai
Si vous utilisez keras, il existe un utilitaire intégré pour cela:
from keras.utils.np_utils import to_categorical
categorical_labels = to_categorical(int_labels, num_classes=3)
Et il fait à peu près la même chose que @ YXD répond (voir code-source ).
numpy.eye (taille de la classe) [vecteur à convertir]
Voici une fonction qui convertit un vecteur unidimensionnel en une matrice bidimensionnelle à une densité.
#!/usr/bin/env python
import numpy as np
def convertToOneHot(vector, num_classes=None):
"""
Converts an input 1-D vector of integers into an output
2-D array of one-hot vectors, where an i'th input value
of j will set a '1' in the i'th row, j'th column of the
output array.
Example:
v = np.array((1, 0, 4))
one_hot_v = convertToOneHot(v)
print one_hot_v
[[0 1 0 0 0]
[1 0 0 0 0]
[0 0 0 0 1]]
"""
assert isinstance(vector, np.ndarray)
assert len(vector) > 0
if num_classes is None:
num_classes = np.max(vector)+1
else:
assert num_classes > 0
assert num_classes >= np.max(vector)
result = np.zeros(shape=(len(vector), num_classes))
result[np.arange(len(vector)), vector] = 1
return result.astype(int)
Ci-dessous quelques exemples d'utilisation:
>>> a = np.array([1, 0, 3])
>>> convertToOneHot(a)
array([[0, 1, 0, 0],
[1, 0, 0, 0],
[0, 0, 0, 1]])
>>> convertToOneHot(a, num_classes=10)
array([[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]])
Je pense que la réponse courte est non. Pour un cas plus générique dans les dimensions n
, j'ai proposé ceci:
# For 2-dimensional data, 4 values
a = np.array([[0, 1, 2], [3, 2, 1]])
z = np.zeros(list(a.shape) + [4])
z[list(np.indices(z.shape[:-1])) + [a]] = 1
Je me demande s'il existe une meilleure solution. Je n'aime pas être obligée de créer ces listes dans les deux dernières lignes. Quoi qu'il en soit, j'ai fait quelques mesures avec timeit
et il semble que la version numpy
- (indices
/arange
) et les versions itératives fonctionnent à peu près de la même façon.
Vous pouvez utiliser le code suivant pour convertir en un vecteur one-hot:
let x est le vecteur de classe normal ayant une seule colonne avec les classes 0 à un certain nombre:
import numpy as np
np.eye(x.max()+1)[x]
si 0 n'est pas une classe; puis supprimez +1.
J'ai récemment rencontré un problème du même genre et j'ai trouvé cette solution qui ne s'est révélée satisfaisante que si vous avez des chiffres correspondant à une certaine formation. Par exemple, si vous voulez encoder une liste à chaud dans la liste suivante:
all_good_list = [0,1,2,3,4]
allez-y, les solutions affichées sont déjà mentionnées ci-dessus. Mais qu'en est-il si on considère ces données:
problematic_list = [0,23,12,89,10]
Si vous le faites avec les méthodes mentionnées ci-dessus, vous obtiendrez probablement 90 colonnes one-hot. En effet, toutes les réponses incluent quelque chose comme n = np.max(a)+1
. J'ai trouvé une solution plus générique qui a fonctionné pour moi et que je voulais partager avec vous:
import numpy as np
import sklearn
sklb = sklearn.preprocessing.LabelBinarizer()
a = np.asarray([1,2,44,3,2])
n = np.unique(a)
sklb.fit(n)
b = sklb.transform(a)
J'espère que quelqu'un a rencontré les mêmes restrictions sur les solutions ci-dessus et que cela pourrait être utile
Utilisez le code suivant. Ça marche mieux.
def one_hot_encode(x):
"""
argument
- x: a list of labels
return
- one hot encoding matrix (number of labels, number of class)
"""
encoded = np.zeros((len(x), 10))
for idx, val in enumerate(x):
encoded[idx][val] = 1
return encoded
Vous l'avez trouvé ici P.S Vous n'avez pas besoin d'entrer dans le lien.
extrait de code
max_elements_i = np.expand_dims(np.argmax(p, axis=1), axis=1)
one_hot = np.zeros(p.shape)
np.put_along_axis(one_hot, max_elements_i, 1, axis=1)
Juste pour élaborer sur le excellente réponse de K3 --- rnc , voici une version plus générique:
def onehottify(x, n=None, dtype=float):
"""1-hot encode x with the max value n (computed from data if n is None)."""
x = np.asarray(x)
n = np.max(x) + 1 if n is None else n
return np.eye(n, dtype=dtype)[x]
En outre, voici un test de performance rapide de cette méthode et une méthode de la réponse actuellement acceptée par YXD (légèrement modifiée, de sorte qu’elles offrent la même API, sauf que ce dernier ne fonctionne qu'avec 1D ndarrays):
def onehottify_only_1d(x, n=None, dtype=float):
x = np.asarray(x)
n = np.max(x) + 1 if n is None else n
b = np.zeros((len(x), n), dtype=dtype)
b[np.arange(len(x)), x] = 1
return b
Cette dernière méthode est environ 35% plus rapide (MacBook Pro 13 2015), mais la première est plus générale:
>>> import numpy as np
>>> np.random.seed(42)
>>> a = np.random.randint(0, 9, size=(10_000,))
>>> a
array([6, 3, 7, ..., 5, 8, 6])
>>> %timeit onehottify(a, 10)
188 µs ± 5.03 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
>>> %timeit onehottify_only_1d(a, 10)
139 µs ± 2.78 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Ce type de codage fait généralement partie du tableau numpy. Si vous utilisez un tableau numpy comme ceci:
a = np.array([1,0,3])
alors il existe un moyen très simple de convertir cela en encodage 1-hot
out = (np.arange(4) == a[:,None]).astype(np.float32)
C'est tout.
Voici une solution autonome indépendante de la dimensionnalité.
Cela convertira tout tableau __dimensionnel arr
de nombres entiers non négatifs en un tableau one_hot
à une seule liste chaude, où one_hot[i_1,...,i_N,c] = 1
signifie arr[i_1,...,i_N] = c
. Vous pouvez récupérer l’entrée via np.argmax(one_hot, -1)
def expand_integer_grid(arr, n_classes):
"""
:param arr: N dim array of size i_1, ..., i_N
:param n_classes: C
:returns: one-hot N+1 dim array of size i_1, ..., i_N, C
:rtype: ndarray
"""
one_hot = np.zeros(arr.shape + (n_classes,))
axes_ranges = [range(arr.shape[i]) for i in range(arr.ndim)]
flat_grids = [_.ravel() for _ in np.meshgrid(*axes_ranges, indexing='ij')]
one_hot[flat_grids + [arr.ravel()]] = 1
assert((one_hot.sum(-1) == 1).all())
assert(np.allclose(np.argmax(one_hot, -1), arr))
return one_hot
Voici un exemple de fonction que j'ai écrit pour le faire en fonction des réponses ci-dessus et de mon propre cas d'utilisation:
def label_vector_to_one_hot_vector(vector, one_hot_size=10):
"""
Use to convert a column vector to a 'one-hot' matrix
Example:
vector: [[2], [0], [1]]
one_hot_size: 3
returns:
[[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 1., 0.]]
Parameters:
vector (np.array): of size (n, 1) to be converted
one_hot_size (int) optional: size of 'one-hot' row vector
Returns:
np.array size (vector.size, one_hot_size): converted to a 'one-hot' matrix
"""
squeezed_vector = np.squeeze(vector, axis=-1)
one_hot = np.zeros((squeezed_vector.size, one_hot_size))
one_hot[np.arange(squeezed_vector.size), squeezed_vector] = 1
return one_hot
label_vector_to_one_hot_vector(vector=[[2], [0], [1]], one_hot_size=3)
J'ajoute pour compléter une fonction simple, en utilisant uniquement des opérateurs numpy:
def probs_to_onehot(output_probabilities):
argmax_indices_array = np.argmax(output_probabilities, axis=1)
onehot_output_array = np.eye(np.unique(argmax_indices_array).shape[0])[argmax_indices_array.reshape(-1)]
return onehot_output_array
Il prend en entrée une matrice de probabilité:
[[0.03038822 0.65810204 0.16549407 0.3797123] ... [0.02771272 0.2760752 0.3280924 0.33458805]]
Et ça va revenir
[[0 1 0 0] ... [0 0 0 1]]