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'); endAlgoritmo 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
Excelente aporte
ResponderEliminar