05.4 RRNN - Ejercicio Wine

Ejercicio de redes neuronales para estudiar características vinícolas

El análisis de productos alimenticios y, en particular, las bebidas alcohólicas resulta de gran interés.

Utilizar redes neuronales para estudiar un conjunto de datos relativos a las caracterísitcas de unos vinos que han sido producidos en tres regiones italianas. Una versión de estos datos se puede encontrar en el repositorio de la Universidad de California Irvine (UCI):

http://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data

También se puede descargar una copia .csv de este fichero wine.csv en Moodle.

Este archivo contiene los datos de trece atributos del vino y una columna que informa de su región de procedencia. En el primer ejemplo de esta práctica cargamos el fichero y damos un nombre a cada una de las columnas.

import numpy as np
import pandas as pd

Carga de datos a partir de CSV

Como el archivo no incluye los nombres de las columnas se asigna el nombre a partir de una lista con el parámetro names de read_csv

ColNames = ["Cultivars","Alcohol","Malic_acid","Ash","Alcalinity_of_ash",
"Magnesium","Total_phenols","Flavanoids","Nonflavanoid_phenols",
"Proanthocyanins","Color intensity","Hue","OD280/OD315","Proline"]
df = pd.read_csv('data/wine.csv', header=None, names=ColNames)
df.head()
Cultivars Alcohol Malic_acid Ash Alcalinity_of_ash Magnesium Total_phenols Flavanoids Nonflavanoid_phenols Proanthocyanins Color intensity Hue OD280/OD315 Proline
0 1 14.23 1.71 2.43 15.6 127 2.80 3.06 0.28 2.29 5.64 1.04 3.92 1065
1 1 13.20 1.78 2.14 11.2 100 2.65 2.76 0.26 1.28 4.38 1.05 3.40 1050
2 1 13.16 2.36 2.67 18.6 101 2.80 3.24 0.30 2.81 5.68 1.03 3.17 1185
3 1 14.37 1.95 2.50 16.8 113 3.85 3.49 0.24 2.18 7.80 0.86 3.45 1480
4 1 13.24 2.59 2.87 21.0 118 2.80 2.69 0.39 1.82 4.32 1.04 2.93 735

Se estándariza el conjunto de datos de entrada

Para lo que se hace uso de la librería StandardScaler de sklearn. Si además hubiese algún atributo etiquetado sin valores continuos previamente a la estandarización se etiquetarían estas columnas del dataset haciendo uso de la librería LabelEncoder de sklearn.preprocessing.

## from sklearn.preprocessing import LabelEncoder
## le = LabelEncoder()
## df("campo-etiquetado") = le.fit_transform(df("campo-etiquetado"))
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
df[["Alcohol","Malic_acid","Ash","Alcalinity_of_ash", "Magnesium","Total_phenols","Flavanoids","Nonflavanoid_phenols",
"Proanthocyanins","Color intensity","Hue","OD280/OD315","Proline"]] = sc.fit_transform(df[["Alcohol",
"Malic_acid","Ash","Alcalinity_of_ash", "Magnesium","Total_phenols","Flavanoids",
"Nonflavanoid_phenols", "Proanthocyanins","Color intensity","Hue","OD280/OD315","Proline"]])
df.head()
Cultivars Alcohol Malic_acid Ash Alcalinity_of_ash Magnesium Total_phenols Flavanoids Nonflavanoid_phenols Proanthocyanins Color intensity Hue OD280/OD315 Proline
0 1 1.518613 -0.562250 0.232053 -1.169593 1.913905 0.808997 1.034819 -0.659563 1.224884 0.251717 0.362177 1.847920 1.013009
1 1 0.246290 -0.499413 -0.827996 -2.490847 0.018145 0.568648 0.733629 -0.820719 -0.544721 -0.293321 0.406051 1.113449 0.965242
2 1 0.196879 0.021231 1.109334 -0.268738 0.088358 0.808997 1.215533 -0.498407 2.135968 0.269020 0.318304 0.788587 1.395148
3 1 1.691550 -0.346811 0.487926 -0.809251 0.930918 2.491446 1.466525 -0.981875 1.032155 1.186068 -0.427544 1.184071 2.334574
4 1 0.295700 0.227694 1.840403 0.451946 1.281985 0.808997 0.663351 0.226796 0.401404 -0.319276 0.362177 0.449601 -0.037874

Se divide el conjunto de datos de entrada en Entrenamiento (70%) y Validación (30%). Conjuntos Train y Test

from sklearn.model_selection import train_test_split
X, y = df.values[:,1:14], df.values[:,0]
X_train, X_test, y_train, y_test =train_test_split(X, y, test_size=0.3, random_state=0, stratify=y)
y_train
array([3., 1., 1., 1., 3., 2., 2., 3., 2., 2., 2., 1., 2., 3., 1., 3., 2.,
       1., 3., 3., 2., 1., 2., 2., 2., 2., 3., 1., 2., 2., 1., 1., 3., 1.,
       2., 1., 1., 2., 3., 3., 1., 3., 3., 3., 1., 2., 3., 3., 2., 3., 2.,
       2., 2., 1., 2., 2., 3., 3., 2., 1., 1., 2., 3., 3., 2., 1., 2., 2.,
       2., 1., 1., 1., 1., 1., 3., 1., 2., 3., 2., 2., 3., 1., 2., 1., 2.,
       2., 3., 2., 1., 1., 1., 3., 2., 1., 1., 2., 2., 3., 3., 2., 1., 1.,
       2., 2., 3., 1., 3., 1., 2., 2., 2., 2., 1., 3., 1., 1., 1., 1., 2.,
       2., 3., 3., 2., 2.])

Efectuar el entrenamiento con el Perceptron multicapa (Multilayer perceptron - MLP)

La librería sk-learn en el módulo neural_network implementa el perceptron multicapa en la clas MLPClassifier.

Los parámetros del constructor de la clase MLPClassifier son:

  • hidden_layer_sizes : Este parámetro permite establecer el número de capas y el número de nodos que se desean tener en el clasificador de redes neuronales. Cada elemento de la tupla representa el número de nodos en la i-ésima posición, donde i es el índice de la tupla. Por tanto, la longitud de la tupla denota el número total de capas ocultas en la red.

  • max_iter : número de épocas de entrenamiento.

  • activation : función de activación de las capas ocultas.

  • solver : algoritmo empleado en la optimización de los pesos de los nodos.

  • random_state : establece una semilla para reproducir los mismos resultados.

len(X_train[0]), np.unique(y)
(13, array([1., 2., 3.]))

El Perceptron va a tener 13 neuronas de entrada (i) y 3 de salida (o)

Si se usa el criterio para la primera predeterminación del nº de neuronas de la capa oculta:

\[h =\frac{2(i+o)}{3}\]

Resulta un primer valor de h=10 que podemos ir subiendo de uno en uno mejorando el score

Probando, encontramos el mejor score en h=13

## Importación de la clase del perceptrón multicapa
from sklearn.neural_network import MLPClassifier
## Inicialización y creación del objeto clasificador
mlp = MLPClassifier(hidden_layer_sizes=(13), max_iter=500,activation = 'logistic',solver='lbfgs',random_state=1)
## Entrenamiento de la red
mlp.fit(X_train, y_train)
MLPClassifier(activation='logistic', hidden_layer_sizes=13, max_iter=500,
              random_state=1, solver='lbfgs')
print("Exactitud del conjunto de entrenamiento: {:.3f}".format(mlp.score(X_train, y_train)))
print("Exactitud del conjunto de prueba: {:.3f}".format(mlp.score(X_test, y_test)))
Exactitud del conjunto de entrenamiento: 1.000
Exactitud del conjunto de prueba: 1.000