Estou tentando usar o scikit-learn's LabelEncoder
para codificar um panda DataFrame
de rótulos de string. Como o dataframe possui muitas (50+) colunas, desejo evitar a criação de um LabelEncoder
objeto para cada coluna; Prefiro ter apenas um grande LabelEncoder
objeto que funcione em todas as minhas colunas de dados.
Jogar o todo DataFrame
para dentro LabelEncoder
cria o erro abaixo. Lembre-se de que estou usando dados fictícios aqui; na verdade, estou lidando com cerca de 50 colunas de dados rotulados com strings; portanto, preciso de uma solução que não faça referência a nenhuma coluna pelo nome.
import pandas
from sklearn import preprocessing
df = pandas.DataFrame({
'pets': ['cat', 'dog', 'cat', 'monkey', 'dog', 'dog'],
'owner': ['Champ', 'Ron', 'Brick', 'Champ', 'Veronica', 'Ron'],
'location': ['San_Diego', 'New_York', 'New_York', 'San_Diego', 'San_Diego',
'New_York']
})
le = preprocessing.LabelEncoder()
le.fit(df)
Traceback (última chamada mais recente): arquivo "", linha 1, no arquivo "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/preprocessing/label.py", linha 103, em forma de = column_or_1d (y, warn = True) Arquivo "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py", linha 306, na coluna 306, em column_or_1d aumento ValueError ("formato de entrada incorreto { 0} ". Formato (forma)) ValorErro: forma incorreta de entrada (6, 3)
Alguma idéia de como contornar esse problema?
fonte
dataframe
de dados de sequência. Estou escolhendo o (s) objeto (s) de codificação, para evitar ter que selecionar / retirar 50 objetos separados. Além disso, gostaria de saber se existe uma maneira de o codificador simplificar os dados, ou seja, apenas retornar uma linha com um identificador para cada combinação única de variáveis em cada coluna.replace
método. Veja esta resposta abaixoRespostas:
Você pode fazer isso facilmente,
EDIT2:
No scikit-learn 0.20, a maneira recomendada é
como o OneHotEncoder agora suporta entrada de string. A aplicação de OneHotEncoder somente a determinadas colunas é possível com o ColumnTransformer.
EDITAR:
Como essa resposta foi feita há mais de um ano e gerou muitos votos positivos (incluindo uma recompensa), eu provavelmente deveria estender isso ainda mais.
Para inverse_transform e transform, você precisa fazer um pouco de hack.
Com isso, você agora mantém todas as colunas
LabelEncoder
como dicionário.fonte
df.apply(LabelEncoder().fit_transform)
?LabelBinarizer
e reutilizar o dicionário para um conjunto de testes? Eu tenteid = defaultdict(LabelBinarizer)
e, em seguida,fit = df.apply(lambda x: d[x.name].fit_transform(x))
mas uma exceção:Exception: Data must be 1-dimensional
. Não tenho certeza de como espero que o DataFrame resultante pareça ... talvez cada coluna deva conter os vetores binarizados.Conforme mencionado por larsmans, LabelEncoder () usa apenas uma matriz 1-d como argumento . Dito isso, é muito fácil rolar seu próprio codificador de etiquetas que opera em várias colunas de sua escolha e retorna um quadro de dados transformado. Meu código aqui é baseado em parte no excelente post de Zac Stewart, encontrado aqui .
Criando um codificador personalizado envolve simplesmente criando uma classe que responde ao
fit()
,transform()
efit_transform()
métodos. No seu caso, um bom começo pode ser algo assim:Suponha que desejemos codificar nossos dois atributos categóricos (
fruit
ecolor
), deixando o atributo numérico emweight
paz. Poderíamos fazer o seguinte:O que transforma nosso
fruit_data
conjunto de dados depara
Passá-lo para um dataframe consistindo inteiramente de variáveis categóricas e omitir o
columns
parâmetro resultará na codificação de todas as colunas (que eu acredito ser o que você estava procurando originalmente):Isso transforma
para
.
Observe que provavelmente ele engasgará quando tentar codificar atributos que já são numéricos (adicione algum código para lidar com isso, se quiser).
Outro recurso interessante sobre isso é que podemos usar esse transformador personalizado em um pipeline:
fonte
Desde o scikit-learn 0.20, você pode usar
sklearn.compose.ColumnTransformer
esklearn.preprocessing.OneHotEncoder
:Se você tiver apenas variáveis categóricas,
OneHotEncoder
diretamente:Se você tiver recursos de tipo heterogêneo:
Mais opções na documentação: http://scikit-learn.org/stable/modules/compose.html#columntransformer-for-heterogeneous-data
fonte
inverse_transform()
não é suportado no ColumnTransformer. Pelo menos, não no momento: github.com/scikit-learn/scikit-learn/issues/11463 . Essa é uma grande desvantagem para meu aplicativo e provavelmente também será para outros.Não precisamos de um LabelEncoder.
Você pode converter as colunas em categorias e obter seus códigos. Usei uma compreensão de dicionário abaixo para aplicar esse processo a todas as colunas e agrupar o resultado novamente em um dataframe da mesma forma com índices e nomes de colunas idênticos.
Para criar um dicionário de mapeamento, basta enumerar as categorias usando uma compreensão de dicionário:
fonte
isso não responde diretamente à sua pergunta (para a qual Naputipulu Jon e PriceHardman têm respostas fantásticas)
No entanto, para o propósito de algumas tarefas de classificação, etc., você pode usar
isso pode inserir o quadro de dados com dados categóricos e retornar um quadro de dados com valores binários. valores de variáveis são codificados em nomes de colunas no quadro de dados resultante. Mais
fonte
Supondo que você esteja simplesmente tentando obter um
sklearn.preprocessing.LabelEncoder()
objeto que possa ser usado para representar suas colunas, tudo que você precisa fazer é:No código acima, você terá um número único correspondente a cada coluna. Mais precisamente, você terá um mapeamento de 1: 1
df.columns
parale.transform(df.columns.get_values())
. Para obter a codificação de uma coluna, simplesmente passe-a parale.transform(...)
. Como exemplo, o seguinte obterá a codificação para cada coluna:Supondo que você deseja criar um
sklearn.preprocessing.LabelEncoder()
objeto para todos os seus rótulos de linha, faça o seguinte:Nesse caso, é provável que você tenha rótulos de linha não exclusivos (como mostrado na sua pergunta). Para ver quais classes o codificador criou, você pode fazer
le.classes_
. Você notará que isso deve ter os mesmos elementos que emset(y for x in df.get_values() for y in x)
. Mais uma vez, para converter um rótulo de linha em um rótulo codificado, usele.transform(...)
. Como exemplo, se você deseja recuperar o rótulo para a primeira coluna nadf.columns
matriz e a primeira linha, você pode fazer o seguinte:A pergunta que você teve no seu comentário é um pouco mais complicada, mas ainda pode ser realizada:
O código acima faz o seguinte:
LabelEncoder
classe que não suporta tuplas como um nome de classe.LabelEncoder
.Agora, para usar esse novo modelo, é um pouco mais complicado. Supondo que desejamos extrair a representação para o mesmo item procurado no exemplo anterior (a primeira coluna em df.columns e a primeira linha), podemos fazer isso:
Lembre-se de que cada pesquisa agora é uma representação em cadeia de uma tupla que contém a (coluna, linha).
fonte
Não,
LabelEncoder
não faz isso. Leva matrizes 1-d de rótulos de classe e produz matrizes 1-d. Ele foi projetado para lidar com rótulos de classe em problemas de classificação, não em dados arbitrários, e qualquer tentativa de forçá-lo a outros usos exigirá código para transformar o problema real no problema que resolve (e a solução de volta ao espaço original).fonte
DataFrame
cada vez?LabelEncoder
código e adapte-o. Eu não uso o Pandas, então não sei o quão difícil será.pandas
pessoas resolvam essa questão - tenho certeza de que não sou a única pessoa com esse desafio, por isso espero que exista uma solução pré-criada por aí.Isso aconteceu um ano e meio após o fato, mas eu também precisava ser capaz de
.transform()
múltiplas colunas de dataframe de pandas de uma só vez (e ser capaz.inverse_transform()
delas também). Isso expande a excelente sugestão do @PriceHardman acima:Exemplo:
Se
df
edf_copy()
sãopandas
quadros de dados de tipo misto, você pode aplicarMultiColumnLabelEncoder()
asdtype=object
colunas da seguinte maneira:Você pode acessar classes de colunas individuais, rótulos de colunas e codificadores de colunas usados para caber em cada coluna por meio de indexação:
mcle.all_classes_
mcle.all_encoders_
mcle.all_labels_
fonte
fit
método acima, que na verdade não produzirá nenhum rótulo até aplicá-lo (transform
/fit_transform
) a os dados.Seguindo os comentários levantados sobre a solução do @PriceHardman , proponho a seguinte versão da classe:
Esta classe encaixa o codificador no conjunto de treinamento e usa a versão ajustada ao transformar. A versão inicial do código pode ser encontrada aqui .
fonte
Um caminho curto para
LabelEncoder()
várias colunas com umdict()
:e você pode usar isso
le_dict
para labelEncode qualquer outra coluna:fonte
É possível fazer isso tudo diretamente nos pandas e é adequado para uma habilidade exclusiva do
replace
método.Primeiro, vamos criar um dicionário de dicionários mapeando as colunas e seus valores para seus novos valores de substituição.
Como esse sempre será um mapeamento individual, podemos inverter o dicionário interno para obter um mapeamento dos novos valores de volta ao original.
Agora, podemos usar a capacidade exclusiva do
replace
método de obter uma lista aninhada de dicionários e usar as chaves externas como colunas e as chaves internas como os valores que gostaríamos de substituir.Podemos voltar facilmente ao original encadeando novamente o
replace
métodofonte
Depois de muita pesquisa e experimentação com algumas respostas aqui e em outros lugares, acho que sua resposta está aqui :
Isso preservará os nomes das categorias nas colunas:
fonte
Eu verifiquei o código fonte ( https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/preprocessing/label.py ) do LabelEncoder. Foi baseado em um conjunto de transformação numpy, que é uma delas np.unique (). E essa função recebe apenas entrada de matriz 1-d. (corrija-me se eu estiver errada).
Idéias muito difíceis ... primeiro, identifique quais colunas precisam do LabelEncoder e, em seguida, faça um loop por cada coluna.
O df retornado seria o após a codificação, e label_list mostrará o que todos esses valores significam na coluna correspondente. Este é um trecho de um script de processo de dados que escrevi para o trabalho. Deixe-me saber se você acha que poderia haver mais melhorias.
Edição: Só quero mencionar aqui que os métodos acima funcionam com quadro de dados sem perder o melhor. Não tenho certeza de como ele está trabalhando no quadro de dados contém dados ausentes. (Eu tinha um acordo com o procedimento ausente antes de executar os métodos acima)
fonte
se tivermos uma coluna para codificar o rótulo e sua transformação inversa, será fácil como fazê-lo quando houver várias colunas em python
fonte
Se você possui os dois tipos de dados numéricos e categóricos no dataframe Você pode usar: aqui X é o meu dataframe com as duas variáveis categóricas e numéricas
Nota: Essa técnica é boa se você não estiver interessado em convertê-las novamente.
fonte
Usando Neuraxle
Com esse método, seu codificador de etiquetas poderá se ajustar e se transformar em um pipeline de aprendizado de scikit regular . Vamos simplesmente importar:
O mesmo codificador compartilhado para colunas:
Aqui está como um LabelEncoder compartilhado será aplicado a todos os dados para codificá-lo:
Resultado:
Diferentes codificadores por coluna:
E aqui está como um primeiro LabelEncoder autônomo será aplicado nos animais de estimação e um segundo será compartilhado para o proprietário e o local das colunas. Para ser mais preciso, aqui temos uma mistura de codificadores de etiqueta diferentes e compartilhados:
Resultado:
fonte
Utilizou a resposta @Alexander principalmente, mas teve que fazer algumas alterações -
Depois, para reutilizar no futuro, você pode salvar a saída em um documento json e, quando precisar, lê-la e usar a
.map()
função como fiz acima.fonte
O problema é a forma dos dados (pd dataframe) que você está passando para a função de ajuste. Você precisa passar na 1ª lista.
fonte
Aqui estou lendo um csv do local e, em função, estou passando a lista de colunas que quero codificar e o quadro de dados que quero aplicar.
fonte
Que tal agora?
Não é o mais eficiente, no entanto, funciona e é super simples.
fonte