Как я могу написать горячую кодировку в Python?
У меня проблема классификации машинного обучения с 80% -ными категориальными переменными. Должен ли я использовать одну горячую кодировку, если я хочу использовать некоторый классификатор для классификации? Могу ли я передать данные в классификатор без кодировки?
Я пытаюсь сделать следующее для выбора функции:
-
Я прочитал файл поезда:
num_rows_to_read = 10000
train_small = pd.read_csv("../../dataset/train.csv", nrows=num_rows_to_read)
-
Я изменяю тип категориальных функций на категорию:
non_categorial_features = ['orig_destination_distance',
'srch_adults_cnt',
'srch_children_cnt',
'srch_rm_cnt',
'cnt']
for categorical_feature in list(train_small.columns):
if categorical_feature not in non_categorial_features:
train_small[categorical_feature] = train_small[categorical_feature].astype('category')
-
Я использую одну горячую кодировку:
train_small_with_dummies = pd.get_dummies(train_small, sparse=True)
Проблема в том, что 3-я часть часто застревает, хотя я использую сильную машину.
Таким образом, без одного горячего кодирования я не могу выполнить какой-либо выбор функции, чтобы определить важность функций.
Что вы порекомендуете?
Ответы
Ответ 1
Подход 1: вы можете использовать get_dummies в pandas dataframe.
Пример 1:
import pandas as pd
s = pd.Series(list('abca'))
pd.get_dummies(s)
Out[]:
a b c
0 1.0 0.0 0.0
1 0.0 1.0 0.0
2 0.0 0.0 1.0
3 1.0 0.0 0.0
Пример 2:
Следующее преобразует данный столбец в один горячий. Используйте префикс, чтобы иметь несколько манекенов.
import pandas as pd
df = pd.DataFrame({
'A':['a','b','a'],
'B':['b','a','c']
})
df
Out[]:
A B
0 a b
1 b a
2 a c
# Get one hot encoding of columns B
one_hot = pd.get_dummies(df['B'])
# Drop column B as it is now encoded
df = df.drop('B',axis = 1)
# Join the encoded df
df = df.join(one_hot)
df
Out[]:
A a b c
0 a 0 1 0
1 b 1 0 0
2 a 0 0 1
Подход 2: использование Scikit-learn
Учитывая набор данных с тремя функциями и четырьмя образцами, мы позволяем кодеру находить максимальное значение для каждой функции и преобразовывать данные в двоичную однострунную кодировку.
>>> from sklearn.preprocessing import OneHotEncoder
>>> enc = OneHotEncoder()
>>> enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])
OneHotEncoder(categorical_features='all', dtype=<class 'numpy.float64'>,
handle_unknown='error', n_values='auto', sparse=True)
>>> enc.n_values_
array([2, 3, 4])
>>> enc.feature_indices_
array([0, 2, 5, 9], dtype=int32)
>>> enc.transform([[0, 1, 1]]).toarray()
array([[ 1., 0., 0., 1., 0., 0., 1., 0., 0.]])
Вот ссылка для этого примера: http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html
Ответ 2
Вы можете сделать это с помощью numpy.eye
и с помощью механизма выбора элемента массива:
import numpy as np
nb_classes = 6
data = [[2, 3, 4, 0]]
def indices_to_one_hot(data, nb_classes):
"""Convert an iterable of indices to one-hot encoded labels."""
targets = np.array(data).reshape(-1)
return np.eye(nb_classes)[targets]
Возвращаемое значение indices_to_one_hot(nb_classes, data)
теперь
array([[[ 0., 0., 1., 0., 0., 0.],
[ 0., 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 1., 0.],
[ 1., 0., 0., 0., 0., 0.]]])
.reshape(-1)
должен убедиться, что у вас есть правильный формат меток (у вас также могут быть [[2], [3], [4], [0]]
).
Ответ 3
Во-первых, самый простой способ для одного горячего кодирования: использовать Sklearn.
http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html
Во-вторых, я не думаю, что использование pandas для одного горячего кодирования - это простое (неподтвержденное, хотя)
Создание фиктивных переменных в pandas для python
Наконец, нужно ли вам для одного горячего кодирования? Одна горячая кодировка экспоненциально увеличивает количество функций, значительно увеличивая время выполнения любого классификатора или всего, что вы собираетесь запускать. Особенно, когда каждая категориальная функция имеет много уровней. Вместо этого вы можете сделать фиктивное кодирование.
Использование фиктивного кодирования обычно работает хорошо, значительно меньше времени выполнения и сложности. Однажды мудрый профессор сказал мне: "Меньше больше".
Здесь код для моей пользовательской функции кодирования, если вы хотите.
from sklearn.preprocessing import LabelEncoder
#Auto encodes any dataframe column of type category or object.
def dummyEncode(df):
columnsToEncode = list(df.select_dtypes(include=['category','object']))
le = LabelEncoder()
for feature in columnsToEncode:
try:
df[feature] = le.fit_transform(df[feature])
except:
print('Error encoding '+feature)
return df
EDIT: сравнение будет более четким:
Однострочное кодирование: преобразование n уровней в n-1 столбцов.
Index Animal Index cat mouse
1 dog 1 0 0
2 cat --> 2 1 0
3 mouse 3 0 1
Вы можете увидеть, как это взорвет вашу память, если у вас есть много разных типов (или уровней) в вашей категориальной функции. Имейте в виду, это всего лишь одна колонка.
Манекен:
Index Animal Index Animal
1 dog 1 0
2 cat --> 2 1
3 mouse 3 2
Вместо этого преобразуйте в числовые представления. Значительно экономит пространство для объектов, ценой небольшой точности.
Ответ 4
Одна горячая кодировка с пандами очень проста:
def one_hot(df, cols):
"""
@param df pandas DataFrame
@param cols a list of columns to encode
@return a DataFrame with one-hot encoding
"""
for each in cols:
dummies = pd.get_dummies(df[each], prefix=each, drop_first=False)
df = pd.concat([df, dummies], axis=1)
return df
РЕДАКТИРОВАТЬ:
Еще один способ использования one_hot с помощью склейнера LabelBinarizer
:
from sklearn.preprocessing import LabelBinarizer
label_binarizer = LabelBinarizer()
label_binarizer.fit(all_your_labels_list) # need to be global or remembered to use it later
def one_hot_encode(x):
"""
One hot encode a list of sample labels. Return a one-hot encoded vector for each label.
: x: List of sample Labels
: return: Numpy array of one-hot encoded labels
"""
return label_binarizer.transform(x)
Ответ 5
Гораздо проще использовать Pandas для базового однократного кодирования. Если вы ищете больше вариантов, вы можете использовать scikit-learn.
Для базового однократного кодирования с помощью Pandas вы просто передаете свой фрейм данных в функцию get_dummies.
Например, если у меня есть фрейм данных с именем imdb_movies:
... и я хочу горячо закодировать столбец Rated, я просто делаю это:
pd.get_dummies(imdb_movies.Rated)
Это возвращает новый фрейм данных со столбцом для каждого существующего "уровня" рейтинга, а также 1 или 0, указывающий наличие этого рейтинга для данного наблюдения.
Обычно мы хотим, чтобы это было частью исходного кадра данных. В этом случае мы просто прикрепляем наш новый фиктивный кадр к исходному кадру, используя "привязку столбца.
Мы можем связать столбцы, используя функцию concat Pandas:
rated_dummies = pd.get_dummies(imdb_movies.Rated)
pd.concat([imdb_movies, rated_dummies], axis=1)
Теперь мы можем запустить анализ на нашем полном кадре данных.
ПРОСТАЯ ФУНКЦИЯ ПО УТИЛИТЕ
Я бы порекомендовал сделать себе служебную функцию, чтобы сделать это быстро:
def encode_and_bind(original_dataframe, feature_to_encode):
dummies = pd.get_dummies(original_dataframe[[feature_to_encode]])
res = pd.concat([original_dataframe, dummies], axis=1)
return(res)
Использование:
encode_and_bind(imdb_movies, 'Rated')
Результат:
Кроме того, согласно комментарию @pmalbu, если вы хотите, чтобы функция удалила исходный код feature_to_encode, используйте эту версию:
def encode_and_bind(original_dataframe, feature_to_encode):
dummies = pd.get_dummies(original_dataframe[[feature_to_encode]])
res = pd.concat([original_dataframe, dummies], axis=1)
res = res.drop([feature_to_encode], axis=1)
return(res)
Ответ 6
Вы можете использовать функцию numpy.eye.
import numpy as np
def one_hot_encode(x, n_classes):
"""
One hot encode a list of sample labels. Return a one-hot encoded vector for each label.
: x: List of sample Labels
: return: Numpy array of one-hot encoded labels
"""
return np.eye(n_classes)[x]
def main():
list = [0,1,2,3,4,3,2,1,0]
n_classes = 5
one_hot_list = one_hot_encode(list, n_classes)
print(one_hot_list)
if __name__ == "__main__":
main()
результат
D:\Desktop>python test.py
[[ 1. 0. 0. 0. 0.]
[ 0. 1. 0. 0. 0.]
[ 0. 0. 1. 0. 0.]
[ 0. 0. 0. 1. 0.]
[ 0. 0. 0. 0. 1.]
[ 0. 0. 0. 1. 0.]
[ 0. 0. 1. 0. 0.]
[ 0. 1. 0. 0. 0.]
[ 1. 0. 0. 0. 0.]]
Ответ 7
pandas as имеет встроенную функцию get_dummies для получения одного горячего кодирования этого конкретного столбца/с.
один код строки для одного горячего кодирования:
df=pd.concat([df,pd.get_dummies(df['column name'],prefix='column name')],axis=1).drop(['column name'],axis=1)
Ответ 8
Вот решение, использующее DictVectorizer
и метод Pandas DataFrame.to_dict('records')
.
>>> import pandas as pd
>>> X = pd.DataFrame({'income': [100000,110000,90000,30000,14000,50000],
'country':['US', 'CAN', 'US', 'CAN', 'MEX', 'US'],
'race':['White', 'Black', 'Latino', 'White', 'White', 'Black']
})
>>> from sklearn.feature_extraction import DictVectorizer
>>> v = DictVectorizer()
>>> qualitative_features = ['country','race']
>>> X_qual = v.fit_transform(X[qualitative_features].to_dict('records'))
>>> v.vocabulary_
{'country=CAN': 0,
'country=MEX': 1,
'country=US': 2,
'race=Black': 3,
'race=Latino': 4,
'race=White': 5}
>>> X_qual.toarray()
array([[ 0., 0., 1., 0., 0., 1.],
[ 1., 0., 0., 1., 0., 0.],
[ 0., 0., 1., 0., 1., 0.],
[ 1., 0., 0., 0., 0., 1.],
[ 0., 1., 0., 0., 0., 1.],
[ 0., 0., 1., 1., 0., 0.]])
Ответ 9
Однострочное кодирование требует бит больше, чем преобразование значений в переменные индикатора. Обычно процесс ML требует, чтобы вы несколько раз применяли это кодирование для проверки или тестирования наборов данных и применяли модель, которую вы создаете, к наблюдаемым в режиме реального времени данным. Вы должны сохранить отображение (преобразование), которое использовалось для построения модели. Хорошим решением будет использование DictVectorizer
или LabelEncoder
(за которым следует get_dummies
. Вот функция, которую вы можете использовать:
def oneHotEncode2(df, le_dict = {}):
if not le_dict:
columnsToEncode = list(df.select_dtypes(include=['category','object']))
train = True;
else:
columnsToEncode = le_dict.keys()
train = False;
for feature in columnsToEncode:
if train:
le_dict[feature] = LabelEncoder()
try:
if train:
df[feature] = le_dict[feature].fit_transform(df[feature])
else:
df[feature] = le_dict[feature].transform(df[feature])
df = pd.concat([df,
pd.get_dummies(df[feature]).rename(columns=lambda x: feature + '_' + str(x))], axis=1)
df = df.drop(feature, axis=1)
except:
print('Error encoding '+feature)
#df[feature] = df[feature].convert_objects(convert_numeric='force')
df[feature] = df[feature].apply(pd.to_numeric, errors='coerce')
return (df, le_dict)
Это работает на базе данных pandas и для каждого столбца создаваемого ими кадра данных и возвращает отображение обратно. Поэтому вы бы назвали это так:
train_data, le_dict = oneHotEncode2(train_data)
Затем по тестовым данным вызов выполняется путем передачи словаря, возвращенного из тренинга:
test_data, _ = oneHotEncode2(test_data, le_dict)
Эквивалентным методом является использование DictVectorizer
. Связанный пост на том же самом находится в моем блоге. Я упоминаю его здесь, так как он обеспечивает некоторые рассуждения позади этого подхода по сравнению с простым использованием get_dummies пост (раскрытие: это мой собственный блог).
Ответ 10
Я знаю, что опаздываю на эту вечеринку, но самый простой способ горячего кодирования файловой системы автоматическим способом - использовать эту функцию:
def hot_encode(df):
obj_df = df.select_dtypes(include=['object'])
return pd.get_dummies(df, columns=obj_df.columns).values
Ответ 11
Вы можете передавать данные в классификатор catboost без кодирования. Catboost сам обрабатывает категориальные переменные, выполняя однозначное и целевое расширяющее среднее кодирование.
Ответ 12
Чтобы добавить к другим вопросам, позвольте мне представить, как я это сделал с помощью функции Python 2.0 с помощью Numpy:
def one_hot(y_):
# Function to encode output labels from number indexes
# e.g.: [[5], [0], [3]] --> [[0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0]]
y_ = y_.reshape(len(y_))
n_values = np.max(y_) + 1
return np.eye(n_values)[np.array(y_, dtype=np.int32)] # Returns FLOATS
Строка n_values = np.max(y_) + 1
может быть жестко закодирована для использования n_values = np.max(y_) + 1
количества нейронов, если вы используете мини-партии, например.
Демо-проект/учебник, в котором эта функция используется: https://github.com/guillaume-chevalier/LSTM-Human-Activity-Recognition
Ответ 13
Я использовал это в своей акустической модели: вероятно, это помогает в вашей модели.
def one_hot_encoding(x, n_out):
x = x.astype(int)
shape = x.shape
x = x.flatten()
N = len(x)
x_categ = np.zeros((N,n_out))
x_categ[np.arange(N), x] = 1
return x_categ.reshape((shape)+(n_out,))
Ответ 14
Это работает для меня:
pandas.factorize( ['B', 'C', 'D', 'B'] )[0]
Выход:
[0, 1, 2, 0]
Ответ 15
Это может и должно быть легко, как:
class OneHotEncoder:
def __init__(self,optionKeys):
length=len(optionKeys)
self.__dict__={optionKeys[j]:[0 if i!=j else 1 for i in range(length)] for j in range(length)}
Использование:
ohe=OneHotEncoder(["A","B","C","D"])
print(ohe.A)
print(ohe.D)
Ответ 16
Вы также можете сделать следующее. Обратите внимание, что ниже не нужно использовать pd.concat
.
import pandas as pd
# intialise data of lists.
data = {'Color':['Red', 'Yellow', 'Red', 'Yellow'], 'Length':[20.1, 21.1, 19.1, 18.1],
'Group':[1,2,1,2]}
# Create DataFrame
df = pd.DataFrame(data)
for _c in df.select_dtypes(include=['object']).columns:
print(_c)
df[_c] = pd.Categorical(df[_c])
df_transformed = pd.get_dummies(df)
df_transformed
Вы также можете изменить явные столбцы на категориальные. Например, здесь я меняю Color
и Group
import pandas as pd
# intialise data of lists.
data = {'Color':['Red', 'Yellow', 'Red', 'Yellow'], 'Length':[20.1, 21.1, 19.1, 18.1],
'Group':[1,2,1,2]}
# Create DataFrame
df = pd.DataFrame(data)
columns_to_change = list(df.select_dtypes(include=['object']).columns)
columns_to_change.append('Group')
for _c in columns_to_change:
print(_c)
df[_c] = pd.Categorical(df[_c])
df_transformed = pd.get_dummies(df)
df_transformed
Ответ 17
Здесь я попытался с таким подходом:
import numpy as np
#converting to one_hot
def one_hot_encoder(value, datal):
datal[value] = 1
return datal
def _one_hot_values(labels_data):
encoded = [0] * len(labels_data)
for j, i in enumerate(labels_data):
max_value = [0] * (np.max(labels_data) + 1)
encoded[j] = one_hot_encoder(i, max_value)
return np.array(encoded)