Classificação Multirrótulo: Propriedades dos Dados Multirrótulo - Parte 5
Olá pessoal! Espero que esteja tudo bem com todos! Esta é a parte 5 da série de artigos sobre as propriedades multirrótulo. Já aprendemos muita coisa até aqui, não é mesmo? No artigo anterior nós aprendemos a calcular a co-ocorrência de pares de rótulos a partir da execução de um comando um pouco mais complexo. Hoje aprenderemos outras propriedades! Preparados?
CARDINALIDADE
A cardinalidade calcula a média de rótulos por instância e é dada pela seguinte equação:
Vamos entender as letrinhas dessa equação:
D: dataset
m: número total de instâncias
i: valor de início para o somatório
Yi: rótulo específico
Quanto maior o valor da cardinalidade, maior é o número de rótulos relevantes por instância. Um valor baixo indicará que a maioria das instâncias possui apenas um rótulo relevante.
Basicamente, o que vamos fazer é somar todos os rótulos e, depois, dividir pelo número total de instâncias, mas isso será feito de forma cumulativa. Antes de mais nada, precisaremos converter os valores do nosso dataframe para valores numéricos! Isso pode ser feito da seguinte forma:
x <- sapply(labels, is.factor)
labels[ , x] <- as.data.frame(apply(labels[ , x], 2, as.numeric))
class(labels$red)
is.factor verifica que o valores são do tipo fator, isto é, valores categóricos. sapply é uma função para manipulação de dataframes, especificamente para aplicar uma função. Em seguida, convertemos os fatores em números, isso significa que os 0's e 1's agora serão tratados como números e poderemos usar operações matemáticas normalmente.
apply também é uma função que nos permite aplicar uma função no dataframe, mas, neste caso, nós podemos especificar se a função será aplicada só na coluna ou só na linha. Na minha série de artigos sobre cálculo de similaridades eu falei bastante sobre essas funções. as.data.frame() converte o resultado da função apply em um dataframe!
A última linha está ai apenas para verificarmos o tipo da classe da coluna que, no caso, será numérico! Podemos usar o código a seguir para calcular a cardinalidade:
cardinality <- function(labels){
add = 0
r = nrow(labels)
c = ncol(labels)
for(i in 1:r){
for(j in 1:c){
add = add + sum(labels[i,j])
}
gc()
}
card = (1/r) * (add)
return(card)
gc()
}
Nessa função estou usando 2 LOOPs para realizar o cálculo, o qual acontece de fato na linha add = add + sum(labels[i,j]). Já mencionei em outros artigos meus aqui na Prensa sobre FOR, aconselho você a dar uma olhadinha lá se tiver alguma dúvida!
Mas, basicamente, como precisamos somar as linhas de cada coluna, é necessário percorrer o dataframe inteiro para isso. Com 2 FORs isso é possível! sum() é uma função pré-definida do R que efetua a soma! Com a função definida, podemos chamá-la:
cardinality(labels)
Se quisermos saber quanto tempo demorou para executar a função podemos fazer o seguinte:
time.card = system.time(cardinality(labels))
system.time() é a função responsável por obter o tempo decorrido da execucação. Mas podemos fazer tudo isso de um jeito muito mais simples:
mean(rowSums(labels))
time.card.2 = system.time(mean(rowSums(labels)))
mean() é uma função pré-definida do R que efetua a média. O resultado será idêntico para as duas formas apresentadas aqui e o mais legal é que, na segunda opção, só precisamos de uma linha para efetuar o cálculo! Vejam:
Notem a diferença de time.card e time.card.2! Os tempos aqui são dados em segundos. Com certeza, a segunda opção é bem mais rápida!
DENSIDADE
A densidade é a norma da cardinalidade. Quanto maior o valor da densidade, melhor a representação dos rótulos em cada instância. Quanto menor, mais dispersão há, indicando que a maioria das instâncias é representada por um pequeno subconjunto de rótulos.
Podemos usar a seguinte função para o cálculo da densidade:
density <- function(labels){
add = 0
r = nrow(labels)
c = ncol(labels)
for(i in 1:r){
for(j in 1:c){
add = add + (sum(labels[i,j])/c)
}
gc()
}
den = (1/r) * (add)
return(den)
gc()
}
Observem que a forma da função da densidade é parecida com a da cardinalidade. Podemos então chamar a função agora:
density(labels)
Ou podemos utilizar o seguinte:
mean(rowSums(labels))/ncol(labels)
rowSums() é uma função do R que permite a soma das linhas de um dataframe! Vamos também verificar os tempos:
time.dens = system.time(density(labels))
time.dens.2 = system.time(mean(rowSums(labels))/ncol(labels))
Vejam os resultados:
Novamente, vemos que a diferença no tempo de execução entre a função que eu criei e o cálculo realizado por uma única linha é realmente muito grande! A segunda opção, com certeza, é a melhor. E, assim, com apenas uma linha resolvemos a questão!
COMBINAÇÕES DE RÓTULOS
Quantas combinações de rótulos existem no espaço de rótulos? Nós calculamos no artigo anterior as co-ocorrências dos pares de rótulos, então sabemos quantas vezes cada par de rótulos aparece no espaço de rótulos. Mas, e quanto às outras combinações? Um rótulo pode aparecer junto com outros dois rótulos, ou três. Qual a frequência dessa ocorrência? É isto o que vamos fazer agora. Observe as imagens a seguir:
Os comandos são os seguintes:
labelsets <- do.call(paste, c(labels, sep = ""))
labelsets <- table(as.factor(labelsets))
A primeira linha deste trechinho de código se encarrega de transformar os conteúdos das colunas/linhas em um texto. Você observa na figura 1 que, de fato, é retornado uma string composta por 0's e 1's: "0101010". Esta linha de código, portanto, se encarrega de descobrir todas as combinações possíveis a partir do conteúdo do próprio espaço de rótulos. Para elucidar o que estou tentando dizer, vamos dar uma olhada no espaço de rótulos lá no Excel:
Os zeros estão marcados de azul na planilha. Os valores 1 correspondem aos rótulos ativos. Na primeira linha estão ativos os rótulos red, green, yellow, white e black, portanto, eles são uma combinação de rótulos! Coloquei outros exemplos na Figura e acredito que vocês já tenham entendido agora o que estou querendo dizer com combinação de rótulos.
Tendo conhecimento dessas combinações na string gerada pela primeira linha de código, podemos usar um as.factor para transformar os dados e, em seguida, colocá-los numa tabela de frequências com table().
Lembrando que FACTOR, ou FATOR, significa categórico, isto é, é um dado que não é uma string mas indica uma categoria. É exatamente o caso dos nossos rótulos: RED é um rótulo, portanto é um dado categórico. RED pode ser 0 ou 1 e isto indica o nível, ou level! Outro exemplo de níveis: alto, baixo, regular; ou ainda: muito, pouco, regular; e assim por diante.
table() também é uma função muito útil do R que usa os fatores (factors/categorias) para construir uma tabela de contingência das frequências de cada combinação de níveis (levels) de fatores. Isso é exatamente o que precisamos aqui para descobrir o total de ocorrências de cada combinação de rótulos.
A função do.call() nos permite chamar qualquer tipo de função usando uma lista de argumentos. A função que está sendo chamada aqui é a paste() que é usada para construir strings. Como queremos montar strings para o dataframe inteiro, então do.call() auxilia no sentido de chamar a função paste para todas as linhas do data.frame.
CONCLUINDO
Por hoje é só, pessoal! Espero que vocês tenham conseguido acompanhar. Caso estejam com dúvidas, me procurem nas minhas redes sociais que estão disponíveis meu perfil aqui na Prensa. Ficarei muito feliz em te ajudar!
Este artigo foi escrito por Elaine Cecília Gatto - Cissa e publicado originalmente em Prensa.li.