quarta-feira, 25 de julho de 2018

Como plotar uma fronteira não-dominada com R

Ciniro Nametala - Escrito na noite de 25 de Julho de 2018 em Medeiros, Minas Gerais. 

Qualquer pessoa que trabalhe com otimização multiobjetivos, certamente, uma hora ou outra, vai precisar plotar um scatter com os indivíduos não dominados referentes a última população do algoritmo.

Quando o problema tem apenas dois objetivos, ok! Simples de fazer, plot de linha normal. Quando o problema tem quatro ou mais objetivos, existem algumas visualizações bem bizarras por aí, contudo muito provavelmente a pessoa irá usar tabelas e não gráficos para demonstrar seus resultados.

(Sobre visualizações em alta dimensionalidade fica como dica o trabalho muito legal do professor Ivan do Campus Formiga aqui do IFMG [1].)

No entanto, quando o problema possui exatamente três objetivos, apenas plotar o scatter pode ser um pesadelo. Isso acontece pois numa impressão para um paper, por exemplo, o leitor não vai poder girar o gráfico, analisar o posicionamento dos indivíduos e, por causa disso, vai ter dificuldades em visualizar a fronteira não-dominada (Pareto aproximada) formada (não, fronteiras reais quase nunca são lindas como as criadas pelo Deb pro set DTLZ).

Passando por essa situação hoje e fazendo uma pesquisa na internet para tentar achar alguém que já tivesse implementado alguma coisa boa em R, vi que não existe quase nada! E o que existe, em geral, além de muito mal feito utiliza-se de mix de funções da ggplot2, com lattice, com rgl e outros "pacotões coloridos e desajeitados" (alguns discordaram do coloridos e desajeitados).

Em todas as soluções que testei vi ainda alguns problemas como:

1) Não plota superfície 3D sob o scatter dos indivíduos não dominados ou não plota os indivíduos não dominados sob a superfície 3D do scatter.
2) Quando plota a superfície ela é mal feita, sem grade que facilita ver as curvas, vales e cristas e, também, sem sombra/iluminação.
3) Superfície colorida demais, parecendo que saiu de um desenho animado (característica bem marcante (e que eu pessoalmente não gosto) da ggplot2).
4) Em geral, muitos pacotes pedem que você gere a manta (matriz de valores verticais) antes e, só depois, informe ela pra função. Isso é horrível, pois no caso de uma população caracterizada por 3 objetivos, o que você tem são 3 coordenadas e não [x, y, f(x,y)]. Nesse caso é necessário rodar uma função de interpolação que crie automaticamente os valores intermediários para gerar a matriz a partir dos valores do terceiro objetivo (ou eixo z como vai estar escrito no código aí embaixo) e, essa tarefa, não vi ninguém em R implementando, apenas em Matlab. Eu já conhecia o pacote Akima e sabia que lá tem uma função pra isso, então esse é o único pacote que acabei usando o que, inclusive, nos leva ao quinto problema.
5) Eu gosto de usar o que o pacote base do R tem pra geração de gráficos :) então estava procurando algo simples, muito simples.

Vamos então a solução. Código simples, gráfico simples. Tem tudo que é necessário. Além disso usa persp e não persp3d/plot3d da rgl naquele device externo sem vergonha do R (#saudadesmatlab).

library(akima)
d <- CARREGUE AQUI SEU DATASET

x <- d[,1]
y <- d[,2]
z <- d[,3]

s=interp(x,y,z,duplicate="strip")
nondom <- persp(s$x,s$y,s$z,
                phi = 40,
                theta = 55,
                xlab="Wear [µm]",
                ylab="Roughness (Ra) [µm]",
                zlab="Cost [US$]",
                main = "Pareto (3 objectives)",
                expand = 0.8,
                scale=TRUE,
                shade=1,
                col="white",
                border="grey80",
                box=TRUE, d = 1.5)

mypoints <- trans3d(x, y, z, pmat=nondom)
points(mypoints, pch=20, col="black", cex=0.75)

Resultado 😍:


Bem, por hoje é isso!
Abraços!

[1] https://formiga.ifmg.edu.br/professor-apresenta-nova-ferramenta-de-visualizacao-de-dados-em-espacos-de-alta-dimensionalidade-em-congresso-internacional

0 Comentários - :

Postar um comentário

Por favor! Comente! Pode ser qualquer coisa!