Acontinuación se realizará una clasificación binaria para predecir en base a las variables si un paciente con un determinado número de medidas médicas es susceptible de tener enfermedad de corazón o no.
La clasificación se considerará satisfactoria si alcanza una exactitud de 0.9.
Para ello se realizará un análisis exploratorio de las variables evaluando que variables aportan a la predicción, posteriormente se dividirán los datos en conjunto de entrenamiento (80%) y conjunto de validación (20%).
Con esto se realizarán diversos algoritmos de clasificación binaria mediante ternsorflow, donde el entrenamiento se realizará utilizando validación cruzada aleatoria (en cada algoritmo hay una descripción del procedimiento utilizado).
Finalmente la comparación de los algoritmos se relizará con la exactitud de cada algoritmo sobre el conjunto de validación.
Esta base de datos contiene 76 atributos, pero todos los experimentos publicados se refieren al uso de un subconjunto de 14 de ellos. En particular, la base de datos de Cleveland es la única que los investigadores de ML han utilizado hasta la fecha. El campo "objetivo" se refiere a la presencia de enfermedad cardíaca en el paciente. Tiene un valor entero de 0 (sin presencia) a 4.
Información del atributo:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import tensorflow as tf
import requests
from sklearn.preprocessing import normalize
import os.path
import csv
data_file_name = "heart.csv"
data = []
with open(data_file_name, newline='') as csvfile:
csv_reader = csv.reader(csvfile)
data_header = next(csv_reader)
for row in csv_reader:
data.append(row)
data_header[0] = 'age'
pd.DataFrame(data, columns=data_header).head(10)
# Transformación de datos de string a float.
x_vals00 = np.array([[float(x[i]) for i in range(np.shape(data)[1])] for x in data])
x_vals0 = np.array([[float(x[i]) for i in range(np.shape(data)[1]-1)] for x in data])
y_vals = np.array([float(x[(np.shape(data)[1]-1)]) for x in data])
df = pd.DataFrame(x_vals00, columns=data_header[0:(np.shape(data)[1])])
df.head(10)
# Gráfico del Variable vs Variable
graf = pd.plotting.scatter_matrix(df, figsize=(20,20), alpha = 0.5)
[plt.setp(item.yaxis.get_majorticklabels(), 'size', 10) for item in graf.ravel()]
[plt.setp(item.xaxis.get_majorticklabels(), 'size', 10) for item in graf.ravel()]
[plt.setp(item.yaxis.get_label(), 'size', 20) for item in graf.ravel()]
[plt.setp(item.xaxis.get_label(), 'size', 20) for item in graf.ravel()]
plt.show()
De acuerdo a los datos vistos se observan varias columnas con datos categóricos. De acuerdo a lo anterior se crearán variables auxiliares para las siguientes variables:
data_header_new = ['age', 'sex', 'cp1', 'cp2', 'cp3', 'trestbps', 'chol', 'fbs', 'restecg1', 'restecg2', 'thalach',
'exang', 'oldpeak', 'slope1', 'slope2', 'ca1', 'ca2', 'ca3', 'ca4', 'thal1', 'thal2', 'thal3', 'target']
x_vals = np.array([[x[0], x[1], x[2]==1, x[2]==2, x[2]==3, x[3], x[4], x[5], x[6]==1, x[6]==2, x[7], x[8], x[9],
x[10]==1, x[10]==2, x[11]==1, x[11]==2, x[11]==3, x[11]==4, x[12]==1, x[12]==2, x[12]==3 ]
for x in x_vals0])
pd.DataFrame(x_vals, columns=data_header_new[0:(len(data_header_new)-1)]).head(10)
# dividir datos en conjunto de entrenamiento y validación
f_train_valid = 0.8
np.random.seed(123)
train_idx = np.random.choice(len(x_vals), round(len(x_vals)*f_train_valid), replace=False)
valid_idx = np.array(list(set(range(len(x_vals)))-set(train_idx)))
x_vals_train = x_vals[train_idx,]
x_vals_valid = x_vals[valid_idx]
y_vals_train = y_vals[train_idx]
y_vals_valid = y_vals[valid_idx]
# función de normalización por columna.
def normalize_cols(m, col_min = np.array([None]), col_max = np.array([None])):
if not col_min[0]:
col_min = m.min(axis=0)
if not col_max[0]:
col_max = m.max(axis=0)
return(m-col_min)/(col_max-col_min), col_min, col_max
x_vals_train, train_min, train_max = np.nan_to_num(normalize_cols(x_vals_train))
x_vals_valid,_,_ = np.nan_to_num(normalize_cols(x_vals_valid, train_min, train_max))
pd.DataFrame(x_vals_train, columns=data_header_new[0:(len(data_header_new)-1)]).head(10)
idx_0 = np.array([x==0 for x in y_vals_train])
idx_1 = np.array([x==1 for x in y_vals_train])
#Gráfico del Puntaje vs cada Predictor
fig, axs = plt.subplots(11, 2, sharex=False, figsize=[15,50])
fig.suptitle('Boxplot predictores en función del target \n (conjunto de entrenamiento)',
y=0.94, size=15)
fig.subplots_adjust(hspace=0.2, wspace=0.2, top=0.92)
plt.setp(axs, xticklabels=['0', '1'])
#color = ['blue', 'red', 'green', 'orange']
nn = 0
for n1 in range(11):
for n2 in range(2):
axs[n1,n2].boxplot([x_vals_train[idx_0,nn], x_vals_train[idx_1,nn]],
flierprops=dict(markerfacecolor='r', marker='s'))
axs[n1,n2].set_title(data_header_new[nn])
nn = nn + 1
for ax in fig.get_axes():
ax.label_outer()
Visualizando los boxplots de cada predictor se observa que algunos predictores no discriminan muy bien en función del target y por otro lado los predictores binarios pueden causar confusión.
Para visualizar mejor la relación entre las variables se realiza la correlación entre estas mostrados en el siguiente mapa de correlación.
import seaborn as sns
x_vals_train3 = pd.DataFrame(x_vals_train, columns=data_header_new[0:(len(data_header_new)-1)])
x_vals_train3['target'] = pd.Series(y_vals_train, index=x_vals_train3.index)
f, ax = plt.subplots(figsize=(10, 8))
corr = abs(pd.DataFrame(x_vals_train3, columns=data_header_new[0:(len(data_header_new))]).corr() )
sns.heatmap(corr, mask=np.zeros_like(corr, dtype=np.bool), cmap=sns.diverging_palette(220, 10, as_cmap=True),
square=True, ax=ax)
corr.loc[['target', 'slope1', 'slope2', 'thal2', 'thal3']][['target', 'slope1', 'slope2', 'thal2', 'thal3']]
Se observa que ninguna variable presenta mucha correlación con el target ni entre si, exceptuando las variables thal2-thal3 y slope1-slope2.
Para simplificar el problema eliminaremos las variables con correlación menor a 0.3, además de las variables slope1 y thal3.
zero = 0 # elimina la variable independiente de su correlación con target
idx_type = [1,1,1,1,1,1,1,1,1,1,1,1,1,zero,1,1,1,1,1,1,zero,1]
corr_min = 0.3
corr2 = corr.loc['target'][0:(len(corr)-1)]*idx_type
print(corr2[corr2>corr_min].index)
# Filtro variables consideradas para clasificación
x_vals_train = x_vals_train[:,np.where(corr2>corr_min)[0]]
x_vals_valid = x_vals_valid[:,np.where(corr2>corr_min)[0]]
Se consideran los siguientes algoritmos de clasificación:
# Declaración de Sesion y fijado de semillas aleatorias.
session = tf.Session()
tf.set_random_seed(123)
np.random.seed(123)
# Hiperparámetros
epochs = 6000
batch_size = int(np.round(x_vals_train.shape[0]*0.6)) # 60% del conjunto de entrenamiento
learning_rate = 0.02
# Declaración de placeholders
x_data = tf.placeholder(shape=[None, x_vals_train.shape[1]], dtype = tf.float32)
y_target = tf.placeholder(shape = [None, 1], dtype = tf.float32)
# Declaración de variables
A_rl = tf.Variable(tf.random_normal(shape = [x_vals_train.shape[1],1]))
b_rl = tf.Variable(tf.random_normal(shape = [1,1]))
# Declaración de predicción
y_pred = tf.add(tf.matmul(x_data, A_rl), b_rl)
# Función de pérdidas
loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=y_pred, labels= y_target))
# Inicialización de varibles
init = tf.global_variables_initializer()
session.run(init)
# Optimizador
my_optim = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
train_step = my_optim.minimize(loss)
# Clasificador (probabilidad de 1)
classification_lr = tf.round(tf.sigmoid(y_pred))
correct_classification = tf.cast(tf.equal(classification_lr, y_target), tf.float32)
accuracy = tf.reduce_mean(correct_classification)
El entrenamiento se lleva a cabo de la siguiente manera:
# perdidas de entrenamiento, pruebas y validación
loss_vec_train = []
loss_vec_test = []
loss_vec_val = []
# accuracy de entrenamiento, pruebas y validación
train_acc = []
test_acc = []
val_acc = []
for i in range(epochs):
# carga las observaciones aleatorias de entrenamiento y pruebas
rand_idx = np.random.choice(len(x_vals_train), size=batch_size)
rand_test_idx = np.array(list(set(range(len(x_vals_train)))-set(rand_idx)))
# separa conjunto de prueba aleatorio
rand_x = x_vals_train[rand_idx]
rand_y = np.transpose([y_vals_train[rand_idx]])
# separa conjunto de prueba aleatorio
rand_test_x = x_vals_train[rand_test_idx]
rand_test_y = np.transpose([y_vals_train[rand_test_idx]])
# entrenamiento iteracion i
session.run(train_step, feed_dict={x_data : rand_x, y_target: rand_y})
# perdidas del conjunto de entrenamiento
temp_loss_train = session.run(loss, feed_dict={x_data: rand_x, y_target: rand_y})
loss_vec_train.append(temp_loss_train)
# perdidas del conjunto de prueba
temp_loss_test = session.run(loss, feed_dict={x_data: rand_test_x, y_target: rand_test_y})
loss_vec_test.append(temp_loss_test)
# perdidas del conjunto de validación
temp_loss_val = session.run(loss, feed_dict={x_data: x_vals_valid, y_target: np.transpose([y_vals_valid])})
loss_vec_val.append(temp_loss_val)
# accuracy del conjunto de entrenamiento
temp_acc_train = session.run(accuracy, feed_dict={x_data: rand_x, y_target: rand_y})
train_acc.append(temp_acc_train)
# accuracy del conjunto de prueba
temp_acc_test = session.run(accuracy, feed_dict={x_data: rand_test_x, y_target: rand_test_y})
test_acc.append(temp_acc_test)
# accuracy del conjunto de validación
temp_acc_val = session.run(accuracy, feed_dict={x_data: x_vals_valid, y_target: np.transpose([y_vals_valid])})
val_acc.append(temp_acc_val)
if(i+1)%np.round(epochs/30)==0:
acc_and_loss = [i+1, temp_loss_train, temp_loss_test, temp_loss_val,
temp_acc_train, temp_acc_test, temp_acc_val]
print("Paso #{}, Train Loss {:.2f}, Test Loss {:.2f}, Valid Loss {:.2f}, Train Acc {:.2f}, Test Acc {:.2f}, Valid Acc {:.2f}".format(*acc_and_loss))
plt.figure(figsize=(14,5))
plt.plot(loss_vec_train, 'b-.', label="Pérdidas de Entrenamiento")
plt.plot(loss_vec_test, 'r--', label="Pérdidas de Prueba")
plt.plot(loss_vec_val, 'k-', label="Pérdidas de Validación")
plt.title("Pérdida de algoritmo Regresión Logística")
plt.xlabel("Iteración")
plt.ylabel("Pérdida")
plt.legend(loc="upper right")
plt.show()
plt.figure(figsize=(14,5))
plt.plot(train_acc, 'b-.', label="Accuracy de Entrenamiento")
plt.plot(test_acc, 'r--', label="Accuracy de Prueba")
plt.plot(val_acc, 'k-', label="Accuracy de Validación")
plt.title("Accuracy de algoritmo Regresión Logística")
plt.xlabel("Iteración")
plt.ylabel("Accuracy")
plt.legend(loc="lower right")
plt.ylim(0,1)
plt.show()
session.close()
ACC_VAL = []
ACC_VAL.append(val_acc[len(val_acc)-1])
# Declaración de Sesion y fijado de semillas aleatorias.
session = tf.Session()
tf.set_random_seed(123)
np.random.seed(123)
# preparación de variables target para algoritmo
y_vals_train2 = np.array([1 if y == 0 else -1 for y in y_vals_train])
y_vals_valid2 = np.array([1 if y == 0 else -1 for y in y_vals_valid])
# Hiperparámetros
epochs = 6000
batch_size = int(np.round(x_vals_train.shape[0]*0.6)) # 60% del conjunto de entrenamiento
learning_rate = 0.01
alpha = tf.constant([0.1])
# Declaración de placeholders
x_data = tf.placeholder(shape=[None, x_vals_train.shape[1]], dtype = tf.float32)
y_target = tf.placeholder(shape = [None, 1], dtype = tf.float32)
# Declaración de variables
A_svml = tf.Variable(tf.random_normal(shape = [x_vals_train.shape[1],1]))
b_svml = tf.Variable(tf.random_normal(shape = [1,1]))
# Declaración de predicción
y_pred = tf.subtract(tf.matmul(x_data, A_svml), b_svml)
# Función de pérdidas
l2_norm = tf.reduce_sum(tf.square(A_svml))
classification_term = tf.reduce_mean(tf.maximum(0.0, tf.subtract(1.0, tf.multiply(y_pred, y_target))))
loss = tf.add(classification_term, tf.multiply(alpha, l2_norm))
# Inicialización de varibles
init = tf.global_variables_initializer()
session.run(init)
# Optimizador
my_optim = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
train_step = my_optim.minimize(loss)
# Clasificador
prediction = tf.sign(y_pred)
accuracy = tf.reduce_mean(tf.cast(tf.equal(prediction, y_target), tf.float32))
El entrenamiento se lleva a cabo de la siguiente manera:
# perdidas de entrenamiento, pruebas y validación
loss_vec_train = []
loss_vec_test = []
loss_vec_val = []
# accuracy de entrenamiento, pruebas y validación
train_acc = []
test_acc = []
val_acc = []
for i in range(epochs):
# carga las observaciones aleatorias de entrenamiento y pruebas
rand_idx = np.random.choice(len(x_vals_train), size=batch_size)
rand_test_idx = np.array(list(set(range(len(x_vals_train)))-set(rand_idx)))
# separa conjunto de prueba aleatorio
rand_x = x_vals_train[rand_idx]
rand_y = np.transpose([y_vals_train2[rand_idx]])
# separa conjunto de prueba aleatorio
rand_test_x = x_vals_train[rand_test_idx]
rand_test_y = np.transpose([y_vals_train2[rand_test_idx]])
# entrenamiento iteracion i
session.run(train_step, feed_dict={x_data : rand_x, y_target: rand_y})
# perdidas del conjunto de entrenamiento
temp_loss_train = session.run(loss, feed_dict={x_data: rand_x, y_target: rand_y})[0]
loss_vec_train.append(temp_loss_train)
# perdidas del conjunto de prueba
temp_loss_test = session.run(loss, feed_dict={x_data: rand_test_x, y_target: rand_test_y})[0]
loss_vec_test.append(temp_loss_test)
# perdidas del conjunto de validación
temp_loss_val = session.run(loss, feed_dict={x_data: x_vals_valid, y_target: np.transpose([y_vals_valid2])})[0]
loss_vec_val.append(temp_loss_val)
# accuracy del conjunto de entrenamiento
temp_acc_train = session.run(accuracy, feed_dict={x_data: rand_x, y_target: rand_y})
train_acc.append(temp_acc_train)
# accuracy del conjunto de prueba
temp_acc_test = session.run(accuracy, feed_dict={x_data: rand_test_x, y_target: rand_test_y})
test_acc.append(temp_acc_test)
# accuracy del conjunto de validación
temp_acc_val = session.run(accuracy, feed_dict={x_data: x_vals_valid, y_target: np.transpose([y_vals_valid2])})
val_acc.append(temp_acc_val)
if(i+1)%np.round(epochs/30)==0:
acc_and_loss = [i+1, temp_loss_train, temp_loss_test, temp_loss_val,
temp_acc_train, temp_acc_test, temp_acc_val]
print("Paso #{}, Train Loss {:.2f}, Test Loss {:.2f}, Valid Loss {:.2f}, Train Acc {:.2f}, Test Acc {:.2f}, Valid Acc {:.2f}".format(*acc_and_loss))
plt.figure(figsize=(14,5))
plt.plot(loss_vec_train, 'b-.', label="Pérdidas de Entrenamiento")
plt.plot(loss_vec_test, 'r--', label="Pérdidas de Pruebas")
plt.plot(loss_vec_val, 'k-', label="Pérdidas d Validación")
plt.title("Pérdida de algoritmo SVM Lineal")
plt.xlabel("Iteración")
plt.ylabel("Pérdida")
plt.legend(loc="upper right")
plt.show()
plt.figure(figsize=(14,5))
plt.plot(train_acc, 'b-.', label="Accuracy de Entrenamiento")
plt.plot(test_acc, 'r--', label="Accuracy de Prueba")
plt.plot(val_acc, 'k-', label="Accuracy de Validación")
plt.title("Accuracy de algoritmo SVM Lineal")
plt.xlabel("Iteración")
plt.ylabel("Accuracy")
plt.legend(loc="lower right")
plt.ylim(0,1)
plt.show()
session.close()
ACC_VAL.append(val_acc[len(val_acc)-1])
# Declaración de Sesion y fijado de semillas aleatorias.
session = tf.Session()
tf.set_random_seed(123)
np.random.seed(123)
# preparación de variables target para algoritmo
y_vals_train2 = np.array([1 if y == 0 else -1 for y in y_vals_train])
y_vals_valid2 = np.array([1 if y == 0 else -1 for y in y_vals_valid])
# Hiperparámetros
epochs = 6000
#batch_size = int(np.round(x_vals_train.shape[0]*0.60)) # 25% del conjunto de entrenamiento
batch_size = int(np.round(x_vals_valid.shape[0])) # Para no tener problemas con el conjunto de validación
learning_rate = 0.001
gamma = tf.constant(-5000.0)
# Declaración de placeholders
x_data = tf.placeholder(shape=[None, x_vals_train.shape[1]], dtype = tf.float32)
prediction_grid = tf.placeholder(shape=[None, x_vals_train.shape[1]], dtype = tf.float32)
y_target = tf.placeholder(shape = [None, 1], dtype = tf.float32)
# Declaración de variables
b_svmr = tf.Variable(tf.random_normal(shape=[1, batch_size]))
# Definición de Kernel
dist = tf.reduce_sum(tf.square(x_data), 1)
dist = tf.reshape(dist, [-1,1])
sq_distance = tf.add(tf.subtract(dist, tf.multiply(2.0, tf.matmul(x_data, tf.transpose(x_data)))),
tf.transpose(dist))
my_kernel = tf.exp(tf.multiply(gamma, tf.abs(sq_distance)))
# Declaración de predicción
rA = tf.reshape(tf.reduce_sum(tf.square(x_data), 1), [-1, 1])
rB = tf.reshape(tf.reduce_sum(tf.square(prediction_grid),1), [-1,1])
pred_sq_dist = tf.add(tf.subtract(rA, tf.multiply(2.0, tf.matmul(x_data, tf.transpose(prediction_grid)))),
tf.transpose(rB))
pred_kernel = tf.exp(tf.multiply(gamma, tf.abs(pred_sq_dist)))
prediction_output = tf.matmul(tf.multiply(tf.transpose(y_target), b_svmr), pred_kernel)
y_pred = tf.sign(prediction_output - tf.reduce_mean(prediction_output))
#y_pred = tf.subtract(tf.matmul(x_data, A_svml), b_svml)
# Función de pérdidas
first_sum = tf.reduce_sum(b_svmr)
b_vect_cross = tf.matmul(tf.transpose(b_svmr), b_svmr)
y_target_cross = tf.matmul(y_target, tf.transpose(y_target))
second_sum = tf.reduce_sum(tf.multiply(my_kernel, tf.multiply(b_vect_cross, y_target_cross)))
loss = tf.negative(tf.subtract(first_sum, second_sum))
# Inicialización de varibles
init = tf.global_variables_initializer()
session.run(init)
# Optimizador
my_optim = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
train_step = my_optim.minimize(loss)
# Clasificador
accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.squeeze(y_pred), tf.squeeze(y_target)), tf.float32))
El entrenamiento se lleva a cabo de la siguiente manera:
# perdidas de entrenamiento, pruebas y validación
loss_vec_train = []
loss_vec_test = []
loss_vec_val = []
# accuracy de entrenamiento, pruebas y validación
train_acc = []
test_acc = []
val_acc = []
for i in range(epochs):
# carga las observaciones aleatorias de entrenamiento y pruebas
rand_idx = np.random.choice(len(x_vals_train), size=batch_size)
rand_test_idx = np.array(list(set(range(len(x_vals_train)))-set(rand_idx)))
rand_test_idx = np.random.choice(rand_test_idx, size=batch_size)
rand_val_idx = np.random.choice(len(x_vals_valid), size=batch_size)
# separa conjunto de prueba aleatorio
rand_x = x_vals_train[rand_idx]
rand_y = np.transpose([y_vals_train2[rand_idx]])
# separa conjunto de prueba aleatorio
rand_test_x = x_vals_train[rand_test_idx]
rand_test_y = np.transpose([y_vals_train2[rand_test_idx]])
# separa conjunto de validacion aleatorio
rand_val_x = x_vals_valid
rand_val_y = np.transpose([y_vals_valid2])
# entrenamiento iteracion i
session.run(train_step, feed_dict={x_data : rand_x, y_target: rand_y})
# perdidas del conjunto de entrenamiento
temp_loss_train = session.run(loss, feed_dict={x_data: rand_x, y_target: rand_y})
loss_vec_train.append(temp_loss_train)
# perdidas del conjunto de prueba
temp_loss_test = session.run(loss, feed_dict={x_data: rand_test_x, y_target: rand_test_y})
loss_vec_test.append(temp_loss_test)
# perdidas del conjunto de validación
temp_loss_val = session.run(loss, feed_dict={x_data: rand_val_x, y_target: rand_val_y})
loss_vec_val.append(temp_loss_val)
# accuracy del conjunto de entrenamiento
temp_acc_train = session.run(accuracy, feed_dict={x_data: rand_x, y_target: rand_y, prediction_grid:rand_x})
train_acc.append(temp_acc_train)
# accuracy del conjunto de prueba
temp_acc_test = session.run(accuracy, feed_dict={x_data: rand_test_x, y_target: rand_test_y, prediction_grid:rand_test_x})
test_acc.append(temp_acc_test)
# accuracy del conjunto de validación
temp_acc_val = session.run(accuracy, feed_dict={x_data: rand_val_x, y_target: rand_val_y, prediction_grid:rand_val_x})
val_acc.append(temp_acc_val)
if(i+1)%np.round(epochs/30)==0:
acc_and_loss = [i+1, temp_loss_train, temp_loss_test, temp_loss_val,
temp_acc_train, temp_acc_test, temp_acc_val]
print("Paso #{}, Train Loss {:.2f}, Test Loss {:.2f}, Valid Loss {:.2f}, Train Acc {:.2f}, Test Acc {:.2f}, Valid Acc {:.2f}".format(*acc_and_loss))
plt.figure(figsize=(14,5))
plt.plot(loss_vec_train, 'b-.', label="Pérdidas de Entrenamiento")
plt.plot(loss_vec_test, 'r--', label="Pérdidas de Prueba")
plt.plot(loss_vec_val, 'k-', label="Pérdidas de Validación")
plt.title("Pérdida para algoritmo SVM Radial")
plt.xlabel("Iteración")
plt.ylabel("Pérdida")
plt.legend(loc="upper right")
plt.show()
plt.figure(figsize=(14,5))
plt.plot(train_acc, 'b-.', label="Accuracy de Entrenamiento")
plt.plot(test_acc, 'r--', label="Accuracy de Prueba")
plt.plot(val_acc, 'k-', label="Accuracy de Validación")
plt.title("Accuracy para algoritmo SVM Radial")
plt.xlabel("Iteración")
plt.ylabel("Accuracy")
plt.legend(loc="lower right")
plt.ylim(0,1)
plt.show()
session.close()
ACC_VAL.append(val_acc[len(val_acc)-1])
# Declaración de Sesion y fijado de semillas aleatorias.
session = tf.Session()
tf.set_random_seed(123)
np.random.seed(123)
# Hiperparámetros
batch_size = len(x_vals_valid)
loops = int(batch_size) # número de iteraciones para calcular metricas promedio para cada k
# Declaración de placeholders
x_data_train = tf.placeholder(shape=[batch_size, x_vals_train.shape[1]], dtype=tf.float32)
x_data_test = tf.placeholder(shape=[batch_size, x_vals_train.shape[1]], dtype=tf.float32)
y_target_train = tf.placeholder(shape = [None, 1], dtype=tf.float32)
y_target_test = tf.placeholder(shape=[None, 1], dtype=tf.float32)
# Cálculo de matriz de ponderación de distancias
weight_matrix_2 = x_vals_train.std(0)
weight_matrix = tf.cast(tf.diag(weight_matrix_2), dtype=tf.float32)
# Cálculo de distancia
subs_term = tf.subtract(x_data_train, tf.expand_dims(x_data_test, 1))
first_prod = tf.matmul(subs_term, tf.tile(tf.expand_dims(weight_matrix,0), [batch_size, 1, 1]))
second_prod = tf.matmul(first_prod, tf.transpose(subs_term, perm=[0,2,1]))
distance = tf.sqrt(tf.matrix_diag_part(second_prod))
def knn(k, loop):
# Toma los k datos con menor distancia al valor dado y cálcula su valor promedio
top_k_xvals, top_k_idx = tf.nn.top_k(tf.negative(distance), k = k)
x_sums = tf.expand_dims(tf.reduce_sum(top_k_xvals,1),1)
x_sums_rep = tf.matmul(x_sums, tf.ones([1,k], tf.float32))
x_vals_w = tf.expand_dims(tf.divide(top_k_xvals, x_sums_rep),1) # -> wi = di / \sum(dj)
# Declaración de predicción
top_k_yvals = tf.gather(y_target_train, top_k_idx)
prediction = tf.squeeze(tf.matmul(x_vals_w, top_k_yvals),axis=[1]) ## \sum w_i y_i
prediction = abs(tf.nn.relu(tf.sign(prediction -0.5)))
# función de pérdida
mse = tf.div(tf.reduce_sum(tf.square(tf.subtract(prediction, y_target_test))), batch_size)
acc = 1 - tf.reduce_mean(abs(tf.subtract(prediction, y_target_test)))
batch_mse =[]
batch_acc = []
for j in range(loop):
# carga las observaciones aleatorias de entrenamiento y pruebas
rand_idx = np.random.choice(len(x_vals_train), size=batch_size)
# separa conjunto de entrenamiento aleatorio
rand_x = x_vals_train[rand_idx]
rand_y = np.transpose([y_vals_train[rand_idx]])
# separa conjunto de validacion aleatorio
rand_val_x = x_vals_valid
rand_val_y = np.transpose([y_vals_valid])
# cálculo pérdida
feed_dict={x_data_train: rand_x, x_data_test: rand_val_x, y_target_train: rand_y, y_target_test: rand_val_y}
predictions = session.run(prediction, feed_dict=feed_dict)
temp_mse = session.run(mse, feed_dict=feed_dict)
temp_acc = session.run(acc, feed_dict=feed_dict)
batch_mse.append(temp_mse)
batch_acc.append(temp_acc)
batch_mse = np.mean(batch_mse)
batch_acc = np.mean(batch_acc)
return batch_mse, batch_acc
Este algoritmo no se entrena, los resultados se calculan a partir de los datos de los k vecinos más cercanos.
Para evaluar el algoritmo, se cálcula la exactitud promedio de los k vecinos más cercanos alrededor de 60 veces por cada k.
El valor de k con mayor exactitud se selecciona para el modelo. La exactitud del conjunto de validación se calcula con este valor.
num_loops = int(batch_size/2)
mse_k = []
acc_k = []
for k in range(1, num_loops):
mse_t, acc_t = knn(k, 30)
mse_k.append(mse_t)
acc_k.append(acc_t)
acc_and_loss = [k, mse_t, acc_t]
print("k = {}, Loss = {:.4f}, Acc = {:.3f}".format(*acc_and_loss))
plt.figure(figsize=(14,5))
plt.plot(acc_k, 'b-.', label="Accuracy de Validación")
plt.title("Accuracy de algoritmo KNN (promedio de "+str(loops)+" iteraciones para cada k)")
plt.xlabel("k")
plt.ylabel("Accuracy")
plt.legend(loc="lower right")
plt.ylim(0,1)
plt.show()
session.close()
ACC_VAL.append(np.max(acc_k))
# Guarda valor de k con máximo Accuracy
indexKNN = np.where(acc_k==np.max(acc_k))[0]
indexKNN = indexKNN[0] + 1
# Declaración de Sesion y fijado de semillas aleatorias.
session = tf.Session()
tf.set_random_seed(123)
np.random.seed(123)
# Hiperparámetros
epochs = 6000
batch_size = int(np.round(x_vals_train.shape[0]*0.7))
learning_rate = 0.008
layers = [x_vals_train.shape[1], 45, 25, 9]
sd = 0.1
alpha = 0.3
# Declaración de funciones weight y bias (variables)
def init_weight(shape, st_dev):
weight = tf.Variable(tf.random_normal(shape = shape, stddev=st_dev))
return weight
def init_bias(shape, st_dev):
bias = tf.Variable(tf.random_normal(shape = shape, stddev=st_dev))
return bias
# Definición de función de conexión
def full_connected(input_layer, weights, biases):
layer = tf.add(tf.matmul(input_layer, weights), biases)
layer = tf.nn.leaky_relu(layer, alpha=alpha)
return(layer)
# Arquitectura de la red
## Capa 1
w1 = init_weight(shape=[layers[0], layers[1]], st_dev=sd)
b1 = init_bias(shape=[layers[1]], st_dev=sd)
layer1 = full_connected(x_data, w1, b1)
## Capa 2
w2 = init_weight(shape=[layers[1], layers[2]], st_dev=sd)
b2 = init_bias(shape=[layers[2]], st_dev=sd)
layer2 = full_connected(layer1, w2, b2)
## Capa 3
w3 = init_weight(shape=[layers[2], layers[3]], st_dev=sd)
b3 = init_bias(shape=[layers[3]], st_dev=sd)
layer3 = full_connected(layer2, w3, b3)
## Capa 4
w4 = init_weight(shape=[layers[3],1], st_dev=sd)
b4 = init_bias(shape=[1], st_dev=sd)
layer4 = full_connected(layer3, w4, b4)
# Función de pérdidas
loss_nn = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=layer4, labels= y_target))
#loss_nn = tf.reduce_mean(tf.square(y_target-layer4)))
# Inicialización de varibles
init = tf.global_variables_initializer()
session.run(init)
# Optimizador
my_optim = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
train_step = my_optim.minimize(tf.div_no_nan(loss_nn, 1))
# Clasificador (probabilidad de 1)
classification_lr = tf.round(tf.sigmoid(layer4))
#classification_lr = abs(tf.nn.relu(tf.sign(layer4 -0.5)))
correct_classification = tf.cast(tf.equal(classification_lr, y_target), tf.float32)
accuracy = tf.reduce_mean(correct_classification)
El entrenamiento se lleva a cabo de la siguiente manera:
loss_vec_train = []
loss_vec_test = []
loss_vec_val = []
train_acc = []
test_acc = []
val_acc = []
for i in range(epochs):
# carga las observaciones aleatorias de entrenamiento y pruebas
rand_idx = np.random.choice(len(x_vals_train), size=batch_size)
rand_test_idx = np.array(list(set(range(len(x_vals_train)))-set(rand_idx)))
# separa conjunto de prueba aleatorio
rand_x = x_vals_train[rand_idx]
rand_y = np.transpose([y_vals_train[rand_idx]])
# separa conjunto de prueba aleatorio
rand_test_x = x_vals_train[rand_test_idx]
rand_test_y = np.transpose([y_vals_train[rand_test_idx]])
# entrenamiento iteracion i
session.run(train_step, feed_dict={x_data : rand_x, y_target: rand_y})
# perdidas del conjunto de entrenamiento
temp_loss_train = session.run(loss_nn, feed_dict={x_data: rand_x, y_target: rand_y})
loss_vec_train.append(temp_loss_train)
# perdidas del conjunto de prueba
temp_loss_test = session.run(loss_nn, feed_dict={x_data: rand_test_x, y_target: rand_test_y})
loss_vec_test.append(temp_loss_test)
# perdidas del conjunto de validación
temp_loss_val = session.run(loss_nn, feed_dict={x_data: x_vals_valid, y_target: np.transpose([y_vals_valid])})
loss_vec_val.append(temp_loss_val)
# accuracy del conjunto de entrenamiento
temp_acc_train = session.run(accuracy, feed_dict={x_data: rand_x, y_target: rand_y})
train_acc.append(temp_acc_train)
# accuracy del conjunto de prueba
temp_acc_test = session.run(accuracy, feed_dict={x_data: rand_test_x, y_target: rand_test_y})
test_acc.append(temp_acc_test)
# accuracy del conjunto de validación
temp_acc_val = session.run(accuracy, feed_dict={x_data: x_vals_valid, y_target: np.transpose([y_vals_valid])})
val_acc.append(temp_acc_val)
if(i+1)%np.round(epochs/30)==0:
acc_and_loss = [i+1, temp_loss_train, temp_loss_test, temp_loss_val,
temp_acc_train, temp_acc_test, temp_acc_val]
print("Paso #{}, Train Loss {:.2f}, Test Loss {:.2f}, Valid Loss {:.2f}, Train Acc {:.2f}, Test Acc {:.2f}, Valid Acc {:.2f}".format(*acc_and_loss))
# Predicción conjunto validación
pred_test_nn = [x for x in session.run(classification_lr, feed_dict={x_data:x_vals_valid})]
plt.figure(figsize=(14,5))
plt.plot(loss_vec_train, 'b-.', label="Pérdidas de Entrenamiento")
plt.plot(loss_vec_test, 'r--', label="Pérdidas de Prueba")
plt.plot(loss_vec_val, 'k-', label="Pérdidas de Validación")
plt.title("Pérdida para algoritmo Red Neuronal")
plt.xlabel("Iteración")
plt.ylabel("Pérdida")
plt.legend(loc="upper right")
plt.show()
plt.figure(figsize=(14,5))
plt.plot(train_acc, 'b-.', label="Accuracy de Entrenamiento")
plt.plot(test_acc, 'r--', label="Accuracy de Prueba")
plt.plot(val_acc, 'k-', label="Accuracy de Validación")
plt.title("Accuracy para algoritmo Red Neuronal")
plt.xlabel("Iteración")
plt.ylabel("Accuracy")
plt.legend(loc="lower right")
plt.ylim(0,1)
plt.show()
session.close()
ACC_VAL.append(val_acc[len(val_acc)-1])
pd.DataFrame(np.round(ACC_VAL, 5), columns=["Accuracy (conjunto de validación)"],
index=["Regresión Logística", " SVM-Lineal", " SVM-Radial", "KNN (k="+str(indexKNN)+")", "Red Neuronal"])
EL algoritmo que presenta el mejor desempeño es el SVM Radial con una exactitud de 0.98.
Es importante mencionar que la red neuronal puede mejorarse optimizando los hiperparámetros learning_rate, layers (define las capas y nodos de la red) y alpha (pendiente negativa de la leaky relu).
Link :https://github.com/desareca/Proyectos_tensorflow/tree/master/Probabilidad-Infarto-Cardiaco