Algoritmos de simulación y aprendizaje de maquina en MatLab




Los algoritmos de simulación son parte del aprendizaje de maquina y son usados en diversos campos de estudio en los cuales la predicción de determinadas variables permite la toma de decisiones, a continuación les comparto la implementación en Matlab de los algoritmos mas usados.

Algoritmo de gradiente descendente: para la implementación del algoritmo se usó la fórmula de gradiente descendente (1) el cual actualiza los pesos en cada iteración, también se usó la estimación del error (2) para detener el algoritmo cuando su error fuera inferior a 1e-10.

    
function w = gradiente(X, Y, eta, num)
%validacion de argumentos
if nargin < 3, eta = 0.001; end
%Numero de filas y columnas
[N,D] = size(X);
%extandarizacion
X = zscore(X);
%matriz extendida
Xext = [X,ones(N,1)];
%maximo de iteraciones
Maxiter = num;
%vector de coeficientes
W =ones(1,D+1);
%vector de errores
E =zeros(1,Maxiter);
for iter = 1:Maxiter
    %gradiente
    W = W - eta*((1/N)*((W*Xext')' - Y)'*Xext);
    %error
    E(iter + 1) = (1/(2*N))*sum(((W*Xext')' - Y).^2); 
    %detener a iteracion si el error es minimo
    if abs(E(iter + 1) - E(iter)) < 1e-10
        break;
    end
end
%grafica del error
E = E(1:iter);
plot(E);
%-----------------
% function Y = milogsitic( x )
% Y = 1./(1+exp(x));
% end


Algoritmo de gradiente descendente para clasificacion: Si se desean evaluar un modelo de clasificación se debe implementar la función sigmoide, a continuación una implementacion generando dos conjuntos de muestras artificiales:

function g = sigmoide( x )
g = exp(x)./(1+exp(x));
end

eta = 0.001; %tasa de aprendizaje
X1 = 1.*randn(100,2)+2; %media 2 y varianza 1
X2 = 2.*randn(100,2)+5; %media 5 varianza 2
 
X = [X1 ; X2];
Y = [ones(100,1);zeros(100,1)];
 
[N,D] = size(X);
%estandarización --- no es necesaria
%X = zscore(X);
%matriz extendida
Xext = [X,ones(N,1)];
%maximo de iteraciones
Maxiter = 10000;
%vector de coeficientes
W =ones(1,D+1);
%vector de errores
E =zeros(1,Maxiter);
for iter = 1:Maxiter
    %version especial con llamado a la funcion sigmoide
    W = W - eta*((1/N)*(sigmoide(W*Xext')' - Y)'*Xext);
    %error
    E(iter + 1) = (1/(N))*sum(abs(((W*Xext')' - Y))); 
    %detener a iteracion si el error es minimo
    if abs(E(iter + 1) - E(iter)) < 1e-10
        break;
    end
end
 
plot(X1(:,1),X1(:,2), '*b');
hold on
plot(X2(:,1),X2(:,2), '*r');
%dibujar la frontera
x1 = linspace(-2,10,100);
x2 = -(W(1)/W(2))*x1 - (W(3)/W(2))
plot(x1,x2,'k');

Algoritmo para clasificación basado en funciones discriminantes Gaussianas: Encontrarmos las funciones de densidad de probabilidad (fdp) de las clases y se realiza la clasificación de una muestra con base en la probabilidad de que esa muestra pertenezca a una u otra clase.

%generativo con funcione gausianas
X1 = randn(100,2) + 2;
X2 = 2*randn(100,2) + 5;
 
%modelo original
% plot(X1(:,1),X1(:,2), '*b');
% hold on
% plot(X2(:,1),X2(:,2), '*r');
 
X = [X1 ; X2]; 
 
Y = [ones(100,1);zeros(100,1)];
%face de entrenamiento
modelo = train(X,Y);
 
Z = zeros(200,3);
 
 
for i=1:200
    
    %funciones de probabilidad para la clase 1
    tem = (X(i,:) - modelo(1).media);
    p1 = 1/(((2*pi)*sqrtm(det(modelo(1).cova)))) * exp(-0.5 * tem * inv(modelo(1).cova) * tem');
    
    %funciones de probabilidad para la clase 2
    tem = (X(i,:) - modelo(2).media);
    p2= 1/(((2*pi)*sqrtm(det(modelo(2).cova)))) * exp(-0.5 * tem * inv(modelo(2).cova) * tem');
    
    if (p1 >= p2)
        %pertenece a la clase 1
        Z(i,:) = [1 X(i,:)];
    else
        %pertence a la clase 2
        Z(i,:) = [0 X(i,:)];
    end
end 
 
%clasificaion!!!
plot(Z(Z(:,1)==0,3), Z(Z(:,1)==0,2), '*b');
hold on
plot(Z(Z(:,1)==1,3), Z(Z(:,1)==1,2), '*r');

Algoritmo SMOTE y SubMuestro Inteligente: Este algoritmo nos permite realizar crear nuevas muestras sinteticamente utilizando el algoritmo de K-vecinos, tambien se usa sub muestreo inteligente que permite reducir la clase mayoritaria cuando la base de datos esta desbalanceada


%--------------------------------SMOTE-----------------------------------
%agrego libreria para llamar el algoritmo de submuestreo inteligente
addpath('CSNN');

%cargo los datos que deseo utilizar
datos  = load ('glass12.dat');

datos2 = datos;
%ahora seleccionas el numero de muestras minoritarias
datos = datos(datos(:,end) == 1, :); %ya se que son los que tienen 1 (76)

%separamos x y y
% lo valores de entrada x 
x = datos(:, 1:end-1);
% los valores de salida en este caso la clase a que pertenece (-1 y 1)

%llamo el algoritmo, le enviamos como parametros, las clases minoritarias
%T, el porcetaje N% que hace referencia a la cantidad de smote que se
%quiere realizar y el numero de vecinos a evaluar K. El algoritmo me
%devolvera nuevas muestras de la clase minoritaria creadas sinteticamente,
%el numero de muestras sera (N/100) * T
syn = smote(x, 200, 5); %152 MUESTRAS NUEVAS
%muestras de la clase minoritaria combinadas con las nuevas muestras;
x = [x;syn];
%armo de nuevo el conjunto de datos
x = [x ones(size(x,1),1)];
datosNew = [x; datos2(datos2(:,end) == -1, :)];

%-------------------------UNDER-SAMPLING----------------------------------

x = datosNew(:, 1:end-1);
% los valores de salida en este caso la clase a que pertenece (-1 y 1)
y = datosNew(:, end);

%para el uso de submuestreo inteligente se uso una libreria ya construida,
%para ello se usa la funcion underSamplig del CSNN, se le entrega como
%parametro, el conjunto de datos x, su salida y, las clases, la relacion de
%salida, y un vector que indica si los datos son numericos o discretos 
%(0 para numericos), entrega como salida el conjunto de los nuevos datos (x,y)
[newTrain,newTrainLabel]=UnderSampling(x',y',[1 -1],[1 2],[0,0,0,0,0,0,0,0,0]);
datos = [newTrain' newTrainLabel'] %nuevos datos

%-------------------------IMPLEMENTACION SMOTE--------------------------

function synthetic = smote(T, N, k)
     
    numattrs = size(T,2); %numero de atributos 
    nt = size(T,1); %cantidad de muestras
    
    if(N < 100)      
        %combino las filas aleatoreamente
        T = T(randperm(size(T,1)),:);
        nt = floor((N/100)*nt); %redondeo el numero
        N = 100;
    end
    
    N = floor(N/100);
    
    %calculo los k vecinos y retorno su indice en la muestra original
 cercaindex = kvecinos(k, T);
    
    synthetic = []; %nueva muestra
 for i =1:nt
        %claculo las nuevas muestras, envio como parametros el % de smote,
        %el indice de la muestra, sus k vecinos, el numero de atrivutos y
        %las muestras
  synthetic = [synthetic; populate(N,i,cercaindex(i,:), numattrs, T)];
    end
end

%-------------------------POPULATE----------------------------------
function synthetic = populate(N, i, nnarray, numattrs, sample)

 newindex = 1;
 synthetic = []; %tamaño de la nueva muestra
    %mientras N sea diferente de cero
 while (N ~= 0)
  
        %selecciono un indice del array aleatoriamente
  nn = randi(size(nnarray,2));
  for attr = 1:numattrs
            %diferencia entre un atributo seleccionado aleatoriamente de
            %los k vecinos mas cercanos y el atributo en cuestion
   dif  = sample(nnarray(nn),attr) -sample(i,attr);
            % numero aleatorio entre 0 -1 
   gap = rand(1);
            %final mente se calcula la nueva muestra
   synthetic(newindex, attr) = sample(i,attr) +(gap*dif);
        end
        %avanzo en el for
  newindex = newindex +1;
  N = N -1;
       
    end
end
%-------------------------K-VECINOS----------------------------------
function cercaindex = kvecinos(k, x)
 
 num = size(x,1) ; %numero de filas
 
 cercaindex = zeros(num,k);
 for i=1:num  
  
        %para calcular la distancia se puede hacer manualmente de la
        %siguiente manera:
        %----------------------------------------------------------------
  %N1 = size(x, 1);
  %N2 = size(x(i,:), 1);
  %L = x(i,:)*x';  
  %|xi-x*|^2 = sum(Xtrain.^2,2)*ones(1,N1)+ones(N2,1)*sum(X.^2,2)'-2*L
  %D = (sum(x(i,:).^2,2)*ones(1,N1)+ones(N2,1)*sum(x.^2,2)'-2*L).^(1/2)
        %----------------------------------------------------------------
        
        %sin embargo investigando se encontro que existe una funcion en
        %matlab que permite calcular la distancia de manera mas simple
        %usando dist:
        D = dist(x(i,:), x');
        %utilizamos la funcion sort para encontrar los k vecinos mas
        %cercanos al vector, luego obtenemos su indice (o) y los extraemos
  [c, o] =  sort(D);  
  cercaindex(i,:) = o(:,2:k+1);
    end
end

Algortimo K-Vecinos para clasificacion: Se usó el conjunto conocido como base de datos Iris que corresponde a un problema de clasificación de 3 tipos de orquídeas con base en información sobre los pétalos, del repositorio  Machine Learning Repository. Estos datos fueron cargados y evaluados usando un modelo para la clasificación de las muestras empleando el método de los k-vecinos con k variando de 1 a 7. Se realizó un cambio en la base de datos cambiando la variable de salida para facilitar su manejo, así: Iris-setosa = 1, Iris-versicolor = 2, Iris-virginica = 3. Se llevaron a cabo mediciones del error de clasificación, así como su respectiva matriz de confusión. A continuación la implementación del algoritmo:

%se cargan los datos, se cambiaron las clases por números Iris-setosa = 1
%Iris-versicolor = 2 Iris-virginica = 3
datos = load('iris.data');
 
%seleccionamos x y
x = datos(:,1:end-1);
y = datos(:,end);
 
%separación de datos de entrenamiento y de prueba
%selecciono muestras aleatorias sin repetir 70%
[datosTrain, o] = datasample(datos,floor((size(datos, 1)*70)/100),'Replace',false);
xTrain = datosTrain(:,1:end-1);
yTrain = datosTrain(:,end);
%escojo las muestras que no han sido seleccionadas 30%
c = 1:size(x,1);
i = setdiff(c,o);
xTest = x(i,1:end);
yTest = y(i,end);
 
%las diferentes clases para construir la matriz de confusión
My = unique(y);
eTem = 0;
kTem = 0;
for k=1:1:7
    [e,m]= kvecinosCla(xTrain,yTrain,xTest,yTest,k, My);
    if(k == 1)
        eTem = e;
        mTem = m;
        kTem =k;
    else
        if(e < eTem)
          eTem = e;
          mTem = m;
          kTem =k;
        end
    end
end
 
disp(strcat('La matriz con mejor resultado fue en k = ', num2str(kTem)));   
disp(mTem);

function [Error,MC] = kvecinosCla(xTrain,yTrain,xTest,yTest,k, My)
 
    %normalización del vector de entrenamiento, se obtiene la media y la
    %desviacion
    [xTraiN,media,desvia] = zscore(xTrain);
        
    medias = repmat(media,size(xTest,1),1);
    xTestN =(xTest- medias)./repmat(desvia,size(xTest,1),1);    
    
    num = size(xTestN,1) ; %numero de filas
    
    yResul = zeros(num, 1); 
    
    for i=1:num     
        %distancia
        D = dist(xTestN(i,:), xTraiN');        
        [c, o] =  sort(D);      
        %saco los k vecinos
        vecinos =  o(:,1:k);
        %calculo la media y ese sera la prediccion
        yResul(i) = mode(yTrain(vecinos));            
    end
    
    %error
    dif = (yResul(:,end) ~=  yTest(:,end));
    Error = sum(dif)/num;    
    disp(strcat('Error de clasificacion= ', sprintf('%0.5e',Error)));
    %Matriz de confusión;    
    disp('Matriz de confucion: ');
    [MC, ord] = confusionmat(yTest,yResul);
    MC = [ord';MC];
    MC = [[0; ord] MC];    
    disp(MC);
end


Algortimo K-Vecinos con estandarizacion de datos (Regresion): 
   
%se cargan los datos
datos = xlsread('Concrete_Data.xls');
 
%seleccionamos x y
x = datos(:,1:end-1);
y = datos(:,end);
 
%separación de datos de entrenamiento y de prueba
%selecciono muestras aleatorias sin repetir 70%
[datosTrain, o] = datasample(datos,floor((size(datos, 1)*70)/100),'Replace',false);
xTrain = datosTrain(:,1:end-1);
yTrain = datosTrain(:,end);
%escojo las muestras que no han sido seleccionadas 30%
i = setdiff(c,o);
xTest = x(i,1:end);
yTest = y(i,end);
 
for k=1:1:7
    kvecinos(xTrain,yTrain,xTest,yTest,k);
end

function kvecinos(xTrain,yTrain,xTest,yTest,k)
 
    %normalización del vector de entrenamiento, se obtiene la media y la
    %desviacion
    [xTraiN,media,desvia] = zscore(xTrain);
        
    medias = repmat(media,size(xTest,1),1);
    xTestN =(xTest- medias)./repmat(desvia,size(xTest,1),1);    
    
    num = size(xTestN,1) ; %número de filas
    
    yResul = zeros(num, 1); 
    
    for i=1:num     
        %distancia
        D = dist(xTestN(i,:), xTraiN');        
        [c, o] =  sort(D);      
        %saco los k vecinos
        vecinos =  o(:,1:k);
        %calculo la media y ese será la predicción
        yResul(i) = mean(yTrain(vecinos));            
    end
    
    %error cuadrático medio
    dif = (yResul - yTest).^2;
    Error = sum(dif)/num;
    
    disp(strcat('Error Cuadratico Medio = ', sprintf('%0.5e',Error)));
       
    mdl = LinearModel.fit(xTest,yResul,'linear');      
    %coeficiente de determinacion ordinario
    disp(strcat('Coe?ciente de Determinacion = ', sprintf('%0.5e',mdl.Rsquared.Ordinary) ));
    
    %grafica de salida real vs predicción del sistema
    figure
    scatter(yTest, yResul);
    title(strcat('Y Real vs Y de prediccion k = ',num2str( k )));
    xlabel('Real');
    ylabel('Train');
    
end

Algoritmo de ventana de Parzen con estimador de Nadaraya-Watson: Modelo de predicción basado en el método de ventana de Parzen utilizando el estimador Nadaraya-Watson para diferentes valores de h (0.01<h<10), con medición del error cuadrático medio y el coeficiente de terminación para cada h. se realiza la mejor predicción al tener el menor MSE. A continuación la implementación del algoritmo
 
%se cargan los datos
datos = xlsread('Concrete_Data.xls');
 
%seleccionamos x y
x = datos(:,1:end-1);
y = datos(:,end);
 
%separación de datos de entrenamiento y de prueba
%selecciono muestras aleatorias sin repetir 70%
[datosTrain, o] = datasample(datos,floor((size(datos, 1)*70)/100),'Replace',false);
xTrain = datosTrain(:,1:end-1);
yTrain = datosTrain(:,end);
%escojo las muestras que no han sido seleccionadas 30%
c = 1:size(x,1);
i = setdiff(c,o);
xTest = x(i,1:end);
yTest = y(i,end);
 
 
ventana_parzen_Nadara(xTrain,yTrain,xTest,yTest, 0.01);
ventana_parzen_Nadara(xTrain,yTrain,xTest,yTest, 0.05);
ventana_parzen_Nadara(xTrain,yTrain,xTest,yTest, 0.1);
ventana_parzen_Nadara(xTrain,yTrain,xTest,yTest, 1.5);
ventana_parzen_Nadara(xTrain,yTrain,xTest,yTest, 3);
ventana_parzen_Nadara(xTrain,yTrain,xTest,yTest, 6);
ventana_parzen_Nadara(xTrain,yTrain,xTest,yTest, 9);

function ventana_parzen_Nadara(xTrain,yTrain,xTest,yTest, h)
 
    %normalización del vector de entrenamiento, se obtiene la media y la
    %desviación
    [xTraiN,media,desvia] = zscore(xTrain);
        
    medias = repmat(media,size(xTest,1),1);
    xTestN =(xTest- medias)./repmat(desvia,size(xTest,1),1);    
    
    num = size(xTestN,1) ; %numero de filas
    
    yResul = zeros(num, 1); 
    
    for i=1:num     
        %distancia
        D = dist(xTestN(i,:), xTraiN');        
        numD = size(D,2);
        %kernel
        k = exp(-(0.5)*(D/h).^2)/2;
        %Nadaraya
        yTem = zeros(numD, 1);
        tem = D./h;
        yTem = (sum(k.*tem*yTrain))./(sum(k.*tem));         
        yResul(i) = mean(yTem);
    end
    
    %error cuadrático medio
    dif = (yResul - yTest).^2;
    Error = nansum(dif)/num;
    
    disp(strcat('Error Cuadratico Medio = ', sprintf('%0.5e',Error)));
       
    mdl = LinearModel.fit(xTest,yResul,'linear');      
    %coeficiente de determinación ordinario
    disp(strcat('Coe?ciente de Determinacion = ', sprintf('%0.5e',mdl.Rsquared.Ordinary) ));
    
    %grafica de salida real vs predicción del sistema
    figure
    scatter(yTest, yResul);
    title(strcat('Y Real vs Y de prediccion h = ',num2str( h )));
    xlabel('Real');
    ylabel('Test');
    
end

Algoritmo de ventana de Parzen para clasificación: Se construyó un modelo para la clasicación de la base de datos Iris empleando el método de ventana de Parzen evaluando diferentes valores de h.
 
%se cargan los datos, se cambiaron las clases por numeros Iris-setosa = 1
%Iris-versicolor = 2 Iris-virginica = 3
datos = load('iris.data');
 
%seleccionamos x y
x = datos(:,1:end-1);
y = datos(:,end);
 
%separacion de datos de entrenamiento y de prueba
%selecciono muestras aleatorias sin repetir 70%
[datosTrain, o] = datasample(datos,floor((size(datos, 1)*70)/100),'Replace',false);
xTrain = datosTrain(:,1:end);
 
%escojo las muestras que no han sido seleccionadas 30%
c = 1:size(x,1);
i = setdiff(c,o);
xTest = x(i,1:end); 
    
yReal = y(i,end);
 
calcularVetana(xTrain,xTest,yReal,0.01);
calcularVetana(xTrain,xTest,yReal,0.05);
calcularVetana(xTrain,xTest,yReal,0.1);
calcularVetana(xTrain,xTest,yReal,1.5);
calcularVetana(xTrain,xTest,yReal,3);
calcularVetana(xTrain,xTest,yReal,6);
calcularVetana(xTrain,xTest,yReal,9);
 
function calcularVetana(xTrain,xTest,yReal,h)
num = size(xTest,1);
yTest = zeros(num, 1);
for i=1:num
    
   p1 = ventana_parzen_Cla(xTrain(xTrain(:,end) == 1,1:end-1),xTest(i,1:end), h);
   p2 = ventana_parzen_Cla(xTrain(xTrain(:,end) == 2,1:end-1),xTest(i,1:end), h);
   p3 = ventana_parzen_Cla(xTrain(xTrain(:,end) == 3,1:end-1),xTest(i,1:end), h);
   [c, o] = max([p1 p2 p3]);
   yTest(i) = o;
end
 
dif = (yTest(:,end) ~=  yReal(:,end));
Error = sum(dif)/num;    
disp(strcat('Error de clasificacion= ', sprintf('%0.5e',Error)));

function suma = ventana_parzen_Cla(xTrain,xTest, h)       
    
    num = size(xTest,1) ; %numero de filas
    
    suma = 0;
    for i=1:num     
        %distancia
        D = dist(xTest(i,:), xTrain');              
        k = exp(-(0.5)*(D/h).^2);
        suma = sum(k);
    end
    
    suma = suma/num;       
    
end

Comentarios

Publicar un comentario

Entradas populares