Métodos de conjunto: técnicas elegantes para produzir resultados aprimorados de aprendizado de máquina
Publicados: 2022-03-11Os métodos de conjunto são técnicas que criam vários modelos e depois os combinam para produzir melhores resultados. Os métodos de conjunto geralmente produzem soluções mais precisas do que um único modelo. Esse foi o caso em várias competições de aprendizado de máquina, onde as soluções vencedoras usaram métodos de conjunto. Na popular Competição Netflix, o vencedor usou um método de conjunto para implementar um poderoso algoritmo de filtragem colaborativa. Outro exemplo é o KDD 2009, onde o vencedor também usou métodos de conjunto. Você também pode encontrar vencedores que usaram esses métodos em competições Kaggle, por exemplo, aqui está a entrevista com o vencedor da competição CrowdFlower.
É importante que entendamos algumas terminologias antes de continuarmos com este artigo. Ao longo do artigo, usei o termo “modelo” para descrever a saída do algoritmo que treinou com dados. Este modelo é então usado para fazer previsões. Esse algoritmo pode ser qualquer algoritmo de aprendizado de máquina, como regressão logística, árvore de decisão, etc. Esses modelos, quando usados como entradas de métodos de ensemble, são chamados de “modelos base”.
Nesta postagem do blog, abordarei métodos de ensemble para classificação e descreverei alguns métodos amplamente conhecidos de ensemble: votação, empilhamento, ensacamento e aumento.
Métodos de conjunto baseados em votação e média
A votação e a média são dois dos métodos de conjunto mais fáceis. Ambos são fáceis de entender e implementar. A votação é usada para classificação e a média é usada para regressão.
Em ambos os métodos, o primeiro passo é criar vários modelos de classificação/regressão usando algum conjunto de dados de treinamento. Cada modelo de base pode ser criado usando diferentes divisões do mesmo conjunto de dados de treinamento e mesmo algoritmo, ou usando o mesmo conjunto de dados com algoritmos diferentes ou qualquer outro método. O pseudocódigo Python-esque a seguir mostra o uso do mesmo conjunto de dados de treinamento com algoritmos diferentes.
train = load_csv("train.csv") target = train["target"] train = train.drop("target") test = load_csv("test.csv") algorithms = [logistic_regression, decision_tree_classification, ...] #for classification algorithms = [linear_regression, decision_tree_regressor, ...] #for regression predictions = matrix(row_length=len(target), column_length=len(algorithms)) for i,algorithm in enumerate(algorithms): predictions[,i] = algorithm.fit(train, target).predict(test)De acordo com o pseudocódigo acima, criamos previsões para cada modelo e as salvamos em uma matriz chamada previsões, onde cada coluna contém previsões de um modelo.
Votação da maioria
Cada modelo faz uma previsão (votos) para cada instância de teste e a previsão de saída final é aquela que recebe mais da metade dos votos. Se nenhuma das previsões obtiver mais da metade dos votos, podemos dizer que o método ensemble não poderia fazer uma previsão estável para esta instância. Embora esta seja uma técnica amplamente utilizada, você pode tentar a previsão mais votada (mesmo que seja menos da metade dos votos) como a previsão final. Em alguns artigos, você pode ver esse método sendo chamado de “votação de pluralidade”.
Votação ponderada
Ao contrário da votação por maioria, onde cada modelo tem os mesmos direitos, podemos aumentar a importância de um ou mais modelos. Na votação ponderada, você conta a previsão dos melhores modelos várias vezes. Encontrar um conjunto razoável de pesos é com você.
Média Simples
No método de média simples, para cada instância do conjunto de dados de teste, as previsões médias são calculadas. Esse método geralmente reduz o overfit e cria um modelo de regressão mais suave. O código de pseudocódigo a seguir mostra esse método simples de média:
final_predictions = [] for row_number in len(predictions): final_predictions.append( mean(prediction[row_number, ]) )Média Ponderada
A média ponderada é uma versão ligeiramente modificada da média simples, onde a previsão de cada modelo é multiplicada pelo peso e então sua média é calculada. O código de pseudocódigo a seguir mostra a média ponderada:
weights = [..., ..., ...] #length is equal to len(algorithms) final_predictions = [] for row_number in len(predictions): final_predictions.append( mean(prediction[row_number, ]*weights) )Empilhando vários modelos de aprendizado de máquina
O empilhamento, também conhecido como generalização empilhada, é um método de conjunto em que os modelos são combinados usando outro algoritmo de aprendizado de máquina. A ideia básica é treinar algoritmos de aprendizado de máquina com conjunto de dados de treinamento e, em seguida, gerar um novo conjunto de dados com esses modelos. Em seguida, esse novo conjunto de dados é usado como entrada para o algoritmo de aprendizado de máquina do combinador.
O pseudocódigo de um procedimento de empilhamento é resumido como abaixo:
base_algorithms = [logistic_regression, decision_tree_classification, ...] #for classification stacking_train_dataset = matrix(row_length=len(target), column_length=len(algorithms)) stacking_test_dataset = matrix(row_length=len(test), column_length=len(algorithms)) for i,base_algorithm in enumerate(base_algorithms): stacking_train_dataset[,i] = base_algorithm.fit(train, target).predict(train) stacking_test_dataset[,i] = base_algorithm.predict(test) final_predictions = combiner_algorithm.fit(stacking_train_dataset, target).predict(stacking_test_dataset)Como você pode ver no pseudocódigo acima, o conjunto de dados de treinamento para o algoritmo combinador é gerado usando as saídas dos algoritmos base. No pseudocódigo, o algoritmo base é gerado usando o conjunto de dados de treinamento e, em seguida, o mesmo conjunto de dados é usado novamente para fazer previsões. Mas, como sabemos, no mundo real não usamos o mesmo conjunto de dados de treinamento para previsão, portanto, para superar esse problema, você poderá ver algumas implementações de empilhamento onde o conjunto de dados de treinamento é dividido. Abaixo você pode ver um pseudocódigo onde o conjunto de dados de treinamento é dividido antes de treinar os algoritmos básicos:

base_algorithms = [logistic_regression, decision_tree_classification, ...] #for classification stacking_train_dataset = matrix(row_length=len(target), column_length=len(algorithms)) stacking_test_dataset = matrix(row_length=len(test), column_length=len(algorithms)) for i,base_algorithm in enumerate(base_algorithms): for trainix, testix in split(train, k=10): #you may use sklearn.cross_validation.KFold of sklearn library stacking_train_dataset[testcv,i] = base_algorithm.fit(train[trainix], target[trainix]).predict(train[testix]) stacking_test_dataset[,i] = base_algorithm.fit(train).predict(test) final_predictions = combiner_algorithm.fit(stacking_train_dataset, target).predict(stacking_test_dataset)Agregação de Bootstrap
O nome Bootstrap Aggregating, também conhecido como “Bagging”, resume os principais elementos desta estratégia. No algoritmo de ensacamento, a primeira etapa envolve a criação de vários modelos. Esses modelos são gerados usando o mesmo algoritmo com subamostras aleatórias do conjunto de dados que são extraídas do conjunto de dados original aleatoriamente com o método de amostragem bootstrap. Na amostragem bootstrap, alguns exemplos originais aparecem mais de uma vez e alguns exemplos originais não estão presentes na amostra. Se você deseja criar um subconjunto de dados com m elementos, deve selecionar um elemento aleatório do conjunto de dados original m vezes. E se o objetivo for gerar n conjunto de dados, siga esta etapa n vezes.
No final, temos n conjuntos de dados onde o número de elementos em cada conjunto de dados é m. O seguinte pseudocódigo no estilo Python mostra a amostragem de bootstrap:
def bootstrap_sample(original_dataset, m): sub_dataset = [] for i in range(m): sub_dataset.append( random_one_element(original_dataset) ) return sub_datasetA segunda etapa do ensacamento é agregar os modelos gerados. Métodos bem conhecidos, como votação e cálculo da média, são usados para este propósito.
O pseudocódigo geral se parece com isso:
def bagging(n, m, base_algorithm, train_dataset, target, test_dataset): predictions = matrix(row_length=len(target), column_length=n) for i in range(n): sub_dataset = bootstrap_sample(train_dataset, m) predictions[,i] = base_algorithm.fit(original_dataset, target).predict(test_dataset) final_predictions = voting(predictions) # for classification final_predictions = averaging(predictions) # for regression return final_predictionsNo ensacamento, cada subamostra pode ser gerada independentemente uma da outra. Assim, a geração e o treinamento podem ser feitos em paralelo.
Você também pode encontrar a implementação da estratégia de ensacamento em alguns algoritmos. Por exemplo, o algoritmo Random Forest usa a técnica de ensacamento com algumas diferenças. Random Forest usa seleção aleatória de recursos, e o algoritmo base é um algoritmo de árvore de decisão.
Impulsionando: convertendo modelos fracos em fortes
O termo “boosting” é usado para descrever uma família de algoritmos que são capazes de converter modelos fracos em modelos fortes. O modelo é fraco se tiver uma taxa de erro substancial, mas o desempenho não for aleatório (resultando em uma taxa de erro de 0,5 para classificação binária). O boosting incremental constrói um ensemble treinando cada modelo com o mesmo conjunto de dados, mas onde os pesos das instâncias são ajustados de acordo com o erro da última previsão. A ideia principal é forçar os modelos a focar nas instâncias que são difíceis. Ao contrário do ensacamento, o boosting é um método sequencial e, portanto, você não pode usar operações paralelas aqui.
O procedimento geral do algoritmo de reforço é definido da seguinte forma:
def adjust_dataset(_train, errors): #create a new dataset by using the hardest instances ix = get_highest_errors_index(train) return concat(_train[ix], random_select(train)) models = [] _train = random_select(train) for i in range(n): #n rounds model = base_algorithm.fit(_train) predictions = model.predict(_train) models.append(model) errors = calculate_error(predictions) _train = adjust_dataset(_train, errors) final_predictions = combine(models, test)A função ajuste_dataset retorna um novo conjunto de dados contendo as instâncias mais difíceis, que podem ser usadas para forçar o algoritmo básico a aprender.
Adaboost é um algoritmo amplamente conhecido que é um método de reforço. Os fundadores da Adaboost ganharam o Prêmio Gödel por seu trabalho. Principalmente, o algoritmo de árvore de decisão é preferido como um algoritmo base para Adaboost e na biblioteca sklearn o algoritmo base padrão para Adaboost é a árvore de decisão (AdaBoostRegressor e AdaBoostClassifier). Como discutimos no parágrafo anterior, o mesmo método incremental se aplica ao Adaboost. As informações coletadas em cada etapa do algoritmo AdaBoost sobre a 'dureza' de cada amostra de treinamento são inseridas no modelo. A etapa de 'ajustar o conjunto de dados' é diferente da descrita acima e a etapa de 'combinar modelos' é calculada usando votação ponderada.
Conclusão
Embora os métodos de conjunto possam ajudá-lo a vencer competições de aprendizado de máquina, criando algoritmos sofisticados e produzindo resultados com alta precisão, geralmente não é preferido nos setores em que a interpretabilidade é mais importante. No entanto, a eficácia desses métodos é inegável e seus benefícios em aplicações apropriadas podem ser enormes. Em áreas como a saúde, mesmo a menor melhoria na precisão dos algoritmos de aprendizado de máquina pode ser algo realmente valioso.
- Uma introdução à teoria do aprendizado de máquina e suas aplicações: um tutorial visual com exemplos
- Máquinas e confiança: como mitigar o viés da IA
