Classificação Multirrótulo: Calculando Similaridades entre Rótulos - Parte 14
Oi gente! Iai? Prontos para terminar esta jornada? No artigo anterior nós finalmente terminamos o conteúdo desta série. O que vou mostrar hoje é um bônus, mas é algo realmente interessante, então espero que gostem.
PARALELISMO
Se o seu computador tem um processador com mais de um núcleo, então você pode executar códigos em paralelo, isto é, você pode usar todos os núcleos ao mesmo tempo para executar partes do seu código, principalmente aquelas que são repetitivas.
Primeiro, vamos adicionar a biblioteca "parallel" e "doParallel" na nossa lista de pacotes. Depois disso, vamos criar um script novo para fazer somente este exemplo, eu chamei de examplo-paralelo.R. Agora, nesse script coloque essas linhas aqui:
FolderRoot = "~/Multirrotulo-Similaridade"
FolderScripts = "~/Multirrotulo-Similaridade/R"# vetor com as funções do meu interesse
funcoes.sim.1 = c("cosine.v1", "jaccard.v1", "russel.rao.v1", "vari.v1")
funcoes.sim.2 = c("cosine.v2", "jaccard.v2", "russel.rao.v2", "vari.v2")# lista para armazenar o resultado das 4 medidas
resultado.v1 = list()
resultado.v2 = list()
Depois disso, vamos verificar quantos nós temos disponíveis em nosso computador através do seguinte comando:
detectCores()
No meu caso, tenho 12 núcleos disponíveis, então posso colocar até 12 tarefas para executar ao mesmo tempo. Mas, olhem, é importante verificar também a quantidade de memória ram.
Em nosso caso, vamos executar coisas pequenas, mas há situações em que a memória pode ser toda consumida, portanto, calcule bem antes de sair colocando tudo em paralelo. Agora podemos usar os seguintes comandos:
cl <- parallel::makeCluster(4)
doParallel::registerDoParallel(cl)
print(cl)
makeCluster() vai reservar 4 nós para execução, enquanto que registerDoParallel vai registrar quais nós estão reservados. O print apenas printa na tela a seguinte mensagem: socket cluster with 4 nodes on host ‘localhost’. Para executar um trecho de código em paralelo temos de usar o foreach: foreach(f = 1:numero_de_nucles) %dopar%{ ...... }. Em nosso caso, ficará assim:
f = 1
resultado <- foreach(f = 1:4) %dopar% {
FolderRoot = "~/Multirrotulo-Similaridade"
FolderScripts = "~/Multirrotulo-Similaridade/R"
# carregando os outros scripts que criamos
setwd(FolderScripts)
source("bibliotecas.R")
source("funcoes.R")
source("similaridades.R")
# abrindo o espaço de rótulos
FolderData = paste(FolderRoot, "/Data", sep="")
setwd(FolderData)
dataset = data.frame(read.csv("dataset.csv"))
dataset = dataset[,-1]
ma = calcula.tabela.contingencia(dataset, ncol(dataset), calcula.a)
mb = calcula.tabela.contingencia(dataset, ncol(dataset), calcula.b)
mc = calcula.tabela.contingencia(dataset, ncol(dataset), calcula.c)
md = calcula.tabela.contingencia(dataset, ncol(dataset), calcula.d)
resultado.v2[[f]] = data.frame(calcula.medida.v2(eval(parse(text=funcoes.sim.2[f])),
a = as.matrix(ma$tabela.contingencia),
b = as.matrix(mb$tabela.contingencia),
c = as.matrix(mc$tabela.contingencia),
d = as.matrix(md$tabela.contingencia)))
}
Como vamos executar cada parte do código em um núcleo diferente, então tudo o que precisamos para que o código seja executado deve ser carregado naquele núcleo. É por isto que dentro do foreach estão partes do código principal.
Existe outra forma de fazer isso? Sim, tem, mas, pra não ficar muito difícil e complicado pra vocês entenderem, achei melhor apresentar algo funcional, simples e objetivo.
Quando esse código é executado, a variável RESULTADO terá guardado as matrizes resultantes e aí podemos fazer a alteração dos nomes dos itens da lista:
resultado
funcoes.sim = c("cosine", "jaccard", "russel.rao", "vari")
names(resultado) <- funcoes.sim
resultado$cosine
resultado$jaccard
resultado$russel.rao
resultado$vari
Muito legal, né? É praticamente igual ao que o WHILE faz, só que diferente! No while tudo é executado sequencialmente, um após o outro, enquanto que no FOREACH, podemos executar a mesma tarefa, para diferentes itens, ao mesmo tempo.
Em nosso caso, foram calculadas as matrizes de similaridades para quatro medidas de similaridades, e cada uma delas foi executada em um núcleo diferente ao mesmo tempo. Isso reduz, e muito, o tempo de execução do código.
Se você se encontra em uma situação dessas, tem a possibilidade de usar vários núcleos e tem memória suficiente, então tente paralelizar o seu código! A única real desvantagem é ficar carregando tudo para os núcleos, mas funciona!
CONCLUSÃO
E, assim, terminamos esta série! Espero, sinceramente, que vocês tenham gostado e aprendido muito. Na área da Classificação Multirrótulo, essas medidas de similaridades vêm sendo muito utilizadas, justamente para medir o nível de relação entre os rótulos do espaço de rótulos.
A partir dessas medidas, podemos descobrir quais pares de rótulos aparecem mais, ou menos, vezes juntos e isso pode ajudar o classificador a aprender os rótulos para, depois, predizê-los. Eu tenho trabalhado esse tópico no meu doutorado e tenho feito descobertas interessantes.
No entanto, as medidas de similaridades são apenas um dos vários meios que existem para tentar entender as relações entre os rótulos do conjunto. Nem sempre elas vão dizer, elucidar ou revelar algo brilhante e magnífico sobre os dados. Entretanto, podem ajudar a entender melhor o próprio conjunto de dados, como resolver o problema que o envolve e, talvez, até mesmo escolher o melhor classificador multirrótulo para ele.
Não existe fórmula mágica, nem fórmula fácil, mas tenho certeza que, com o conhecimento adquirido aqui, vocês já conseguirão dar os primeiros passos nesta área. Ficarei feliz em ter notícias de vocês, me mandem uma mensagem em uma das minhas redes, tá legal?!
É isso, então, gente! Façam o download da versão final do projeto. Fiquem à vontade para fazer modificações e compartilhar com seus amigos, mas lembrem-se de incluir a referência original destes artigos. Eu agradeço demais. A gente se vê na próxima série.
Este artigo foi escrito por Elaine Cecília Gatto - Cissa e publicado originalmente em Prensa.li.