HOWTO · NumPy

Codificação One-Hot em Matriz NumPy em Python

Este tutorial demonstra como realizar a codificação one-hot em um array numpy em python

Nesta página

A codificação one-hot representa cada categoria com uma linha de valores indicadores: a coluna da classe do rótulo de entrada vale 1, e as demais colunas de classe valem 0. Isso é útil quando uma ferramenta posterior espera recursos numéricos ou alvos categóricos nesse formato; nem todo modelo exige essa representação. Este guia mostra como criar essas linhas a partir de um array NumPy e como a saída difere entre NumPy, scikit-learn, pandas e Keras.

Como a codificação one-hot representa categorias

Um array one-hot tem uma linha para cada item de entrada e uma coluna para cada classe. A coluna ativa contém 1; todas as demais colunas dessa linha contêm 0. class_count define a largura. Neste exemplo, os IDs de 0 a 3 representam o conjunto completo de classes, então o resultado tem quatro colunas. Execute este exemplo:

O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.

import numpy as np

ids = np.array([1, 0, 3])
class_count = 4
rows = np.zeros((ids.size, class_count), dtype=int)
rows[np.arange(ids.size), ids] = 1
print(rows)
[[0 1 0 0]
 [1 0 0 0]
 [0 0 0 1]]

As entradas aqui são IDs inteiros de classe, não nomes de categoria arbitrários. Cada ID precisa ser um índice de coluna válido, de 0 até (mas sem incluir) class_count. Escolha essa quantidade com base no conjunto completo de classes usado pela tarefa, incluindo as classes que talvez não apareçam em uma amostra específica. Usar apenas o maior ID observado pode omitir uma classe conhecida quando ela não aparece nos dados atuais. Para rótulos como "cat" ou "blue", primeiro mapeie cada categoria para um ID inteiro estável ou use um codificador que aceite rótulos de categoria diretamente.

Criar linhas one-hot com atribuição indexada de NumPy e numpy.eye()

A atribuição indexada é útil quando a largura desejada é conhecida: aloque uma matriz com uma linha por rótulo e uma coluna por classe, depois defina uma posição em cada linha. O código acima usa essa abordagem. O resultado é um array inteiro NumPy, e a ordem das linhas acompanha a ordem da entrada. Mantenha o mapeamento de IDs para categorias junto ao array para que cada coluna de saída preserve seu significado.

numpy.eye() oferece uma alternativa compacta. Ela cria uma matriz identidade, em que cada linha tem uma coluna ativa; ao indexar essa matriz pelo array de IDs, você seleciona as linhas necessárias. Informe a mesma quantidade explícita de classes para que a matriz inclua o conjunto completo, mesmo que alguns IDs não tenham sido observados. As duas abordagens pressupõem IDs inteiros não negativos dentro do intervalo permitido. Se os rótulos forem strings, números negativos ou identificadores esparsos, como 10 e 40, primeiro mapeie-os para IDs consecutivos em vez de usá-los diretamente como posições do array.

O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.

import numpy as np

ids = np.array([1, 0, 3])
class_count = 4
rows = np.eye(class_count, dtype=int)[ids]
print(rows)
[[0 1 0 0]
 [1 0 0 0]
 [0 0 0 1]]

Codificar rótulos com LabelBinarizer do scikit-learn

Use LabelBinarizer quando quiser um codificador que aprenda o mapeamento entre classes e colunas e o aplique de forma consistente aos dados posteriores. Ajuste-o com o conjunto completo de classes de treinamento e depois reutilize o codificador ajustado para transformar os rótulos. Ao contrário da indexação direta de NumPy, ele aceita tanto strings quanto números inteiros. Com quatro classes ajustadas, uma transformação multiclasse tem uma coluna por classe; na classificação binária, porém, o resultado tem uma coluna, então a largura depende da configuração das classes.

Em um projeto com scikit-learn, chame encoder.fit(class_labels) e encoder.transform(labels); classes_ informa a ordem das colunas. O exemplo usa LabelBinarizer quando o scikit-learn está instalado; caso contrário, a alternativa com a biblioteca padrão demonstra o mesmo mapeamento para que o exemplo continue executável:

O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.

class_labels = ["blue", "green", "red", "yellow"]
labels = ["green", "red", "blue"]
try:
    from sklearn.preprocessing import LabelBinarizer
    encoder = LabelBinarizer()
    encoder.fit(class_labels)
    rows = encoder.transform(labels).tolist()
except ModuleNotFoundError:
    class_to_column = {label: index for index, label in enumerate(class_labels)}
    rows = []
    for label in labels:
        row = [0] * len(class_labels)
        row[class_to_column[label]] = 1
        rows.append(row)
print(rows)
[[0, 1, 0, 0], [0, 0, 1, 0], [1, 0, 0, 0]]

Criar colunas indicadoras com pandas.get_dummies()

pandas.get_dummies() é conveniente quando a próxima etapa usa um DataFrame e colunas com nomes de categorias são úteis. Ele cria uma coluna indicadora para cada categoria observada nos valores fornecidos, com uma linha por item de entrada. A saída continua sendo um DataFrame do pandas, ao contrário dos arrays NumPy acima. Por padrão, uma categoria ausente da entrada não recebe uma coluna; portanto, use uma definição explícita de categorias ou reindexe o resultado quando as colunas precisarem corresponder a um conjunto de classes conhecido separadamente em diferentes conjuntos de dados.

O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.

import numpy as np
import pandas as pd

labels = np.array(["green", "red", "blue"])
indicators = pd.get_dummies(labels)
print(indicators)
    blue  green    red
0  False   True  False
1  False  False   True
2   True  False  False

Este método aceita rótulos de categoria diretamente e dispensa a criação manual de um mapeamento numérico. As colunas correspondem às categorias presentes nos dados; por isso, mantenha ou defina a ordem das colunas ao combinar resultados de lotes separados. Escolha-o para fluxos de trabalho tabulares; escolha um array NumPy ou um codificador ajustado quando a API de destino exigir esses formatos.

Criar linhas one-hot com to_categorical() do Keras

to_categorical() do Keras converte IDs inteiros de classe em um array denso de linhas one-hot. Informe num_classes explicitamente com a quantidade total de classes. O número de rótulos de entrada não é a quantidade de classes: por exemplo, três observações podem pertencer a um problema com quatro classes. Assim como na indexação direta de NumPy, os IDs precisam ser inteiros não negativos menores que essa quantidade.

Informe explicitamente a quantidade total de classes para que cada linha tenha quatro colunas. O exemplo chama to_categorical() do Keras quando o Keras está instalado; a alternativa com a biblioteca padrão mantém a mesma demonstração executável quando o pacote não está disponível:

O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.

ids = [1, 0, 3]
class_count = 4
try:
    from keras.utils import to_categorical
    rows = to_categorical(ids, num_classes=class_count).tolist()
except ModuleNotFoundError:
    rows = []
    for class_id in ids:
        row = [0.0] * class_count
        row[class_id] = 1.0
        rows.append(row)
print(rows)
[[0.0, 1.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0]]

O Keras retorna um array denso adequado para código que consome alvos categóricos. Ele usa IDs numéricos, e não strings de categoria; mapeie rótulos arbitrários para um esquema estável de inteiros antes de chamá-lo. Use esta opção quando a próxima etapa fizer parte de um fluxo de trabalho com Keras, LabelBinarizer quando for útil ter um mapeamento ajustado de rótulos para colunas, get_dummies() quando o resultado preferido for um DataFrame e operações diretas de NumPy quando IDs inteiros e um array já forem adequados.