Array van indices converteren naar 1-hot gecodeerde numpy array

Stel dat ik een 1d numpy array heb

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

Ik wil dit graag coderen als een 2D one-hot array

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

Is er een snelle manier om dit te doen? Sneller dan alleen aherhalen om elementen van bin te stellen, tenminste.


Antwoord 1, autoriteit 100%

Uw array adefinieert de kolommen van de niet-nul-elementen in de uitvoerarray. U moet ook de rijen definiëren en vervolgens mooie indexering gebruiken:

>>> a = np.array([1, 0, 3])
>>> b = np.zeros((a.size, a.max()+1))
>>> b[np.arange(a.size),a] = 1
>>> b
array([[ 0.,  1.,  0.,  0.],
       [ 1.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  1.]])

Antwoord 2, autoriteit 48%

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

Antwoord 3, autoriteit 10%

Als je keras gebruikt, is daar een ingebouwde tool voor:

from keras.utils.np_utils import to_categorical   
categorical_labels = to_categorical(int_labels, num_classes=3)

En het doet vrijwel hetzelfde als @YXD’s antwoord(zie broncode).


Antwoord 4, autoriteit 9%

Dit vind ik handig:

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

Hier staat num_classesvoor het aantal lessen dat je hebt. Dus als je een avector hebt met de vorm (10000,), transformeert deze functie deze naar (10000,C). Merk op dat anul-geïndexeerd is, dwz one_hot(np.array([0, 1]), 2)geeft [[1, 0], [0, 1]].

Precies wat je wilde hebben geloof ik.

PS: de bron is Sequence models – deeplearning.ai


Antwoord 5, autoriteit 8%

U kunt ook de oog-functie van numpy gebruiken :

numpy.eye(number of classes)[vector containing the labels]


Antwoord 6, autoriteit 6%

U kunt sklearn.preprocessing.LabelBinarizer:

Voorbeeld:

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

uitvoer:

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

U kunt onder andere sklearn.preprocessing.LabelBinarizer()initialiseren zodat de uitvoer van transformschaars is.


Antwoord 7

Voor 1-hot-codering

  one_hot_encode=pandas.get_dummies(array)

Bijvoorbeeld

GENIET VAN CODEREN


Antwoord 8

U kunt de volgende code gebruiken om te converteren naar een one-hot vector:

let x is de normale klassenvector met een enkele kolom met klassen 0 tot een of ander getal:

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

als 0 geen klasse is; verwijder vervolgens +1.


Antwoord 9

Hier is een functie die een 1-D vector omzet in een 2-D one-hot array.

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

Hieronder ziet u een voorbeeld van gebruik:

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

Antwoord 10

Ik denk dat het korte antwoord nee is. Voor een meer algemeen geval in ndimensies, kwam ik met dit:

# 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

Ik vraag me af of er een betere oplossing is — ik vind het niet prettig dat ik die lijsten in de laatste twee regels moet maken. Hoe dan ook, ik heb wat metingen gedaan met timeiten het lijkt erop dat de op numpygebaseerde (indices/arange) en de iteratieve versies presteren ongeveer hetzelfde.


Antwoord 11

Gewoon om uit te wijden over het uitstekende antwoordvan K3—rnc, hier is een meer algemene versie:

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 is ook een quick-and-dirty benchmark van deze methode en een methode uit het momenteel geaccepteerde antwoordvan YXD(enigszins gewijzigd, zodat ze dezelfde API bieden, behalve dat de laatste alleen werkt met 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

De laatste methode is ~35% sneller (MacBook Pro 13 2015), maar de eerste is algemener:

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

Antwoord 12

def one_hot(n, class_num, col_wise=True):
  a = np.eye(class_num)[n.reshape(-1)]
  return a.T if col_wise else a
# Column for different hot
print(one_hot(np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 8, 7]), 10))
# Row for different hot
print(one_hot(np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 8, 7]), 10, col_wise=False))

Antwoord 13

Ik kwam onlangs een soortgelijk probleem tegen en vond de oplossing die alleen bevredigend bleek te zijn als je getallen hebt die binnen een bepaalde formatie vallen. Als u bijvoorbeeld de volgende lijst in één keer wilt coderen:

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

ga je gang, de geposte oplossingen zijn hierboven al genoemd. Maar wat als u deze gegevens overweegt:

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

Als u het doet met de hierboven genoemde methoden, krijgt u waarschijnlijk 90 one-hot-kolommen. Dit komt omdat alle antwoorden iets bevatten als n = np.max(a)+1. Ik heb een meer algemene oplossing gevonden die voor mij werkte en die ik met jullie wil delen:

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)

Ik hoop dat iemand dezelfde beperkingen heeft ondervonden bij bovenstaande oplossingen en dat dit van pas kan komen


Antwoord 14

Dergelijke codering maakt meestal deel uit van een numpy-array. Als u een numpy-array zoals deze gebruikt:

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

dan is er een heel eenvoudige manier om dat om te zetten in 1-hot codering

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

Dat is het.


Antwoord 15

  • p zal een 2d ndarray zijn.
  • We willen weten welke waarde de hoogste op een rij is, om daar 1 te zetten en overal 0.

schone en gemakkelijke oplossing:

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)

Antwoord 16

Hier is een voorbeeldfunctie die ik heb geschreven om dit te doen op basis van de bovenstaande antwoorden en mijn eigen gebruiksscenario:

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)

Antwoord 17

Ik voeg ter voltooiing een eenvoudige functie toe, waarbij alleen numpy-operators worden gebruikt:

  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 invoer is een kansmatrix nodig: bijv.:

[[0.03038822 0.65810204 0.16549407 0.3797123 ]

[0.02771272 0.2760752 0.3280924 0.33458805]]

En het zal terugkeren

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


Antwoord 18

Hier is een dimensionaliteitsonafhankelijke zelfstandige oplossing.

Dit converteert elke N-dimensionale array arrvan niet-negatieve gehele getallen naar een een-hot N+1-dimensionale array one_hot, waarbij one_hot[i_1,...,i_N,c] = 1betekent arr[i_1,...,i_N] = c. U kunt de invoer herstellen 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

Antwoord 19

Gebruik de volgende code. Het werkt het beste.

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

Hier gevondenPS je hebt het niet nodig om naar de link te gaan.


Antwoord 20

Ik vind de gemakkelijkste oplossing een combinatie van np.takeen np.eye

def one_hot(x, depth: int):
  return np.take(np.eye(depth), x, axis=0)

werkt voor xvan elke vorm.


Antwoord 21

Een Neuraxle-pijplijnstap gebruiken:

  1. Stel je voorbeeld in
import numpy as np
a = np.array([1,0,3])
b = np.array([[0,1,0,0], [1,0,0,0], [0,0,0,1]])
  1. Doe de daadwerkelijke conversie
from neuraxle.steps.numpy import OneHotEncoder
encoder = OneHotEncoder(nb_columns=4)
b_pred = encoder.transform(a)
  1. Beweer dat het werkt
assert b_pred == b

Link naar documentatie: neuraxle .steps.numpy.OneHotEncoder


Antwoord 22

Als u tensorflowgebruikt, is er one_hot():

import tensorflow as tf
import numpy as np
a = np.array([1, 0, 3])
depth = 4
b = tf.one_hot(a, depth)
# <tf.Tensor: shape=(3, 3), dtype=float32, numpy=
# array([[0., 1., 0.],
#        [1., 0., 0.],
#        [0., 0., 0.]], dtype=float32)>

Other episodes