Как я могу сделать одно горячее кодирование с несколькими значениями в одной ячейке?

У меня есть эта таблица в 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()
Другие вопросы по тегам