Одно горячее кодирование строковых категориальных функций

Я пытаюсь выполнить одно горячее кодирование тривиального набора данных.

data = [['a', 'dog', 'red']
        ['b', 'cat', 'green']]

Каков наилучший способ предварительной обработки этих данных с помощью Scikit-Learn?

По первому инстинкту вы бы посмотрели на Scikit-Learn OneHotEncoder. Но один горячий кодер не поддерживает строки как функции; он только дискретизирует целые числа.

Итак, вы должны использовать LabelEncoder, который будет кодировать строки в целые числа. Но тогда вы должны применять кодер метки в каждом столбце и хранить каждый из этих кодов ярлыков (а также столбцы, на которые они были применены). И это кажется крайне неуклюжим.

Итак, что такое лучший способ сделать это в Scikit-Learn?

Пожалуйста, не предлагайте pandas.get_dummies. Это то, что я обычно использую в настоящее время для одного горячего кодирования. Тем не менее, он ограничен в том, что вы не можете кодировать ваш набор для обучения/тестирования отдельно.

Ответы

Ответ 1

Если вы на sklearn> 0.20.dev0

In [11]: from sklearn.preprocessing import OneHotEncoder
    ...: cat = OneHotEncoder()
    ...: X = np.array([['a', 'b', 'a', 'c'], [0, 1, 0, 1]], dtype=object).T
    ...: cat.fit_transform(X).toarray()
    ...: 
Out[11]: array([[1., 0., 0., 1., 0.],
           [0., 1., 0., 0., 1.],
           [1., 0., 0., 1., 0.],
           [0., 0., 1., 0., 1.]])

Если вы на sklearn == 0.20.dev0

In [30]: cat = CategoricalEncoder()

In [31]: X = np.array([['a', 'b', 'a', 'c'], [0, 1, 0, 1]], dtype=object).T

In [32]: cat.fit_transform(X).toarray()
Out[32]:
array([[ 1.,  0., 0.,  1.,  0.],
       [ 0.,  1.,  0.,  0.,  1.],
       [ 1.,  0.,  0.,  1.,  0.],
       [ 0.,  0.,  1.,  0.,  1.]])

Другой способ сделать это - использовать category_encoders.

Вот пример:

% pip install category_encoders
import category_encoders as ce
le =  ce.OneHotEncoder(return_df=False, impute_missing=False, handle_unknown="ignore")
X = np.array([['a', 'dog', 'red'], ['b', 'cat', 'green']])
le.fit_transform(X)
array([[1, 0, 1, 0, 1, 0],
       [0, 1, 0, 1, 0, 1]])

Ответ 2

Очень хороший вопрос.

Однако, в некотором смысле, это частный случай чего-то, что появляется (по крайней мере для меня) довольно часто - с учетом sklearn этапов, применимых к подмножествам матрицы X, я хотел бы применить ( возможно, несколько), учитывая всю матрицу. Здесь, например, у вас есть сцена, которая умеет работать в одном столбце, и вы хотите применить ее трижды - один раз за столбец.

Это классический случай использования Композитный шаблон дизайна.

Вот (эскиз a) многоразового этапа, который принимает словарь, сопоставляющий индекс столбца с преобразованием, чтобы применить к нему:

class ColumnApplier(object):
    def __init__(self, column_stages):
        self._column_stages = column_stages

    def fit(self, X, y):
        for i, k in self._column_stages.items():
            k.fit(X[:, i])

        return self

    def transform(self, X):
        X = X.copy()
        for i, k in self._column_stages.items():
            X[:, i] = k.transform(X[:, i])

        return X

Теперь, чтобы использовать его в этом контексте, начиная с

X = np.array([['a', 'dog', 'red'], ['b', 'cat', 'green']])
y = np.array([1, 2])
X

вы просто используете его для сопоставления каждого индекса столбца с желаемым преобразованием:

multi_encoder = \
    ColumnApplier(dict([(i, preprocessing.LabelEncoder()) for i in range(3)]))
multi_encoder.fit(X, None).transform(X)

Как только вы разработаете такой этап (я не могу опубликовать тот, который я использую), вы можете использовать его снова и снова для различных настроек.

Ответ 3

Я столкнулся с этой проблемой много раз, и я нашел решение в эту книгу на своей странице 100:

Мы можем применять оба преобразования (от текстовых категорий до целых категорий, затем от целого числа категориям к одним горячим векторам) одним выстрелом с использованием класса LabelBinarizer:

и пример кода:

from sklearn.preprocessing import LabelBinarizer
encoder = LabelBinarizer()
housing_cat_1hot = encoder.fit_transform(data)
housing_cat_1hot

и в результате: Обратите внимание, что это возвращает по умолчанию массив плотных NumPy. Вместо этого вы можете получить разреженную матрицу sparse_output = Верно для конструктора LabelBinarizer.

И вы можете найти больше о LabelBinarizer, здесь в официальной документации sklearn