Visualizando dados em 2D e 3D com Python por categoria

Guilherme Silveira
Guilherme Silveira

Compartilhe

Avalie este artigo

Na Alura, alunos fazem diversos cursos de diversas categorias. Queremos visualizar isso. Pense por exemplo um aluno que faz 5 cursos de programação e 2 de design pode ser representado como (5,2) enquanto uma aluna que fez 10 de design e 1 de programação como (1,10). Portanto se tenho duas dimensões (programação e design) os estudantes caem num plano em R^2 (estritamente positivo) que pode ser facilmente plotado.

Pensando em estudantes que fazem muitos ou poucos cursos, podemos gerar uma quantidade (1000) aleatórias de cursos que eles fazem em Python:


import numpy as np
import pandas as pd
ALUNOS = 1000
def poucos_cursos():
    return (np.random.randn(ALUNOS) + 3).astype(int)
def muitos_cursos():
    return (3 * np.random.randn(ALUNOS) + 20).astype(int)

E imprimir dois exemplo de muitos cursos feitos e poucos cursos feitos:

Banner da Alura com desenvolvedor programando no computador e convite para aproveitar o feriado para entrar no mundo da tecnologia. A oferta destaca até 40% de desconto em cursos online de programação, mais um mês grátis, com botão “Comece agora” para iniciar a carreira tech.

print("Exemplo de muitos cursos ", muitos_cursos()[:5])
print("Exemplo de poucos cursos ", poucos_cursos()[:5])

Com a saída:


Exemplo de muitos cursos  [21 19 21 20 15]
Exemplo de poucos cursos  [4 3 1 3 4]

Ótimo, somos capazes de criar agora um conjunto de dados de alunos que fazem muitos cursos de programação e poucos de design, por exemplo:


def gera_alunos(programacao, design):
    linhas = np.array([programacao, design]).T
    alunos = pd.DataFrame(linhas, columns=["programacao", "design"])
    return alunos
gera_alunos(muitos_cursos(), poucos_cursos())

Tendo como exemplo de resultado:


    programacao     design
0   18              2
1   17              2
2   16              4
3   21              3
4   19              3

Ótimo, somos capazes então de criarmos um conjunto de dados aleatório de alunos e alunas que fizeram mais programação e mais design:


programacao = gera_alunos(muitos_cursos(), poucos_cursos())
design = gera_alunos(poucos_cursos(), muitos_cursos())
alunos = programacao.append(design, sort=False)

Agora podemos usar a biblioteca seaborn para plotar os alunos:


import seaborn as sns
sns.scatterplot(x="programacao", y="design", data=alunos)

Vamos colocar mais uma dimensão, cursos de mobile:


def gera_alunos(programacao, design, mobile):
    linhas = np.array([programacao, design, mobile]).T
    alunos = pd.DataFrame(linhas, columns=["programacao", "design", "mobile"])
    return alunos
programacao = gera_alunos(muitos_cursos(), poucos_cursos(), poucos_cursos())
design = gera_alunos(poucos_cursos(), muitos_cursos(), poucos_cursos())
mobile = gera_alunos(poucos_cursos(), poucos_cursos(), muitos_cursos())
alunos = programacao.append(design, sort=False).append(mobile, sort=False).fillna(0)
sns.scatterplot(x="programacao", y="design", data=alunos)

Curioso que mesmo com os dados em 3 dimensões (R^3), o gráfico permite visualizarmos os 3 grupos de alunos de maneira clara. Isso pois o grupo de mobile foi gerado intencionalmente com um número baixo de cursos de programação e design.

É comum em situações como essa desejarmos colorir cada ponto de acordo com uma característica ou categoria. Vamos definir uma categoria (texto) para cada ponto:


def gera_alunos(categoria, programacao, design, mobile):
    linhas = np.array([programacao, design, mobile]).T
    alunos = pd.DataFrame(linhas, columns=["programacao", "design", "mobile"])
    alunos['categoria'] = categoria
    return alunos
gera_alunos('programacao', muitos_cursos(), poucos_cursos(), poucos_cursos())[:5]

Que resulta em uma coluna nova chamada categoria, indicando o que escolhemos para esse grupo:


   programacao  design  mobile    categoria
0           18       3       2  programacao
1           18       2       2  programacao
2           15       2       2  programacao
3           22       1       3  programacao
4           19       3       2  programacao

Ótimo, mas o código está bastante repetitivo, que tal deixarmos valores padrão de poucos cursos para todos os cursos que não passarmos?


def gera_alunos(categoria, programacao=poucos_cursos(), design=poucos_cursos(), mobile=poucos_cursos()):
    linhas = np.array([programacao, design, mobile]).T
    alunos = pd.DataFrame(linhas, columns=["programacao", "design", "mobile"])
    alunos['categoria'] = categoria
    return alunos

Pronto, vamos indicar no plot que queremos o tom de cor (hue) de acordo com a coluna categoria:


programacao = gera_alunos('programacao',programacao=muitos_cursos())
design = gera_alunos('design',design=muitos_cursos())
mobile = gera_alunos('mobile',mobile=muitos_cursos())
alunos = programacao.append(design, sort=False).append(mobile, sort=False)
sns.scatterplot(x="programacao", y="design", hue="categoria", data=alunos)

sns.scatterplot(x="programacao", y="design", hue="categoria", data=alunos)

E para plotar esse gráfico em 3d? Podemos usar a própria biblioteca do matplotlib para isso:


from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(alunos.programacao, alunos.design, alunos.mobile, c=alunos.categoria)

Mas isso não funciona. O seaborn já é inteligente e percebe que passamos uma variável categórica (no nosso caso, uma coluna com strings distintas agrupáveis) para determinar a cor. O scatter do matplotlib é mais baixo nível e requer, nessa situação, strings que condizam com cores reais, e não categorias. Uma maneira de fazer isso é mapearmos cada categoria para uma cor com um dicionário:


cores = {'programacao':'red', 'mobile':'blue', 'design':'green'}

E agora usarmos uma lambda para mapearmos a coluna categoria pra a cor:


fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(alunos.programacao, alunos.design, alunos.mobile, c=alunos.categoria.apply(lambda x: cores[x]))

Você pode encontrar todo o código desse primeiro post no github. Dentre alguns dos cursos existentes de Data Science e Machine Learning na Alura, o plot de dados em diversas dimensões é fundamental para explorar os mesmos.

Avalie este artigo

Guilherme Silveira
Guilherme Silveira

Co-fundador da Alura. Com mais de 20 anos de ensino de tecnologia, criou mais de 100 cursos. Possui formação em engenharia de software, viés matemático e criativo, além de ser medalhista de ouro em competições nacionais de computação, tendo representado o Brasil nos mundiais. Participante de comunidades open source e de educação em tecnologia, tendo escrito 7 livros. Faz mágica e fala coreano no tempo livre.

Veja outros artigos sobre Programação