Criador: Eduardo Gonçalves (https://edugvs.github.io/)
Vamos importar as bibliotecas necessárias.
# Para manipulação dos dados
import pandas as pd
import numpy as np
# Para visualização dos dados
import seaborn as sns
import plotly.graph_objs as go
import plotly.offline as py
import plotly.express as px
import matplotlib.pyplot as plt
%matplotlib inline
# Para o cálculo de algumas estatísticas
from scipy.stats import kurtosis, skew
# Para a etapa de pré-processamento dos dados.
from sklearn.preprocessing import MinMaxScaler
# Para balancear o conjunto de dados.
from imblearn.over_sampling import SMOTE
#pip install -U imbalanced-learn
#conda install -c conda-forge imbalanced-learn
# Para a fase de Feature Selection.
from sklearn.feature_selection import SelectKBest, SelectPercentile, mutual_info_classif, f_classif, RFE, chi2
from sklearn.model_selection import KFold, cross_val_score, RepeatedStratifiedKFold, train_test_split, GridSearchCV
# Para a etapa de modelagem preditiva.
from sklearn import svm
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier
import sklearn
# Para a avaliação dos modelos
import time
from sklearn.metrics import precision_score, recall_score, f1_score, accuracy_score, roc_auc_score
from sklearn.metrics import confusion_matrix
from sklearn.metrics import classification_report
# Para ignorar os avisos dentro deste notebook
import warnings
warnings.filterwarnings("ignore")
# Instala o pacote watermark.
# Esse pacote é usado para gravar as versões de outros pacotes usados neste jupyter notebook.
#!pip install -q -U watermark
# Versões dos pacotes usados neste jupyter notebook
%reload_ext watermark
%watermark -a "Eduardo Gonçalves" --iversions
start_notebook = time.time()
Variable | Description | Type |
---|---|---|
geo_level_1_id, geo_level_2_id, geo_level_3_id | geographic region in which building exists, from largest (level 1) to most specific sub-region (level 3). Possible values: level 1: 0-30, level 2: 0-1427, level 3: 0-12567. | (type: int) |
count_floors_pre_eq | number of floors in the building before the earthquake. | (type: int) |
age | age of the building in years. | (type: int) |
area_percentage | normalized area of the building footprint. | (type: int) |
height_percentage | normalized height of the building footprint. | (type: int) |
land_surface_condition | surface condition of the land where the building was built. Possible values: n, o, t. | (type: categorical) |
foundation_type | type of foundation used while building. Possible values: h, i, r, u, w. | (type: categorical) |
roof_type | type of roof used while building. Possible values: n, q, x. | (type: categorical) |
ground_floor_type | type of constructions used in higher than the ground floors (except of roof). Possible values: j, q, s, x. | (type: categorical) |
position | position of the building. Possible values: j, o, s, t. | (type: categorical) |
plan_configuration | building plan configuration. Possible values: a, c, d, f, m, n, o, q, s, u. | (type: categorical) |
has_superstructure_adobe_mud | flag variable that indicates if the superstructure was made of Adobe/Mud. | (type: binary) |
has_superstructure_mud_mortar_stone | flag variable that indicates if the superstructure was made of Mud Mortar - Stone. | (type: binary) |
has_superstructure_stone_flag | flag variable that indicates if the superstructure was made of Stone. | (type: binary) |
has_superstructure_cement_mortar_stone | flag variable that indicates if the superstructure was made of Cement Mortar - Stone. | (type: binary) |
has_superstructure_mud_mortar_brick | flag variable that indicates if the superstructure was made of Mud Mortar - Brick. | (type: binary) |
has_superstructure_cement_mortar_brick | flag variable that indicates if the superstructure was made of Cement Mortar - Brick. | (type: binary) |
has_superstructure_timber | flag variable that indicates if the superstructure was made of Timber. | (type: binary) |
has_superstructure_bamboo | flag variable that indicates if the superstructure was made of Bamboo. | (type: binary) |
has_superstructure_rc_non_engineered | flag variable that indicates if the superstructure was made of non-engineered reinforced concrete. | (type: binary) |
has_superstructure_other | flag variable that indicates if the superstructure was made of any other material. | (type: binary) |
legal_ownership_status | legal ownership status of the land where building was built. Possible values: a, r, v, w. | (type: categorical) |
count_families | number of families that live in the building. | (type: int) |
has_secondary_use | flag variable that indicates if the building was used for any secondary purpose. | (type: binary) |
has_secondary_use_agriculture | flag variable that indicates if the building was used for agricultural purposes. | (type: binary) |
has_secondary_use_hotel | flag variable that indicates if the building was used as a hotel. | (type: binary) |
has_secondary_use_rental | flag variable that indicates if the building was used for rental purposes. | (type: binary) |
has_secondary_use_institution | flag variable that indicates if the building was used as a location of any institution. | (type: binary) |
has_secondary_use_school | flag variable that indicates if the building was used as a school. | (type: binary) |
has_secondary_use_industry | flag variable that indicates if the building was used for industrial purposes. | (type: binary) |
has_secondary_use_health_post | flag variable that indicates if the building was used as a health post. | (type: binary) |
has_secondary_use_gov_office | flag variable that indicates if the building was used fas a government office. | (type: binary) |
has_secondary_use_use_police | flag variable that indicates if the building was used as a police station. | (type: binary) |
has_secondary_use_other | flag variable that indicates if the building was secondarily used for other purposes | (type: binary) |
damage_grade [TARGET] | represents a level of damage to the building that was hit by the earthquake. There are 3 grades of the damage: 1 = low damage; 2 = a medium amount of damage; 3 = almost complete destruction. | (type: int) |
Estamos tentando prever a variável ordinal damage_grade, que representa o nível de dano ao imóvel que foi atingido pelo terremoto.
Existem 3 graus de dano:
# Carregando os dados de treino
dataset = pd.read_csv("train_data.csv", sep ='|')
# Criando uma cópia do dataset
df = dataset
display(df)
# Visualizando qual o tipo de objeto
type(df)
# Checando se há dados duplicados
df.duplicated().sum()
# Checando se há valores ausentes
df.isna().sum()
# Verificando as dimensões do objeto
df.shape
# Contando valores únicos
info = df.nunique().sort_values()
# Determinando o tipo de dados para cada variável
info = pd.DataFrame(info.values, index = info.index, columns = ['NUniques'])
# Atribuindo as informações sobre o tipo de dados das variáveis a um DataFrame.
info['dtypes'] = df.dtypes
# Exibe o dataframe
display(info)
Variáveis contendo muitos valores únicos podem atrapalhar a classificação. Uma boa estratégia é utilizar a técnica de engenharia de atributos. Neste caso, podemos criar um range de valores e transformar a variável em categórica (fator), processo também conhecido como "quantization". Por exemplo, podemos pegar uma variável que representa a idade de clientes e que possua muitos valores únicos e então criar um range de idade, ou faixas etárias. Essa etapa também pode ser aplicada durante o pré-processamento, tudo irá depender do problema de negócio.
# Definindo uma função, para converter variáveis para o tipo categórico, e criar suas respectivas versões dummy.
def categoryToDummyVariables(data, columnsName):
# Criando um dicionário vazio.
newTypes = dict()
# Criando o nome das variáveis dummy.
newColumnsName = [n + '_dummy' for n in columnsName]
# Definindo que cada variável especificada, deve ser convertida para o tipo de dado categórico.
for i in range(0, len(columnsName)):
newTypes.update({columnsName[i]: 'category'})
# Convertendo o tipo de dado das variáveis especificadas.
data = df.astype(newTypes)
# Criando variáveis dummy.
for i in range(0, len(columnsName)):
data[newColumnsName[i]] = data[columnsName[i]].cat.codes
# Retornando o DataFrame modificado.
return data
# Definindo uma função, para realizar as tarefas de Data Munging, necessárias para o conjunto de dados em análise.
def organizeData(data):
# Criando variáveis dummy para o conjunto de dados.
data = categoryToDummyVariables(data = data, columnsName = data.select_dtypes(include = np.object).columns)
# Eliminando as variáveis "building_id", "geo_level_1_id", "geo_level_2_id", "geo_level_3_id" de índice do conjunto de dados e as variáveis categóricas (com letras)
data = data.drop(columns = data.columns[[0,1,2,3,8,9,10,11,12,13,14,26]], axis = 1)
# Retornando o DataFrame modificado.
return data
# Limpando e organizando o conjunto de dados de treino.
df = organizeData(data = df)
display(df)
# Checando os tipo de dados
df.dtypes
Criando algumas funções auxiliares
# Definindo uma função para gerar um dataframe com estatísticas de variáveis numéricas.
def varStats(col, data, target = ''):
if target == '':
stats = pd.DataFrame({
'Min' : data[col].min(),
'Q1' : data[col].quantile(.25),
'Median': data[col].median(),
'Mean' : data[col].mean(),
'Q3' : data[col].quantile(.75),
'Max' : data[col].max(),
'SD' : data[col].std(),
'SK' : skew(data[col]),
'KU' : kurtosis(data[col])
}, index = [col])
else:
stats = pd.concat([
df[[col, target]].groupby(target).min(),
df[[col, target]].groupby(target).quantile(.25),
df[[col, target]].groupby(target).median(),
df[[col, target]].groupby(target).mean(),
df[[col, target]].groupby(target).quantile(.75),
df[[col, target]].groupby(target).max(),
df[[col, target]].groupby(target).std(),
df[[col, target]].groupby(target).skew(),
df[[col, target]].groupby(target).apply(lambda group: kurtosis(group)[0])
], axis = 1)
stats.columns = ['Min', 'Q1', 'Median', 'Mean', 'Q3', 'Max', 'SD', 'SK', 'KU']
return stats
# Definindo uma função para traçar gráficos interativos em um ambiente jupyter não padrão.
def configure_plotly_browser_state():
import IPython
display(IPython.core.display.HTML('''
<script src="/static/components/requirejs/require.js"></script>
<script>
requirejs.config({
paths: {
base: '/static/base',
plotly: 'https://cdn.plot.ly/plotly-1.43.1.min.js?noext',
},
});
</script>
'''))
# Definindo uma função, para criar gráficos de Barra interativos com o plotly.
def plotBar(data, col = '', target = '', title = '', yaxis = '', xaxis = '', kind = 'normal',
color = ['#8783D1', '#FADF63', '#FF9F43', '#EE6352', '#FC7A1E'], opacity = 0.65,
template = 'plotly_white', orientation = 'v', barmode = 'group'):
# Realizando as pré-configurações necessárias para a plotagem do gráfico interativo.
configure_plotly_browser_state()
# Criando gráficos na vertical.
if orientation == 'v':
# Plotando gráfico de barras simples.
if kind == 'normal':
# Definindo os dados, a cor, orientação e a transparência que serão utilizados para criar as barras.
dataTrace = go.Bar(
x = data.index,
y = data.values,
marker = {'color': color[2], "opacity": opacity},
orientation = orientation
)
# Plotando gráfico de barras agrupado por uma variável categórica.
elif kind == 'groups':
# Captura os registros pertencentes a cada categoria, da variável categórica.
g = [data[data[target] == cat] for cat in data[target].cat.categories]
# Definindo os dados, a cor, orientação e a transparência que serão utilizados para criar as barras.
dataTrace = [
go.Bar(
x = g[cat][col],
y = g[cat]['count'],
name = data[target].cat.categories[cat].capitalize(),
marker = {'color': color[cat], "opacity": opacity},
orientation = orientation
) for cat in range(0,len(g))
]
# Criando gráficos na horizontal.
else:
# Plotando gráfico de barras simples.
if kind == 'normal':
# Definindo os dados, a cor, orientação e a transparência que serão utilizados para criar as barras.
dataTrace = go.Bar(
x = data.values,
y = data.index,
marker = {'color': color[3], "opacity": opacity},
orientation = orientation
)
# Plotando gráfico de barras agrupado por uma variável categórica.
elif kind == 'groups':
# Captura os registros pertencentes a cada categoria, da variável categórica.
g = [data[data[target] == cat] for cat in data[target].cat.categories]
# Definindo os dados, a cor, orientação e a transparência que serão utilizados para criar as barras.
dataTrace = [
go.Bar(
x = g[cat]['count'],
y = g[cat][col],
name = data[target].cat.categories[cat].capitalize(),
marker = {'color': color[cat], "opacity": opacity},
orientation = orientation
) for cat in range(0,len(g))
]
# Defindo as configurações de layout.
layout = go.Layout(
title = title,
yaxis = {'title': yaxis},
xaxis = {'title': xaxis},
template = template
)
# Criando uma Figure, com os dados e o layout defindos.
fig = go.Figure(data = dataTrace, layout = layout)
# Definindo que as barras devem ser dispostas uma ao lado da outra caso estejam agrupadas por categoria.
# Para criar Stacked Bars, utilize: 'stack'.
fig.update_layout(barmode = barmode)
# Plotando o Figure com o pyplot.
fig.show()
configure_plotly_browser_state()
# Definindo a variável a ser analisada
col = 'damage_grade'
# Definindo a label
label = 'damage_grade'
# Criando o plot
fig = px.histogram(df,
x = col,
template = 'plotly_white',
title = 'Absolute frequency of ' + col,
labels = {col: label},
opacity = 0.70,
color = "damage_grade"
)
# Exibe o gráfico
fig.show()
# Obtendo a frequência relativa
display(df['damage_grade'].value_counts(normalize=True).map('{:.2%}'.format))
Podemos observar um certo desbalanceamento entre as classes da variável target. Talvez seja necessário balancear antes da etapa de modelagem preditiva.
configure_plotly_browser_state()
# Criando o boxplot
fig1 = px.box(df,
x = 'age',
template = 'plotly_white',
title = 'Building age (years)',
color = "damage_grade",
)
# Exbie o gráfico
fig1.show()
Vamos tratar os valores extremos (outliers). O critério para identificar um outlier é quando um ponto de dado fica 1,5 vezes fora de um intervalo interquartil acima do 3º quartil (Q3) e abaixo do 1º quartil (Q1)
# Verificando o shape dos dados
df['age'].shape
# Obtendo o intervalo entre o 1 e o 3 quartil
Q1 = df['age'].quantile(0.25)
Q3 = df['age'].quantile(0.75)
IQR = Q3 - Q1
print(Q1, Q3, IQR)
# Fazendo cálculo para filtrar os dados que estiverem 1,5x abaixo do 1Q ou acima do 3Q
Lower_Whisker = Q1 - 1.5 * IQR
Upper_Whisker = Q3 + 1.5 * IQR
print(Lower_Whisker, Upper_Whisker)
# Limpando os dados
df = df[df['age']< Upper_Whisker]
# Verificando o shape após o tratamento dos outliers
df['age'].shape
configure_plotly_browser_state()
# Definindo a variável a ser analisada
col = 'age'
# Definindo a label
label = 'Building age (years)'
# Criando o plot
fig = px.histogram(df,
x = col,
template = 'plotly_white',
title = 'Absolute frequency of ' + col,
labels = {col: label},
opacity = 0.70,
color = "damage_grade"
)
# Exibe o gráfico
fig.show()
# Obtendo a frequência relativa
display(df['age'].value_counts(normalize=True).map('{:.2%}'.format))
# Definindo a variável a ser calculada
col = 'age'
# Aplicando a função para calcular as estatísticas
varStats(col, target = 'damage_grade', data = df)
configure_plotly_browser_state()
# Definindo a variável a ser analisada
col = 'count_floors_pre_eq'
# Definindo a label
label = 'Number of floors in the building'
# Criando o plot
fig = px.histogram(df,
x = col,
template = 'plotly_white',
title = 'Absolute frequency of ' + col,
labels = {col: label},
opacity = 0.70,
color = "damage_grade"
)
# Exibe o gráfico
fig.show()
# Obtendo a frequência relativa
display(df['count_floors_pre_eq'].value_counts(normalize=True).map('{:.2%}'.format))
# Filtrando os dados da variável count_floors_pre_eq para selecionar somente os imóveis de até 4 andares.
df['count_floors_pre_eq'] = df.query('count_floors_pre_eq < 5')
# Definindo a variável a ser calculada
col = 'count_floors_pre_eq'
# Aplicando a função para calcular as estatísticas
varStats(col, target = 'damage_grade', data = df)
configure_plotly_browser_state()
# Cria o boxplot
fig1 = px.box(df,
x = 'area_percentage',
template = 'plotly_white',
title = 'Normalized area of the building footprint',
color = "damage_grade",
)
# Exibe o gráfico
fig1.show()
configure_plotly_browser_state()
# Definindo a variável a ser analisada
col = 'area_percentage'
# Definindo a label
label = 'Normalized area of the building footprint'
# Criando o plot
fig = px.histogram(df,
x = col,
template = 'plotly_white',
title = 'Absolute frequency of ' + col,
labels = {col: label},
opacity = 0.70,
color = "damage_grade"
)
# Exibe o gráfico
fig.show()
# Obtendo a frequência relativa
display(df['area_percentage'].value_counts(normalize=True).map('{:.2%}'.format))
# Definindo a variável a ser calculada
col = 'area_percentage'
# Aplicando a função para calcular as estatísticas
varStats(col, target = 'damage_grade', data = df)
configure_plotly_browser_state()
# Cria o boxplot
fig1 = px.box(df,
x = 'height_percentage',
template = 'plotly_white',
title = 'Normalized height of the building footprint',
color = "damage_grade",
)
# Exibe o gráfico
fig1.show()
configure_plotly_browser_state()
# Definindo a variável a ser analisada
col = 'height_percentage'
# Definindo a label
label = 'Normalized height of the building footprint'
# Criando o plot
fig = px.histogram(df,
x = col,
template = 'plotly_white',
title = 'Absolute frequency of ' + col,
labels = {col: label},
opacity = 0.70,
color = "damage_grade"
)
# Exibe o gráfico
fig.show()
# Obtendo a frequência relativa
display(df['height_percentage'].value_counts(normalize=True).map('{:.2%}'.format))
# Definindo a variável a ser calculada
col = 'height_percentage'
# Aplicando a função para calcular as estatísticas
varStats(col, target = 'damage_grade', data = df)
configure_plotly_browser_state()
# Definindo a variável a ser analisada
col = 'count_families'
# Definindo a label
label = 'Number of families that live in the building'
# Criando o plot
fig = px.histogram(df,
x = col,
template = 'plotly_white',
title = 'Absolute frequency of ' + col,
labels = {col: label},
opacity = 0.70,
color = "damage_grade"
)
# Exibe o gráfico
fig.show()
# Obtendo a frequência relativa
display(df['count_families'].value_counts(normalize=True).map('{:.2%}'.format))
# Definindo a variável a ser calculada
col = 'count_families'
# Aplicando a função para calcular as estatísticas
varStats(col, target = 'damage_grade', data = df)
# Definindo o nome da variável a ser analisada.
col = 'land_surface_condition'
# Definindo o nome da variável Target.
target = 'damage_grade'
# Capturando variáveis especificadas do Dataset.
data = dataset[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de barras para a variável especificada.
fig = px.bar(data, x=col, y='count', title='Absolute frequency of ' + col, color = target, template = 'plotly_white', opacity = 0.70)
fig.show()
# Obtendo a frequência relativa
display(dataset['land_surface_condition'].value_counts(normalize=True).map('{:.2%}'.format))
# Definindo o nome da variável a ser analisada.
col = 'foundation_type'
# Definindo o nome da variável Target.
target = 'damage_grade'
# Capturando variáveis especificadas do Dataset.
data = dataset[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de barras para a variável especificada.
fig = px.bar(data, x=col, y='count', title='Absolute frequency of ' + col, color = target, template = 'plotly_white', opacity = 0.70)
fig.show()
# Obtendo a frequência relativa
display(dataset['foundation_type'].value_counts(normalize=True).map('{:.2%}'.format))
# Definindo o nome da variável a ser analisada.
col = 'roof_type'
# Definindo o nome da variável Target.
target = 'damage_grade'
# Capturando variáveis especificadas do Dataset.
data = dataset[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de barras para a variável especificada.
fig = px.bar(data, x=col, y='count', title='Absolute frequency of ' + col, color = target, template = 'plotly_white', opacity = 0.70)
fig.show()
# Obtendo a frequência relativa
display(dataset['roof_type'].value_counts(normalize=True).map('{:.2%}'.format))
# Definindo o nome da variável a ser analisada.
col = 'ground_floor_type'
# Definindo o nome da variável Target.
target = 'damage_grade'
# Capturando variáveis especificadas do Dataset.
data = dataset[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de barras para a variável especificada.
fig = px.bar(data, x=col, y='count', title='Absolute frequency of ' + col, color = target, template = 'plotly_white', opacity = 0.70)
fig.show()
# Obtendo a frequência relativa
display(dataset['ground_floor_type'].value_counts(normalize=True).map('{:.2%}'.format))
# Definindo o nome da variável a ser analisada.
col = 'other_floor_type'
# Definindo o nome da variável Target.
target = 'damage_grade'
# Capturando variáveis especificadas do Dataset.
data = dataset[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de barras para a variável especificada.
fig = px.bar(data, x=col, y='count', title='Absolute frequency of ' + col, color = target, template = 'plotly_white', opacity = 0.70)
fig.show()
# Obtendo a frequência relativa
display(dataset['other_floor_type'].value_counts(normalize=True).map('{:.2%}'.format))
# Definindo o nome da variável a ser analisada.
col = 'position'
# Definindo o nome da variável Target.
target = 'damage_grade'
# Capturando variáveis especificadas do Dataset.
data = dataset[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de barras para a variável especificada.
fig = px.bar(data, x=col, y='count', title='Absolute frequency of ' + col, color = target, template = 'plotly_white', opacity = 0.70)
fig.show()
# Obtendo a frequência relativa
display(dataset['position'].value_counts(normalize=True).map('{:.2%}'.format))
# Definindo o nome da variável a ser analisada.
col = 'plan_configuration'
# Definindo o nome da variável Target.
target = 'damage_grade'
# Capturando variáveis especificadas do Dataset.
data = dataset[[col, target]]
# Criando uma variável count para contabilizar as ocorrências de cada registro.
data['count'] = 1
# Agrupando dados e contabilizando o número de ocorrências.
data = data.groupby(by = [target, col]).sum()
# Reorganizando DataFrame.
data = data.reset_index()
# Plotando um gráfico de barras para a variável especificada.
fig = px.bar(data, x=col, y='count', title='Absolute frequency of ' + col, color = target, template = 'plotly_white', opacity = 0.70)
fig.show()
# Obtendo a frequência relativa
display(dataset['plan_configuration'].value_counts(normalize=True).map('{:.2%}'.format))
# Criando um dataframe somente com as variáveis de interesse
numerics = ['int16', 'int32', 'int64', 'int8', 'float16', 'float32', 'float64']
corr_features = df.select_dtypes(include=numerics)
# Criando um clustermap para a análise correlação em grupos
clustermap = sns.clustermap(corr_features.corr(), vmin=-1, vmax=1, annot=True, figsize=(30, 30),cmap="mako", method='centroid', metric='euclidean')
Não há nenhuma correlação significativa nos dados quando olhamos para a variável target, isso pode representar um problema para os modelos, afetando a precisão.
Alguns algorítmos, como o kNN e o SVM, requerem a normalização dos dados.
# Criando um objeto da classe StandardScaler().
scaler = MinMaxScaler()
# Selecionando as variáveis a serem normalizadas
features = df[["count_floors_pre_eq", "count_families", "height_percentage", "age", "area_percentage"]]
# Aplicando a escala nas Features e capturando o resultado obtido.
featuresTransformed = scaler.fit_transform(features)
# Criando um DataFrame com os resultados obtidos.
featuresTransformed = pd.DataFrame(data = featuresTransformed, columns = features.columns)
# Removendo as colunas não normalizadas
data = df.drop(columns = df.columns[[0,1,2,3,15]], axis = 1)
# Concatenando os dataframes
df_norm = pd.concat([featuresTransformed, data], axis = 1)
display(df_norm)
# Verificando valores ausentes
df_norm.isna().sum()
# Verificando o shape
df_norm.shape
# Deletando valores nulos
df_norm = df_norm.dropna(how='any')
# Verificando o shape
df_norm.shape
# Contando valores únicos
info = df_norm.nunique().sort_values()
# Determinando o tipo de dados para cada variável
info = pd.DataFrame(info.values, index = info.index, columns = ['NUniques'])
# Atribuição de informações sobre o tipo de dados das variáveis a um DataFrame.
info['dtypes'] = df_norm.dtypes
# Exibe o dataframe
display(info)
# Ajustando a variável target para o final do dataframe
target = df_norm.pop('damage_grade')
df_norm['damage_grade'] = target
df_final = df_norm
display(df_final)
df_final.shape
# Salvando o dataset final como csv
df_final.to_csv(r'D:\OneDrive\DS_PROJECTS\Project03-damage-earthquake\df_final.csv', index=False)
SMOTE (técnica de sobreamostragem minoritária sintética) é um dos métodos de sobreamostragem (oversampling) mais comumente usados para resolver o problema de desequilíbrio entre classes de uma variável. Seu objetivo é equilibrar a distribuição de classes, aumentando aleatoriamente os exemplos de classes minoritárias, replicando os dados. O SMOTE sintetiza novas instâncias minoritárias entre instâncias minoritárias existentes.
df_final.columns
# Para reproduzir os mesmo resultados
seed = 100
# Separa X e y
X = df_final.iloc[:,0:35]
y = df_final.iloc[:,35]
# Cria o balanceador SMOTE
smt = SMOTE(random_state = seed)
# Aplica o balanceador
X_res, y_res = smt.fit_resample(X, y)
# Plot
sns.countplot(y_res, palette = "OrRd")
plt.box(False)
plt.xlabel('Grau de dano: Pouco(1) / Médio (2) / Quase destruído (3)', fontsize = 11)
plt.ylabel('count', fontsize = 11)
plt.title('Contagem de Classes\n')
plt.show()
df_final.shape
X_res.shape
y_res.shape
# Ajustando X e y
X = X_res
y = y_res
# Criando conjunto de dados de treino e de teste.
trainFeatures, testFeatures, trainTarget, testTarget = train_test_split(X, y, test_size = 0.30, random_state = 101)
# Divisão dos dados de treino em dados de treino e dados de validação
trainData, validData, trainLabels, validLabels = train_test_split(trainFeatures,
trainTarget,
test_size = 0.1,
random_state = 84)
# Imprimindo o número de exemplos (observações) em cada dataset
print("Exemplos de Treino: {}".format(len(trainData)))
print("Exemplos de Validação: {}".format(len(validLabels)))
print("Exemplos de Teste: {}".format(len(testTarget)))
# Shape dos datasets
print(trainData.shape, validData.shape, testFeatures.shape)
Se os recursos forem categóricos, calcularemos uma estatística qui-quadrado entre cada recurso e a variável target. No entanto, se os recursos forem quantitativos, calcularemos a ANOVA F-Value entre cada recurso e a variável target.
As pontuações do F-Value examinam se, quando agrupamos a característica numérica pela variável target, as médias para cada grupo se tornam significativamente diferentes.
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeatures
# Instanciando um objeto da classe SelectKBest para selecionar as melhores variáveis preditoras a partir dos scores ANOVA F-Values.
skb = SelectKBest(f_classif, k = 8)
# Capturando as variáveis preditoras.
bestFeatuesANOVA = skb.fit_transform(tFeatures, trainTarget)
# Capturando o nome das variáveis preditoras.
bfAnova = tFeatures.columns[skb.get_support()]
# Exibindo o nome das variáveis preditoras.
bfAnova
# Criando uma Série Temporal com os scores obtidos para cada uma das Features segundo a técnica utilizada.
sc = pd.Series(skb.scores_, index = tFeatures.columns)
# Capturando os scores das variáveis preditoras.
sc = sc[skb.get_support()]
# Ordenando a Série Temporal em ordem decrescente dos scores.
sc = sc.sort_values(ascending = False)
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.
plotBar (
data = sc,
title = 'Scores das melhores features com o ANOVA F-value',
yaxis = 'Features',
xaxis = 'Scores',
orientation = 'h'
)
# Capturando o nome das variáveis preditoras.
bfAnv = sc.index
# Exibindo o nome das variáveis preditoras.
bfAnv
O Extremely Randomized Trees Classifier (Extra Trees Classifier) é um tipo de técnica de aprendizagem de conjunto que agrega os resultados de várias árvores de decisão descorrelacionadas coletadas em uma “floresta” para produzir seu resultado de classificação. Em conceito, é muito semelhante a um classificador Random Forest e só difere na forma de construção das árvores de decisão na floresta.
Cada árvore de decisão na floresta de árvores extras é construída a partir da amostra de treinamento original. Então, em cada nó de teste, cada árvore é fornecida com uma amostra aleatória de k recursos do conjunto de recursos a partir do qual cada árvore de decisão deve selecionar o melhor recurso para dividir os dados com base em alguns critérios matemáticos (normalmente o índice de Gini). Essa amostra aleatória de recursos leva à criação de várias árvores de decisão não correlacionadas.
Para realizar a seleção de características usando a estrutura de floresta acima, durante a construção da floresta, para cada característica, a redução total normalizada nos critérios matemáticos usados na decisão da característica de divisão (Índice de Gini se for usado na construção de floresta) é computado. Esse valor é chamado de Importância Gini do recurso. Para realizar a seleção de recursos, cada recurso é ordenado em ordem decrescente de acordo com a Importância Gini de cada recurso e o usuário seleciona os k principais recursos de acordo com sua escolha.
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeatures
# Instanciando um objeto da classe ExtraTreesClassifier.
modelETC = ExtraTreesClassifier()
# Computando os scores de cada feature.
modelETC.fit (X = tFeatures, y = trainTarget)
# Inserindo Scores obtidos em uma Série Temporal.
featuresImpETC = pd.Series(data = modelETC.feature_importances_, index = tFeatures.columns)
# Ordenando o nome das variáveis preditoras segundo seu score em ordem decrescente.
bfEtc = featuresImpETC.sort_values(ascending = False)
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.
plotBar (
data = bfEtc,
title = 'Scores das melhores features com o Extra Trees Classifier',
yaxis = 'Features',
xaxis = 'Scores',
orientation = 'h'
)
# Capturando o nome das variáveis preditoras.
bfEtc = bfEtc.index
# Exibindo o nome das variáveis preditoras.
bfEtc
O Random Forest, é um dos algoritmos de aprendizado de máquina mais populares. É um dos mais bem-sucedidos porque fornece, em geral, um bom desempenho preditivo, baixo overfitting e é de fácil interpretabilidade.
Essa interpretabilidade é dada pela facilidade de se derivar a importância de cada variável na árvore de decisão. Em outras palavras, é fácil calcular o quanto cada variável está contribuindo para a decisão do modelo.
O Random Forest consiste em 4-12 centenas de árvores de decisão, cada uma delas construída sobre uma extração aleatória das observações do conjunto de dados e uma extração aleatória das características. Nem toda árvore vê todas as características ou todas as observações, e isso garante que as árvores sejam descorrelacionadas e, portanto, menos sujeitas a sobreajuste. Cada árvore também é uma sequência de perguntas sim-não com base em um único recurso ou em uma combinação de recursos. Em cada nó (isto é em cada questão), os três dividem o conjunto de dados em 2 depósitos, cada um deles hospedando observações que são mais semelhantes entre si e diferentes das do outro bloco. Portanto, a importância de cada recurso é derivada do quão "puro" cada um dos blocos é.
Para classificação, a medida de impureza é a impureza de Gini ou o ganho/entropia de informação. Para regressão, a medida de impureza é a variância. Portanto, ao treinar uma árvore, é possível calcular o quanto cada recurso diminui a impureza. Quanto maior for a diminuição da impureza que um recurso gerar, mais importante ele será. Em florestas aleatórias, a diminuição da impureza de cada recurso pode ser calculada em média entre as árvores para determinar a importância final da variável.
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.
tFeatures = trainFeatures
# Instanciando um objeto da classe RandomForestClassifier.
rfImp = RandomForestClassifier (n_estimators = 200, random_state = 0)
# Treinando o classificador com o conjunto de dados de treino.
rfImp.fit(X = tFeatures, y = trainTarget)
# Prevendo os scores das features dos dados de treino.
pred = rfImp.predict(tFeatures)
# Convertendo os scores para um DataFrame.
featuresImpRf = pd.Series(data = rfImp.feature_importances_, index = tFeatures.columns)
# Capturando os scores de cada uma das features.
bfRf = featuresImpRf.nlargest(13)
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.
plotBar (
data = bfRf,
title = 'Scores das melhores features com o Random Forest',
yaxis = 'Features',
xaxis = 'Scores',
orientation = 'h'
)
# Capturando o nome das variáveis preditoras.
bfRf = bfRf.index
# Exibindo o nome das variáveis preditoras.
bfRf
O k-Nearest-Neighbours (kNN) é um método de classificação não paramétrico, que é simples mas eficaz em muitos casos. Para que um registro de dados seja classificado, seus "k" vizinhos mais próximos são recuperados e isso forma uma vizinhança ao redor dos dados. O algoritmo kNN utiliza medidas matemáticas de distância a fim de comparar os pontos de dados, geralmente o método mais comum é a distância euclidiana, entretanto, há outras maneiras como: Distância Manhattan, Distância de Minkowsky e Distância de Hamming. Para aplicar o kNN, precisamos escolher um valor apropriado para k, e o sucesso da classificação depende muito desse valor. Em certo sentido, o método kNN é influenciado por k. Existem muitas maneiras de escolher o valor k, mas a maneira mais simples é executar o algoritmo várias vezes com valores k diferentes e escolher aquele com o melhor desempenho.
Se o valor de K for muito alto, o algoritmo kNN pode resultar em um modelo com baixa precisão. Se o valor de K for muito baixo, o modelo será muito sensível a outliers, gerando classificações incorretas. O objetivo é definir um valor de k que gere o modelo mais generalizável possível.
# Range de valores de k que iremos testar
kVals = range(1, 15, 2)
Números ímpares tendem a evitar o problema de empate na votação do algorítmo para determinar o vizinho mais próximo.
# Lista vazia para receber as acurácias
acuracias = []
# Loop em todos os valores de k para testar cada um deles
start = time.time()
for k in kVals:
# Treinando o modelo KNN com cada valor de k com as melhores variáveis selecionadas pelo Random Forest
modeloKNN = KNeighborsClassifier(n_neighbors = k)
modeloKNN.fit(trainFeatures[bfRf], trainTarget)
# Avaliando o modelo e atualizando a lista de acurácias
score = modeloKNN.score(validData[bfRf], validLabels)
print("Com valor de k = %d, a acurácia é = %.2f%%" % (k, score * 100))
acuracias.append(score)
end = time.time()
print('Tempo de Treinamento do Modelo:', end - start)
# Obtendo o valor de k que apresentou a maior acurácia
i = np.argmax(acuracias)
print("O valor de k = %d alcançou a mais alta acurácia de %.2f%% nos dados de validação!" % (kVals[i], acuracias[i] * 100))
# Criando a versão final do modelo com o maior valor de k
modeloFinal = KNeighborsClassifier(n_neighbors = kVals[i])
# Treinamento do modelo
start = time.time()
modeloFinal.fit(trainFeatures[bfRf], trainTarget)
end = time.time()
print('Tempo de Treinamento do Modelo:', end - start)
# Previsões com os dados de teste
predictions = modeloFinal.predict(testFeatures[bfRf])
# Performance do modelo nos dados de teste
print("Avaliação do Modelo nos Dados de Teste")
print(classification_report(testTarget, predictions))
Accuracy: mede a exatidão do modelo de classificação, como a proporção de resultados verdadeiros em relação ao total de casos analisados. Quanto maior, melhor!
Precision: é a proporção de resultados verdadeiros sobre os resultados positivos. Quanto maior, melhor!
Recall: é a fração de resultados corretos retornados pelo modelo. Quanto maior, melhor!
F-Score: é a média ponderada entre a precisão e o recall. O valor ideal para o F-Score é igual a 1.
Support: é o número de ocorrências reais da classe no conjunto de dados especificado. O suporte desequilibrado nos dados de treinamento pode indicar fraquezas estruturais nas pontuações relatadas do classificador e pode indicar a necessidade de amostragem estratificada ou rebalanceamento.
As médias relatadas incluem macro média (média da média não ponderada por label), média ponderada (média da média ponderada de suporte por label) e média da amostra (apenas para classificação multiclasse). A micro média (calculando a média do total de positivos verdadeiros, falsos negativos e falsos positivos) só é exibida para várias labels ou várias classes com um subconjunto de classes, porque corresponde à precisão de outra forma e seria o mesmo para todas as métricas. Para mais informações acesse: https://scikit-learn.org/stable/modules/generated/sklearn.metrics.classification_report.html
# Confusion Matrix do Modelo Final
print ("Confusion matrix")
print(confusion_matrix(testTarget, predictions))
Um hiperparâmetro importante a ser ajustado para regressão logística multinomial é o termo de penalidade. Este termo impõe pressão sobre o modelo para buscar pesos de modelo menores. Isso é obtido adicionando uma soma ponderada dos coeficientes do modelo à função de perda, encorajando o modelo a reduzir o tamanho dos pesos junto com o erro durante o ajuste do modelo. Um tipo popular de penalidade é a penalidade L2 que adiciona a soma (ponderada) dos coeficientes quadrados à função de perda. Uma ponderação dos coeficientes pode ser usada para reduzir a força da penalidade de penalidade total para uma penalidade muito leve. Por padrão, a classe LogisticRegression usa a penalidade L2 com uma ponderação de coeficientes definida como 1,0. O tipo de penalidade pode ser definido por meio do argumento "penalidade" com valores de "l1", "l2", "elasticnet" (por exemplo, ambos), embora nem todos os solucionadores suportem todos os tipos de penalidade. A ponderação dos coeficientes na penalidade pode ser definida por meio do argumento “C”.
Isso significa que valores próximos a 1,0 indicam uma penalidade muito pequena e valores próximos de zero indicam uma penalidade forte. Um valor C de 1,0 pode indicar nenhuma penalidade.
A penalidade pode ser desabilitada definindo o argumento “penalidade” para a string “nenhum“.
# Obtendo uma lista de modelos para avaliar
def get_models():
models = dict()
for p in [0.0, 0.0001, 0.001, 0.01, 0.1, 1.0]:
# cria o nome do modelo
key = '%.4f' % p
# desliga a penalidade em alguns casos
if p == 0.0:
# Sem penalidade neste caso
models[key] = LogisticRegression(multi_class='multinomial', solver='lbfgs', penalty='none')
else:
models[key] = LogisticRegression(multi_class='multinomial', solver='lbfgs', penalty='l2', C=p)
return models
# avaliando o modelo usando validação cruzada
def evaluate_model(model, X, y):
# define o procedimento de validação
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# avalia o modelo
scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
return scores
start = time.time()
# define o conjunto de dados
X, y = trainFeatures[bfRf], trainTarget
# obtem os modelos para avaliação
models = get_models()
# avalia os modelos e armazena os resultados
results, names = list(), list()
for name, model in models.items():
# avalia os modelos e coleta os scores
scores = evaluate_model(model, X, y)
# armazena os resultados nas listas
results.append(scores)
names.append(name)
# resume o progresso ao longo do caminho
print('>%s %.3f (%.3f)' % (name, np.mean(scores), np.std(scores)))
end = time.time()
print('Tempo de Treinamento do Modelo:', end - start)
# plot do desempenho dos modelos para comparação de acordo com as penalidades
plt.boxplot(results, labels=names, showmeans=True)
plt.show()
Nesse caso, podemos ver que um valor C de 1,0 tem a melhor pontuação de cerca de 52%, que é o mesmo score do modelo com a penalidade mais forte (0,0)
O objetivo do algoritmo da máquina de vetores de suporte (SVM – Support Vector Machine) é encontrar um hiperplano em um espaço N-dimensional (N - o número de recursos ou atributos) que classifica distintamente os pontos de dados. Para separar as duas classes de pontos de dados, existem muitos hiperplanos possíveis que podem ser escolhidos. Nosso objetivo é encontrar um hiperplano com a margem máxima, ou seja, a distância máxima entre os pontos de dados das duas classes. A maximização da distância da margem fornece um limite para que os pontos de dados futuros possam ser classificados com mais confiança. Hiperplanos são limites de decisão que ajudam a classificar os pontos de dados.
A dimensão do hiperplano depende do número de recursos. Se o número de recursos de entrada for 2, o hiperplano será apenas uma linha. Se o número de recursos de entrada for 3, o hiperplano se tornará um plano bidimensional. Os vetores de suporte são pontos de dados que estão mais próximos do hiperplano e influenciam a posição e a orientação do hiperplano. Usando esses vetores de suporte, maximizamos a margem do classificador. A exclusão dos vetores de suporte alterará a posição do hiperplano. Esses são os pontos que nos ajudam a criar nosso modelo SVM.
# Cria o modelo
modelo_svm_v1 = svm.SVC(kernel = 'linear')
# Selecionando uma amostragem aleatória do conjuntos de dados
train_sample = trainFeatures[bfRf].sample(n=20000, random_state=59)
# Selecionando uma amostragem aleatória do conjuntos de dados
target_sample = trainTarget.sample(n=20000, random_state=59)
# Treinamento
start = time.time()
modelo_svm_v1.fit(train_sample, target_sample)
end = time.time()
print('Tempo de Treinamento do Modelo:', end - start)
# Selecionando uma amostragem aleatória do conjuntos de dados
test_sample = testFeatures[bfRf].sample(n=10000, random_state=59)
# Previsões
previsoes_v1 = modelo_svm_v1.predict(test_sample)
# Selecionando uma amostragem aleatória do conjuntos de dados
test_target_sample = testTarget.sample(n=10000, random_state=59)
#y_class = np.argmax(y_pred, axis = 0)
# Dicionário de métricas e metadados
SVM_dict_v1 = {'Modelo':'SVM',
'Versão':'1',
'Kernel':'Linear com dados normalizados',
'Precision':precision_score(previsoes_v1, test_target_sample, average='weighted'),
'Recall':recall_score(previsoes_v1, test_target_sample, average='weighted'),
'F1 Score':f1_score(previsoes_v1, test_target_sample, average='weighted'),
'Acurácia':accuracy_score(previsoes_v1, test_target_sample)},
#'AUC':roc_auc_score(test_target_sample, previsoes_v1, average='weighted', multi_class='ovo')}
# Print
print("Métricas em Teste:\n")
SVM_dict_v1
As funções de Kernel são usadas para mapear o conjunto de dados original (linear / não linear) em um espaço dimensional mais alto, com vista a torná-lo linear. O Kernel Linear, Polinomial e RBF (ou Gaussiano) são simplesmente diferentes opções para estabelecer o limite de decisão do hiperplano entre as classes. Geralmente, os Kernels ineares e Polinomiais consomem menos tempo e fornecem menos precisão do que os Kernels RBF.
O Kernel RBF é o mais amplamente usado ao treinar modelos SVM e dois Hiperparâmetros nos ajudam a ajustar o modelo ideal: C e gama. Intuitivamente, o parâmetro gama define até que ponto a influência de um único exemplo de treinamento alcança, com valores baixos significando 'longe' e valores altos significando 'próximos'. Os parâmetros gama podem ser vistos como o inverso do raio de influência das amostras selecionadas pelo modelo como vetores de suporte. O parâmetro C negocia a lassificação correta dos exemplos de treinamento contra a maximização da margem da função de decisão.
Para valores maiores de C, uma margem menor será aceita se a função de decisão for melhor na classificação correta de todos os pontos de treinamento. Um C mais baixo incentivará uma margem maior, portanto, uma função de decisão mais simples, ao custo da precisão do treinamento. Em outras palavras, “C” se comporta como um parâmetro de regularização no SVM
# Cria o modelo
modelo_svm_v2 = svm.SVC(kernel = 'rbf')
# Valores para o grid
C_range = np.array([50., 100., 200.])
gamma_range = np.array([0.3*0.001,0.001,3*0.001])
# Grid de hiperparâmetros
svm_param_grid = dict(gamma = gamma_range, C = C_range)
# Grid Search
modelo_svm_v2_grid_search_rbf = GridSearchCV(modelo_svm_v2, svm_param_grid, cv = 3)
# Treinamento
start = time.time()
modelo_svm_v2_grid_search_rbf.fit(train_sample, target_sample)
end = time.time()
print('Tempo de Treinamento do Modelo com Grid Search:', end - start)
print("")
# Acurácia em Treino
print(f"Acurácia em Treinamento: {modelo_svm_v2_grid_search_rbf.best_score_ :.2%}")
print("")
print(f"Hiperparâmetros Ideais: {modelo_svm_v2_grid_search_rbf.best_params_}")
# Previsões
previsoes_v2 = modelo_svm_v2_grid_search_rbf.predict(test_sample)
# Dicionário de métricas e metadados
SVM_dict_v2 = {'Modelo':'SVM',
'Versão':'2',
'Kernel':'RBF com dados normalizados',
'Precision':precision_score(previsoes_v2, test_target_sample, average='weighted'),
'Recall':recall_score(previsoes_v2, test_target_sample, average='weighted'),
'F1 Score':f1_score(previsoes_v2, test_target_sample, average='weighted'),
'Acurácia':accuracy_score(previsoes_v2, test_target_sample)},
#'AUC':roc_auc_score(test_target_sample, previsoes_v2)}
# Print
print("Métricas em Teste:\n")
SVM_dict_v2
# Cria o modelo
modelo_v3 = svm.SVC(kernel = 'poly')
# Valores para o grid
r_range = np.array([0.5, 1])
gamma_range = np.array([0.001, 0.01])
d_range = np.array([2, 3, 4])
# Grid de hiperparâmetros
param_grid_poly = dict(gamma = gamma_range, degree = d_range, coef0 = r_range)
# Grid Search
modelo_v3_grid_search_poly = GridSearchCV(modelo_v3, param_grid_poly, cv = 3)
# Treinamento
start = time.time()
modelo_v3_grid_search_poly.fit(train_sample, target_sample)
end = time.time()
print('Tempo de Treinamento do Modelo com Grid Search:', end - start)
# Acurácia em Treino
print(f"Acurácia em Treinamento: {modelo_v3_grid_search_poly.best_score_ :.2%}")
print("")
print(f"Hiperparâmetros Ideais: {modelo_v3_grid_search_poly.best_params_}")
# Previsões
previsoes_v3 = modelo_v3_grid_search_poly.predict(test_sample)
# Dicionário de métricas e metadados
SVM_dict_v3 = {'Modelo':'SVM',
'Versão':'3',
'Kernel':'Polinomial com dados normalizados',
'Precision':precision_score(previsoes_v3, test_target_sample, average='weighted'),
'Recall':recall_score(previsoes_v3, test_target_sample, average='weighted'),
'F1 Score':f1_score(previsoes_v3, test_target_sample, average='weighted'),
'Acurácia':accuracy_score(previsoes_v3, test_target_sample)},
#'AUC':roc_auc_score(testTarget, previsoes_v3)}
# Print
print("Métricas em Teste:\n")
SVM_dict_v3
# Criando dataframes com os resultados dos modelos
df1 = pd.DataFrame.from_dict(SVM_dict_v1)
df2 = pd.DataFrame.from_dict(SVM_dict_v2)
df3 = pd.DataFrame.from_dict(SVM_dict_v3)
# Concatenando os dataframes
resumo_svm = pd.concat([df1, df2, df3], axis = 0)
# Exibe o df
display(resumo_svm)
end_notebook = time.time()
print('Tempo de Execução do Notebook:', end_notebook - start_notebook)
Versão | Editor | Data | Observação |
---|---|---|---|
1.0 | Eduardo Gonçalves | 05/06/2021 | Primeira versão do projeto. |