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 destino i = índice conector origen * 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
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); } } }
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ónimode 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++; } }
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)
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)); } }
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)
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:
/* 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; }
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:
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]); }
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 */