# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     name: python3
# ---

# + [markdown] id="dvosFKszd4FQ"
# # **Machine Learning - case: estilo musical**

# + [markdown] id="ofrAoZQ9NpfC"
# #### **Importando as bibliotecas necessárias**

# + id="r0TVvSNAMakd"
import sklearn
import pandas as pd
import numpy as np
# para ignorar os avisos de mensagens das funções
import warnings
warnings.filterwarnings("ignore")

# pacote para trabalhar com data frame (tabelas)
import pandas as pd
# pacote mais básico para vizualização gráfica
import matplotlib.pyplot as plt
# um dos pacotes para fazer gráficos
import seaborn as sns
# sklearn - pacote análise de dados
# existe grande parte dos métodos mais famosos
from sklearn.model_selection import train_test_split
# função para fazer avaliação dos modelos
from sklearn.metrics import classification_report

# + [markdown] id="_aCnz7Ooa4Tt"
# #### **Explicação da base de dados**
#
# * **Base de dados**: devido à natureza artística da música, as classificações são frequentemente arbitrárias e controversas, e alguns gêneros podem se sobrepor.
# * **Variáveis**:
#   * <u>filename</u> - nome do arquivo conforme fornecido no conjunto de dados marsyas;
#   * <u>tempo</u> - a velocidade com que uma passagem de música é tocada;
#   * <u>beats</u> - unidade rítmica na música;
#   * <u>chroma_stft</u> - transformada de Fourier de curto tempo;
#   * <u>rmse</u> - erro de raiz quadrada média;
#   * <u>spectral_centroid</u> - indica onde o "centro de massa" do espectro está localizado;
#   * <u>spectral_bandwidth</u> - é o intervalo de comprimento de onda em que uma quantidade espectral irradiada não é inferior a metade de seu valor máximo;
#   * <u>rolloff</u> - roll-off é a inclinação de uma função de transmissão com frequência;
#   * <u>zero_crossing_rate</u> - a taxa na qual o sinal muda de positivo para negativo ou de volta;
#   * <u>mfcc1 a mfcc20</u> - coeficientes cepstrais de frequência de Mel (MFCCs) são coeficientes que coletivamente constituem um MFC;
#   * <u>label</u> - o estilo musical da música.
# * **Objetivo**: treinar uma modelo e saiba a qual gênero sua música favorita pertence.
#   * A variável resposta será: label (nome do estilo musical).
# * **Técnica usada**: modelos ensembles: Bagging, Random Forest, AdaBoost, Gradiente Estocástico Boosting e Voting Ensemble.
#
# [base de dados](https://www.kaggle.com/insiyeah/musicfeatures)

# + [markdown] id="osvPPHa0a4UQ"
# #### **Carregando os dados**

# + id="kYXkBU76dTsn" colab={"base_uri": "https://localhost:8080/"} outputId="82d65ef3-8ef5-48d0-b26e-dbd19dca4739"
from google.colab import drive
drive.mount('/content/drive')

# + id="B_EXLQNwa4UR" colab={"base_uri": "https://localhost:8080/"} outputId="ab2f000b-22da-4492-9a4f-50c43e37bef1"
df = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/Estagio_TAO_Python/Datasets/data_music.csv', sep = ",")

# tamanho da base de dados
print(df.shape)

# + [markdown] id="6wYu8UDLmbJr"
# Temos na base 30 variáveis, sendo 29 variáveis explciativas ($X$) e 1 variável resposta ($y$). Em cada linha temos dados de uma música.

# + id="nNH1eSkD-5m5" colab={"base_uri": "https://localhost:8080/", "height": 223} outputId="26d9b9e6-93d7-402b-a1e3-c3ffb752e36c"
# vizualizando as cinco primeiras linhas da base de dados
df.head(5)

# + id="KJtGI5HD4Fru" colab={"base_uri": "https://localhost:8080/"} outputId="9e84bc9c-fd35-4ae6-e53b-e250c36018c2"
df.label.unique()

# + [markdown] id="ocLsSkr5mnwc"
# Nesta base de dados sobre música temos 10 estilos musicais, mostrados acima.

# + [markdown] id="H8gO9oww0cDM"
# #### **Informações da base de dados**

# + [markdown] id="55ltrJS0jvFT"
# **Informações sobre os tipos das variáveis da base de dados**

# + id="ufotTlW---BG" colab={"base_uri": "https://localhost:8080/"} outputId="7aa82993-b884-4ca8-be0a-0d273f7ad692"
df.info()

# + [markdown] id="8Gy6GvkQm3cC"
# A base de dados tem 1000 linhas de dados, não havendo dados faltantes. A maiori dos dados é numérico (inteiro ou real), com exceção da label que é a variável resposta que contém o estilo musical da música e do filename, que tem o código da música.

# + [markdown] id="KDFdwlvbPqSP"
# **Quantidade de dados por estilo musical**

# + id="j8CyQXWcPAD7" colab={"base_uri": "https://localhost:8080/", "height": 357} outputId="75151014-cbed-4dab-860f-2c181b7a2aa2"
geral = pd.DataFrame([df['label'].value_counts(normalize = False), df['label'].value_counts(normalize = True)*100]).T
geral.columns = ['valor', 'proporção']
geral

# + [markdown] id="TdmR5NGAnppy"
# Verificamos que as classes referente ao estilo musical tem mesma proporção de dados.

# + [markdown] id="fXnr0t6UFdoR"
# #### **Análise descritiva dos dados**

# + [markdown] id="lgBDTkU5oHZr"
# A seguir temos as estatísticas de cada variável da base de dados.

# + id="X7iHz2pzFdoT" colab={"base_uri": "https://localhost:8080/", "height": 911} outputId="f03208c0-d770-4da3-c1ac-e7621d6fcc26"
df.describe().T

# + [markdown] id="NT8cxXj-FdoV"
# **correlação entre as variáveis**

# + id="ruE2atf8FdoV" colab={"base_uri": "https://localhost:8080/", "height": 630} outputId="1ff8a882-e635-42b6-dae9-fbdc414ad875"
corr = df.corr(method = 'spearman')
corr.style.background_gradient(cmap='coolwarm')

# + [markdown] id="0PitKbBMoPir"
# * Com a matriz de correlação, podemos notar que há grande relação entre a vaariável tempo que se refere a velocidade da música e tempo que é o tempo total da música, o que instintivamente se espera porque o tempo total da música depende da velocidade.
#
# * Também verificamos correlação das variáveis "spectral_centroid", "spectral_bandwidth", "rolloff", "zero_crossing_rate", "mfcc1" com as variáveis "spectral_bandwidth", "rolloff", "zero_crossing_rate" entre si. O que referência a onda sonora e o espectro da onda, como as variáveis tem referência a aspectos semelhantes, faz sentido tem correlação entre estas variáveis.
#
# * Há outras correlações que são grande, mas nada que se deve ter um estudo separado.

# + [markdown] id="eNGvvYvLFdoW"
# **Gráfico box plot para verificar existência de outliers**

# + id="pZnDFMIr7PS1" colab={"base_uri": "https://localhost:8080/", "height": 279} outputId="18659caf-5dc4-4277-e4d9-983bf3f6d442"
sns.boxplot(x = 'value', y = 'variable', data = df[['spectral_centroid', 'spectral_bandwidth',
                                                   'rolloff']].melt())
plt.show()

# + id="3PL6vLSY6oDz" colab={"base_uri": "https://localhost:8080/", "height": 279} outputId="af7722dc-73a2-4a51-905c-4ec2a4fd7f49"
sns.boxplot(x = 'value', y = 'variable', data = df[['mfcc1']].melt())
plt.show()

# + id="x728L2B97bKr" colab={"base_uri": "https://localhost:8080/", "height": 279} outputId="73076d95-5fde-4718-bd0c-5d7b6a30aaa0"
sns.boxplot(x = 'value', y = 'variable', data = df[['tempo', 'mfcc2']].melt())
plt.show()

# + id="Y40GmKYdFdoX" colab={"base_uri": "https://localhost:8080/", "height": 279} outputId="0a59ef1a-6daa-4d6c-8154-a4075129aeca"
sns.boxplot(x = 'value', y = 'variable', data = df.drop(['filename', 'label', 'tempo', 'mfcc2',
                                                         'spectral_centroid', 'spectral_bandwidth',
                                                         'rolloff', 'mfcc1'], axis = 1).iloc[:, 0:28].melt())
plt.show()

# + [markdown] id="7v_9PPioKSOY"
# Pelos bloxplot acima verificamos que existe outliers na marioria das variáveis. Para remover os outliers utilizamos o código a seguir. Neste código removemos os valores abaixo de $Q1 - 1.5 IQR$ e acima de $Q3 + 1.5 IQR$, para cada uma das variáveis.

# + id="jKdgbCC2lQT-"
for i in range(0, 26):
  data = df.drop(['filename', 'label'], axis = 1)
  name_column = data.columns[i]
  Q1 = data.describe().unstack()[name_column, '25%']
  Q3 = data.describe().unstack()[name_column, '75%']
  IQR = Q3 - Q1
  df_extra = np.array(data[name_column].values.tolist())
  df[name_column] = np.where(df_extra < Q1 - 1.5 * IQR, data.iloc[:, i].mean(), df_extra).tolist()
  df[name_column] = np.where(df_extra > Q3 + 1.5 * IQR, data.iloc[:, i].mean(), df_extra).tolist()

# + id="9OxKtTIc8YqR" colab={"base_uri": "https://localhost:8080/", "height": 279} outputId="25f102ce-2e2b-462f-862c-3f6f499b50df"
sns.boxplot(x = 'value', y = 'variable', data = df[['spectral_centroid', 'spectral_bandwidth',
                                                   'rolloff']].melt())
plt.show()

# + id="CwSNJzuQ8YqU" colab={"base_uri": "https://localhost:8080/", "height": 279} outputId="337bb8aa-0545-4290-f91a-1785c23bf2d7"
sns.boxplot(x = 'value', y = 'variable', data = df[['mfcc1']].melt())
plt.show()

# + id="V2woTit68YqV" colab={"base_uri": "https://localhost:8080/", "height": 279} outputId="0eeec82a-02c3-4c00-aadb-e3225b527468"
sns.boxplot(x = 'value', y = 'variable', data = df[['tempo', 'mfcc2']].melt())
plt.show()

# + id="P0x8U1PP8YqW" colab={"base_uri": "https://localhost:8080/", "height": 279} outputId="6edaa982-8a3e-44de-c819-fea60e6d674d"
sns.boxplot(x = 'value', y = 'variable', data = df.drop(['filename', 'label', 'tempo', 'mfcc2',
                                                         'spectral_centroid', 'spectral_bandwidth',
                                                         'rolloff', 'mfcc1'], axis = 1).iloc[:, 0:28].melt())
plt.show()

# + [markdown] id="G-6hXuBFLPe9"
# A maioria dos outliers foram removidos.

# + [markdown] id="qKXxrWKDYrx5"
# #### Normalizando as variáveis

# + [markdown] id="L8ud55j3qcH7"
# Neste passo separamos a variável explicativa ($X$) da variável resposta ($y$). Em seguinda normalizamos as variáveis, usando 'StandardScaler', para que fiquem na mesma escala.

# + id="cXQkI926h2e5"
X = df.drop(['filename', 'label'], axis = 1)
y = df['label']

# + id="pBfjgrOo-tJh" colab={"base_uri": "https://localhost:8080/"} outputId="23fb05da-2070-4874-b5f4-b2fa76a8f13b"
X.info()

# + id="gbEW7yunYwRV"
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X = scaler.fit_transform(X)

X = pd.DataFrame(X, columns = df.drop(['filename', 'label'], axis = 1).columns)

# + [markdown] id="pyXrKMtldQ6g"
# #### **Análise de Componentes Principais (PCA)**

# + [markdown] id="U2QQ1lAHr7P8"
# Usamos a análise de componentes principais para reduzir o tamanho da base de dados.

# + id="mEq3pPyJRE2S"
from sklearn.decomposition import PCA
# escolhendo número de dimensões
pca = PCA()
pca.fit(X)
cumsum = np.cumsum(pca.explained_variance_ratio_)
d = np.argmax(cumsum >= 0.99999999) + 1

# + id="cOLA5TB_Spez" colab={"base_uri": "https://localhost:8080/", "height": 279} outputId="f87a3205-b3e9-4853-df5a-651cb471b0f7"
plt.plot(cumsum)
plt.ylabel('Variância explicada')
plt.xlabel('Dimensões')
plt.show()

# + id="Q3ZIeFjodQdZ"
from sklearn.decomposition import PCA
pca = PCA(n_components = d)
principalComponents = pca.fit_transform(X)
X = pd.DataFrame(data = principalComponents) #,  columns = ['principal component 1', 'principal component 2'])

# + [markdown] id="D3JlW6Nrh72o"
# #### **Dados em treinamento e teste**

# + [markdown] id="YQT7836ssRkr"
# Separamos dividimos os dados em dados de treinamento e dados de teste, sendo 30% para teste e 70% para treinamento.

# + id="lyU4IEWDNSOa"
# todas as colunas da base de dados
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, shuffle = 'False', random_state = 376)

# + [markdown] id="PytgdNvGBWnN"
# #### **Treinamento dos modelos Ensemble**

# + [markdown] id="T3WDOeL2setE"
# * Agora com os dados organizados e arrumados aplicamos os modelos Ensemble.
#
# * Os modelos usados são os modelos ensemble. Os modelos ensemble são técnicas avançadas para resolver problemas conplexos, em que modelos independentes são conbinados para se conseguir um resultado melhor. A relação dos modelos usados é a seguinte:
#   * Bagging;
#   * Random Forest;
#   * AddaBoost;
#   * Gradiente Estocástico Boosting;
#   * Voting Ensemble.
#
# * Em cada aplicação de modelo, são apresentados os melhores modelos parâmetros usados em cada modelo ou o melhor modelo com seus parâmetros como no caso do modelo Voting Ensemble.

# + [markdown] id="9n2DKzF9sutb"
# ##### **Modelo Bagging**

# + id="gDhmQobB9vfJ" colab={"base_uri": "https://localhost:8080/", "height": 1000} outputId="86dd86e3-bcea-43b6-b276-d7ddb8348ce3"
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier
from sklearn import model_selection

kfold = model_selection.KFold(n_splits = 10, random_state = 376)
model_1 = BaggingClassifier(base_estimator = DecisionTreeClassifier(), n_estimators = 100, random_state = 376)

print(model_1.fit(X_train, y_train), '\n')

# predizendo a nota de novos alunos
y_pred = model_1.predict(X_test)

from sklearn.metrics import accuracy_score, confusion_matrix, classification_report

results_1 = accuracy_score(y_test, y_pred)
print('Acurácia modelo Bagging: {}.'.format(results_1))

print("Melhores parâmetros:")
print(model_1.base_estimator, '\n')

cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot = True)
plt.show()

print(classification_report(y_test, y_pred))

# + [markdown] id="oLZ9xWsSszjC"
# ##### **Random Forest Classification**

# + id="cJDtAyet_aDZ" colab={"base_uri": "https://localhost:8080/", "height": 853} outputId="d1084a39-292e-4440-f939-cd5a91a2bed8"
from sklearn.ensemble import RandomForestClassifier

kfold = model_selection.KFold(n_splits = 10, random_state = 376)
model_rf = RandomForestClassifier(n_estimators = 100, max_features = 5)

print(model_rf.fit(X_train, y_train), '\n')

# predizendo a nota de novos alunos
y_pred = model_rf.predict(X_test)

from sklearn.metrics import accuracy_score, confusion_matrix, classification_report

results_rf = accuracy_score(y_test, y_pred)
print('Acurácia modelo Random Forest: {}.'.format(results_rf))

print("Melhores parâmetros:")
print(model_rf.base_estimator, '\n')

cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot = True)
plt.show()

print(classification_report(y_test, y_pred))

# + [markdown] id="80QNwCr2s3Qy"
# ##### **Modelo AdaBoost**

# + id="X2_YCYO6_aqd" colab={"base_uri": "https://localhost:8080/", "height": 672} outputId="ac430e9d-3558-47d8-cb71-01fac2a797b1"
from sklearn.ensemble import AdaBoostClassifier

kfold_ada = model_selection.KFold(n_splits = 10, random_state = 376)
model_ada = AdaBoostClassifier(n_estimators = 30, random_state = 376)

print(model_ada.fit(X_train, y_train), '\n')

# predizendo a nota de novos alunos
y_pred = model_ada.predict(X_test)
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report

results_ada = accuracy_score(y_test, y_pred)
print('Acurácia modelo AdaBoost: {}.'.format(results_ada))

print("Melhores parâmetros:")
print(model_ada.base_estimator, '\n')

cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot = True)
plt.show()

print(classification_report(y_test, y_pred))

# + [markdown] id="KxrVm5AXs6It"
# ##### **Modelo Gradiente Estocástico Boosting**

# + id="wZHzKobd_ata" colab={"base_uri": "https://localhost:8080/", "height": 954} outputId="d2165e84-a01b-4cf5-9ef5-afb4a4c86d4e"
from sklearn.ensemble import GradientBoostingClassifier

kfold_sgb = model_selection.KFold(n_splits = 10, random_state = 376)
model_sgb = GradientBoostingClassifier(n_estimators = 100, random_state = 376)

print(model_sgb.fit(X_train, y_train), '\n')

# predizendo a nota de novos alunos
y_pred = model_sgb.predict(X_test)

from sklearn.metrics import accuracy_score, confusion_matrix, classification_report

results_sgb = accuracy_score(y_test, y_pred)
print('Acurácia modelo Gradiente Estocástico Boosting: {}.'.format(results_sgb))

print("Melhores parâmetros:")
print(model_sgb.get_params, '\n')

cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot = True)
plt.show()

print(classification_report(y_test, y_pred))

# + [markdown] id="hlrnUVMMs98t"
# ##### **Modelo Voting Ensemble**

# + id="xy9OL7lh_n2q" colab={"base_uri": "https://localhost:8080/", "height": 1000} outputId="8c69757a-fef3-4539-ee6b-7b1a45343526"
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.ensemble import VotingClassifier

kfold_vc = model_selection.KFold(n_splits = 10, random_state = 376)
# Lines 2 to 8
estimators = []
mod_lr = LogisticRegression()
estimators.append(('logistic', mod_lr))
mod_dt = DecisionTreeClassifier()
estimators.append(('cart', mod_dt))
mod_sv = SVC()
estimators.append(('svm', mod_sv))
 
# Lines 9 to 11
ensemble = VotingClassifier(estimators)
results_vc = model_selection.cross_val_score(ensemble, X, y, cv = kfold_vc)
print(results_vc.mean())

from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.ensemble import VotingClassifier

kfold_vc = model_selection.KFold(n_splits = 10, random_state = 376)
# Lines 2 to 8
estimators = []
mod_lr = LogisticRegression()
estimators.append(('logistic', mod_lr))
mod_dt = DecisionTreeClassifier()
estimators.append(('cart', mod_dt))
mod_sv = SVC()
estimators.append(('svm', mod_sv))

# Lines 9 to 11
ensemble = VotingClassifier(estimators)
print(ensemble.fit(X_train, y_train), '\n')

# predizendo a nota de novos alunos
y_pred = ensemble.predict(X_test)

from sklearn.metrics import accuracy_score, confusion_matrix, classification_report

results_vc = accuracy_score(y_test, y_pred)
print('Acurácia modelo Voting Ensemble: {}.'.format(results_vc))

print("Melhores parâmetros:")
print(ensemble.named_estimators_, '\n')

cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot = True)
plt.show()

print(classification_report(y_test, y_pred))

# + [markdown] id="xcKTDYbFNDLd"
# #### **Resumo dos modelos**

# + [markdown] id="risO09FzvARt"
# Por último apresentamos os resultados da acurácia dos modelos em forma de tabela e gráfico.

# + id="eB4eYlKF_n5E" colab={"base_uri": "https://localhost:8080/", "height": 203} outputId="7c2c6009-afd5-47ae-8dd6-dafd9ff672e6"
import pandas as pd

results_ac = []
results_ac.append(round(results_1.mean(), 4))
results_ac.append(round(results_rf.mean(), 4))
results_ac.append(round(results_sgb.mean(), 4))
results_ac.append(round(results_ada.mean(), 4))
results_ac.append(round(results_vc.mean(), 4))
names = ['Bagging', 'Random Forest', 'Boosting Adaptável', 'AdaBoost', 'Voting Ensemble']
results_final = pd.DataFrame([names, results_ac]).T
results_final.columns = ['Modelo Ensemble', 'Acurácia']
results_final
results_final.sort_values(['Acurácia'], ascending = False)

# + id="ZzV8kMM__n7o" colab={"base_uri": "https://localhost:8080/", "height": 281} outputId="4ab8dbc5-82e2-4758-87bc-c0546601424d"
plt.scatter(results_final['Acurácia'], results_final['Modelo Ensemble'])
for i in range(0, len(results_final['Acurácia'])):
  plt.annotate(results_final['Acurácia'][i], xy = (results_final['Acurácia'][i], 0.05 + i),
               xytext = (results_final['Acurácia'][i] - 0.14, -0.08 + i))
plt.title('Acurácia dos modelos Ensemble')
axes = plt.gca()
axes.set_xlim([0, 1])
# plt.set_ylim([ymin,ymax])
plt.show()

# + [markdown] id="YSkss1PTvGy9"
# * Pelos resultados o melhor modelo é o Voting Ensemble com $63.00%$ de acurácia, neste modelo utiliza-se os modelos Regressão Logística, Árvore de Decisão e Máquina de Vetor Suporte (SVM). Apesar disso o modelo Random Forest também teve acurácia próxima. E o pior foi o modelo AdaBoost com acurácia de $15.33\%$.
#
# * Apesar do modelo Voting Ensemble se apresentar melhor entre os modelos apresentados, pode haver modelos melhores. Porém, o objetivo do estudo foi a aplciação dos métodos Ensemble.

StarcoderdataJupyterScriptsDedupFiltered