Diagramas de Hertzsprung-Russell e um modelo de machine learning para classificação de estrelas

João Cláudio Nunes Carvalho
7 min readJul 3, 2021

--

Em astronomia, o diagrama de Hertzsprung-Russell é um gráfico de distribuição que mostra a relação entre a magnitude absoluta ou luminosidade versus o tipo espectral ou classificação estelar e a temperatura efetiva. Os diagramas de Hertzsprung-Russell não são quadros ou mapas da localização das estrelas. Em vez disso, eles colocam cada estrela em um gráfico indicando a sua magnitude absoluta ou brilho contra sua temperatura e cor.

Os diagramas de Hertzsprung-Russell são também chamados pelas abreviações diagrama H-R ou HRD. Eles foram criados por volta de 1910 por Ejnar Hertzsprung e Henry Norris Russell e representam um passo importante em direção ao entendimento da evolução estelar.

O objetivo de analisar este conjunto de dados é classificar as estrelas traçando suas características com base nesse gráfico.

This is a dataset consisting of several features of stars.

Some of them are:

  • Absolute Temperature (in K)
  • Relative Luminosity (L/Lo)
  • Relative Radius (R/Ro)
  • Absolute Magnitude (Mv)
  • Star Color (white,Red,Blue,Yellow,yellow-orange etc)
  • Spectral Class (O,B,A,F,G,K,,M)
  • Star Type **(Red Dwarf, Brown Dwarf, White Dwarf, Main Sequence , SuperGiants, HyperGiants)**

Lo = 3.828 x 10^26 Watts (Avg Luminosity of Sun)
Ro = 6.9551 x 10^8 m (Avg Radius of Sun)

Vamos iniciar nossa análise importando as bibliotecas comentada no trecho de código abaixo:

# Biblioteca para modelagem de dados
import pandas as pd
# Biblioteca para recursos matemáticos
import numpy as np
# Bibliotecas de plotagem de dados
import seaborn as sns
import matplotlib.pyplot as plt
# Biblioteca/Função para ignorar avisos
from warnings import filterwarnings

Agora vamos importar o nosso dataset:

Fonte dos dados: https://www.kaggle.com/deepu1109/star-dataset

# Lendo a Base de DadosBase_Dados = pd.read_csv('Stars.csv')

Vamos verificar aqui o cabeçalho de nosso dataframe Base_Dados:

# Verificando as primeiras linhasBase_Dados.head()

Teremos o resultado abaixo:

Aqui temos para cada linha: a temperatura de cada estrela(T); a sua luminosidade (L); seu raio (R); sua Magnitude absoluta(A_M) que é a medida do brilho intrínseco de um objeto celeste; a cor da estrela(Color), sua classificação estelar (O,B,A,F,G,K,M) e por fim o seu tipo(Anã vermelha, anã marrom, anã branca, sequência principal, supergigantes, hipergigantes).

Podemos verificar a dimensão da base de dados e o formato de cada um dos campos do dataset , por meio dos comandos abaixo:

Base_Dados.shape
Base_Dados.info()

Podemos perceber que temos 7 tipos de dados, 4 referentes as suas características e 3 referentes a sua classificação.

Vamos agora verificar alguns dados estatístico acerca de nossa base de dados:

# Dicionário para entender as estatísticas abaixo:

# count → Total de registros
# mean → Média
# std → Desvio Padrão
# min → Valor mínimo
# 25% → 1º Quartil
# 50% → Mediana
# 75% → 3º Quartil
# max → Valor Maior

# Comando para gerar estatísticas sobre os dados

Base_Dados.describe()
por aqui, podemos ver as médias de cada uma das variáveis de nosso dataset, seus valores máximos e mínimos por exemplo, bem como o desvio padrão.

Para verificarmos se existe algum valor não nulo na base de dados, iremos utilizar aqui a função heatmap do seaborn.

# Verificando se há um valor nulo na base de dados
# Caso exista haverá linhas brancas no gráfico
plt.figure( figsize=(10,6) )
sns.heatmap( Base_Dados.isnull() );

A ideia agora é verificar se existe alguma correlação entre as variáveis do nosso conjunto de dados, ou seja queremos ver se tem alguma variável aqui que explica outra(de forma positiva ou não). Ou seja se a primeira variável crescer a segunda pode diminuir, ou crescer também. Caso a segunda variável cresça teremos uma correlação positiva, caso contrário a correlação é negativa.

plt.figure( figsize=(10,6) )
sns.heatmap( Base_Dados.corr(), annot=True );

Percebemos aqui, que todas as variáveis de nosso dataset, possuem algum tipo de correlação entre si. Podemos ver aqui que Temperatura está correlacionada com o tipo da estrela, assim como por exemplo percebe-se uma forte correlação negativa entre a Magnitude absoluta da estrela e seu tipo.

# Vamos explorar todas as variaveis da base de dados
sns.pairplot(Base_Dados);

Esse gráfico mostra as relações entre todas as variáveis do conjunto de dados. Note que o único parâmetro que foi passado para a função pairplot é o conjunto Base_Dados. A função faz por si só todas as combinações de todas as variáveis, colocando scatterplots e histogramas mostrando suas relações.

Podemos agora fazer a plotagem de alguns gráficos acerca de nossas variáveis, para uma melhor análise de nosso conjunto de dados.

Para isso vamos fazer um import de algumas funções do pacote plotly

import plotly.express as px
import plotly.graph_objects as go

em seguida , vamos plotar o histograma de cada uma de nossas variáveis, por meio do comando abaixo, note que o x de cada um dos 6 gráficos abaixo, será cada uma das colunas de nosso dataset, no y teremos a frequência deste valor.

col = ['Temperature (K)', 'Luminosity(L/Lo)', 'Radius(R/Ro)',
'Absolute magnitude(Mv)', 'Star color', 'Spectral Class']
for column in col:
fig = px.histogram(Base_Dados,x=column,color='Star type',template='plotly_white',opacity=0.7)
fig.show()
Analisando esse gráfico, percebemos que temos uma quantidade maior de estrelas com temperaturas menores que 10K.
Analisando esse gráfico, percebemos que a maior parte das estrelas de nosso dataset apresentam uma luminosidade relativa mais próximo de zero.

Irei plotar aqui, os outros 4 histogramas, neles de modo geral, podemos contar a quantidade de estrelas dentro do espectro (ou range) de cada uma de nossas variáveis(raio, magnitude absoluta, cor da estrela e classe espectral).

Existem diversas outra forma de plotar estes gráficos. Como por exemplo, vamos analisar de um outro modo o histograma da magnitude absoluta em função do tipo da estrela:

# Plotagem a Magnitude das Estrelas por Tipoplt.figure( figsize=(10,5) )
sns.boxplot(x=’Type’, y=’A_M’, data=Base_Dados);
Aqui podemos visualizar para cada um dos 6 tipos de estrela , qual a magnitude delas.

Um resultado interessante aqui é que para as estrelas do tipo 1 e 2 o intervalo de valores de suas magnitudes são os mesmos.

Concluído essa análise estatística dos dados, vamos construir aqui um modelo de machine learning para encontrarmos a sua classe espectral tendo-se como entrada os dados de: ‘Temperature (K)’, ‘Luminosity(L/Lo)’, ‘Radius(R/Ro)’,
‘Absolute magnitude(Mv)’.

Para isso vamos separar nossos dados em x e y.

# Preparando os dados para o modelo
# Separando os Dados de Caracteristicas
x = Base_Dados.iloc[:,0:4].values
# Separando os Dado de classificação
y = Base_Dados.iloc[:, 6:7].values

Vamos trabalhar aqui com uma conhecida biblioteca Scikitlearn, que é uma biblioteca de aprendizado de máquina de código aberto para a linguagem de programação Python.

# Biblioteca para fazer o escalonamento dos Dadosfrom sklearn.preprocessing import StandardScaler# Fazendo o escalonamento do XEscala_x = StandardScaler()x = Escala_x.fit_transform( x )

O algorimo que iremos utilizar aqui para fazer nossa classificação será o Floresta Aleatória (Random Forest), o qual é muito utilizado em machine learning, sendo fácil de usar e que produz excelentes resultados a maioria das vezes, mesmo sem ajuste de hiperparâmetros. O algoritmo de florestas aleatórias cria várias árvores de decisão e as combina para obter uma predição com maior acurácia e mais estável.

O algoritmo de floresta aleatória adiciona aleatoriedade extra ao modelo, quando está criando as árvores. Quando você está criando uma árvore no floresta aleatória, apenas um subconjunto aleatório das características é considerada na partição de um nodo. Fonte(https://medium.com/machina-sapiens/o-algoritmo-da-floresta-aleat%C3%B3ria-3545f6babdf8)

# Criando o modelo de Floresta de Decisão# Importando a função para separar os dados em teste e treinofrom sklearn.model_selection import train_test_split# Separando os dados em teste e treinox_treinamento, x_teste, y_treinamento, y_teste = train_test_split(x, y,test_size = 0.30 )# Importando a função da Floresta de Decisãofrom sklearn.ensemble import RandomForestClassifier# Definindo o algoritmoAlgoritmo_Floresta_Decisao = RandomForestClassifier( n_estimators=500 )
#vamos gerar aqui 500 árvores aleatórias, para que a combinação #delas faça com que obtemos uma predição com maior acurácia e seja #mais estável.
# Aplicando o modelo nos dadosAlgoritmo_Floresta_Decisao.fit( x_treinamento, y_treinamento )

Após criar o nosso modelo, devemos agora fazer a nossa classificação, para isso vamos usar os dados de teste:

# Avaliando o modelo
# Prevendo os valores do X_teste
y_predicoes = Algoritmo_Floresta_Decisao.predict( x_teste )# Métrica do score de acurraciafrom sklearn.metrics import accuracy_score
Acuracio_Score = accuracy_score( y_teste, y_predicoes )
Acuracio_Score

Aqui como resultado de nossa previsão, obtivemos uma acurácia de 100% com nossa base de teste. Podemos pensar aqui que nosso modelo pode ter tido um problema de overfitting com os dados, porém a divisão das estrelas é “matematicamente correta”, ou seja, suas características são muito bem definidas dentro de cada tipo, ou seja seus “valores” não são próximos, sendo bem distintos uns dos outros.

--

--

João Cláudio Nunes Carvalho

Professor of Physics at the Federal Institute of Ceará. Phd in physics(UFC). MBA in Data Science and Analytics — USP — University of São Paulo