Una forma sencilla y rápida de aprender JAVA, observando y deduciendo cómo se comporta el lenguaje a través de ejemplos prácticos.

domingo, 19 de noviembre de 2017

Creación de una estructura de red neuronal artificial perceptrón multicapa.

Se trata de que a partir de un vector se cree una estructura neuronal artificial basada en capas (perceptrón multicapa).
El funcionamiento es que los valores introducidos en el vector indican el número de neuronas que tiene cada capa, y la posición o el índice de estos valores corresponde a la capa a la que se aplica.

Ejemplo:

Con el vector {2, 3, 3, 1} la red tendría la siguiente estructura:




En el ejemplo también se agregan los pesos(w) de las conexiones y se calculan todas las salidas de las neuronas(s). El cálculo de las salidas se le llama "propagación hacia delante".


* Nomenclatura de los pesos(w):

w[k][j][i]

k = índice capa
j = índice conector origen
i = índice conector destino


* Nomenclatura de las salidas(s):

s[k][j]

k = índice capa
j = índice neurona

En última instancia se calcula el error, teniendo como referencia la salida deseada (d1) en contraste con la salida real.


Código1 (Red.java):

package red;
public class Red {
   public static void main(String[] args) {
      Estructura red = new Estructura();
      red.estruct();
   }
}


Código2 (Estructura.java):

package red;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

public class Estructura {

   int nK[] = {2, 3, 3, 1};
   double[][][] w = new double[nK.length][9][9]; //peso
   double[][] s = new double[nK.length][9]; //salida

   // tabla de entrenamiento
   final int x1[] = {34}; // entrada 1 (x1)
   final int x2[] = {23}; // entrada 2 (x2)
   final int d1[] = {57}; // salida deseada 1 (d1)

   public void estruct() {

      int row = 1;
      for (int i = 0; i < nK.length; i++) {
         row *= nK[i];
      }

      // inicializar vector con pesos aleatorios.
      double[] vw = new double[row];
      for (int i = 0; i < vw.length; i++) {
         vw[i] = new Random().nextDouble();
      }

      // Añadir los pesos(w) y cálculo salidas(s) - Propagación hacia delante -
      propagacion_hacia_delante(vw);

   }

   private void propagacion_hacia_delante(double[] vw) {

      // vector a lista  
      List<Double> lw = new ArrayList<>();
      for (int i = 0; i < vw.length; i++) {
         lw.add(vw[i]);
      }
      Iterator wi = lw.iterator();

      System.out.println("* Entradas (x1, x2): ");
      int k = 0;
      s[k][0] = x1[0] / 100.0;
      s[k][1] = x2[0] / 100.0;
      System.out.println("s[" + k + "][" + 0 + "] = " + s[k][0]);
      System.out.println("s[" + k + "][" + 1 + "] = " + s[k][1]);
      double aux;
      for (k = 1; k < nK.length; k++) {
         System.out.println("\n* Capa(k): " + k);
         for (int j = 0; j < nK[k]; j++) {
            aux = 0.0;
            for (int i = 0; i < nK[k - 1]; i++) {
               if (wi.hasNext()) {
                  w[k][j][i] = (double) wi.next();
                  System.out.println("w[" + k + "][" + j + "][" + i + "] = " + w[k][j][i]);
                  aux += s[k - 1][i] * w[k][j][i];
               }
            }
            s[k][j] = F(aux);
            System.out.println("s[" + k + "][" + j + "] = " + s[k][j]);
            System.out.println("");
         }
      }

      double error = error(s[nK.length - 1][0]);
      System.out.println("Error(%) = " + error + "\n");

   }

   // cálculo error
   private double error(double salida) {
      System.out.println("\nCalculando error: ");
      System.out.println("Salida real (s) = " + salida);
      System.out.println("Salida deseada (d1) = " + d1[0] / 100.0);
      double error = (d1[0] / 100.0) - salida;
      return Math.abs(error) * 100.0;
   }

   // función de activación(F)
   public double F(double n) {
      return 1 / (1 + Math.pow(Math.E, -n));
   }

}


Resultado:

run:

* Entradas (x1, x2):
s[0][0] = 0.34
s[0][1] = 0.23

* Capa(k): 1
w[1][0][0] = 0.7784702928226366
w[1][0][1] = 0.6257786601112015
s[1][0] = 0.6007542942239193

w[1][1][0] = 0.5968623640712245
w[1][1][1] = 0.6454353802610788
s[1][1] = 0.5869529953218492

w[1][2][0] = 0.6365114581851211
w[1][2][1] = 0.5225522235927118
s[1][2] = 0.5833646070992183


* Capa(k): 2
w[2][0][0] = 0.8144433731113941
w[2][0][1] = 0.3745491950410721
w[2][0][2] = 0.8572794764916719
s[2][0] = 0.7701626126927235

w[2][1][0] = 0.7461525150108156
w[2][1][1] = 0.016718260683668218
w[2][1][2] = 0.7820072960095001
s[2][1] = 0.7138716176876397

w[2][2][0] = 0.6111430308203408
w[2][2][1] = 0.471402921978638
w[2][2][2] = 0.36959971608321707
s[2][2] = 0.7025456368129452


* Capa(k): 3
w[3][0][0] = 0.5283695321605173
w[3][0][1] = 0.14549272162478644
w[3][0][2] = 0.27585354985756827
s[3][0] = 0.6692053761568678


Calculando error:
Salida real (s) = 0.6692053761568678
Salida deseada (d1) = 0.57
Error(%) = 9.920537615686786

BUILD SUCCESSFUL (total time: 0 seconds)


domingo, 23 de julio de 2017

Serie armónica.

La serie armónica es la suma de los inversos de los números naturales.











Código java (numeroArmonico.java):

// Serie armónica hasta el 16
package numeroarmonico;

public class SerieArmonica {
   public static void main(String[] args) {
      int n = 16;
      double sum = 0.0;
      for (int k = 1; k <= n; k++) {
         sum += 1.0 / k;
         System.out.printf("H(%d) = %f\n", k, sum);
      }
   }
}




Resultado:

run:
H(1) = 1,000000
H(2) = 1,500000
H(3) = 1,833333
H(4) = 2,083333
H(5) = 2,283333
H(6) = 2,450000
H(7) = 2,592857
H(8) = 2,717857
H(9) = 2,828968
H(10) = 2,928968
H(11) = 3,019877
H(12) = 3,103211
H(13) = 3,180134
H(14) = 3,251562
H(15) = 3,318229
H(16) = 3,380729
BUILD SUCCESSFUL (total time: 0 seconds)


domingo, 19 de marzo de 2017

Discretización basada en Entropía (I).

La entropía calcula el grado de desorden de un sistema. En este ejemplo será calculada en base a dos tipos de clases (A, B).
En minería de datos se utiliza para encontrar la partición con la máxima ganancia de información posible. 



* Procedimiento:

Sea S un conjunto de 1000 pares (AtributoValor, Clase) por ejemplo:

 
S = {(15, A), (280, B), (319, A), (775, B), (801, B), (850, A), (855, B), (880, B)....}

p1 = núm. de atributos de A / 1000 -> (la fracción de pares con clase = A)
p2 = núm. de atributos de B / 1000 -> (la fracción de pares con clase = B)

La entropía (o contenido de información) para S es:

    Entropia(S) = - p1 * log2(p1) – p2 * log2(p2)


* Características resultado:

    - Nos tiene que dar un valor entre 0 y 1.
    - Si la entropía es pequeña, entonces el conjunto esta muy ordenado.
    - Si la entropía es grande, entonces el conjunto esta muy desordenado.
    - En este ejemplo al obtener las clases aleatoriamente, nos debería dar una entropía alta, ya que lo aleatorio es sinónimo de desorden.


Código java (DiscretizarEntropia.java):

package discretizarentropia;

public class DiscretizarEntropia {

   public static void main(String[] args) {

      int nRegistros = 1000;
      Object[][] v = new Object[nRegistros][2];

      int cont = 0;
      for (int i = 0; i < nRegistros; i++) {
         v[i][0] = (int) (Math.random() * 1000);
         v[i][1] = (int) (Math.random() * 2);
         if (v[i][1].equals(0)) {
            cont++;
         }
      }

      double p1 = (float) cont / (float) nRegistros;
      double p2 = ((float) nRegistros - (float) cont) / (float) nRegistros;


      double S = -(p1 * log(p1, 2)) - (p2 * log(p2, 2));

      System.out.println("Número de clases A: " + cont);
      System.out.println("Número de clases B: " + (nRegistros - cont));
      System.out.println("Fracción de pares con clase A (p1) = " + p1);
      System.out.println("Fracción de pares con clase B (p2) = " + p2);
      System.out.println("Entropia(S) = " + S);

   }

   private static Double log(double num, int base) {
      return (Math.log10(num) / Math.log10(base));
   }

}


Resultado:

run:
Número de clases A: 481
Número de clases B: 519
Fracción de pares con clase A (p1) = 0.48100000619888306
Fracción de pares con clase B (p2) = 0.5189999938011169
Entropia(S) = 0.9989581240309595
BUILD SUCCESSFUL (total time: 0 seconds)



Cálculo de logaritmos en distintas bases.

En java no existe ninguna función que nos calcule directamente logaritmos en bases distintas a 10. Para ello habrá que crear nuestra propia función.


Código java (Logaritmos1.java):

//Cálculo de logaritmos en distintas bases.
package logaritmos1;

public class Logaritmos1 {

   public static void main(String[] args) {
      int num = 5;
      for (int base = 0; base < 10; base++) {
         System.out.println("Logaritmo de 5 en base " + base + " = " + log(num, base));
      }
   }

   private static Double log(double num, int base) {
      return (Math.log10(num) / Math.log10(base));
   }


}


Resultado:

run:
Logaritmo de 5 en base 0 = -0.0
Logaritmo de 5 en base 1 = Infinity
Logaritmo de 5 en base 2 = 2.3219280948873626
Logaritmo de 5 en base 3 = 1.4649735207179273
Logaritmo de 5 en base 4 = 1.1609640474436813
Logaritmo de 5 en base 5 = 1.0
Logaritmo de 5 en base 6 = 0.8982444017039273
Logaritmo de 5 en base 7 = 0.8270874753469162
Logaritmo de 5 en base 8 = 0.7739760316291209
Logaritmo de 5 en base 9 = 0.7324867603589637
BUILD SUCCESSFUL (total time: 0 seconds)


viernes, 17 de marzo de 2017

Pasar un array de valores numéricos a escala percentual - atributo continuo -

Siguiendo con el post anterior esta vez se intentará reestructurar el código anterior y añadir la función "DiscretizarFine" que consiste en añadir en el rango mínimo y máximo (que son indeterminados) la media de los espacios que existen entre todos los valores del array. Esto en teoría afinaría en la precisión en el machine learning.


* Ejemplo gráfico para ver las diferencias entre los distintos modelos:




Código Java 1 (BloggerDiscretizar2.java):

package bloggerdiscretizar2;

import java.util.Arrays;


public class BloggerDiscretizar2 {
  
   public static void main(String[] args) {

      Array arr = new Array();

      double v_inicial[] = new double[16];
      double v_discretizar[] = new double[16];
      double v_discretizarFine[] = new double[16];

      for (int i = 0; i < v_inicial.length; i++) {
         v_inicial[i] = (double) Math.random() * 512;
      }
     
      //copiar v_inicial
      System.arraycopy(v_inicial, 0, v_discretizar, 0, v_inicial.length);
      System.arraycopy(v_inicial, 0, v_discretizarFine, 0, v_inicial.length);

      //discretizar percentual
      v_discretizar = arr.toDiscretizar(v_inicial);
      v_discretizarFine = arr.toDiscretizarFine(v_inicial);
     
      //ordenar arrays de menor a mayor
      Arrays.sort(v_inicial);
      Arrays.sort(v_discretizar);
      Arrays.sort(v_discretizarFine);
     
      //mostrar resultados
      System.out.println("vector inicial:");
      for (int i = 0; i < v_inicial.length; i++) {        
         System.out.println(v_inicial[i]);        
      }
     
      System.out.println("\nvector discretizado (atributo discreto):");
      for (int i = 0; i < v_discretizar.length; i++) {
         System.out.println(v_discretizar[i]);
      }
     
      System.out.println("\nvector discretizado_fino (atributo continuo):");
      for (int i = 0; i < v_discretizarFine.length; i++) {
         System.out.println(v_discretizarFine[i]);
      }

   }

}


Código Java 2 (Array.java):

bloggerdiscretizar2;

public class Array {

     /*
   Transformar un campo numérico a categórico usando percentiles
   Atributo discreto tiene un número finito o contable de valores   
    */

   public double[] toDiscretizar(double[] array) {
      double[] array2 = new double[array.length];
      //obtener min y max apartir del array base
      double min = this.getMin(array);
      double max = this.getMax(array);
      for (int i = 0; i < array.length; i++) {
         array2[i] = (array[i] - min) / (max - min);
      }
      return array2;
   }

   /*
   Transformar un campo numérico a categórico usando percentiles (afinado)
   Atributo continuo tiene un número indeterminado de valores (no se sabe el valor min ni el max)
    */

   public double[] toDiscretizarFine(double[] array) {
      double[] array2 = new double[array.length];
      double[] array3 = new double[array.length + 2];
      for (int i = 0; i < array.length - 1; i++) {
         array2[i] = array[i] - array[i + 1];//distancia entre valores
      }
      System.arraycopy(array, 0, array3, 2, array.length);

      //calculo aproximado del min y max y se añade al array
      array3[0] = this.getMin(array) - this.getMed(array2); //min
      array3[1] = this.getMax(array) + this.getMed(array2); //max
      return this.toDiscretizar(array3);
   }

   public double getMin(double[] array) {
      double min = array[0];
      for (int i = 0; i < array.length; i++) {
         if (min > array[i]) {
            min = array[i];
         }
      }
      return min;
   }

   public double getMax(double[] array) {
      double max = array[0];
      for (int i = 0; i < array.length; i++) {
         if (max < array[i]) {
            max = array[i];
         }
      }
      return max;
   }

   public double getMed(double[] array) {
      double med = 0;
      for (int i = 0; i < array.length; i++) {
         med = med + array[i];
      }
      return med / array.length;
   }

}



Resultado:

run:
vector inicial:
6.915959656
27.4665411
106.4488495
111.8923782
146.6526326
178.1616741
185.2529849
203.4995067
223.2984554
250.5640114
262.7295496
272.2483547
319.3729241
436.0795028
441.7362144
461.5955789

vector discretizado (atributo discreto):
0
0.045197938
0.218907744
0.230879974
0.307329968
0.376629405
0.392225685
0.432356188
0.475901023
0.535867546
0.562623833
0.583559025
0.687202486
0.943881197
0.95632229
1

vector discretizado_fino (atributo continuo):
0
0.030742192
0.073161163
0.236190529
0.247426653
0.319176167
0.38421477
0.398852123
0.436515226
0.477382733
0.533662252
0.558773445
0.578421449
0.675692456
0.916589435
0.928265595
0.969257808
1
BUILD SUCCESSFUL (total time: 0 seconds)


Nota: Atributo continuo: Tiene un rango indeterminado de valores posibles.

jueves, 16 de marzo de 2017

Pasar un array de valores numéricos a escala percentual - atributo discreto -

En machine learning se le llama "discretizar array por percentiles", que consiste en uniformizar los valores numéricos de un array a escala [0:1]. Esta transformación es usada para ayudar en el aprendizaje automático de máquinas (machine learning) ya que adapta los términos absolutos del array a términos porcentuales.

Ejemplo:

Arrays iniciales:

    array1 (numérico):    0        1       2       5       7       10
    array2 (numérico):    653.7    1382    2403    4214    8890    9935
    ...
    ...

Arrays ya uniformizados (discretizados por percentiles):

    array1 (percentil):    0%      0.1%    0.2%    0.5%    0.7%    1%   
    array2 (percentil):    0%      0.07%   0.18%   0.38%   0.89%   1%
    ...
    ...

La diferencia entre los valores del array1 y array2 iniciales son dispares. Una vez transformados los campos numéricos a percentiles se observa de que los campos son más semejantes entre sí (misma escala).


Código java: (DiscretizarNormalizar.java)

//Transformar un campo numérico a categórico usando percentiles
package discretizarnormalizar;

public class DiscretizarNormalizar {

   public static void main(String[] args) {

      int nRegistros = 10;
      double[] v = new double[nRegistros];

      //crear array aleatorio
      for (int i = 0; i < nRegistros; i++) {
         v[i] = Math.random() * 10000;
      }

      //buscar valores minimos y maximos del array
      double min = v[0];
      double max = v[0];
      for (int i = 0; i < nRegistros; i++) {
         if (min > v[i]) {
            min = v[i];
         }
         if (max < v[i]) {
            max = v[i];
         }
      }

      //normalizacion-descretizar?
      double[] v2 = new double[nRegistros];
      for (int i = 0; i < nRegistros; i++) {
         v2[i] = (v[i] - min) / (max - min);
      }


      //mostrar resultado
      System.out.println("Array inicial:\t\tArray transformado:");
      for (int i = 0; i < nRegistros; i++) {
         System.out.println(i + "- " + v[i] + "\t" + v2[i]);
      }

   }

}


Resultado:

run:

Array inicial:          Array transformado:
0- 7671.886736201123    0.8019001791662852
1- 9479.117533535893    1.0
2- 4876.0856974944645   0.4954381126326166
3- 6808.418910630855    0.7072510497947576
4- 356.28849851238044   0.0
5- 6556.185784681601    0.6796024854096415
6- 5931.890253043281    0.6111702557535137
7- 8510.956094814934    0.8938748676529962
8- 589.2424296425359    0.02553527313027795
9- 1432.7279151298521   0.11799403589444743
BUILD SUCCESSFUL (total time: 0 seconds)


Nota: Atributo discreto: tiene un rango finito o contable de valores.

miércoles, 15 de marzo de 2017

Copiar arrays. Uso de la instrucción "System.arraycopy".

Código java (CopiaArray.java):

package copiaarray;

public class CopiaArray {

   public static void main(String[] args) {

      double[] array1 = new double[5];
      double[] array2 = new double[10];
      double[] array3 = new double[array1.length + array2.length];

      //rellena array1
      for (int i = 0; i < array1.length; i++) {
         array1[i] = i;
      }


      //rellena array2
      for (int i = 0; i < array2.length; i++) {
         array2[i] = Math.random();
      }

      /*
         Parametros del System.arraycopy:
         Array origen,
         Posición inicial del array origen,
         Array destino,
         Posición incial en el array de destino,
         Numero de elementos a copiar del array origen al array destino
       */

     
      System.arraycopy(array1, 0, array3, 0, array1.length);
      System.arraycopy(array2, 0, array3, array1.length, array2.length);


      //mostrar resultados
      System.out.println("\nArray1");
      for (int i = 0; i < array1.length; i++) {
         System.out.println(i + "- " + array1[i]);
      }


      System.out.println("\nArray2");
      for (int i = 0; i < array2.length; i++) {
         System.out.println(i + "- " + array2[i]);
      }


      System.out.println("\nArray3");
      for (int i = 0; i < array3.length; i++) {
         System.out.println(i + "- " + array3[i]);
      }

   }

}



Resultado:

run:

Array1
0- 0.0
1- 1.0
2- 2.0
3- 3.0
4- 4.0

Array2
0- 0.5287887048803938
1- 0.46771014928163135
2- 0.8333523729100707
3- 0.4965787587571521
4- 0.26861092247251583
5- 0.822652997195613
6- 0.5053721779352607
7- 0.896713025382418
8- 0.9093387247823286
9- 0.8910677970677133

Array3
0- 0.0
1- 1.0
2- 2.0
3- 3.0
4- 4.0
5- 0.5287887048803938
6- 0.46771014928163135
7- 0.8333523729100707
8- 0.4965787587571521
9- 0.26861092247251583
10- 0.822652997195613
11- 0.5053721779352607
12- 0.896713025382418
13- 0.9093387247823286
14- 0.8910677970677133
BUILD SUCCESSFUL (total time: 0 seconds)


Con la tecnología de Blogger.