Одно горячее кодирование строковых категориальных функций
Я пытаюсь выполнить одно горячее кодирование тривиального набора данных.
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