wake-up-neo.net

Konvertieren Sie ein Array von Indizes in ein 1-hot-codiertes numpy-Array

Nehmen wir an, ich habe ein numpy 1d Array

a = array([1,0,3])

Ich möchte dieses als 2d 1-hot-Array kodieren 

b = array([[0,1,0,0], [1,0,0,0], [0,0,0,1]])

Gibt es einen schnellen Weg, dies zu tun? Schneller als nur das Schleifen von a, um Elemente von b zu setzen.

137
James Atwood

Ihr Array a definiert die Spalten der Nicht-Null-Elemente im Ausgabearray. Sie müssen auch die Zeilen definieren und dann die fantastische Indizierung verwenden:

>>> 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.]])
267
YXD
>>> 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.]])
113
K3---rnc

Sie können sklearn.preprocessing.LabelBinarizer verwenden:

Beispiel:

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))

ausgabe:

[[0 1 0 0]
 [1 0 0 0]
 [0 0 0 1]]

Sie können ua sklearn.preprocessing.LabelBinarizer() so initialisieren, dass die Ausgabe von transform spärlich ist.

24

Folgendes finde ich nützlich:

def one_hot(a, num_classes):
  return np.squeeze(np.eye(num_classes)[a.reshape(-1)])

Hier steht num_classes für die Anzahl der Klassen, die Sie haben. Wenn Sie also einen a-Vektor mit der Form (10000,) haben, transformiert diese Funktion ihn in (10000, C). Beachten Sie, dass a nullindiziert ist, d. H. one_hot(np.array([0, 1]), 2) ergibt [[1, 0], [0, 1]].

Genau das, was Sie haben wollten, glaube ich.

PS: Die Quelle ist Sequenzmodelle - deeplearning.ai

21
D.Samchuk

Falls Sie Keras verwenden, gibt es dafür ein eingebautes Hilfsprogramm:

from keras.utils.np_utils import to_categorical   

categorical_labels = to_categorical(int_labels, num_classes=3)

Und es ist so ziemlich das Gleiche wie @ YXDs Antwort (siehe Quellcode ).

18
Jodo

numpy.eye (Größe der Klasse) [zu konvertierender Vektor]

5
Karma

Hier ist eine Funktion, die einen 1-D-Vektor in ein 2D-Hot-Array konvertiert.

#!/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)

Nachfolgend einige Verwendungsbeispiele:

>>> 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]])

Ich denke, die kurze Antwort ist nein. Für einen allgemeineren Fall in n-Dimensionen habe ich Folgendes gefunden:

# 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

Ich frage mich, ob es eine bessere Lösung gibt - ich mag es nicht, dass ich diese Listen in den letzten beiden Zeilen erstellen muss. Wie auch immer, ich habe einige Messungen mit timeit durchgeführt und es scheint, dass die numpy-basiert (indices/arange) und die iterativen Versionen ungefähr das gleiche bewirken. 

2
David Nemeskey

Sie können den folgenden Code zum Konvertieren in einen One-Hot-Vektor verwenden:

let x ist der normale Klassenvektor mit einer einzelnen Spalte mit Klassen 0 bis zu einer bestimmten Zahl:

import numpy as np
np.eye(x.max()+1)[x]

wenn 0 keine Klasse ist; dann entferne +1.

1
Inaam Ilahi

Ich bin kürzlich auf ein Problem derselben Art gestoßen und habe diese Lösung gefunden, die sich nur dann als zufriedenstellend erwies, wenn Sie Zahlen haben, die in eine bestimmte Formation passen. Zum Beispiel, wenn Sie die folgende Liste mit einem Hot-Code kodieren möchten:

all_good_list = [0,1,2,3,4]

los, die veröffentlichten Lösungen sind bereits oben erwähnt. Was aber, wenn man diese Daten betrachtet:

problematic_list = [0,23,12,89,10]

Wenn Sie dies mit den oben genannten Methoden tun, werden Sie wahrscheinlich 90 One-Hot-Spalten erhalten. Dies liegt daran, dass alle Antworten so etwas wie n = np.max(a)+1 enthalten. Ich habe eine allgemeinere Lösung gefunden, die für mich funktioniert hat und mit Ihnen teilen wollte:

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)

Ich hoffe, dass bei den oben genannten Lösungen die gleichen Einschränkungen aufgetreten sind, und dies könnte hilfreich sein

1
Hans T

Verwenden Sie den folgenden Code. Es funktioniert am besten.

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

Fand es hier P.S Sie müssen nicht in den Link gehen.

1
Inaam Ilahi
  • p wird ein 2. ndarray sein.
  • Wir möchten wissen, welcher Wert der höchste Wert in einer Reihe ist, und dort 1 und überall sonst 0. 

saubere und einfache Lösung:

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)
1
MiFi

Um nur auf die excellent answer from K3 --- rnc einzugehen, hier eine allgemeinere Version:

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]

Hier ist auch ein schneller und schmutziger Benchmark dieser Methode und eine Methode aus der aktuell akzeptierten Antwort by YXD (etwas geändert, so dass sie dieselbe API anbieten, außer dass die letztere funktioniert nur bei 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

Die letztere Methode ist ~ 35% schneller (MacBook Pro 13 2015), aber die erstere ist allgemeiner:

>>> 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)
1
Emil Melnikov

Diese Art der Codierung ist normalerweise Teil eines numpy-Arrays. Wenn Sie ein numpy-Array wie folgt verwenden:

a = np.array([1,0,3])

dann gibt es eine sehr einfache Möglichkeit, diese in 1-hot-Kodierung umzuwandeln

out = (np.arange(4) == a[:,None]).astype(np.float32)

Das ist es.

1
Sudeep K Rana

Hier ist eine dimensionalitätsunabhängige eigenständige Lösung.

Dies konvertiert jedes N-dimensionale Array arr von nichtnegativen Ganzzahlen in ein N + 1-dimensionales Array one_hot, wobei one_hot[i_1,...,i_N,c] = 1arr[i_1,...,i_N] = c bedeutet. Sie können die Eingabe über np.argmax(one_hot, -1) wiederherstellen.

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
0
eqzx

Hier ist eine Beispielfunktion, die ich dazu geschrieben habe, basierend auf den obigen Antworten und meinem eigenen Anwendungsfall:

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)
0
Aaron Lelevier

Ich füge zur Vervollständigung eine einfache Funktion hinzu, die nur numpy-Operatoren verwendet: 

   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

Als Eingabe wird eine Wahrscheinlichkeitsmatrix verwendet: z. 

[[0.03038822 0,65810204 0,16549407 0,3797123] ... [0,02771272 0,2760752 0,3280924 0,33458805]] 

Und es wird wiederkommen

[[0 1 0 0] ... [0 0 0 1]]

0