Chuyển đổi mảng chỉ số sang mảng numpy được mã hóa 1-hot


227

Hãy nói rằng tôi có một mảng numpy 1d

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

Tôi muốn mã hóa nó thành một mảng 2d 1-hot

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

Có một cách nhanh chóng để làm điều này? Nhanh hơn là chỉ lặp đi lặp lại ađể thiết lập các yếu tố của b, đó là.

Câu trả lời:


395

Mảng của bạn axác định các cột của các phần tử khác 0 trong mảng đầu ra. Bạn cũng cần xác định các hàng và sau đó sử dụng lập chỉ mục ưa thích:

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

111
Xinh đẹp. Tổng quát hóa nó một chút : b = np.zeros((a.size, a.max()+1)), sau đó `b [np.arange (a.size), a] = 1`
James Atwood

10
@JamesAtwood tùy thuộc vào ứng dụng nhưng tôi sẽ tạo tối đa một tham số và không tính toán nó từ dữ liệu.
Mohammad Moghimi 8/2/2016

1
@MohammadMoghimi Chắc chắn, có ý nghĩa với tôi.
James Atwood

7
Nếu 'a' được 2ngày thì sao? và bạn muốn một ma trận 3-d một nóng?
AD

8
Bất cứ ai cũng có thể chỉ ra một lời giải thích tại sao điều này hoạt động, nhưng lát cắt với [:, a] thì không?
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.]])

9
Giải pháp này là duy nhất hữu ích cho ma trận ND đầu vào thành ma trận N + 1D nóng. Ví dụ: input_matrix = np.asarray ([[0,1,1], [1,1,2]]); np.eye (3) [input_matrix] # đầu ra 3D tenor
Isaías

5
+1 vì điều này nên được ưu tiên hơn giải pháp được chấp nhận. Đối với một giải pháp tổng quát hơn, valuesnên là một mảng Numpy chứ không phải là một danh sách Python, sau đó nó hoạt động ở tất cả các chiều, không chỉ trong 1D.
Alex

8
Lưu ý rằng việc lấy np.max(values) + 1số lượng xô có thể không được mong muốn nếu tập dữ liệu của bạn được lấy mẫu ngẫu nhiên và chỉ có thể nó không chứa giá trị tối đa. Số lượng xô phải là một tham số và có thể có xác nhận / kiểm tra để kiểm tra xem mỗi giá trị nằm trong 0 (bao gồm) và số lượng xô (excl).
NightElfik

2
Đối với tôi giải pháp này là tốt nhất và có thể dễ dàng khái quát cho bất kỳ tenor nào: def one_hot (x, height = 10): return np.eye (độ sâu) [x]. Lưu ý rằng việc cung cấp tenx x làm chỉ mục trả về một tenor của hàng mắt x.shape.
cecconeurale 27/03/18

4
Cách dễ dàng để "hiểu" giải pháp này và lý do tại sao nó hoạt động cho N-dims (không đọc numpytài liệu): tại mỗi vị trí trong ma trận gốc ( values), chúng tôi có một số nguyên kvà chúng tôi "đặt" vectơ 1 nóng eye(n)[k]ở vị trí đó . Điều này thêm một thứ nguyên vì chúng ta "đặt" một vectơ vào vị trí của vô hướng trong ma trận gốc.
avivr

35

Trong trường hợp bạn đang sử dụng máy ảnh, có một tiện ích tích hợp cho điều đó:

from keras.utils.np_utils import to_categorical   

categorical_labels = to_categorical(int_labels, num_classes=3)

Và nó thực hiện khá giống câu trả lời của @ YXD (xem mã nguồn ).


32

Đây là những gì tôi thấy hữu ích:

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

Ở đây num_classeslà viết tắt của số lớp bạn có. Vì vậy, nếu bạn có avectơ có hình dạng (10000,) thì hàm này biến đổi nó thành (10000, C) . Lưu ý rằng akhông có chỉ mục, tức là one_hot(np.array([0, 1]), 2)sẽ cung cấp [[1, 0], [0, 1]].

Chính xác những gì bạn muốn có tôi tin.

PS: nguồn là các mô hình Sequence - deeplearning.ai


Ngoài ra, lý do của việc thực hiện np.squeeze () là gì khi lấy (vectơ kích thước) nhiều mảng được mã hóa nóng bằng np.eye(num_classes)[a.reshape(-1)]. What you are simply doing is using np.eye`, bạn đang tạo một ma trận đường chéo với mỗi chỉ số lớp là 1 phần 0 và sau đó sử dụng các chỉ mục được cung cấp bằng cách a.reshape(-1)sản xuất đầu ra tương ứng với chỉ số trong np.eye(). Tôi không hiểu sự cần thiết np.sqeezevì chúng tôi sử dụng nó để loại bỏ các kích thước đơn lẻ mà chúng tôi sẽ không bao giờ có vì kích thước của đầu ra sẽ luôn là(a_flattened_size, num_classes)
Anu

27

Bạn có thể sử dụng sklearn.preprocessing.LabelBinarizer:

Thí dụ:

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

đầu ra:

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

Trong số những thứ khác, bạn có thể khởi tạo sklearn.preprocessing.LabelBinarizer()để đầu ra của transformthưa thớt.


21

Bạn cũng có thể sử dụng chức năng mắt của numpy:

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


1
Để rõ ràng hơn bằng cách sử dụng np.identity(num_classes)[indices]có thể tốt hơn. Câu trả lời tốt đẹp!
Oliver

5

Đây là một hàm chuyển đổi một vectơ 1-D thành một mảng 2-D một nóng.

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

Dưới đây là một số ví dụ sử dụng:

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

Lưu ý rằng điều này chỉ hoạt động trên các vectơ (và không có assertđể kiểm tra hình dạng vectơ;)).
johndodo

1
+1 cho cách tiếp cận tổng quát và kiểm tra tham số. Tuy nhiên, như một thông lệ, tôi đề nghị KHÔNG sử dụng các xác nhận để thực hiện kiểm tra các đầu vào. Chỉ sử dụng các xác nhận để xác minh các điều kiện trung gian nội bộ. Thay vào đó, chuyển đổi tất cả assert ___thành if not ___ raise Exception(<Reason>).
fnunnari

3

Đối với mã hóa 1 nóng

   one_hot_encode=pandas.get_dummies(array)

Ví dụ

THƯỞNG THỨC


Cảm ơn vì nhận xét, nhưng một mô tả ngắn gọn về những gì mã đang làm sẽ rất hữu ích!
Clarus

vui lòng tham khảo ví dụ
Shubham Mishra

@Clarus Kiểm tra ví dụ dưới đây. Bạn có thể truy cập một mã hóa nóng của từng giá trị trong mảng np của mình bằng cách thực hiện one_hot_encode [value]. >>> 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

Tôi nghĩ rằng câu trả lời ngắn gọn là không. Đối với một trường hợp chung hơn về nkích thước, tôi đã đưa ra điều này:

# 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

Tôi tự hỏi liệu có một giải pháp tốt hơn - tôi không muốn phải tạo ra những danh sách đó trong hai dòng cuối cùng. Dù sao, tôi đã thực hiện một số phép đo với timeitvà có vẻ như các phiên bản numpydựa trên ( indices/ arange) và lặp lại thực hiện giống nhau.


2

Chỉ cần giải thích về câu trả lời xuất sắc từ K3 --- rnc , đây là một phiên bản chung hơn:

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]

Ngoài ra, đây là một điểm chuẩn nhanh và bẩn của phương pháp này và một phương pháp từ câu trả lời hiện được chấp nhận bởi YXD (thay đổi một chút, để họ cung cấp cùng một API ngoại trừ phương pháp sau chỉ hoạt động với 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

Phương pháp sau nhanh hơn ~ 35% (MacBook Pro 13 2015), nhưng phương pháp trước đây chung chung hơn:

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

2

Bạn có thể sử dụng mã sau đây để chuyển đổi thành một vectơ nóng:

Đặt x là vectơ lớp bình thường có một cột với các lớp từ 0 đến một số:

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

nếu 0 không phải là một lớp; sau đó xóa +1.


1

Gần đây tôi đã gặp phải một vấn đề cùng loại và tìm thấy giải pháp mà hóa ra chỉ thỏa mãn nếu bạn có những con số nằm trong một đội hình nhất định. Ví dụ: nếu bạn muốn mã hóa một danh sách sau:

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

đi trước, các giải pháp được đăng đã được đề cập ở trên. Nhưng nếu xem xét dữ liệu này:

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

Nếu bạn làm điều đó với các phương pháp được đề cập ở trên, bạn có thể sẽ kết thúc với 90 cột một nóng. Điều này là bởi vì tất cả các câu trả lời bao gồm một cái gì đó như n = np.max(a)+1. Tôi tìm thấy một giải pháp chung chung hơn cho tôi và muốn chia sẻ với bạn:

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)

Tôi hy vọng ai đó gặp phải những hạn chế tương tự đối với các giải pháp trên và điều này có thể có ích


1

Loại mã hóa như vậy thường là một phần của mảng numpy. Nếu bạn đang sử dụng một mảng numpy như thế này:

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

sau đó, có một cách rất đơn giản để chuyển đổi nó thành mã hóa 1 nóng

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

Đó là nó.


1
  • p sẽ là một ndarray 2d.
  • Chúng tôi muốn biết giá trị nào cao nhất trong một hàng, để đặt ở đó 1 và mọi nơi khác 0.

giải pháp sạch sẽ và dễ dàng:

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

Sử dụng bước đường ống Neuraxle :

  1. Thiết lập ví dụ của bạn
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. Thực hiện chuyển đổi thực tế
from neuraxle.steps.numpy import OneHotEncoder
encoder = OneHotEncoder(nb_columns=4)
b_pred = encoder.transform(a)
  1. Khẳng định nó hoạt động
assert b_pred == b

Liên kết đến tài liệu: neuraxle.steps.numpy.OneHotEncoder


0

Đây là một hàm ví dụ mà tôi đã viết để làm điều này dựa trên các câu trả lời ở trên và trường hợp sử dụng của riêng tôi:

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

Tôi đang thêm để hoàn thành một chức năng đơn giản, chỉ sử dụng các toán tử 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

Nó nhận như là một ma trận xác suất: vd:

[[0,03038822 0,65810204 0,12549407 0,3797123] ... [0,02771272 0,2760752 0,3280924 0,33458805]]

Và nó sẽ trở lại

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


0

Đây là một giải pháp độc lập độc lập về chiều.

Điều này sẽ chuyển đổi bất kỳ mảng N chiều nào arrcủa các số nguyên không âm thành một mảng N + 1 chiều nóng one_hot, one_hot[i_1,...,i_N,c] = 1có nghĩa là arr[i_1,...,i_N] = c. Bạn có thể khôi phục đầu vào thông quanp.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

0

Sử dụng mã sau đây. Nó hoạt động tốt nhất.

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

Tìm thấy nó ở đây PS Bạn không cần phải đi vào liên kết.


5
Bạn nên tránh sử dụng các vòng lặp với numpy
Kenan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.