Как я могу сделать одно горячее кодирование с несколькими значениями в одной ячейке?
У меня есть эта таблица в Excel:
id class
0 2 3
1 1 3
2 3 5
Теперь я хочу сделать "специальную" горячую кодировку в Python. Для каждого идентификатора в первой таблице есть два числа. Каждое число соответствует классу (class1, class2 и т. Д.). Вторая таблица создается на основе первой, так что для каждого идентификатора каждое число в ее строке отображается в соответствующем столбце класса, а остальные столбцы просто получают нули. Например, числа для идентификатора 0 равны 2 и 3. 2 помещается в class2, а 3 помещается в class3. Классы 1, 4 и 5 получают значение по умолчанию 0. Результат должен быть таким:
id class1 class2 class3 class4 class5
0 0 2 3 0 0
1 1 0 3 0 0
2 0 0 3 0 5
Мое предыдущее решение,
foo = lambda x: pd.Series([i for i in x.split()])
result=onehot['hotel'].apply(foo)
result.columns=['class1','class2']
pd.get_dummies(result, prefix='class', columns=['class1','class2'])
результаты в:
class_1 class_2 class_3 class_3 class_5
0 0.0 1.0 0.0 1.0 0.0
1 1.0 0.0 0.0 1.0 0.0
2 0.0 0.0 1.0 0.0 1.0
(class_3 появляется дважды). Что я могу сделать, чтобы это исправить? (После этого шага я могу преобразовать его в нужный формат.)
4 ответа
Вам нужно, чтобы ваши переменные были categorical
и тогда вы можете использовать one hot encoding
как показано:
In [18]: df1 = pd.DataFrame({"class":pd.Series(['2','1','3']).astype('category',categories=['1','2','3','4','5'])})
In [19]: df2 = pd.DataFrame({"class":pd.Series(['3','3','5']).astype('category',categories=['1','2','3','4','5'])})
In [20]: df_1 = pd.get_dummies(df1)
In [21]: df_2 = pd.get_dummies(df2)
In [22]: df_1.add(df_2).apply(lambda x: x * [i for i in range(1,len(df_1.columns)+1)], axis = 1).astype(int).rename_axis('id')
Out[22]:
class_1 class_2 class_3 class_4 class_5
id
0 0 2 3 0 0
1 1 0 3 0 0
2 0 0 3 0 5
Удовлетворяет ли это вашу проблему, как указано?
#!/usr/bin/python
input = [
(0, (2,3)),
(1, (1,3)),
(2, (3,5)),
]
maximum = max(reduce(lambda x, y: x+list(y[1]), input, []))
# Or ...
# maximum = 0
# for i, classes in input:
# maximum = max(maximum, *classes)
# print header.
print "\t".join(["id"] + ["class_%d" % i for i in range(1, 6)])
for i, classes in input:
print i,
for r in range(1, maximum+1):
print "\t",
if r in classes:
print float(r),
else:
print 0.0,
print
Выход:
id class_1 class_2 class_3 class_4 class_5
0 0.0 2.0 3.0 0.0 0.0
1 1.0 0.0 3.0 0.0 0.0
2 0.0 0.0 3.0 0.0 5.0
Может быть проще разделить исходный фрейм данных на 3 столбца:
id class_a class_b
0 2 3
1 1 3
2 3 5
А затем выполните обычную горячую кодировку. После этого вы можете получить дубликаты столбцов, например:
id ... class_a_3 class_b_3 ... class_b_5
0 0 1 0
1 0 1 0
2 1 0 0
Но вы можете объединить / суммировать эти факты просто.
Точно так же вы можете повернуть ту же логику и преобразовать свой df в форму:
id class
0 2
0 3
1 1
1 3
2 3
2 5
Затем один горячий, и агрегировать, используя сумму на идентификатор ключа.
Что насчет этого?
Учитывая эти данные
import pandas as pd
df = pd.DataFrame({'id': [0, 1, 2], 'class': ['2 3', '1 3', '3 5']})
1- разделить значения
df['class'] = df['class'].apply(lambda x: x.split(' '))
df
id class
0 0 [2, 3]
1 1 [1, 3]
2 2 [3, 5]
2- взорвать --> каждую запись подряд
df_long = df.explode('class')
df_long
id class
0 0 2
0 0 3
1 1 1
1 1 3
2 2 3
2 2 5
3- получить одно горячее закодированное значение
df_one_hot_encoded = pd.concat([df, pd.get_dummies(df_long['class'],prefix='class', prefix_sep='_')], axis=1)
df_one_hot_encoded
id class class_1 class_2 class_3 class_5
0 0 [2, 3] 0 1 0 0
0 0 [2, 3] 0 0 1 0
1 1 [1, 3] 1 0 0 0
1 1 [1, 3] 0 0 1 0
2 2 [3, 5] 0 0 1 0
2 2 [3, 5] 0 0 0 1
4- по группам
id
и получить максимальное значение для столбца (тот же результат логического ИЛИ для двоичных значений) -> одна строка на идентификатор
df_one_hot_encoded.groupby('id').max().reset_index()
id class class_1 class_2 class_3 class_5
0 0 [2, 3] 0 1 1 0
1 1 [1, 3] 1 0 1 0
2 2 [3, 5] 0 0 1 1
Объединяя все вместе
import pandas as pd
df = pd.DataFrame({'id': [0, 1, 2], 'class': ['2 3', '1 3', '3 5']})
df['class'] = df['class'].apply(lambda x: x.split(' '))
df_long = df.explode('class')
df_one_hot_encoded = pd.concat([df, pd.get_dummies(df_long['class'],prefix='class', prefix_sep='_')], axis=1)
df_one_hot_encoded_compact = df_one_hot_encoded.groupby('id').max().reset_index()