Я пытаюсь использовать набор данных оценки автомобиля из репозитория UCI, и мне интересно, есть ли удобный способ бинаризации категориальных переменных в sklearn. Один из подходов заключался бы в использовании DictVectorizer LabelBinarizer, но здесь я получаю k разных функций, тогда как для избежания коллинеарности вы должны иметь только k-1. Думаю, я мог бы написать свою собственную функцию и сбросить один столбец, но эта бухгалтерская работа утомительна, есть ли простой способ выполнить такие преобразования и получить в результате разреженную матрицу?
Как закодировать категориальную переменную в sklearn?
Ответ 1
DictVectorizer - рекомендуемый способ генерации однострунной кодировки категориальных переменных; вы можете использовать аргумент sparse
для создания разреженной матрицы CSR вместо плотного массива numpy. Я обычно не забочусь о мультиколлинеарности, и я не заметил проблемы с подходами, которые я обычно использую (например, LinearSVC, SGDClassifier, Tree-based methods).
Не следует пытаться исправлять DictVectorizer для удаления одного столбца за категориальную функцию - вам просто нужно удалить один термин из DictVectorizer.vocabulary
в конце метода fit
. (Запросы Pull всегда приветствуются!)
Ответ 2
если ваши данные являются pandas DataFrame, тогда вы можете просто вызвать get_dummies. Предположим, что ваш фрейм данных равен df, и вы хотите иметь одну двоичную переменную на уровень переменной "ключ". Вы можете просто позвонить:
pd.get_dummies(df['key'])
а затем удалите одну из фиктивных переменных, чтобы избежать проблемы с несколькими коллинеарностями. Надеюсь, это поможет...
Ответ 3
Основной метод
import numpy as np
import pandas as pd, os
from sklearn.feature_extraction import DictVectorizer
def one_hot_dataframe(data, cols, replace=False):
vec = DictVectorizer()
mkdict = lambda row: dict((col, row[col]) for col in cols)
vecData = pd.DataFrame(vec.fit_transform(data[cols].apply(mkdict, axis=1)).toarray())
vecData.columns = vec.get_feature_names()
vecData.index = data.index
if replace is True:
data = data.drop(cols, axis=1)
data = data.join(vecData)
return (data, vecData, vec)
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
'year': [2000, 2001, 2002, 2001, 2002],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}
df = pd.DataFrame(data)
df2, _, _ = one_hot_dataframe(df, ['state'], replace=True)
print df2
Вот как это сделать в разреженном формате
import numpy as np
import pandas as pd, os
import scipy.sparse as sps
import itertools
def one_hot_column(df, cols, vocabs):
mats = []; df2 = df.drop(cols,axis=1)
mats.append(sps.lil_matrix(np.array(df2)))
for i,col in enumerate(cols):
mat = sps.lil_matrix((len(df), len(vocabs[i])))
for j,val in enumerate(np.array(df[col])):
mat[j,vocabs[i][val]] = 1.
mats.append(mat)
res = sps.hstack(mats)
return res
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
'year': ['2000', '2001', '2002', '2001', '2002'],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}
df = pd.DataFrame(data)
print df
vocabs = []
vals = ['Ohio','Nevada']
vocabs.append(dict(itertools.izip(vals,range(len(vals)))))
vals = ['2000','2001','2002']
vocabs.append(dict(itertools.izip(vals,range(len(vals)))))
print vocabs
print one_hot_column(df, ['state','year'], vocabs).todense()