Classificação Multirrótulo: Calculando Similaridades entre Rótulos - Parte 9
Oi gente!! Voltando aqui com mais conteúdo para vocês. Vamos continuar otimizando nosso código para calcular as similaridades entre rótulos. Hoje vamos trabalhar com a função para calcular as probabilidades marginais. Ah sim! É importante que você leia esta série de artigos na sequência tá bom!
Abstraindo e otimizando a função
Originalmente a nossa função está da seguinte forma:
compute.marg.probs2 <- function(labels, num.labels, ma, mb, mc, md){
retorno = list()
mab <- build.matrix.sim(labels, num.labels)
mac <- build.matrix.sim(labels, num.labels)
mad <- build.matrix.sim(labels, num.labels)
mbc <- build.matrix.sim(labels, num.labels)
mbd <- build.matrix.sim(labels, num.labels)
mcd <- build.matrix.sim(labels, num.labels)
mn <- build.matrix.sim(labels, num.labels)
u = (num.labels*num.labels)
pb <- progress_bar$new(total = u)
for (i in 1:num.labels){
for (j in 1:num.labels){
mab[i,j] = compute.ab(ma[i,j], mb[i,j])
mac[i,j] = compute.ac(ma[i,j], mc[i,j])
mad[i,j] = compute.ad(ma[i,j], md[i,j])
mbc[i,j] = compute.bc(mb[i,j], mc[i,j])
mbd[i,j] = compute.bd(mb[i,j], md[i,j])
mcd[i,j] = compute.cd(mc[i,j], md[i,j])
mn[i,j] = compute.n(ma[i,j], mb[i,j], mc[i,j], md[i,j])
pb$tick()
Sys.sleep(1/u)
gc()
} # fim do for interno
gc()
} # fim do for externo
retorno$mab = mab
retorno$mac = mac
retorno$mad = mad
retorno$mbc = mbc
retorno$mbd = mbd
retorno$mcd = mcd
retorno$mn = mn
return(retorno)
gc()
}
Agora essa função vai se transformar 7 funções diferentes:
# 1
compute.mab <- function(labels, num.labels, ma, mb){
retorno = list()
mab <- build.matrix.sim(labels, num.labels)
u = (num.labels*num.labels)
pb <- progress_bar$new(total = u)
for (i in 1:num.labels){
for (j in 1:num.labels){
mab[i,j] = compute.ab(ma[i,j], mb[i,j])
pb$tick()
Sys.sleep(1/u)
gc()
}
gc()
}
retorno$mab = mab
return(retorno)
gc()
}
# 2
compute.mac <- function(labels, num.labels, ma, mc){
retorno = list()
mac <- build.matrix.sim(labels, num.labels)
u = (num.labels*num.labels)
pb <- progress_bar$new(total = u)
for (i in 1:num.labels){
for (j in 1:num.labels){
mac[i,j] = compute.ac(ma[i,j], mc[i,j])
pb$tick()
Sys.sleep(1/u)
gc()
}
gc()
}
retorno$mac = mac
return(retorno)
gc()
}
# 3
compute.mad <- function(labels, num.labels, ma, md){
retorno = list()
mad <- build.matrix.sim(labels, num.labels)
u = (num.labels*num.labels)
pb <- progress_bar$new(total = u)
for (i in 1:num.labels){
for (j in 1:num.labels){
mad[i,j] = compute.ad(ma[i,j], md[i,j])
pb$tick()
Sys.sleep(1/u)
gc()
}
gc()
}
retorno$mad = mad
return(retorno)
gc()
}
# 4
compute.mbc <- function(labels, num.labels, mb, mc){
retorno = list()
mbc <- build.matrix.sim(labels, num.labels)
u = (num.labels*num.labels)
pb <- progress_bar$new(total = u)
for (i in 1:num.labels){
for (j in 1:num.labels){
mbc[i,j] = compute.bc(mb[i,j], mc[i,j])
pb$tick()
Sys.sleep(1/u)
gc()
}
gc()
}
retorno$mbc = mbc
return(retorno)
gc()
}
# 5
compute.mbd <- function(labels, num.labels, mb, md){
retorno = list()
mbd <- build.matrix.sim(labels, num.labels)
u = (num.labels*num.labels)
pb <- progress_bar$new(total = u)
for (i in 1:num.labels){
for (j in 1:num.labels){
mbd[i,j] = compute.bd(mb[i,j], md[i,j])
pb$tick()
Sys.sleep(1/u)
gc()
}
gc()
}
retorno$mbd = mbd
return(retorno)
gc()
}
# 6
compute.mcd <- function(labels, num.labels, mc, md){
retorno = list()
mcd <- build.matrix.sim(labels, num.labels)
u = (num.labels*num.labels)
pb <- progress_bar$new(total = u)
for (i in 1:num.labels){
for (j in 1:num.labels){
mcd[i,j] = compute.cd(mc[i,j], md[i,j])
pb$tick()
Sys.sleep(1/u)
gc()
}
gc()
}
retorno$mcd = mcd
return(retorno)
gc()
}
# 7
compute.mn <- function(labels, num.labels, ma, mb, mc, md){
retorno = list()
mn <- build.matrix.sim(labels, num.labels)
u = (num.labels*num.labels)
pb <- progress_bar$new(total = u)
for (i in 1:num.labels){
for (j in 1:num.labels){
mn[i,j] = compute.n(ma[i,j], mb[i,j], mc[i,j], md[i,j])
pb$tick()
Sys.sleep(1/u)
gc()
}
gc()
}
retorno$mn = mn
return(retorno)
gc()
}
As chamadas para essas funções ficam da seguinte forma:
res_mab = compute.mab(dataset_2, 5, ma3$computed, mb3$computed) # 1
res_mac = compute.mab(dataset_2, 5, ma3$computed, mc3$computed) # 2
res_mad = compute.mab(dataset_2, 5, ma3$computed, md3$computed) # 3
res_mbc = compute.mab(dataset_2, 5, mb3$computed, mc3$computed) # 4
res_mbd = compute.mab(dataset_2, 5, mb3$computed, md3$computed) # 5
res_mcd = compute.mab(dataset_2, 5, mc3$computed, md3$computed) # 6
res_mn = compute.mn(dataset_2, 5,
ma3$computed,
mb3$computed,
mc3$computed,
md3$computed) # 7
$computed é usado pois esse é o retorno da função que contém o resultado de fato e é ele que devemos passar como parâmetro! Com exceção da função compute.mn, todas as outras 6 funções são idênticas, mudando apenas a chamada da função dentro delas. Assim como no artigo passado, neste também vamos abstrair esse código e criar uma única função para essas 6 funções. Segue o código:
compute.marg.probs.0 <- function(labels, num.labels, m1, m2, FUN){
retorno = list()
m <- build.matrix.sim(labels, num.labels)
u = (num.labels*num.labels)
pb <- progress_bar$new(total = u)
for (i in 1:num.labels){
for (j in 1:num.labels){
m[i,j] = FUN(m1[i,j], m2[i,j])
pb$tick()
Sys.sleep(1/u)
gc()
}
gc()
}
retorno$computed = m
return(retorno)
gc()
}
Olha só!!! Aqui estamos usando novamente FUN! FUN aqui não é funny ok!!! É função hehehe. Brincadeiras a parte, notem que agora temos:
1.º parâmetro - labels: espaço de rótulos
2.º parâmetro - num.labels: número total de rótulos do espaço de rótulos
3.º parâmetro - m1: a primeira matriz que deve entrar no cálculo (ma, mb, mc ou md)
4.º parâmetro - m2: a segunda matriz que deve entrar no cálculo (ma, mb, mc ou md)
5.º parâmetro - FUN: a função que deve ser chamada dentro da função compute.marg.probs.0 que deve ser uma dessas aqui = compute.ab, compute.ac, compute.ad, compute.bc, compute.bd ou compute.cd.
Eliminamos uma quantidade considerável de código e o resultado que vamos obter é exatamente o mesmo!! Obviamente que você pode melhorar os nomes das funções, variáveis e retornos ok! Confesso que é bem difícil definir e organizar esses nomes de forma que não nos confunda também. Pergunte a qualquer programadora sobre isso, apenas de curiosidade! Bom, como ficam as chamadas então??
res_mab2 = compute.marg.probs.0(dataset_2, 5,
ma3$computed, mb3$computed, compute.ab)
res_mac2 = compute.marg.probs.0(dataset_2, 5,
ma3$computed, mc3$computed, compute.ac)
res_mad2 = compute.marg.probs.0(dataset_2, 5,
ma3$computed, md3$computed, compute.ad)
res_mbc2 = compute.marg.probs.0(dataset_2, 5,
mb3$computed, mc3$computed, compute.bc)
res_mbd2 = compute.marg.probs.0(dataset_2, 5,
mb3$computed, md3$computed, compute.bd)
res_mcd2 = compute.marg.probs.0(dataset_2, 5,
mc3$computed, md3$computed, compute.cd)
Usamos dataset_2 que é o nosso espaço de rótulos, depois 5 que é o nosso número total de rótulos, e então passamos as matrizes e função correspondentes em cada chamada. O resultado é:
Agora, que tal guardarmos o resultado da função mais o tempo de execução dela? O código é o seguinte:
time_mab = system.time(mab <- compute.marg.probs.0(dataset_2, 5,
ma3$computed,
mb3$computed,
compute.ab))
time_mac = system.time(mac <- compute.marg.probs.0(dataset_2, 5,
ma3$computed,
mc3$computed,
compute.ac))
time_mad = system.time(mad <- compute.marg.probs.0(dataset_2, 5,
ma3$computed,
md3$computed,
compute.ad))
time_mbc = system.time(mabc <- compute.marg.probs.0(dataset_2, 5,
mb3$computed,
mc3$computed,
compute.bc))
time_mbd = system.time(mbd <- compute.marg.probs.0(dataset_2, 5,
mb3$computed,
md3$computed,
compute.bd))
time_mcd = system.time(mcd <- compute.marg.probs.0(dataset_2, 5,
mc3$computed,
md3$computed,
compute.cd))
Observe que cada chamada foi colocada dentro do system.time(), só que agora precisamos usar <- ao inves de =. Se vocês tentarem usar o sinal de igual, o código dará erro! Dessa forma, guardamos o resultado da função na variável que quisermos e ao mesmo tempo guardamos o tempo em outra variável! Novamente, podemos juntar todos os tempos em um único dataframe:
tempos = rbind(time_mab, time_mac, time_mad,
time_mbc, time_mbd, time_mcd)
Que fica como:
Desta vez eu não converti em matriz, apenas usei rbind para juntar todas as linhas e isso fez com o que o nome da variável do tempo ficasse salvo! Quando convertemos para matriz, perdemos os nomes de linhas e por isso eles não aparecerem no artigo anterior. Aliás, rbind significa juntar linhas e o R vem de ROW que indica linha em inglês.
E seu quisermos obter o total de cada coluna? É bem fácil também, use o seguinte comando:
apply(tempos,2,sum)
E o resultado será:
Não entrarei em detalhes agora sobre a função APPLY pois o artigo já ficou bem extenso! Deixarei pra falar dela em outra oportunidade.
FINALIZANDO
Com tudo isso terminamos o artigo de parte 9! No próximo artigo vamos continuar nossa aventura. Espero vocês lá =)
Este artigo foi escrito por Elaine Cecília Gatto - Cissa e publicado originalmente em Prensa.li.