El algoritmo PCA método no supervisado que utilizado para la reducción de la dimensionalidad.

El algoritmo PCA o análisis de componentes principales es un método supervisado que se utiliza para la reducción de la dimensionalidad, donde vamos a reducir la dimensionalidad de un conjunto de datos que consta de muchas variables correlacionadas entre sí, vamos a transformar las variables en un nuevo conjunto de variables que es una combinación de variables o atributos de nuestro conjunto de datos original de tal manera que se conserva la máxima variación, ademas de ello vamos a mejorar  la eficiencia  y el rendimiento de los algoritmos de machine learning.

Como implementar el algoritmo PCA en Python

Los siguientes pasos que vamos a aplicar son:

  • Estandarizamos el conjunto de datos de d dimensiones.

  • Obtenemos la matriz de covarianza.

  • Calculamos los autovalores y autovectores de la matriz de covarianza.

  • Ordenamos los autovalores para clasificar los autovectores.

  • Seleccionamos k autovectores que correspondan a los k autovalores más altos.

  • Construimos la matriz de proyección W a partir de estos k autovectores.

  • Transformamos los datos originales X (de d dimensiones) al nuevo subespacio reducido de k dimensiones.

Búsqueda de los componentes CP1 y CP2

Los componentes CP1 y CP2 que serán los auto vectores de la matriz de covarianza:

PCA

Implementación del algoritmo PCA de dos características de datos proyectados sobre una recta

Si tenemos la siguiente tabla:

X Y
1 3
1 4
2 5
2 7
3 6
3 8
5 6
5 8

Generación de la matriz de covarianza

LLamamos a la función np.cov(matrizDatos) de la clase numpy para que nos genere la matriz:

matrizDatos = np.array([(1,1,2,2,3,3,5,5),(3,4,5,7,6,8,6,8)])
matrizCovarianza=np.cov(matrizDatos)
2.5 1.96428571
1.96428571 3.26785714

Si tenemos la función definida por:

Función de R2 a R2

Función de R2 a R2 que transforma un vector en otro vector

Búsqueda de los autovalores y autovectores

Buscamos los autovalores y autovectores de esa matriz, que seran nuestras componentes CP1 y CP2, cuyos autovectores seran ortogonales cuyo producto escalar es cero.

autovalores, autovectores = np.linalg.eig(matrizCovarianza)
  • λ1 0.8824742213855528 asociado al autovector (-0.77195362, 0.63567885)
  • λ2 4.8853829214715905 asociado al autovector (-0.63567885, -0.77195362)  ***cogemos este que tiene la mayor variabilidad

Nota: Como la librería Numpy da los autovectores con signos invertidos los cambiamos.

Ordenación de los autovectores

Ordenamos los autovectores de mayor a menor según λ

  • PC1 –> (0.63567885, 0.77195362)
  • PC2 –> (0.77195362, -0.63567885)

Finalmente proyectamos nuestros puntos sobre la primera componente principal que es la que mayor variabilidad de datos tiene (PC1)

La función definida que tiene por matriz de proyección W el mayor autovector es decir la componente PC1:

función de R2 a R

función de R2 a R

A esa función le pasamos los datos de entrada para hacer la proyección dando como resultado:

2.95153972
3.72349335
5.13112582
6.67503307
6.5387583
8.08266555
7.810116
9.35402325

Codigo de implementacion

El siguiente codigo en Python implementa paso a paso una visualización del análisis de componentes principales (PCA) aplicado a un conjunto de datos bidimensional. Aquí tienes una descripción breve y clara de lo que hace cada parte:

Objetivo del código:

Ilustrar gráficamente cómo funciona el Análisis de Componentes Principales (PCA), mostrando los autovectores (componentes principales), los datos originales y sus proyecciones sobre el primer componente principal.


Resumen del funcionamiento del código:

  1. Generación de datos:

    getDatos()

    Crea una matriz de datos con 8 puntos bidimensionales.

  2. Cálculo de matriz de covarianza:

    getMatrizCovarianza(matrizDatos)

    Se obtiene la matriz de covarianza del conjunto de datos, que indica la relación lineal entre las dos variables.

  3. Extracción de autovalores y autovectores:

    getAutovaloresVectores(matrizCovarianza)

    Se obtienen los autovalores (importancia de cada componente) y autovectores (direcciones principales).

  4. Ordenación de componentes principales:

    getOrdenAutovalores() y getMayoresAutovalores()

    Se seleccionan los 2 autovectores más significativos, es decir, los que explican mayor varianza.

  5. Proyección sobre el primer componente principal:

    getArrayProyeccionesSobrePC1()

    Cada punto es proyectado sobre el primer componente principal para reducir la dimensionalidad.

  6. Visualización de resultados:

    dibujarMatriz()

    Dibuja:

    • Los datos originales.

    • Las rectas que representan los componentes principales.

    • Las proyecciones de los datos sobre el componente principal.

import numpy as np
import matplotlib.pyplot as plt
def dibujarMatriz(matrizDatos,pc1, pc2,arrayProyecciones):
    #Pinta nuestros datos
     plt.scatter(matrizDatos[:][0],matrizDatos[:][1])
     #Inicializa las variables    
     rectaAutovector1_x=[]
     rectaAutovector1_y=[]
     rectaAutovector2_x=[]
     rectaAutovector2_y=[]
     x=[]
     y=[]   
     
     #Genera la recta del autovector 1
     for lamda in np.arange(0,15.2,0.2):
         lamda=np.round(lamda, 2)         
         x1 = 0 + lamda * pc1[0]
         x2 = 0 + lamda * pc1[1]        
         rectaAutovector1_x.append(x1) 
         rectaAutovector1_y.append(x2)  
     #Genera la recta del autovector 2   
     for lamda in np.arange(-15,0.2,0.2):
         lamda=np.round(lamda, 2)      
         x1 = 0 + lamda * pc2[0]
         x2 = 0 + lamda * pc2[1]        
         rectaAutovector2_x.append(x1) 
         rectaAutovector2_y.append(x2)    
     #Dibuja las rectas de los autovectores
     plt.plot(rectaAutovector1_x,rectaAutovector1_y,label='autovector1') 
     plt.plot(rectaAutovector2_x,rectaAutovector2_y,label='autovector2') 
     plt.legend(loc="lower right")    
     #Proyecta los datos sobre el vector de componentes p1
     for i in range(0,8):
        v = arrayProyecciones[i]         
        x.append(v[0])
        y.append(v[1])
     plt.scatter(x,y)  
     # Escala de los ejes
     plt.xlim(-10,10)
     plt.ylim(-10,10)
     plt.grid(True)
     plt.show()
def getDatos():    
    matrizDatos = np.array([(1,1,2,2,3,3,5,5),(3,4,5,7,6,8,6,8)])
    return matrizDatos
def getMatrizCovarianza(matrizDatos):
    return np.cov(matrizDatos)
def getAutovaloresVectores(matrizCovarianza):
    autovalores, autovectores = np.linalg.eig(matrizCovarianza)
    return autovalores, autovectores
def getOrdenAutovalores(autovalores, autovectores):
    # Hacemos una lista de las tuplas (autovalor, autovector)
    paresAutoVecAutoVal = [(np.abs(autovalores[i]), autovectores[:, i])
                           for i in range(len(autovalores))]
    return paresAutoVecAutoVal
def getMayoresAutovalores(paresAutoVecAutoVal):
     # Ordenamos las tuplas de mayor a menor
    paresAutoVecAutoVal.sort(key=lambda k: k[0], reverse=True)  
    #Devolvemos los dos primeros autovectores y le añadimos una dimension extra
    a = paresAutoVecAutoVal[0][1][:, np.newaxis]
    b = paresAutoVecAutoVal[1][1][:, np.newaxis]
    lamda1 = paresAutoVecAutoVal[0][0]
    lamda2 = paresAutoVecAutoVal[1][0]
    a = a*(-1)
    b = b*(-1)
    return a, b, lamda1, lamda2
def getModuloVector(u):
    return np.linalg.norm(u)
def getArrayProyeccionesSobrePC1(w,a):
    #Vamos a calcular las proyecciones de cada punto sobre 
    arrayProyecciones = []
    for i in range(0,8):
      s = a*w[i]
      arrayProyecciones.append(s)
    return arrayProyecciones    
def productoEscalar(u,v):
  s = np.dot(u,v)
  return s
matrizDatos=getDatos()
matrizCovarianza=getMatrizCovarianza(matrizDatos)
print(matrizCovarianza)
autovalores, autovectores = getAutovaloresVectores(matrizCovarianza)
paresAutoVecAutoVal = getOrdenAutovalores(autovalores, autovectores)
# Seleccionamos 2 autovectores que correspondan a los k autovalores mayores
a, b,lamda1,lamda2 = getMayoresAutovalores(paresAutoVecAutoVal)
matrizDatosTranspuesta = matrizDatos.T
w = matrizDatosTranspuesta.dot(a)
arrayProyeccionesSobrePC1=getArrayProyeccionesSobrePC1(w,a)
dibujarMatriz(matrizDatos,a, b,arrayProyeccionesSobrePC1)

Salida

Donde los datos proyectados son el producto escalar de estos datos de los datos de la tabla anterior con el vector de la matriz de proyección dando como resultado:

extraccion caracteristicas | proyeccionPuntos

Los datos azules al proyectarse van a caer sobre la recta en la dirección del mayor autovalor o la PC1

Implementación de algoritmo de PCA sobre el set de datos wine

En el siguiente set datos de wine vamos a transformar un espacio de 13 dimensiones a un espacio de 2 dimensiones, mostrando como predice en las dimensiones originales y la dimensiones reducidas.

Codigo en python

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
def getDatos():    
    # Lectura de datos
    wine = pd.read_csv("wine.csv")
    X = wine.iloc[:, 1:14].values
    Y = wine.iloc[:, 0].values
    return X,Y
def getDivisionDatos(X,Y):
    # Division del conjunto de los datos
    X_train, X_test, Y_train, Y_test = train_test_split(
    X, Y, test_size=0.3, random_state=1, stratify=Y)
    return X_train, X_test, Y_train, Y_test
def getOrdenAutovalores(autovalores, autovectores):
    # Hacemos una lista de las tuplas (autovalor, autovector)
    paresAutoVecAutoVal = [(np.abs(autovalores[i]), autovectores[:, i])
                           for i in range(len(autovalores))]
    return paresAutoVecAutoVal
def getMatrizProyeccion(a, b):
    # Funcion R13x1 --> R13x2 definida por la union de dos columnas (13x1) y (13x1)
    matrizProyeccion = np.hstack((a, b))  
    return matrizProyeccion 
def getMayoresAutovalores(paresAutoVecAutoVal):
     # Ordenamos las tuplas de mayor a menor
    paresAutoVecAutoVal.sort(key=lambda k: k[0], reverse=True)  
    #Devolvemos los dos primeros autovectores y le añadimos una dimension extra
    a = paresAutoVecAutoVal[0][1][:, np.newaxis]
    b = paresAutoVecAutoVal[1][1][:, np.newaxis]
    return a, b
def estandarizacionDatos(X_train, X_test):
    sc = StandardScaler()
    sc.fit(X_train)  # Estima los parametros u y o para dimension de los datos
    X_train_std = sc.fit_transform(X_train)
    X_test_std = sc.transform(X_test)
    return X_train_std, X_test_std
def getMatrizCovarianza(X_train_std):
    matrizCovarianza = np.cov(X_train_std.T)
    return matrizCovarianza
def getAutovaloresVectores(matrizCovarianza):
    autovalores, autovectores = np.linalg.eig(matrizCovarianza)
    return autovalores, autovectores
def predicion(texto,X_train_std,X_test_std,Y_train,Y_test):
    print(texto)
    lr = LogisticRegression()
    lr.fit(X_train_std,Y_train)
    Y_predic = lr.predict(X_test_std)
    metricas(Y_test,Y_predic) 
def metricas(Y_test,Y_predic):    
    exactitud = accuracy_score(Y_test,Y_predic)
    print("Exactitud del modelo:")
    print(exactitud)
    matriz = confusion_matrix(Y_test,Y_predic)
    print('Matriz de confusion:')
    print(matriz) 
    print() 
def datosReducidos(X,W):
    M= np.dot(X,W)
    return M
X,Y = getDatos()
X_train, X_test, Y_train, Y_test = getDivisionDatos(X,Y)
# Estandarizacion de datos 
X_train_std, X_test_std = estandarizacionDatos(X_train, X_test)
# Obtenemos de la matriz de covarianza
matrizCovarianza = getMatrizCovarianza(X_train_std)
# Pedimos los autovalores y autovectores a la matriz de covarianza
autovalores, autovectores = getAutovaloresVectores(matrizCovarianza)
# Ordenamos los autovalores por orden decreciente segun los autovectores
paresAutoVecAutoVal = getOrdenAutovalores(autovalores, autovectores)
# Seleccionamos 2 autovectores que correspondan a los k autovalores mayores
a, b = getMayoresAutovalores(paresAutoVecAutoVal)
# Obtenemos la matriz de proyeccion W a partir de los k autovectores
matrizProyeccion = getMatrizProyeccion(a, b)
#Realizamos el producto xW con los datos de entrenamiento 
X_train_stdR=datosReducidos(X_train_std,matrizProyeccion)
#Realizamos el producto xW con los datos de test
X_test_stdR=datosReducidos(X_test_std,matrizProyeccion)
predicion("Predicion sin reducir",X_train_std,X_test_std,Y_train,Y_test)
predicion("Predicion modo reducido",X_train_stdR,X_test_stdR,Y_train,Y_test) 

Salida

Predicion sin reducir

Exactitud del modelo:

0.9814814814814815

Matriz de confusion:

18 0 0
0 20 1
0 0 15

Predicion modo reducido

Exactitud del modelo:

0.9814814814814815

Matriz de confusion:

18 0 0
1 20 0
0 0 15

PCA sobre el set de datos wine usando la libreria scikit learn

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression
from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import precision_score
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
def getDatos():
# Lectura de datos
wine = pd.read_csv("wine.csv")
X = wine.iloc[:, 1:14].values
Y = wine.iloc[:, 0].values
return X,Y
def getDivisionDatos(X,Y):
# Division del conjunto de los datos
X_train, X_test, Y_train, Y_test = train_test_split(
X, Y, test_size=0.3, random_state=1, stratify=Y)
return X_train, X_test, Y_train, Y_test
def estandarizacionDatos(X_train, X_test):
sc = StandardScaler()
sc.fit(X_train) # Estima los parametros u y o para dimension de los datos
X_train_std = sc.fit_transform(X_train)
X_test_std = sc.transform(X_test)
return X_train_std, X_test_std
def entrenamiento(numeroComponentes,X_train_std,X_test_std):
pca = PCA(n_components=numeroComponentes)
X_train_pca = pca.fit_transform(X_train_std)
X_test_pca = pca.transform(X_test_std)
lr = LogisticRegression()
lr.fit(X_train_pca,Y_train)
return X_train_pca, X_test_pca,lr
def regionesDecision(X, y, X_prueba, clasificador, mostrarDatosPrueba , resolution=0.02):
marcas = ('s', 'x', 'o', '^', 'v')
colores= ('red','black','blue','green','yellow')
clases=np.unique(y)
arrayColores=colores[:len(clases)]
listedColormap = ListedColormap(arrayColores)
rangoA= np.arange(X[:,0].min()-1,X[:,0].max()+1,resolution)
rangoB= np.arange(X[:,1].min()-1,X[:,1].max()+1,resolution)
xx, yy = np.meshgrid(rangoA,rangoB)
s= np.array([xx.ravel(), yy.ravel()]).T
Z = clasificador.predict(s)
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.3, cmap=listedColormap)
for a, b in enumerate(clases):
plt.scatter(x=X[y == b, 0],
y=X[y == b, 1],
alpha=0.8,
c=colores[a],
marker=marcas[a],
label=b,
edgecolor='black')

if (mostrarDatosPrueba):
plt.scatter(X_prueba[:, 0],
X_prueba[:, 1],
c='',
edgecolor='red',
alpha=1.0,
linewidth=1,
marker='o',
s=100,
label='test set')
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='lower left')
plt.tight_layout()
plt.savefig('trainRegionesDecision.jpg', dpi=150)
plt.show()
def metricas(Y_test,Y_predic):
exactitud = accuracy_score(Y_test,Y_predic)
print("Exactitud del modelo:")
print(exactitud)
matriz = confusion_matrix(Y_test,Y_predic)
print('Matriz de confusion:')
print(matriz)
print()
def getDatosReducidos(X_train_std,X_test_std,numeroComponentes):
pca = PCA(n_components=numeroComponentes)
X_train_pca = pca.fit_transform(X_train_std)
X_test_pca = pca.transform(X_test_std)
return X_train_pca,X_test_pca
def predicion(texto,X_train_std,X_test_std,Y_train,Y_test):
print(texto)
lr = LogisticRegression()
lr.fit(X_train_std,Y_train)
Y_predic = lr.predict(X_test_std)
metricas(Y_test,Y_predic)
X,Y = getDatos()
X_train, X_test, Y_train, Y_test = getDivisionDatos(X,Y)
# Estandarizacion de datos
X_train_std, X_test_std = estandarizacionDatos(X_train, X_test)
#Transformacion de datos para dos componentes
X_train_pca, X_test_pca, lr = entrenamiento(2,X_train_std,X_test_std)
y_predic = lr.predict(X_test_pca)
X_train_pca,X_test_pca= getDatosReducidos(X_train_std,X_test_std,2)
predicion("Predicion sin reducir",X_train_std,X_test_std,Y_train,Y_test)
predicion("Predicion modo reducido",X_train_pca,X_test_pca,Y_train,Y_test)

Salida

Predicion sin reducir

Exactitud del modelo:

0.9814814814814815

Matriz de confusion:

18 0 0
0 20 1
0 0 15

Predicion modo reducido

Exactitud del modelo:

0.9814814814814815

Matriz de confusion:

18 0 0
1 20 0
0 0 15