segunda-feira, 1 de junho de 2015

Validação Cruzada (Cross Validation)

Uma das etapas mais importantes em um projeto de machine learning é a etapa de validação dos resultados. Muitas das técnicas mais poderosas de aprendizado apresentam uma grande quantidade de parâmetros e quanto menos restrições colocarmos no nosso modelo maior a probabilidade de encontrarmos um super ajustamento, ou como é mais conhecido, o overfitting.
                Mas o que é overfitting? Overfitting ocorre quando o método que estimamos consegue bons resultados apenas nos dados que eles foram treinados. Já na presença de novas observações, percebemos uma grande piora na qualidade da predição. Ou seja, o overfitting ocorre quando o método de aprendizado não consegue generalizar os resultados para dados que não foram utilizados no processo de treino.
                Para evitar este problema existe o processo de validação. Há diversos tipos de validação, um dos mais utilizados na prática corresponde a dividir os seus dados em três bases, base de treino, validação e teste. A base de treino, como o próprio nome diz, é utilizada para treinar o seu modelo, enquanto que a base de teste serve para verificarmos a eficiência do método em “novos” dados. Já a base de validação, que pode não existir, é utilizada para a escolha de algum parâmetro da técnica de aprendizado, o que chamamos de model tuning. Um exemplo do model tuning pode ser desde a escolha do número de neurônios de uma rede neural ou até mesmo no uso do random forest para seleção de variáveis, comentada no post anterior, em que podemos ajustar modelos adicionando a cada nova etapa uma variável respeitando a ordem do random forest e escolher o conjunto que apresente melhor resultado nesta base de validação. Um outro tipo de validação é a validação out-of-time, muito utilizada para projetos de aprendizado com dados obtidos ao longo do tempo, em que os últimos dados ou últimos meses são deixados para verificar se o modelo se comporta de maneira estável e se continuará com boa performance à medida que novos dados forem sendo observados.
                Neste post iremos discutir um tipo de validação que vem sendo a cada dia mais utilizado, trata-se da validação cruzada.
                A validação cruzada estima o erro do método de aprendizado em observações não utilizadas no treino, ou seja, estima como o modelo construído irá se comportará em novos dados, claro que isto é válido apenas se mantivermos a mesma probabilidade conjunta das variáveis explicativas e da variável resposta utilizada durante o treino.
                O k-fold cross validation consiste em dividir a base em k pedaços. Para cada pedaço, estimamos o método sem a presença desta parte e verificamos o erro médio no pedaço não utilizado durante o treino. Abaixo, um exemplo de 8-fold cross validation.

1
Treino
2
Validação
3
Treino
4
Treino
5
Treino
6
Treino
7
Treino
8
Treino

                A estimativa do erro de predição de cross validation é dada pela média dos erros médios nos k pedaços. O model tuning, discutido anteriormente, pode também ser realizado com o método de validação cruzada ao invés de apenas uma base de validação. Uma importante escolha ao utilizarmos este método é justamente a escolha do k, que pode variar de 2 a N, em que N é o número total de observações disponíveis. Mas por que o método é sensível à escolha do k?
                Imagine que você escolha k igual a N, um caso particular é denotado como leave-one-out, pois somente uma observação é deixada de fora em cada etapa. Com esta escolha, primeiramente teremos um custo computacional alto, pois teríamos que ajustar o modelo N vezes. Além disso, como os vários ajustes são muito parecidos, apenas uma observação será diferente em cada etapa, teremos um estimador não viesado, no entanto com alta variância. Já diminuindo o valor de k, diminuiremos a variância, mas podemos aumentar o viés do estimador. Na prática, costuma-se utilizar k variando de 5 a 10.
                Um detalhe importante que muitas vezes é esquecido ou deixado de lado em muitos projetos de machine learning ocorre quando há, por exemplo, um processo de seleção de variáveis. Muitas pessoas costumam aplicar o método de validação cruzada apenas na estimação do modelo final, no entanto, isto pode produzir viés na estimativa do erro de previsão com o método. Nestes casos, devemos fazer a seleção de variáveis em conjunto com a estimação, ou seja, deixando cada pedaço fora, realizamos a seleção e ajustamos o modelo sem este pedaço e calculamos o erro em cada um dos pedaços.
                Com o intuito de exemplificar o que foi discutido neste post, construí um exemplo com ajuda do software R e do pacote caret. Esta library do R é tão completa e possibilita tantas coisas que com certeza será tema de um post específico no futuro. A base de exemplo utilizada foi novamente a base de spam já utilizada em outros posts. O código em R e a base estão disponíveis em (https://github.com/carlosrelvas/Cross_validation).
                Primeiramente, deixei 3.000 observações para o treino. As restantes, deixei separadas para avaliar a performance e comparar com os resultados da validação cruzada. Optei por utilizar a 10-fold cross validation, assim cada um dos 10 ajustes utilizou 2.700 observações e avaliou as 300 restantes. A medida de performance que optei por utilizar foi a AUC (area under the curve) que é a área sob a curva ROC. Como o intuito era só exemplificar, utilizei todas as variáveis explicativas disponíveis (57) em um modelo de árvore de decisão, mais precisamente optei por utilizar o algoritmo do pacote “ctree” que estima conditional inference trees. Um dos parâmetros deste algoritmo é a profundidade da árvore que representa a quantidade de nós finais na árvore. A validação cruzada foi utilizada para escolher este parâmetro, ou seja, para construir o model tuning. Optei por testar apenas os valores de 10, 15 e 20 como profundidade e obtive a seguinte tabela:

Profundidade
ROC
10
0.946
15
0.951
20
0.95

                Podemos perceber que a validação cruzada não escolhe o modelo mais complexo (profundidade 20) e sim aquele que generaliza melhor os resultados (profundidade 15).
A estimativa de validação cruzada com profundidade 15 foi 0.951 enquanto que a mesma medida na base de teste, deixada totalmente de fora da validação cruzada, foi 0.929.



sábado, 9 de maio de 2015

Dados Missing

Hoje falaremos de um problema que acontece quase sempre em projetos de machine learning, dados missing ou faltantes. Por ser tão comum, principalmente quando falamos em big data, não consideramos de fato um problema e sim uma etapa a mais na análise. Na literatura especializada há muitas abordagens tratando de qual a melhor forma de analisar os seus dados na presença de dados missing. Discutiremos algumas destas formas e mostraremos uma aplicação em map reduce R, que também serve como um exemplo do nosso primeiro post, R com hadoop.
                Há três tipos de dados faltantes: missing completamente aleatórios (MCAR – missing completely at random), missing aleatórios (MAR – missing at random) e missing não aleatórios (MNAR – missing not at random).
O MCAR ocorre quando os dados faltantes são completamente independentes das variáveis observadas e dos parâmetros de interesse. O MCAR acontece, por exemplo, quando o sensor de captura de dados para de funcionar por algum período de tempo. Infelizmente, este tipo de missing não é comum. A razão do infelizmente ficará clara adiante, pois o MCAR é o tipo mais fácil de ser solucionado. As vezes pode parecer que os seus dados são MCAR, mas na verdade não o são. Por exemplo, se o sensor de captura parar de funcionar por aumento demasiado de entrada de dados de uma determinada característica, não será mais um mecanismo de missing MCAR.
O MAR ocorre quando o missing é dependente de alguma outra variável explicativa. O nome missing at random confunde muito as pessoas, que, ao ouvirem, geralmente pensam no missing completely at random. Pessoas com renda alta tendem a não querer responder quantos televisores possuem em casa. Isto é um exemplo de MAR e indica que o número de televisores está relacionado com a renda.
Por fim, o MNAR ocorre quando o missing depende da própria variável. Um exemplo clássico deste tipo de missing é a estimação de renda. Pessoas com renda alta tendem a não querer informar a sua renda.
Há diversas formas de tentar contornar o problema de missing. A primeira utilizada historicamente foi simplesmente excluir das análises as observações que tinham dados faltantes. Por ser uma solução fácil, foi muito utilizada. No entanto, é fácil depreender que, excluído o MCAR, nos outros tipos de missing, as estimativas serão viesadas.
Outra alternativa é a categorização das variáveis. Assim, por exemplo, podemos transformar a variável renda em várias categorias, como de 0 a 1.000 reais, de 1.001 a 3.000 reais, maior que 3.001 reais e deixar os campos missing em uma nova categoria. Se a variável for categórica, basta adicionar uma nova categoria de missing. Esta discretização pode ser proposta por experiência prévia ou até mesmo ser feita com algum algoritmo de otimização para criar categorias mais heterogêneas entre si em relação a variável resposta. Este método também é utilizado para evitar problemas de valores aberrantes (outliers). O problema desta proposta é que perdemos toda a variância dos dados. Assim, no exemplo acima, quem tem renda igual a 3.005 reais será tratado de forma igual a quem tem uma renda de 20.000 reais.
A imputação pela média é outro método fácil que foi muito utilizado no passado. Consiste em substituir os dados faltantes pela média dos dados observados. A grande crítica deste método é que diminuímos consideravelmente a variância, por colocarmos o mesmo valor para vários campos. Assim, o erro padrão de uma regressão logística será subestimado e podemos considerar, por engano, algumas variáveis como significativas.
Outra técnica bastante conhecida é substituir os missing por algum modelo. Este procedimento, se bem executado, soluciona os casos de MAR, visto que podemos utilizar a variável dependente para estimar o valor do dado faltante. Falaremos de uma aplicação desta abordagem adiante, em que substituiremos o missing por um modelo aditivo generalizado (GAM – generalized additive models) que ajusta funções não lineares por meio de splines.
Uma outra forma de imputação que já utilizei na prática para testes foi a substituição pelo método do vizinho mais próximo. Com esta abordagem, primeiramente calculamos a distância entre todas as observações. Para cada observação com dados missing, escolhemos como o valor para a substituição, a média dos valores das k observações mais próximas. Este método até produz bons resultados, mas é complicado computacionalmente, principalmente para projetos com muitas observações.
Duas técnicas vêm ganhando destaque nos últimos anos por conseguirem bons resultados. Uma consiste em encontrar os estimadores de máxima verossimilhança, diretamente dos dados incompletos por meio do algoritmo EM (expectation-maximization). A ideia apesar de simples e elegante é computacionalmente complicada. A outra técnica é conhecida como multiple imputation e consiste em, primeiramente, criarmos várias bases de dados completos, substituindo os valores faltantes por um valor simulado da distribuição preditiva baseada nos dados observados por meio de um método de Monte Carlo. Outra forma de realizar a imputação dos dados para a formação das bases completas é por meio de uma regressão estocástica, que consiste na construção de modelos de regressão, da mesma forma que foi comentada acima, e da simulação do erro pressuposto no modelo para chegar a vários valores previstos para a formação de todas as bases, assim trazendo uma maior variabilidade aos dados imputados. Com a criação das bases, procedemos com a nossa análise em todas as bases e agrupamos os resultados obtidos. Por exemplo, se o objetivo for a construção de um modelo de regressão, calculamos a regressão em todas as bases e usamos as médias dos valores estimados como estimativa final.
Para exemplificar tudo o que discutimos até aqui, irei aplicar o método de imputação por modelo pensado para ser realizado na presença de muitas variáveis com valores missing. Nestes casos, fica inviável a construção de um modelo manual para cada uma destas variáveis. Os códigos em R, base de dados e as queries utilizadas dentro do Hive estão disponíveis em (https://github.com/carlosrelvas/Imputation).
Há 8 arquivos disponibilizados. Segue abaixo uma descrição de cada:
·         Simulation_correlation_data.R – código em R para a simulação de uma base de dados supondo uma distribuição normal multivariada. Usamos este código para a construção da base de dados com variáveis correlacionadas utilizadas neste exemplo.
·     Imputation_data.txt – base de dados com 10 variáveis simuladas construídas com o código acima.
·         Mapper_pearson.R e Reducer_pearson.R – funções mapper e reducer em R utilizadas para o cálculo da correlação de Pearson entre todas as variáveis da base de entrada.
·  Order_pearson.R – código em R utilizado para devolver as variáveis mais correlacionadas com cada uma.
·   Mapper_gam_imp.R e Reducer_gam_imp.R – funções mapper e reducer em R utilizadas para os cálculos dos modelos aditivos generalizados.
·    Queries_imputation.txt – queries utilizadas dentro do hive para executar todas as funções acima.
Como temos muitas variáveis com dados faltantes e por consequência muitos modelos a serem construídos, a primeira coisa que fazemos é calcular a correlação de Pearson entre todas as variáveis. Fazemos isso com um código em map reduce em R. Trata-se de um bom exemplo de como utilizar o R com hadoop e pode ser visto como um complemento ao primeiro post deste blog. Não entrarei em detalhes de como foi desenhada a lógica deste código, mas qualquer dúvida é só escrever ou comentar por aqui mesmo.
Com todas as correlações calculadas, utilizamos o código order_pearson.R cujo objetivo é devolver as variáveis mais correlacionadas para cada uma das variáveis. Ele possui um argumento que indica quantas variáveis desejamos utilizar nos modelos a serem construídos. No caso escolhi o valor de 3. Assim ele irá salvar um arquivo com as 3 variáveis mais correlacionadas em valor absoluto para cada uma das variáveis.
O próximo passo é a construção dos modelos, que fazemos em paralelo com a lógica map reduce. A função mapper irá passar para os reducers as variáveis com valores faltantes e as variáveis com maiores correlações. O reducer, por sua vez, irá construir o modelo aditivo generalizado para substituir os missing pelos valores previstos por estes modelos. Utilizamos o modelo aditivo generalizado para capturar possíveis relações não lineares por meio do ajuste de splines. Caso o interesse do leitor seja o ajuste de modelos de regressão, basta substituir no código esta parte.
Resumindo o que apresentamos aqui, temos o método de Pearson para fazer uma seleção automática de variáveis para serem usadas em cada um dos modelos. Fazemos isso por não ser viável a construção de todos os modelos de forma manual. É claro que a correlação de Pearson pode não ser o melhor método para se fazer isso. Aqui está apenas uma possível solução. O uso de apenas três variáveis para cada modelo também foi escolhido sem nenhum critério, mas é facilmente alterado no código.
Com estes scripts, alterando apenas a parte final do código reducer_gam_imp.R para fazer uma regressão estocástica, podemos construir diversas bases completas e continuar nossa análise com o método de multiple imputation que vem se mostrando mais eficaz.
Já testei vários destes métodos na prática e a eficiência de cada um depende muito do problema em questão.

segunda-feira, 6 de abril de 2015

Seleção de variáveis usando Random Forest.

No post de hoje iremos discutir um tema muito importante e que vem ganhando cada vez importância neste mundo de big data: a seleção de variáveis.
A cada dia temos mais e mais informações de tudo o que acontece em nossa volta, o que significa que nossos problemas de predição têm a cada dia novas variáveis explicativas disponíveis. É claro que quanto mais dados melhor, no entanto, isto acaba dificultando, do ponto de vista computacional e estatístico, para a escolha do melhor subconjunto de variáveis nesta imensidão de dados. Atualmente, em média, os problemas nos quais trabalho apresentam cerca de 1.000 a 3.000 features, mas já participei de projetos com mais de 40.000 variáveis.
O que acontece é que dentre estas 40.000 variáveis, há muitas que são consideradas não informativas, ou seja, que não têm relação nenhuma com aquilo que queremos prever. Outro ponto é que há muitas variáveis que contêm as mesmas informações. Estes fatores, se não tratados, podem causar o que chamamos de overfitting que é a construção de uma solução que pode ser muito boa apenas para seus dados mas não consegue generalizar para novas amostras. Além disso, com este número de variáveis dificilmente conseguiremos interpretar algum resultado.
Para contornar estes problemas existe a etapa de seleção de variáveis, que faz parte de quase todos os projetos de aprendizado. Basicamente, a etapa de seleção de variáveis consiste em tentar escolher o subconjunto de variáveis que forneça a melhor predição possível.
Muitas das técnicas de machine learning não foram feitas para lidar com esta quantidade de variáveis, no entanto, é importante ressaltar que algumas técnicas de aprendizado já realizam uma seleção de variáveis, como o LASSO (Least Absolute Shrinkage and Selection Operator), que podemos discutir com mais detalhes em um futuro post. Muitos de vocês devem estar pensando, por que não construímos todas as combinações possíveis e escolhemos o melhor subconjunto de variáveis. A resposta é porque não temos hoje poder computacional suficiente. Por exemplo, se tivéssemos 10 variáveis disponíveis, o número total de combinação de subconjuntos para estimarmos seria 2^10 que são 1024 modelos, o que representa um número plausível. Mas imagine agora que temos 1.000 variáveis, o que não é difícil atualmente. Neste caso o número total de ajustes necessários é 2^1000 que é um número muito, mas muito maior que o número estimado de estrelas no universo.
A técnica de random forest tem como objetivo fornecer previsões de algum fenômeno e surgiu a partir dos métodos de bagging. O método de bagging (bootstrap aggregation) consiste em “n” repetições de uma mesma técnica de aprendizado em várias amostras de bootstrap, sendo mais comum o uso de árvores de decisão. Assim, a estimativa final de cada observação será a média destas “n” árvores no caso de variável resposta contínua e na maioria de votos no caso de problemas de classificação. Esta técnica tem mostrado maior performance em relação ao uso de uma única árvore basicamente por diminuir a variância, pois


Podemos perceber pela fórmula acima que quanto menor for a covariância entre as diferentes estimativas maior deverá ser a performance esperada. Assim, surgiu a ideia do random forest, que tenta diminuir exatamente esta covariância entre as estimativas. Para atingir tal objetivo, além de a cada iteração a amostra de bootstrap ser alterada, as variáveis disponíveis para serem utilizadas na árvore também são alteradas.
Além de frequentemente superar um único classificador, o random forest, assim como o bagging, apresenta a grande vantagem de serem compostas por várias árvores independentes. Assim, o paralelismo e até mesmo a programação em map reduce podem ser alcançadas facilmente.
O objetivo deste post não é explicar com detalhes a técnica de random forest. Caso seja do interesse do leitor, maiores informações podem ser encontradas no livro “The Elements of Statistical Learning” de Hastie, Tibsharani e Friedman.
Além de obter bons resultados em termos de predição, o método de random forest também tem alcançado resultados satisfatórios quando o objetivo é seleção de variáveis, superando vários métodos conhecidos e historicamente utilizados. O algoritmo de importância das variáveis consiste em cada iteração:

  • Amostra de bootstrap da base. Cerca de 37% da amostra original não é escolhida na amostra de bootstrap e consiste na amostra out-of-bag desta iteração;
  • Aleatorização das variáveis para serem utilizadas na árvore;
  • Construção da árvore de decisão;
  • Aleatoriamente, para cada variável separadamente, permute seus valores e verifique quanto alguma medida de performance, como por exemplo o Gini Index, é alterado na amostra out-of-bag em relação a performance sem a perturbação.
Repita este processo para todas as árvores construídas. A importância de cada variável será a média do delta de performance em todas as árvores. Assim, a variável mais importante será aquela que, quando perturbada, mais altera o desempenho do nosso classificador.
                O resultado final será o ranking de variáveis em que poderemos trabalhar com as melhores variáveis e construir nosso modelo final, por exemplo, uma regressão logística, utilizando apenas as melhores variáveis explicativas e assim evitando diversos problemas citados anteriormente.
                No entanto, nem tudo são flores. Alguns estudos recentes mostram alguns vieses com esta técnica de seleção. Um bastante conhecido é quando temos muitas variáveis à disposição, mais de 200. Nestes casos, precisaremos de muitas árvores para gerar um resultado satisfatório e, além disso, se tivermos muitas variáveis fracas, teremos muitas árvores construídas apenas com estas variáveis, o que prejudicará a seleção final. Para contornar este problema, podemos utilizar antes alguns métodos de seleção por filtro para eliminarmos as piores variáveis antes de utilizarmos o random forest e obtermos o ranking final. Falaremos sobre algumas opções em um post futuro.
                Para exemplificar o uso do algoritmo de random forest para seleção de variáveis com o software R, disponibilizo no GitHub (https://github.com/carlosrelvas/RandomForest_varselection) um código utilizando a library randomForest. Os dados são provenientes de um exemplo de classificação em que o objetivo é classificar um e-mail como um spam ou não spam. Estes dados estão disponíveis no GitHub, mas também estão na seguinte fonte (http://archive.ics.uci.edu/ml/datasets/Spambase) e contém 57 variáveis explicativas.
                Com estes dados, construímos 500 árvores para fazer a seleção, obtendo o seguinte gráfico que apresenta no eixo x cada uma das variáveis explicativas e no eixo y a medida de performance obtida. Colocamos o gráfico em ordem decrescente para melhorar a visualização. Podemos notar que as primeiras 15/16 variáveis se destacam em relação às demais. Por conta disso, utilizamos estas variáveis em um modelo logístico obtendo um Gini de 93,4 e 92,2, nas bases de treino e de teste respectivamente.
                Como esta base é pequena, construímos as 500 variáveis em cerca de 35 segundos. Este número pode ser diminuído consideravelmente com a versão do random forest em map reduce.


terça-feira, 24 de março de 2015

R + hadoop - Big Data Analytics

      Neste post iremos discutir um tema que está em alta ultimamente, big data analytics. Mais precisamente, discutiremos como combinar o poder computacional do hadoop com a flexibilidade e variedade de algoritmos encontrados no software R.
O surgimento do hadoop no final da década passada revolucionou e continua revolucionando a forma que armazenamos e processamos os dados. Baseado em processamento paralelo, baixo custo de hardware e à prova de falhas, este projeto open source expandiu consideravelmente a capacidade de processamento sem grande elevação do custo final para o manuseio destes dados. Vale lembrar que podemos combinar quantos processadores forem necessários em um cluster hadoop, permitindo uma grande escalabilidade dos seus dados.
Para facilitar o manuseio dos dados dentro do hadoop que é uma plataforma em Java, surgiu nos anos posteriores algumas ferramentas, sendo a mais famoso o Hive, que em linhas gerais, permite o uso de uma linguagem SQL dentro de um cluster hadoop. Embora o Hive seja muito poderoso para trabalharmos com os dados, a linguagem SQL não é a mais adequada para advanced analytics.
Como complemento à linguagem SQL, várias soluções foram surgindo desde então, como o projeto Mahout, que consiste em uma biblioteca de códigos em Java de machine learning. No entanto, este projeto acabou não se consolidando como solução para analytics com hadoop.
Uma possível solução para isto é o casamento do software R com o hadoop. O R é uma linguagem de computação extremamente popular para cálculos estatísticos e, por ser uma ferramenta aberta, conta com diversos algoritmos construídos pela comunidade de programadores R ao redor do mundo.
 Trabalhamos o R com o hadoop de três formas que descreveremos a seguir, cada uma com vantagens e desvantagens. O uso de algumas delas depende exclusivamente da sua necessidade.


  • Base na memória: se os seus dados não são tão “big” assim, ou podem ser sumarizados, e há memória RAM suficiente no seu cluster, uma alternativa é fazer uma conexão JDBC e colocar esses dados na memória do R. Assim, usaremos o R normalmente, podendo aplicar qualquer um dos algoritmos disponíveis nos diversos pacotes. Com este método, também podem ser utilizados vários pacotes existentes no R para processamento em paralelo e assim conseguir utilizar todos os processadores disponíveis. Vale ressaltar que esta forma de trabalho com o R é delicada, podendo impactar o cluster se não for bem utilizada. Recomenda-se o uso de servidores dedicados para processamento R neste caso, o R Studio Web é uma solução muito interessante para isso.
  •   Uso de ferramentas pagas como o Oracle R Advanced Analytics ou o R revolution: estas empresas desenvolveram e continuam desenvolvendo alguns algoritmos para o uso do R combinado com o hadoop. No entanto, ainda há poucas funções implementadas em ambas as soluções, principalmente se compararmos com os números de algoritmos disponíveis do software R.
  • Hadoop streaming: Pela minha experiência, esta alternativa é a que atinge melhores resultados, embora seja a que exige mais trabalho para a sua implementação. O hadoop streaming é uma utilidade presente no hadoop que permite programarmos as funções Map e Reduce (filosofia Map Reduce em que o Hadoop se baseia) em qualquer linguagem que permite stdin e stdout, como R ou Python.
    A grande dificuldade desta abordagem é adaptar o seu problema dentro da filosofia
    Map Reduce, o que nem sempre é trivial e requer horas de trabalho árduo. No entanto, uma vez que as funções Map e Reduce estejam prontas, poderemos trabalhar com bases de dados gigantescas e realmente fazer analytics em Big Data.
O hadoop streaming pode ser utilizado dentro do Hive por meio da função “transform”. Para exemplificar o uso desta abordagem, construí um exemplo de contagem de palavras de um arquivo utilizando o R em Map Reduce. Tanto os dados de exemplo quantos os códigos utilizados estão disponíveis na minha conta do GitHub (https://github.com/carlosrelvas/Word_Count_R).
O arquivo “mapper_word_count.R” contém a função Map em R. A lógica é bem simples, cada mapper irá receber um pedaço do arquivo de entrada e fará a contagem de palavras em cada um destes pedaços. Assim, digamos que o primeiro mapper receba a seguinte parte do arquivo “casa casa casa gato casa gato” e o segundo “gato gato casa pato”. Cada mapper irá emitir uma lista de chave valor, em que chave será o nome da palavra e o valor a contagem parcial. Logo, o primeiro mapper emitirá {casa; 4} e {gato; 2}, enquanto que o segundo terá {gato; 2}, {casa; 1} e {pato; 1}.
Todas as chaves iguais irão para o mesmo reducer (“reducer_word_count.R”), assim, por exemplo, todas as tuplas que contém a chave “casa” irão para o mesmo reducer, que farão a contagem final. Assim os reducers irão devolver {casa; 4+1=5}, {gato; 2+2=4} e {pato;1}.
O arquivo usado para testarmos as funções é o “text.txt” e o quebramos, por conveniência, em dois (“text1.txt” e “text2.txt”) para simularmos as funções sem a necessidade de uma máquina virtual com hadoop. Assim conseguimos testar facilmente a função dentro de um ambiente Unix por meio dos seguintes comandos:

cat text1.txt | Rscript mapper_word_count.R > mapper1.txt
cat text2.txt | Rscript mapper_word_count.R > mapper2.txt
cat mapper1.txt mapper2.txt | sort -k1,1 | Rscript reducer_word_count.R.

          Os dois primeiros comandos simulam um mapper cada, enquanto que o terceiro simula um reducer ao receber as duas saídas do mapper.

O arquivo do GitHub “simulator_mapreduce.txt” contém os códigos desta simulação no Linux bem como os códigos para colocar a base dentro hadoop distributed file system (hdfs) e testar as funções dentro do Hive por meio da função transform.