En esta práctica se introduce una serie de ejercicios para estudiar las técnicas de reducción de dimensionalidad. Seguiremos trabajando con los datos de la práctica anterior realizando un estudio para que intentemos determinar que parámetros son los mejores para un ejercicio de clasificación.
El objetivo de esta práctica es que adquiramos conocimientos básicos para solventar problemas de reducción de dimensionalidad de los datos. Esto se enmarca dentro del área de preparación de datos previos a un algoritmo de machine learning.
Tras una preparación previa de los datos que realizamos según lo aprendido en la práctica anterior, analizamos distintos métodos de reducción de dimensionalidad con el objetivo de aplicar luego un algoritmo de aprendizaje y evaluar la eficacia de dicho algoritmo en función de las variables eliminadas según los métodos descritos. Así somos capaces de evaluar los métodos aplicados de reducción de dimensionalidad.
In [1]:
#Libraries
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
import matplotlib.pyplot as plt # Read Dataset
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn import metrics
import sklearn.feature_selection as FS
%matplotlib inline
import warnings
warnings.filterwarnings('ignore')
In [2]:
#Path para linux
path = '../Recursos/indian_liver_patient.csv'
#Path para Windows
#path = '..\Recursos\indian_liver_patient.csv'
dataset = pd.read_csv(path,delimiter=',',header=0)
# Eliminación de Missing values
dataset=dataset.dropna()
# Transformación de valores a binario
dataset["Gender"] = pd.Categorical.from_array(dataset["Gender"]).codes
#Modificamos la clase, para que la clase pase de 1-2 a 0-1
dataset['Dataset']=dataset['Dataset']-1
# División aleatorioa 70 Traning 30 Test
train_test=train_test_split(dataset, test_size=0.3)
train=train_test[0]
test=train_test[1]
dataset
Out[2]:
In [3]:
#Separamos la variable target del resto
train_Y=train["Dataset"]
train_X=train.drop("Dataset",1)
test_Y=test["Dataset"]
test_X=test.drop("Dataset",1)
In [4]:
mi_regr = FS.mutual_info_regression(train_X, train_Y)
print(mi_regr)
indice_regr=np.argsort(mi_regr)[::-1]
print(indice_regr)
Como en cada ejecución de información mutua los valores varian bastante, debido a los bajos resultados obtenidos, hemos decidido realizar el calculo 100 veces y trabajar con la media de los calculos, donde vemos que ya mas o menos se obtienen resultados similares, o con cambios de posicion pequeños.
Algunos ejemplos de variacion de indices:
ej1: 5 0 9 6 3 4 2 8 7 1
ej2: 0 6 3 4 2 5 8 9 1 7
ej3: 0 6 2 3 5 1 4 9 8 7
ej4: 6 2 3 0 9 5 8 4 7 1
ej5: 9 2 3 0 6 5 4 8 7 1
In [5]:
mi_regr = [ 0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,]
for i in range(1, 100):
mi_regr = mi_regr+ FS.mutual_info_regression(train_X, train_Y)
mi_regr=mi_regr/100
print(mi_regr)
names=train_X.axes[1]
print (names)
indice_regr=np.argsort(mi_regr)[::-1]
print(indice_regr)
#print(names)
names[indice_regr]
Out[5]:
En el caso de realizar la media vemos que los valores no varian tanto de una ejecucion a otra:
ej1:3 5 0 6 2 4 9 1 8 7
ej2:3 0 5 6 2 4 9 8 1 7
ej3:3 0 5 6 2 4 9 8 1 7
ej4:3 5 6 0 2 4 9 8 1 7
ej5:5 6 3 0 2 4 9 8 1 7
Y nos a partir de aqui vamos a usar los valores de ejecución 2 y 3 que son los mismos.
In [6]:
indice_regr = [ 3, 0, 5, 6, 2, 4, 9, 8, 1, 7]
regr_var=names[indice_regr]
regr_var
Out[6]:
In [7]:
plt.figure(figsize=(8,6))
plt.subplot(121)
plt.scatter(dataset[dataset.Dataset==0].Direct_Bilirubin,dataset[dataset.Dataset==0].Age, color='red')
plt.scatter(dataset[dataset.Dataset==1].Direct_Bilirubin,dataset[dataset.Dataset==1].Age, color='blue')
plt.title('Good Predictor Variables \n Direct_Bilirubin vs Age')
plt.xlabel('Direct_Bilirubin')
plt.ylabel('Age')
plt.legend(['Enfermos','Sanos'])
plt.subplot(122)
plt.scatter(dataset[dataset.Dataset==0].Total_Protiens,dataset[dataset.Dataset==0].Albumin, color='red')
plt.scatter(dataset[dataset.Dataset==1].Total_Protiens,dataset[dataset.Dataset==1].Albumin, color='blue')
plt.title('Good Predictor Variables \n Total_Protiens vs Albumin')
plt.xlabel('Total_Protiens')
plt.ylabel('Albumin')
plt.legend(['Sick','Healthy'])
plt.show()
Como se ve en las graficas, aunque las primeras dos variables (Direct_Bilirubin y Age) no separan bien los elementos, algo de esperar por los resultados tan bajos obtenidos, si estan mejor separadas que con dos de las tres ultimas variables (Total_Protiens y Albumin)
In [8]:
def specificity(y_true, y_pred):
tn, fp, fn, tp = metrics.confusion_matrix(y_true, y_pred).ravel()
return tn/(tn+fp)
In [9]:
#Con todas las variables 10
modelo_lr = LogisticRegression()
modelo_lr.fit(X=train_X,y=train_Y)
predicion = modelo_lr.predict(test_X)
print('Regresion logistica con todas las variables\n')
print(f'\tprecision_score={metrics.precision_score(y_true=test_Y, y_pred=predicion)}')
print(f'\trecall_score={metrics.recall_score(y_true=test_Y, y_pred=predicion)}')
print(f'\taccuracy_score={metrics.accuracy_score(y_true=test_Y, y_pred=predicion)}')
print(f'\tspecificity_score={specificity(y_true=test_Y, y_pred=predicion)}')
In [10]:
train_X_copia=train_X.copy()
test_X_copia=test_X.copy()
allvar="";
#quitando variables
nvar=9
for i in regr_var[:0:-1]:
allvar=allvar+i+", "
train_X_copia=train_X_copia.drop(i,1)
test_X_copia=test_X_copia.drop(i,1)
modelo_lr = LogisticRegression()
modelo_lr.fit(X=train_X_copia,y=train_Y)
print('Con',nvar," variables")
nvar=nvar-1
print('Quitando \n'+allvar+"\n")
predicion = modelo_lr.predict(test_X_copia)
print(f'\tprecision_score={metrics.precision_score(y_true=test_Y, y_pred=predicion)}')
print(f'\trecall_score={metrics.recall_score(y_true=test_Y, y_pred=predicion)}')
print(f'\taccuracy_score={metrics.accuracy_score(y_true=test_Y, y_pred=predicion)}')
print(f'\tspecificity_score={specificity(y_true=test_Y, y_pred=predicion)}')
In [11]:
#EN chi^2 no se pueden usar valores negativos, por lo que no se pueden usar los datos normalizados
chi = FS.chi2(X = train_X, y = train_Y)[0]
print(chi)
indice_chi=np.argsort(chi)[::-1]
print(indice_chi)
print(names[indice_chi])
chi_var=names[indice_chi]
In [12]:
plt.figure()
plt.scatter(dataset[dataset.Dataset==0].Aspartate_Aminotransferase,dataset[dataset.Dataset==0].Alamine_Aminotransferase, color='red')
plt.scatter(dataset[dataset.Dataset==1].Aspartate_Aminotransferase,dataset[dataset.Dataset==1].Alamine_Aminotransferase, color='blue')
plt.title('Good Predictor Variables Chi-Square \n Aspartate_Aminotransferase vs Alamine_Aminotransferase')
plt.xlabel('Aspartate_Aminotransferase')
plt.ylabel('Alamine_Aminotransferase')
plt.legend(['Sick','Healthy'])
plt.show()
In [13]:
train_X_copia=train_X.copy()
test_X_copia=test_X.copy()
allvar="";
nvar=9
#quitando variables
for i in chi_var[:0:-1]:
allvar=allvar+i+", "
train_X_copia=train_X_copia.drop(i,1)
test_X_copia=test_X_copia.drop(i,1)
modelo_lr = LogisticRegression()
modelo_lr.fit(X=train_X_copia,y=train_Y)
print('Con',nvar," variables")
nvar=nvar-1
print('Quitando \n'+allvar+'\n')
predicion = modelo_lr.predict(test_X_copia)
print(f'\tprecision_score={metrics.precision_score(y_true=test_Y, y_pred=predicion)}')
print(f'\trecall_score={metrics.recall_score(y_true=test_Y, y_pred=predicion)}')
print(f'\taccuracy_score={metrics.accuracy_score(y_true=test_Y, y_pred=predicion)}')
print(f'\tspecificity_score={specificity(y_true=test_Y, y_pred=predicion)}')
In [14]:
from sklearn.decomposition.pca import PCA
from sklearn import preprocessing
X_scaled = preprocessing.scale(train_X)
pca = PCA()
pca.fit(X_scaled)
# Representamos los resultados de PCA
plt.plot(pca.explained_variance_)
plt.ylabel("eigenvalues")
plt.xlabel("position")
plt.show()
print ("Eigenvalues\n",pca.explained_variance_)
# # Porcentaje de varianza por cada componente
print('\nExplained variance ratio:\n %s'
% str(pca.explained_variance_ratio_))
In [15]:
pca = pca.explained_variance_ratio_
indice_pca=np.argsort(pca)[::-1]
print(indice_pca)
print(names[indice_pca])
pca_var=names[indice_pca]
train_X_copia=train_X.copy()
test_X_copia=test_X.copy()
allvar="";
nvar=9
# Calculamos algoritmo de ML según variables guiadas por PCA
for i in pca_var[:0:-1]:
allvar=allvar+i+", "
train_X_copia=train_X_copia.drop(i,1)
test_X_copia=test_X_copia.drop(i,1)
modelo_lr = LogisticRegression()
modelo_lr.fit(X=train_X_copia,y=train_Y)
print('Con',nvar," variables")
nvar=nvar-1
print('Quitando \n'+allvar+'\n')
predicion = modelo_lr.predict(test_X_copia)
print(f'\tprecision_score={metrics.precision_score(y_true=test_Y, y_pred=predicion)}')
print(f'\trecall_score={metrics.recall_score(y_true=test_Y, y_pred=predicion)}')
print(f'\taccuracy_score={metrics.accuracy_score(y_true=test_Y, y_pred=predicion)}')
print(f'\tspecificity_score={specificity(y_true=test_Y, y_pred=predicion)}')
Según hemos visto con las pruebas anteriores, podemos ver como alcanzamos la mejor precisión quitando las variables _Albumin_and_Globulin_Ratio, Albumin, Total_Protiens, Aspartate_Aminotransferase, Alamine_Aminotransferase, AlkalinePhosphotase. Hasta ahora ha sido el mejor resultado que hemos obtenido entre todos los métodos.
Al contrario de PCA, LDA es invariante a escala y por tanto no tenemos por que trabajara con los datos normalizados.
In [16]:
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
lda = LDA()
lda.fit(train_X,train_Y)
print("Porcentaje explicado:", lda.explained_variance_ratio_)
ldaRes = lda.explained_variance_ratio_
indice_lda=np.argsort(ldaRes)[::-1]
print(indice_lda)
print(names[indice_lda])
pca_var=names[indice_lda]
train_X_copia=train_X.copy()
test_X_copia=test_X.copy()
allvar="";
nvar=9
#quitando variables
for i in pca_var[:0:-1]:
allvar=allvar+i+", "
train_X_copia=train_X_copia.drop(i,1)
test_X_copia=test_X_copia.drop(i,1)
modelo_lr = LogisticRegression()
modelo_lr.fit(X=train_X_copia,y=train_Y)
print('Con',nvar," variables")
nvar=nvar-1
print('Quitando \n'+allvar+'\n')
predicion = modelo_lr.predict(test_X_copia)
print(f'\tprecision_score={metrics.precision_score(y_true=test_Y, y_pred=predicion)}')
print(f'\trecall_score={metrics.recall_score(y_true=test_Y, y_pred=predicion)}')
print(f'\taccuracy_score={metrics.accuracy_score(y_true=test_Y, y_pred=predicion)}')
print(f'\tspecificity_score={specificity(y_true=test_Y, y_pred=predicion)}')
Según vemos como resultado, LDA nos da un unos resultados que no nos sirven para discernir entre ninguna de las variables.
Esto se da debido a que los datos con los que trabajamos no se asemejan a una distribución gaussiana.
Según los resultados obtenidos, el mejor método es PCA pero hay que dejar claro que esto es sólamente debido a los datos que tenemos. Por tanto, eliminar las variables _Albumin_and_Globulin_Ratio, Albumin, Total_Protiens, Aspartate_Aminotransferase, Alamine_Aminotransferase, AlkalinePhosphotase nos hace alcanzar una precisión del 55% frente al 33% que nos da con todos los datos del conjunto.
Con esta práctica hemos sido capaces de usar los métodos habituales de reducción de dimensionalidad y de darnos cuenta de su grán utilidad. Aun así, la dependencia de la distribución de los datos así como de su formato es algo a tener en cuenta, como ya hemos visto en la práctica anterior.