Adicionar Novo Registro com Variável Categórica

Home Fóruns Fórum Machine Learning e Data Science com Python de A à Z Adicionar Novo Registro com Variável Categórica

Visualizando 10 posts - 1 até 10 (de 10 do total)
  • Autor
    Posts
  • #28440

    Estava fazendo o Load do meu classificador da base de dados Census e ai gostaria de saber se há um modo alimentar o novo registro de forma categórica e fazer um tratamento para a entrega do resultado. Caso a maneira mais fácil seja a al realmente a alimentação númerica do novo registro, existe alguma função que correlaciona os dados categóricos da base original com os gerados no LabelEncoder?

    Segue o código abaixo:

    import pandas as pd
    import pickle
    from sklearn.impute import SimpleImputer
    from sklearn.preprocessing import StandardScaler
    import numpy as np
    
    
    base = pd.read_csv('census.csv')
    previsores = base.iloc[:, 0:14].values
    classe = base.iloc[:, 14].values
    
    from sklearn.preprocessing import LabelEncoder, OneHotEncoder
    from sklearn.compose import ColumnTransformer
    
    labelencoder_previsores = LabelEncoder()
    previsores[:,1] = labelencoder_previsores.fit_transform(previsores[:,1])
    previsores[:,3] = labelencoder_previsores.fit_transform(previsores[:,3])
    previsores[:,5] = labelencoder_previsores.fit_transform(previsores[:,5])
    previsores[:,6] = labelencoder_previsores.fit_transform(previsores[:,6])
    previsores[:,7] = labelencoder_previsores.fit_transform(previsores[:,7])
    previsores[:,8] = labelencoder_previsores.fit_transform(previsores[:,8])
    previsores[:,9] = labelencoder_previsores.fit_transform(previsores[:,9])
    previsores[:,13] = labelencoder_previsores.fit_transform(previsores[:,13])
    
    column_tranformer = ColumnTransformer([('one_hot_encoder', OneHotEncoder(), [1, 3, 5, 6, 7, 8, 9, 13])],remainder='passthrough')
    previsores = column_tranformer.fit_transform(previsores).toarray()
    
    labelencoder_classe = LabelEncoder()
    classe = labelencoder_classe.fit_transform(classe)
    
    from sklearn.preprocessing import StandardScaler
    scaler = StandardScaler()
    previsores = scaler.fit_transform(previsores)
    
    mlp = pickle.load(open('mlp_final.sav', 'rb'))
    resultado_mlp = mlp.score(previsores, classe)
    
    novo_registro = [[39,'State-gov',77516,'Bachelor',13,'Never-married','Adm-clerical','Not-in-family','White','Male',2174,0,40,'United-States']]
    novo_registro = np.asarray(novo_registro)
    #28465

    Olá Nikolas, segue a resposta do instrutor Denny:

    O novo registro deve primeiro passar por todo o processamento da mesma forma que o dataset usado no treinamento passou, ou seja, todas as etapas de LabelEncoder e o OneHotEncoder no final, mas desta vez usando o método transform já que fit é usado somente com os dados de treinamento. Entretanto, você precisa observar que, sempre que usa o método fit_transform na mesma instância do LabelEncoder (no caso, labelencoder_previsores), como foi mostrado na aula, ele perde a informação referente à variável que já havia processado. Para evitar isso, é preciso criar uma instância separada para cada variável, como por exemplo:

    labelencoder_previsores_1 = LabelEncoder()
    labelencoder_previsores_3 = LabelEncoder()
    labelencoder_previsores_5 = LabelEncoder()
    [...]
    labelencoder_previsores_13 = LabelEncoder()

    Aí você aplica cada instância separadamente a cada variável:

    previsores[:,1] = labelencoder_previsores_1.fit_transform(previsores[:,1])
    previsores[:,3] = labelencoder_previsores_3.fit_transform(previsores[:,3])
    previsores[:,5] = labelencoder_previsores_5.fit_transform(previsores[:,5])
    [...]
    previsores[:,13] = labelencoder_previsores_13.fit_transform(previsores[:,13])

    E depois, no novo registro, somente o método transform:

    novo_registro[:,1] = labelencoder_previsores_1.transform(novo_registro[:,1])
    novo_registro[:,3] = labelencoder_previsores_3.transform(novo_registro[:,3])
    novo_registro[:,5] = labelencoder_previsores_5.transform(novo_registro[:,5])
    [...]
    novo_registro[:,13] = labelencoder_previsores_13.transform(novo_registro[:,13])

    O ColumnTransformer não precisa mudar, já que ele processa mais de uma coluna por vez:

    novo_registro = column_transformer.transform(novo_registro).toarray()

    Aí é só chamar seu modelo com o método predict para classificar o novo registro.

    • Esta resposta foi modificada 6 meses atrás por Fábio Spak.
    #28469

    Desculpa Denny, acho que fiquei um pouco confuso. Bom, tentei seguir pelo o que entendi mas ao tentar passar o labelencoder com o método transform, está gerando um erro conforme a imagem abaixo. Uma observação que os dados do novo registro são exatamente iguais aos utiliziados na primeira linha da base de dados.

    Error
    
    import pandas as pd
    import pickle
    from sklearn.impute import SimpleImputer
    from sklearn.preprocessing import StandardScaler
    import numpy as np
    
    
    base = pd.read_csv('census.csv')
    previsores = base.iloc[:, 0:14].values
    classe = base.iloc[:, 14].values
    
    from sklearn.preprocessing import LabelEncoder, OneHotEncoder
    from sklearn.compose import ColumnTransformer
    
    labelencoder_previsores1 = LabelEncoder()
    labelencoder_previsores3 = LabelEncoder()
    labelencoder_previsores5 = LabelEncoder()
    labelencoder_previsores6 = LabelEncoder()
    labelencoder_previsores7 = LabelEncoder()
    labelencoder_previsores8 = LabelEncoder()
    labelencoder_previsores9 = LabelEncoder()
    labelencoder_previsores13 = LabelEncoder()
    
    
    previsores[:,1] = labelencoder_previsores1.fit_transform(previsores[:,1])
    previsores[:,3] = labelencoder_previsores3.fit_transform(previsores[:,3])
    previsores[:,5] = labelencoder_previsores5.fit_transform(previsores[:,5])
    previsores[:,6] = labelencoder_previsores6.fit_transform(previsores[:,6])
    previsores[:,7] = labelencoder_previsores7.fit_transform(previsores[:,7])
    previsores[:,8] = labelencoder_previsores8.fit_transform(previsores[:,8])
    previsores[:,9] = labelencoder_previsores9.fit_transform(previsores[:,9])
    previsores[:,13] = labelencoder_previsores13.fit_transform(previsores[:,13])
    
    column_tranformer = ColumnTransformer([('one_hot_encoder', OneHotEncoder(), [1, 3, 5, 6, 7, 8, 9, 13])],remainder='passthrough')
    previsores = column_tranformer.fit_transform(previsores).toarray()
    
    labelencoder_classe = LabelEncoder()
    classe = labelencoder_classe.fit_transform(classe)
    
    from sklearn.preprocessing import StandardScaler
    scaler = StandardScaler()
    previsores = scaler.fit_transform(previsores)
    
    mlp = pickle.load(open('mlp_final.sav', 'rb'))
    resultado_mlp = mlp.score(previsores, classe)
    
    novo_registro = [[39,"State-gov",77516,"Bachelor",13,"Never-married","Adm-clerical","Not-in-family","White","Male",2174,0,40,"United-States"]]
    novo_registro = np.asarray(novo_registro)
    
    
    novo_registro[:,1] = labelencoder_previsores1.transform(novo_registro[:,1])
    novo_registro[:,3] = labelencoder_previsores3.transform(novo_registro[:,3])
    novo_registro[:,5] = labelencoder_previsores5.transform(novo_registro[:,5])
    novo_registro[:,6] = labelencoder_previsores6.transform(novo_registro[:,6])
    novo_registro[:,7] = labelencoder_previsores7.transform(novo_registro[:,7])
    novo_registro[:,8] = labelencoder_previsores8.transform(novo_registro[:,8])
    novo_registro[:,9] = labelencoder_previsores9.transform(novo_registro[:,9])
    novo_registro[:,13] = labelencoder_previsores13.transform(novo_registro[:,13])
    #28476

    Olá Nikolas, segue a resposta do instrutor Denny:

    Tem duas causas potenciais: A primeira, verifique quais são os nomes das colunas de base. Aqui, o Pandas criou uma coluna 0 sem nome onde colocou os índices das instâncias, o que desalinha todas as operações de LabelEncoder. Se este for o caso, carregue os dados de novo com base = pd.read_csv(‘census.csv’, index_col = 0).

    A segunda, se você pedir pra verificar os valores da coluna workclass com base[‘workclass’].tolist(), vai verificar que todos os nomes têm um espaço na frente. Eu abri o arquivo census.csv e este é o caso para todas as categorias. Então, em seu novo registro, adicione um espaço na frente de todos os nomes de categorias.

    #28477

    Consegui.Era isso mesmo. Tem um espaço antes de alguns registros ali. Bom, até essa parte consegui fazer. Continuei com o processo e fiz o reshape para poder fazer o escalonamento e tudo mais. Mas agora o problema que quando vou passar  o predict, meu modelo de treinamento usado foi com OneHotEncoder e ai gerou as variáveis dummy, que no caso aumentou minha base para 108 colunas. Ao tentar passar o predict ele não consegue por pelo fato do novo registro só possuir 14 colunas.

     

    import pandas as pd
    import pickle
    from sklearn.impute import SimpleImputer
    from sklearn.preprocessing import StandardScaler
    import numpy as np
    
    
    base = pd.read_csv('census.csv')
    previsores = base.iloc[:, 0:14].values
    classe = base.iloc[:, 14].values
    
    from sklearn.preprocessing import LabelEncoder, OneHotEncoder
    from sklearn.compose import ColumnTransformer
    
    labelencoder_previsores1 = LabelEncoder()
    labelencoder_previsores3 = LabelEncoder()
    labelencoder_previsores5 = LabelEncoder()
    labelencoder_previsores6 = LabelEncoder()
    labelencoder_previsores7 = LabelEncoder()
    labelencoder_previsores8 = LabelEncoder()
    labelencoder_previsores9 = LabelEncoder()
    labelencoder_previsores13 = LabelEncoder()
    
    
    previsores[:,1] = labelencoder_previsores1.fit_transform(previsores[:,1])
    previsores[:,3] = labelencoder_previsores3.fit_transform(previsores[:,3])
    previsores[:,5] = labelencoder_previsores5.fit_transform(previsores[:,5])
    previsores[:,6] = labelencoder_previsores6.fit_transform(previsores[:,6])
    previsores[:,7] = labelencoder_previsores7.fit_transform(previsores[:,7])
    previsores[:,8] = labelencoder_previsores8.fit_transform(previsores[:,8])
    previsores[:,9] = labelencoder_previsores9.fit_transform(previsores[:,9])
    previsores[:,13] = labelencoder_previsores13.fit_transform(previsores[:,13])
    
    column_tranformer = ColumnTransformer([('one_hot_encoder', OneHotEncoder(), [1, 3, 5, 6, 7, 8, 9, 13])],remainder='passthrough')
    previsores = column_tranformer.fit_transform(previsores).toarray()
    
    labelencoder_classe = LabelEncoder()
    classe = labelencoder_classe.fit_transform(classe)
    
    from sklearn.preprocessing import StandardScaler
    scaler = StandardScaler()
    previsores = scaler.fit_transform(previsores)
    
    mlp = pickle.load(open('mlp_final.sav', 'rb'))
    resultado_mlp = mlp.score(previsores, classe)
    
    novo_registro = [[39," State-gov",77516," Bachelors",13," Never-married"," Adm-clerical"," Not-in-family"," White"," Male",2174,0,40," United-States"]]
    novo_registro = np.asarray(novo_registro)
    
    
    novo_registro[:,1] = labelencoder_previsores1.transform(novo_registro[:,1])
    novo_registro[:,3] = labelencoder_previsores3.transform(novo_registro[:,3])
    novo_registro[:,5] = labelencoder_previsores5.transform(novo_registro[:,5])
    novo_registro[:,6] = labelencoder_previsores6.transform(novo_registro[:,6])
    novo_registro[:,7] = labelencoder_previsores7.transform(novo_registro[:,7])
    novo_registro[:,8] = labelencoder_previsores8.transform(novo_registro[:,8])
    novo_registro[:,9] = labelencoder_previsores9.transform(novo_registro[:,9])
    novo_registro[:,13] = labelencoder_previsores13.transform(novo_registro[:,13])
    
    
    novo_registro = novo_registro.reshape(-1, 1)
    novo_registro = scaler.fit_transform(novo_registro)
    novo_registro = novo_registro.reshape(-1, 14)
    
    resposta_mlp = mlp.predict(novo_registro)
    #28478

    Olá Nikolas, segue a resposta do instrutor Denny:

    Nikolas,

    Você não deve fazer este reshape:

    novo_registro = novo_registro.reshape(-1, 1)

    porque os dados que o modelo recebe devem estar representados pelas instâncias nas linhas e atributos nas colunas. Então, o formato original já estava correto.

    Ainda assim, depois do último LabelEncoder, faltou aplicar o ColumnTransformer que vai transformar as variáveis categóricas no formato one-hot, convertendo os 14 atributos originais para 108:

    novo_registro = column_tranformer.transform(novo_registro).toarray()

    e depois, finalmente, aplicar o scaler, mas novamente somente com o método transform:

    novo_registro = scaler.transform(novo_registro)

    Aí sim o registro pode ser passado ao modelo.

    #28479

    Eu tentei realizar essas mudanças Denny mas não funcionou. Ao tentar fazer o column_tranformer ele acusa o erro da imagem. Dei uma pesquisada e alguns lugares falava para utilizar o OneHotEncoder(handle_unknown=’ignore’), mas não funcionou.

    import pandas as pd
    import pickle
    from sklearn.impute import SimpleImputer
    from sklearn.preprocessing import StandardScaler
    import numpy as np
    
    
    base = pd.read_csv('census.csv')
    previsores = base.iloc[:, 0:14].values
    classe = base.iloc[:, 14].values
    
    from sklearn.preprocessing import LabelEncoder, OneHotEncoder
    from sklearn.compose import ColumnTransformer
    
    labelencoder_previsores1 = LabelEncoder()
    labelencoder_previsores3 = LabelEncoder()
    labelencoder_previsores5 = LabelEncoder()
    labelencoder_previsores6 = LabelEncoder()
    labelencoder_previsores7 = LabelEncoder()
    labelencoder_previsores8 = LabelEncoder()
    labelencoder_previsores9 = LabelEncoder()
    labelencoder_previsores13 = LabelEncoder()
    
    
    previsores[:,1] = labelencoder_previsores1.fit_transform(previsores[:,1])
    previsores[:,3] = labelencoder_previsores3.fit_transform(previsores[:,3])
    previsores[:,5] = labelencoder_previsores5.fit_transform(previsores[:,5])
    previsores[:,6] = labelencoder_previsores6.fit_transform(previsores[:,6])
    previsores[:,7] = labelencoder_previsores7.fit_transform(previsores[:,7])
    previsores[:,8] = labelencoder_previsores8.fit_transform(previsores[:,8])
    previsores[:,9] = labelencoder_previsores9.fit_transform(previsores[:,9])
    previsores[:,13] = labelencoder_previsores13.fit_transform(previsores[:,13])
    
    column_tranformer = ColumnTransformer([('one_hot_encoder', OneHotEncoder(), [1, 3, 5, 6, 7, 8, 9, 13])],remainder='passthrough')
    previsores = column_tranformer.fit_transform(previsores).toarray()
    
    labelencoder_classe = LabelEncoder()
    classe = labelencoder_classe.fit_transform(classe)
    
    from sklearn.preprocessing import StandardScaler
    scaler = StandardScaler()
    previsores = scaler.fit_transform(previsores)
    
    mlp = pickle.load(open('mlp_final.sav', 'rb'))
    resultado_mlp = mlp.score(previsores, classe)
    
    novo_registro = [[39," State-gov",77516," Bachelors",13," Never-married"," Adm-clerical"," Not-in-family"," White"," Male",2174,0,40," United-States"]]
    novo_registro = np.asarray(novo_registro)
    
    
    novo_registro[:,1] = labelencoder_previsores1.transform(novo_registro[:,1])
    novo_registro[:,3] = labelencoder_previsores3.transform(novo_registro[:,3])
    novo_registro[:,5] = labelencoder_previsores5.transform(novo_registro[:,5])
    novo_registro[:,6] = labelencoder_previsores6.transform(novo_registro[:,6])
    novo_registro[:,7] = labelencoder_previsores7.transform(novo_registro[:,7])
    novo_registro[:,8] = labelencoder_previsores8.transform(novo_registro[:,8])
    novo_registro[:,9] = labelencoder_previsores9.transform(novo_registro[:,9])
    novo_registro[:,13] = labelencoder_previsores13.transform(novo_registro[:,13])
    
    
    novo_registro = column_tranformer.transform(novo_registro).toarray()
    
    novo_registro = scaler.transform(novo_registro)
    
    resposta_mlp = mlp.predict(novo_registro)

     

    #28481

    Bom Denny, acho que agora consegui. Eu tive que colocar um parâmetro dentro do OneHotEncoder e também modificar o tipo de array do novo registro. Não sei se isso influencia, mas antes de trocar de array string para objeto, não estava conseguindo.

     

    import pandas as pd
    import pickle
    from sklearn.impute import SimpleImputer
    from sklearn.preprocessing import StandardScaler
    import numpy as np
    
    
    base = pd.read_csv('census.csv')
    previsores = base.iloc[:, 0:14].values
    classe = base.iloc[:, 14].values
    
    from sklearn.preprocessing import LabelEncoder, OneHotEncoder
    from sklearn.compose import ColumnTransformer
    
    labelencoder_previsores1 = LabelEncoder()
    labelencoder_previsores3 = LabelEncoder()
    labelencoder_previsores5 = LabelEncoder()
    labelencoder_previsores6 = LabelEncoder()
    labelencoder_previsores7 = LabelEncoder()
    labelencoder_previsores8 = LabelEncoder()
    labelencoder_previsores9 = LabelEncoder()
    labelencoder_previsores13 = LabelEncoder()
    
    
    previsores[:,1] = labelencoder_previsores1.fit_transform(previsores[:,1])
    previsores[:,3] = labelencoder_previsores3.fit_transform(previsores[:,3])
    previsores[:,5] = labelencoder_previsores5.fit_transform(previsores[:,5])
    previsores[:,6] = labelencoder_previsores6.fit_transform(previsores[:,6])
    previsores[:,7] = labelencoder_previsores7.fit_transform(previsores[:,7])
    previsores[:,8] = labelencoder_previsores8.fit_transform(previsores[:,8])
    previsores[:,9] = labelencoder_previsores9.fit_transform(previsores[:,9])
    previsores[:,13] = labelencoder_previsores13.fit_transform(previsores[:,13])
    
    column_tranformer = ColumnTransformer([('one_hot_encoder', OneHotEncoder(handle_unknown='ignore'), [1, 3, 5, 6, 7, 8, 9, 13])],remainder='passthrough')
    previsores = column_tranformer.fit_transform(previsores).toarray()
    
    labelencoder_classe = LabelEncoder()
    classe = labelencoder_classe.fit_transform(classe)
    
    from sklearn.preprocessing import StandardScaler
    scaler = StandardScaler()
    previsores = scaler.fit_transform(previsores)
    
    mlp = pickle.load(open('mlp_final.sav', 'rb'))
    resultado_mlp = mlp.score(previsores, classe)
    
    novo_registro = [[52," Self-emp-not-inc",209642," HS-grad",9," Married-civ-spouse"," Exec-managerial"," Husband"," White"," Male",0,0,45," United-States"]]
    novo_registro = np.asarray(novo_registro)
    
    
    novo_registro[:,1] = labelencoder_previsores1.transform(novo_registro[:,1])
    novo_registro[:,3] = labelencoder_previsores3.transform(novo_registro[:,3])
    novo_registro[:,5] = labelencoder_previsores5.transform(novo_registro[:,5])
    novo_registro[:,6] = labelencoder_previsores6.transform(novo_registro[:,6])
    novo_registro[:,7] = labelencoder_previsores7.transform(novo_registro[:,7])
    novo_registro[:,8] = labelencoder_previsores8.transform(novo_registro[:,8])
    novo_registro[:,9] = labelencoder_previsores9.transform(novo_registro[:,9])
    novo_registro[:,13] = labelencoder_previsores13.transform(novo_registro[:,13])
    
    novo_registro = np.asarray(novo_registro, object)
    
    novo_registro = column_tranformer.transform(novo_registro).toarray()
    
    novo_registro = scaler.transform(novo_registro)
    
    resposta_mlp = mlp.predict(novo_registro)
    #28493

    Olá Nikolas, segue a resposta do instrutor Denny:

    Não precisa mudar o parâmetro do OneHotEncoder; com handle_unknown = ‘ignore’, você está dizendo para ele ignorar as categorias que não tenha visto no dataset de treinamento, mas se for algum outro tipo de erro relacionado ao tipo de dado por exemplo (que é o que houve), ele também vai ignorar a categoria, o que não é o comportamento desejado.
    A outra transformação está correta, inclusive se você verificar o tipo de dado em previsores antes do column_transformer (com previsores.dtype), vai ver que é um objeto. Mas você pode simplificar um pouco o código já instanciando o novo_registro como array do tipo objeto:

    novo_registro = np.array([[39," State-gov",77516," Bachelors",13," Never-married"," Adm-clerical"," Not-in-family"," White"," Male",2174,0,40," United-States"]], object)

    Parabéns por ter conseguido resolver esta última questão por conta, saber procurar as respostas pesquisando na internet é essencial para um bom profissional da área.

    #28503

    Ah sim. Entendido Denny. Muito obrigado pelo suporte. Irei dar algumas simplificadas como você instruiu.

Visualizando 10 posts - 1 até 10 (de 10 do total)
  • Você deve fazer login para responder a este tópico.