Konversi array indeks ke array numpy disandikan 1-panas

227

Katakanlah saya memiliki array numpy 1d

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

Saya ingin menyandikan ini sebagai array 2d 1-hot

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

Apakah ada cara cepat untuk melakukan ini? Lebih cepat daripada hanya mengulang auntuk mengatur elemen b, yaitu.

James Atwood
sumber

Jawaban:

395

Array Anda amenentukan kolom elemen-elemen bukan nol dalam array output. Anda juga perlu menentukan baris dan kemudian menggunakan pengindeksan mewah:

>>> 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.]])
YXD
sumber
111
Cantik. Generalisasi sedikit b = np.zeros((a.size, a.max()+1)):, lalu `b [np.arange (a.size), a] = 1`
James Atwood
10
@ JamesAtwood itu tergantung pada aplikasi tapi saya akan membuat maks parameter dan tidak menghitungnya dari data.
Mohammad Moghimi
1
@MohammadMoghimi Tentu, masuk akal bagi saya.
James Atwood
7
bagaimana jika 'a' adalah 2d? dan Anda ingin 3-d matriks satu-panas?
AD
8
Adakah yang bisa menjelaskan mengapa ini berhasil, tetapi irisan dengan [:, a] tidak?
N. McA.
168
>>> 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.]])
K3 --- rnc
sumber
9
Solusi ini adalah satu-satunya yang berguna untuk input matriks ND ke matriks N + 1D satu-panas. Contoh: input_matrix = np.asarray ([[0,1,1], [1,1,2]]); np.eye (3) [input_matrix] # output tensor 3D
Isaías
5
+1 karena ini harus lebih disukai daripada solusi yang diterima. Untuk solusi yang lebih umum, valuesharuslah array Numpy daripada daftar Python, kemudian bekerja di semua dimensi, tidak hanya dalam 1D.
Alex
8
Perhatikan bahwa mengambil np.max(values) + 1sebagai jumlah kotak mungkin tidak diinginkan jika kumpulan data Anda dikatakan sebagai sampel acak dan kebetulan itu mungkin tidak mengandung nilai maksimal. Jumlah ember harus lebih sebagai parameter dan pernyataan / pemeriksaan dapat dilakukan untuk memeriksa bahwa setiap nilai berada dalam 0 (incl) dan jumlah bucket (excl).
NightElfik
2
Bagi saya solusi ini adalah yang terbaik dan dapat dengan mudah digeneralisasikan ke tensor apa pun: def one_hot (x, depth = 10): return np.eye (depth) [x]. Perhatikan bahwa memberikan tensor x sebagai indeks mengembalikan tensor dari x.shape eye row.
cecconeurale
4
Cara mudah untuk "memahami" solusi ini dan mengapa ia bekerja untuk N-dims (tanpa membaca numpydokumen): di setiap lokasi dalam matriks asli ( values), kami memiliki bilangan bulat k, dan kami "meletakkan" vektor 1-panas eye(n)[k]di lokasi itu . Ini menambahkan dimensi karena kita "meletakkan" vektor di lokasi skalar dalam matriks asli.
avivr
35

Jika Anda menggunakan keras, ada utilitas bawaan untuk itu:

from keras.utils.np_utils import to_categorical   

categorical_labels = to_categorical(int_labels, num_classes=3)

Dan itu hampir sama dengan jawaban @ YXD (lihat kode sumber ).

Jodo
sumber
32

Inilah yang menurut saya berguna:

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

Di sini num_classesadalah singkatan dari jumlah kelas yang Anda miliki. Jadi, jika Anda memiliki avektor dengan bentuk (10000,) fungsi ini mengubahnya menjadi (10000, C) . Perhatikan bahwa aindeks-nol, yaituone_hot(np.array([0, 1]), 2) akan memberi [[1, 0], [0, 1]].

Persis seperti yang Anda inginkan, saya percaya.

PS: sumbernya adalah model Sequence - deeplearning.ai

D. Samchuk
sumber
juga, apa alasan melakukan np.squeeze () karena mendapatkan (ukuran vektor) banyak array panas yang dikodekan menggunakan np.eye(num_classes)[a.reshape(-1)]. What you are simply doing is using np.eye` Anda membuat matriks diagonal dengan setiap indeks kelas sebagai 1 sisa nol dan kemudian menggunakan indeks yang disediakan dengan a.reshape(-1)menghasilkan output yang sesuai dengan indeks dalam np.eye(). Saya tidak mengerti kebutuhan np.sqeezekarena kita menggunakannya untuk hanya menghapus dimensi tunggal yang tidak akan pernah kita miliki karena dalam dimensi output akan selalu(a_flattened_size, num_classes)
Anu
27

Anda bisa menggunakan sklearn.preprocessing.LabelBinarizer:

Contoh:

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

keluaran:

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

Di antara hal-hal lain, Anda dapat menginisialisasi sklearn.preprocessing.LabelBinarizer()sehingga output transformjarang.

Franck Dernoncourt
sumber
21

Anda juga dapat menggunakan fungsi mata numpy:

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

Karma
sumber
1
Untuk lebih jelas menggunakan np.identity(num_classes)[indices]mungkin lebih baik. Jawaban bagus!
Oliver
5

Berikut adalah fungsi yang mengubah vektor 1-D menjadi array panas satu-D.

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

Di bawah ini adalah beberapa contoh penggunaan:

>>> 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]])
stackoverflowuser2010
sumber
Perhatikan bahwa ini hanya berfungsi pada vektor (dan tidak ada assertuntuk memeriksa bentuk vektor;)).
johndodo
1
+1 untuk pendekatan umum dan pemeriksaan parameter. Namun, sebagai praktik umum, saya menyarankan untuk TIDAK menggunakan konfirmasi untuk melakukan pemeriksaan pada input. Gunakan hanya menegaskan untuk memverifikasi kondisi perantara internal. Sebaliknya, konversikan semua assert ___menjadi if not ___ raise Exception(<Reason>).
fnunnari
3

Untuk 1-hot-encoding

   one_hot_encode=pandas.get_dummies(array)

Sebagai contoh

NIKMATI CODING

Shubham Mishra
sumber
Terima kasih atas komentarnya, tetapi deskripsi singkat tentang apa yang dilakukan kode akan sangat membantu!
Clarus
silakan lihat contohnya
Shubham Mishra
@Clarus Periksa contoh di bawah ini. Anda dapat mengakses satu pengodean panas dari setiap nilai dalam array np Anda dengan melakukan one_hot_encode [nilai]. >>> import numpy as np >>> import pandas >>> a = np.array([1,0,3]) >>> one_hot_encode=pandas.get_dummies(a) >>> print(one_hot_encode) 0 1 3 0 0 1 0 1 1 0 0 2 0 0 1 >>> print(one_hot_encode[1]) 0 1 1 0 2 0 Name: 1, dtype: uint8 >>> print(one_hot_encode[0]) 0 0 1 1 2 0 Name: 0, dtype: uint8 >>> print(one_hot_encode[3]) 0 0 1 0 2 1 Name: 3, dtype: uint8
Deepak
2

Saya pikir jawaban singkatnya adalah tidak. Untuk kasus yang lebih umum dalam ndimensi, saya datang dengan ini:

# 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

Saya bertanya-tanya apakah ada solusi yang lebih baik - saya tidak suka saya harus membuat daftar itu di dua baris terakhir. Lagi pula, saya melakukan beberapa pengukuran dengan timeitdan tampaknya numpy-based ( indices/ arange) dan versi iteratif melakukan hal yang sama.

David Nemeskey
sumber
2

Hanya untuk menguraikan jawaban luar biasa dari K3 --- rnc , berikut adalah versi yang lebih umum:

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]

Juga, berikut ini adalah tolok ukur cepat dan kotor dari metode ini dan metode dari jawaban yang saat ini diterima oleh YXD (sedikit berubah, sehingga mereka menawarkan API yang sama kecuali bahwa yang terakhir hanya berfungsi dengan ndarrays 1D):

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

Metode terakhir ~ 35% lebih cepat (MacBook Pro 13 2015), tetapi yang pertama lebih umum:

>>> 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)
Emil Melnikov
sumber
2

Anda dapat menggunakan kode berikut untuk mengkonversi menjadi vektor satu-panas:

misalkan x adalah vektor kelas normal yang memiliki satu kolom dengan kelas 0 ke beberapa nomor:

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

jika 0 bukan kelas; lalu hapus +1.

Inaam Ilahi
sumber
1

Saya baru-baru ini mengalami masalah yang sama dan menemukan solusi yang ternyata hanya memuaskan jika Anda memiliki angka yang masuk dalam formasi tertentu. Misalnya jika Anda ingin menyandiaksarakan satu daftar hot berikut:

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

Silakan, solusi yang diposting sudah disebutkan di atas. Tetapi bagaimana jika mempertimbangkan data ini:

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

Jika Anda melakukannya dengan metode yang disebutkan di atas, Anda kemungkinan akan berakhir dengan 90 kolom satu-panas. Ini karena semua jawaban mencakup sesuatu seperti n = np.max(a)+1. Saya menemukan solusi yang lebih umum yang berhasil untuk saya dan ingin berbagi dengan Anda:

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)

Saya harap seseorang menemukan batasan yang sama pada solusi di atas dan ini mungkin berguna

Hans T
sumber
1

Jenis pengkodean seperti itu biasanya merupakan bagian dari numpy array. Jika Anda menggunakan array numpy seperti ini:

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

maka ada cara yang sangat sederhana untuk mengubahnya menjadi 1-hot encoding

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

Itu dia.

Sudeep K Rana
sumber
1
  • p akan menjadi ndarray 2d.
  • Kami ingin tahu nilai mana yang tertinggi dalam satu baris, untuk menempatkan di sana 1 dan di mana saja 0.

solusi bersih dan mudah:

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

Menggunakan langkah pipa Neuraxle :

  1. Siapkan contoh Anda
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. Lakukan konversi yang sebenarnya
from neuraxle.steps.numpy import OneHotEncoder
encoder = OneHotEncoder(nb_columns=4)
b_pred = encoder.transform(a)
  1. Tegaskan itu berhasil
assert b_pred == b

Tautan ke dokumentasi: neuraxle.steps.numpy.OneHotEncoder

Guillaume Chevalier
sumber
0

Berikut adalah contoh fungsi yang saya tulis untuk melakukan ini berdasarkan jawaban di atas dan kasus penggunaan saya sendiri:

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

Saya menambahkan untuk penyelesaian fungsi sederhana, hanya menggunakan operator 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

Diperlukan sebagai input matriks probabilitas: misalnya:

[[0,03038822 0.65810204 0.16549407 0.3797123] ... [0.02771272 0.2760752 0.3280924 0.33458805]]

Dan itu akan kembali

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

Jordy Van Landeghem
sumber
0

Inilah solusi mandiri dimensi-independen.

Ini akan mengkonversi array N-dimensi arrdari bilangan bulat negatif ke array N + 1-dimensi satu-panas one_hot, di mana one_hot[i_1,...,i_N,c] = 1artinya arr[i_1,...,i_N] = c. Anda dapat memulihkan input melaluinp.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
eqzx
sumber
0

Gunakan kode berikut. Ini bekerja paling baik.

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

Ditemukan di sini PS Anda tidak perlu masuk ke tautan.

Inaam Ilahi
sumber
5
Anda harus menghindari menggunakan loop dengan numpy
Kenan