Реверсирование "одного горячего" кодирования в Pandas
Заявление о проблемах
Я хочу перейти из этого фрейма данных, который в основном является одним горячим кодированием.
In [2]: pd.DataFrame({"monkey":[0,1,0],"rabbit":[1,0,0],"fox":[0,0,1]})
Out[2]:
fox monkey rabbit
0 0 0 1
1 0 1 0
2 1 0 0
3 0 0 0
4 0 0 0
К этому, который является "обратным" одним горячим кодированием.
In [3]: pd.DataFrame({"animal":["monkey","rabbit","fox"]})
Out[3]:
animal
0 monkey
1 rabbit
2 fox
Я предполагаю, что есть какое-то умное использование приложения или почтового индекса, но я не уверен, как... Может ли кто-нибудь помочь?
У меня не было большого успеха, используя индексирование и т.д., чтобы попытаться решить эту проблему.
Ответы
Ответ 1
Я бы применил для декодирования столбцов:
In [2]: animals = pd.DataFrame({"monkey":[0,1,0,0,0],"rabbit":[1,0,0,0,0],"fox":[0,0,1,0,0]})
In [3]: def get_animal(row):
...: for c in animals.columns:
...: if row[c]==1:
...: return c
In [4]: animals.apply(get_animal, axis=1)
Out[4]:
0 rabbit
1 monkey
2 fox
3 None
4 None
dtype: object
Ответ 2
ОБНОВЛЕНИЕ: Я думаю, ayhan прав, и это должно быть:
df.idxmax(axis=1)
Демо:
In [40]: s = pd.Series(['dog', 'cat', 'dog', 'bird', 'fox', 'dog'])
In [41]: s
Out[41]:
0 dog
1 cat
2 dog
3 bird
4 fox
5 dog
dtype: object
In [42]: pd.get_dummies(s)
Out[42]:
bird cat dog fox
0 0.0 0.0 1.0 0.0
1 0.0 1.0 0.0 0.0
2 0.0 0.0 1.0 0.0
3 1.0 0.0 0.0 0.0
4 0.0 0.0 0.0 1.0
5 0.0 0.0 1.0 0.0
In [43]: pd.get_dummies(s).idxmax(1)
Out[43]:
0 dog
1 cat
2 dog
3 bird
4 fox
5 dog
dtype: object
OLD answer: (скорее всего, неверный ответ)
попробуйте следующее:
In [504]: df.idxmax().reset_index().rename(columns={'index':'animal', 0:'idx'})
Out[504]:
animal idx
0 fox 2
1 monkey 1
2 rabbit 0
Данные:
In [505]: df
Out[505]:
fox monkey rabbit
0 0 0 1
1 0 1 0
2 1 0 0
3 0 0 0
4 0 0 0
Ответ 3
Я бы сделал:
cols = df.columns.to_series().values
pd.DataFrame(np.repeat(cols[None, :], len(df), 0)[df.astype(bool).values], df.index[df.any(1)])
![введите описание изображения здесь]()
Timing
Метод MaxU имеет край для больших кадров данных
Маленький df
5 x 3
![введите описание изображения здесь]()
Большой df
1000000 x 52
![введите описание изображения здесь]()
Ответ 4
Это работает как с одной, так и с несколькими метками.
Мы можем использовать расширенную индексацию для решения этой проблемы. Здесь ссылка.
import pandas as pd
df = pd.DataFrame({"monkey":[1,1,0,1,0],"rabbit":[1,1,1,1,0],\
"fox":[1,0,1,0,0], "cat":[0,0,0,0,1]})
df['tags']='' # to create an empty column
for col_name in df.columns:
df.ix[df[col_name]==1,'tags']= df['tags']+' '+col_name
print df
И результат:
cat fox monkey rabbit tags
0 0 1 1 1 fox monkey rabbit
1 0 0 1 1 monkey rabbit
2 0 1 0 1 fox rabbit
3 0 0 1 1 monkey rabbit
4 1 0 0 0 cat
Объяснение:
Мы перебираем столбцы в кадре данных.
df.ix[selection criteria, columns to write value] = value
df.ix[df[col_name]==1,'tags']= df['tags']+' '+col_name
Вышеуказанная строка в основном находит все места, где df [col_name] == 1, выбирает столбец 'tags' и устанавливает для него значение RHS, равное df ['tags'] + '' + col_name
Примечание: .ix
устарело с Pandas v0.20. Вместо этого вы должны использовать .loc
или .iloc
, в зависимости от ситуации.
Ответ 5
Попробуйте следующее:
df = pd.DataFrame({"monkey":[0,1,0,1,0],"rabbit":[1,0,0,0,0],"fox":[0,0,1,0,0], "cat":[0,0,0,0,1]})
df
cat fox monkey rabbit
0 0 0 0 1
1 0 0 1 0
2 0 1 0 0
3 0 0 1 0
4 1 0 0 0
pd.DataFrame([x for x in np.where(df ==1, df.columns,'').flatten().tolist() if len(x) >0],columns= (["animal"]) )
animal
0 rabbit
1 monkey
2 fox
3 monkey
4 cat
Ответ 6
Вы можете попробовать использовать melt()
. Этот метод также работает, когда у вас есть несколько меток OHE для строки.
# Your OHE dataframe
df = pd.DataFrame({"monkey":[0,1,0],"rabbit":[1,0,0],"fox":[0,0,1]})
mel = df.melt(var_name=['animal'], value_name='value') # Melting
mel[mel.value == 1].reset_index(drop=True) # this gives you the result
Ответ 7
Это может быть достигнуто простым применением на фрейме данных
# function to get column name with value one for each row in dataframe
def get_animal(row):
return(row.index[row.apply(lambda x: x==1)][0])
# prepare a animal column
df['animal'] = df.apply(lambda row:get_animal(row), axis=1)