Метка, кодирующая несколько столбцов с одинаковой категорией

Рассмотрим следующий кадр данных:

import pandas as pd
from sklearn.preprocessing import LabelEncoder

df = pd.DataFrame(data=[["France", "Italy", "Belgium"], ["Italy", "France", "Belgium"]], columns=["a", "b", "c"])
df = df.apply(LabelEncoder().fit_transform)
print(df)

В настоящее время выводит:

   a  b  c
0  0  1  0
1  1  0  0

Моя цель - заставить его выводить что-то вроде этого, передавая столбцы, которые я хочу разделить категориальными значениями:

   a  b  c
0  0  1  2
1  1  0  2

4 ответа

Решение

Проходить axis=1 звонить LabelEncoder().fit_transform один раз для каждого ряда. (По умолчанию, df.apply(func) звонки func один раз для каждого столбца).

import pandas as pd
from sklearn.preprocessing import LabelEncoder

df = pd.DataFrame(data=[["France", "Italy", "Belgium"], 
                        ["Italy", "France", "Belgium"]], columns=["a", "b", "c"])

encoder = LabelEncoder()

df = df.apply(encoder.fit_transform, axis=1)
print(df)

доходность

   a  b  c
0  1  2  0
1  2  1  0

В качестве альтернативы, вы можете использовать сделать данные category Введите и используйте коды категорий в качестве меток:

import pandas as pd

df = pd.DataFrame(data=[["France", "Italy", "Belgium"], 
                        ["Italy", "France", "Belgium"]], columns=["a", "b", "c"])

stacked = df.stack().astype('category')
result = stacked.cat.codes.unstack()
print(result)

также дает

   a  b  c
0  1  2  0
1  2  1  0

Это должно быть значительно быстрее, так как не требует вызова encoder.fit_transform один раз для каждой строки (что может привести к ужасной производительности, если у вас много строк).

Вы можете сделать это с pd.factorize,

df = df.stack()
df[:] = pd.factorize(df)[0]
df.unstack()

   a  b  c
0  0  1  2
1  1  0  2

В случае, если вы хотите encode только некоторые столбцы в кадре данных:

temp = df[['a', 'b']].stack()
temp[:] = temp.factorize()[0]
df[['a', 'b']] = temp.unstack()

   a  b        c
0  0  1  Belgium
1  1  0  Belgium

Если порядок кодирования не имеет значения, вы можете сделать:

df_new = (         
    pd.DataFrame(columns=df.columns,
                 data=LabelEncoder()
                 .fit_transform(df.values.flatten()).reshape(df.shape))
)

df_new
Out[27]: 
   a  b  c
0  1  2  0
1  2  1  0

Вот альтернативное решение с использованием категориальных данных. Подобно @unutbu's, но сохраняет порядок факторизации. Другими словами, первое найденное значение будет иметь код 0.

df = pd.DataFrame(data=[["France", "Italy", "Belgium"],
                        ["Italy", "France", "Belgium"]],
                  columns=["a", "b", "c"])

# get unique values in order
vals = df.T.stack().unique()

# convert to categories and then extract codes
for col in df:
    df[col] = pd.Categorical(df[col], categories=vals)
    df[col] = df[col].cat.codes

print(df)

   a  b  c
0  0  1  2
1  1  0  2
Другие вопросы по тегам