/***********************************************************************
This file is part of KEEL-software, the Data Mining tool for regression,
classification, clustering, pattern mining and so on.
Copyright (C) 2004-2010
F. Herrera (herrera@decsai.ugr.es)
L. S�nchez (luciano@uniovi.es)
J. Alcal�-Fdez (jalcala@decsai.ugr.es)
S. Garc�a (sglopez@ujaen.es)
A. Fern�ndez (alberto.fernandez@ujaen.es)
J. Luengo (julianlm@decsai.ugr.es)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/
**********************************************************************/
/** Linear and Cuadratic discriminant analysis,
with a normal distribution of the examples for each class
**/
package keel.Algorithms.Statistical_Classifiers.Shared.DiscrAnalysis;
import keel.Algorithms.Statistical_Classifiers.Shared.MatrixCalcs.*;
import keel.Algorithms.Statistical_Classifiers.Shared.*;
import java.io.*;
import java.util.Vector;
public class AD {
double COVAR[][][];
double MEDIA[][][];
double ejemplos[][];
double deseado[][];
int nentradas;
int nsalidas;
int nelem;
int nejemplos[];
public AD(double[][] vejemplos, double[][] vdeseado) {
ejemplos = vejemplos;
deseado = vdeseado;
nentradas = ejemplos[0].length;
nsalidas = deseado[0].length;
nelem = ejemplos.length;
COVAR = new double[nsalidas][nentradas][nentradas];
MEDIA = new double[nsalidas][nentradas][1];
nejemplos = new int[nsalidas];
for (int i = 0; i < nelem; i++) {
for (int s = 0; s < nsalidas; s++) {
if (deseado[i][s] != 0) {
nejemplos[s]++;
}
}
}
}
public void computeParameter(boolean lineal) throws ErrorDimension, ErrorSingular {
// If 'lineal' is true, Every covariance matrix are equal
for (int i = 0; i < nelem; i++) {
for (int s = 0; s < nsalidas; s++) {
if (deseado[i][s] != 0) {
MEDIA[s] = MatrixCalcs.matsum(MEDIA[s], MatrixCalcs.columna(ejemplos[i]));
}
}
}
for (int s = 0; s < nsalidas; s++) {
MEDIA[s] = MatrixCalcs.matmul(MEDIA[s], 1.0f / nejemplos[s]);
}
double tmp[][];
if (lineal) {
// Every calculus are made over COVAR[0]
for (int i = 0; i < nelem; i++) {
for (int s = 0; s < nsalidas; s++) {
if (deseado[i][s] != 0) {
tmp = MatrixCalcs.matsum(
MatrixCalcs.columna(ejemplos[i]),
MatrixCalcs.matmul(MEDIA[s], -1.0f));
tmp = MatrixCalcs.matmul(tmp, MatrixCalcs.tr(tmp));
COVAR[0] = MatrixCalcs.matsum(COVAR[0], tmp);
}
}
}
// Covariance matrix is inverted
COVAR[0] = MatrixCalcs.matmul(COVAR[0], 1.0f / nelem);
COVAR[0] = MatrixCalcs.inv(COVAR[0]);
// Results are copied to every matrix
for (int s = 1; s < nsalidas; s++) {
for (int i = 0; i < COVAR[s].length; i++) {
for (int j = 0; j < COVAR[s][i].length; j++) {
COVAR[s][i][j] = COVAR[0][i][j];
}
}
}
} else {
// Covariance matrix are estimated separately
for (int i = 0; i < nelem; i++) {
for (int s = 0; s < nsalidas; s++) {
if (deseado[i][s] != 0) {
tmp = MatrixCalcs.matsum(
MatrixCalcs.columna(ejemplos[i]),
MatrixCalcs.matmul(MEDIA[s], -1.0f));
tmp = MatrixCalcs.matmul(tmp, MatrixCalcs.tr(tmp));
COVAR[s] = MatrixCalcs.matsum(COVAR[s], tmp);
}
}
}
// Covariace matrixes are inverted
for (int s = 0; s < nsalidas; s++) {
COVAR[s] = MatrixCalcs.matmul(COVAR[s], 1.0f / nejemplos[s]);
COVAR[s] = MatrixCalcs.inv(COVAR[s]);
}
}
}
public String AString(double[] s) {
String result = "[";
for (int i = 0; i < s.length; i++) {
result = result + s[i] + " ";
}
return result + "]";
}
public String AString(double[][] s) {
String result = "[";
for (int i = 0; i < s.length; i++) {
result = result + AString(s[i]) + " ";
}
return result + "]";
}
public double[] distances(double[] x) throws ErrorDimension, ErrorSingular {
// Distance from each example to each prototype is calculated
double d[] = new double[nsalidas];
double g[][];
double[][] cx = MatrixCalcs.columna(x);
for (int s = 0; s < nsalidas; s++) {
// Cuadratic term
g = MatrixCalcs.matmul(
MatrixCalcs.tr(cx),
MatrixCalcs.matmul(COVAR[s], cx));
g = MatrixCalcs.matmul(g, -0.5f);
// Linear term
double[][] w = MatrixCalcs.tr(
MatrixCalcs.matmul(COVAR[s], MEDIA[s]));
g = MatrixCalcs.matsum(g, MatrixCalcs.matmul(w, cx));
// Constant term
double[][] C1 = MatrixCalcs.matmul(
MatrixCalcs.tr(MEDIA[s]),
MatrixCalcs.matmul(COVAR[s], MEDIA[s]));
C1 = MatrixCalcs.matmul(C1, -0.5f);
double C2 = 0.5f * (double) Math.log(
MatrixCalcs.determinante(COVAR[s]));
double C3 = (double) Math.log(nejemplos[s] / (double) nelem);
d[s] = g[0][0] + C1[0][0] + C2 + C3;
}
return d;
}
public void AlmacenaParametros(double[] pesos) {
int p = 0;
for (int i = 0; i < COVAR.length; i++) {
for (int j = 0; j < COVAR[i].length; j++) {
for (int k = 0; k < COVAR[i][j].length; k++) {
pesos[p++] = COVAR[i][j][k];
}
}
}
for (int i = 0; i < MEDIA.length; i++) {
for (int j = 0; j < MEDIA[i].length; j++) {
for (int k = 0; k < MEDIA[i][j].length; k++) {
pesos[p++] = MEDIA[i][j][k];
}
}
}
for (int i = 0; i < nejemplos.length; i++) {
pesos[p++] = nejemplos[i];
}
}
public void RecuperaParametros(double[] pesos) {
int p = 0;
for (int i = 0; i < COVAR.length; i++) {
for (int j = 0; j < COVAR[i].length; j++) {
for (int k = 0; k < COVAR[i][j].length; k++) {
COVAR[i][j][k] = pesos[p++];
}
}
}
for (int i = 0; i < MEDIA.length; i++) {
for (int j = 0; j < MEDIA[i].length; j++) {
for (int k = 0; k < MEDIA[i][j].length; k++) {
MEDIA[i][j][k] = pesos[p++];
}
}
}
for (int i = 0; i < nejemplos.length; i++) {
nejemplos[i] = (int) pesos[p++];
}
}
public static int argmax(double[] x) {
double max = x[0];
int imax = 0;
for (int i = 1; i < x.length; i++) {
if (x[i] > max) {
max = x[i];
imax = i;
}
}
return imax;
}
}