Java desde Cero Arreglos 2 – Arreglos Bidimensionales

INTRODUCCIÓN

Anteriormente ya hemos explicado que son y como funcionan los arreglos; sin embargo, los arreglos como hemos mencionado son matrices y hasta el momento solo hemos contemplado matrices o arreglos de una sola dimensión, entonces, ¿Qué ocurre con los arreglos de dos dimensiones, o en adelante?, en Java no existen los arreglos bidimensionales por definición, sino que se trata de arreglos dentro de arreglos, siendo que un arreglo de 2 dimensiones puede ser representado como una tabla (aunque no es una tabla) y un arreglo de 3 dimensiones como un cubo y así sucesivamente, siendo que los arreglos de mayores dimensiones representan un verdadero problema al menos en su representación. Un arreglo bidimensional se puede representar de la siguiente forma:

m2.png

DECLARACIÓN

Su declaración de forma implícita sigue la siguiente sintaxis:

int [][] matrix1=new int [4][5];

Quizá una forma sencilla de entenderlo sería que el arreglo principal tendrá 4 sub-arreglos y que cada sub-arreglo tendrá 5 elementos. ¿Podemos declarar un arreglo bidimensional de forma explícita?, sí, pero realmente resultaría muy engorroso, sino observa:

matrix1[0][0]=15;
matrix1[0][1]=21;
matrix1[0][2]=18;
matrix1[0][3]=9;
matrix1[0][4]=15;

matrix1[1][0]=10;
matrix1[1][1]=52;
matrix1[1][2]=17;
matrix1[1][3]=19;
matrix1[1][4]=7;

matrix1[2][0]=19;
matrix1[2][1]=2;
matrix1[2][2]=13;
matrix1[2][3]=17;
matrix1[2][4]=7;

matrix1[3][0]=92;
matrix1[3][1]=13;
matrix1[3][2]=13;
matrix1[3][3]=32;
matrix1[3][4]=41;

También podemos hacerlo de forma explícita de la siguiente forma:

int [][] matrix={{15,21,18,9,15}, {10,52,17,19,7}, {19,2,13,17,7}, {92,13,13,32,41} }

Pero esto resulta quizá sencillo por la cantidad de elementos que alberga el arreglo, imagina ahora si fuera un arreglo de 100×100, definitivamente la forma implícita resulta una mejor opción

RECORRIDO

Obtener una posición específica del arreglo es indicando la posición exacta que estamos buscando:

System.out.println(matrix1[2][0])

Obviamente que debe de existir un valor ya asignado en dicha posición. ¿Cómo podemos recorrer un arreglo bidimensional?, el recorrido se realiza a través de un bucle for anidado, para ello podemos emplear tanto el for convencional como el foreach:

Por ejemplo asignemos los valores a los elementos

for (int i = 0; i < matrix1.length; i++) {
   for(int j =0; j < matrix1[i].length; j++){
      matrix1[i][j]=j+i;
   }
}

Observemos la estructura del bucle for anidado, tanto i como j representan los índices del arreglo y sub-arreglos respectivamente, la estructura se resuelve primero iterando sobre el sub-arreglo manteniendo fijo el valor de i, cuando se ha recorrido todo el sub-arreglo (es decir j) se pasa al siguiente valor de i. Ahora recorramos el arreglo bidimensional pero esta vez haciendo uso del bucle foreach:

for (int[] submatriz : matrix1) {
   for(int elemento : submatriz){
      System.out.println(elemento);
   }
}

Podemos observar que el recorrido es mucho más simplificado solo siempre recordar que deben ser del mismo tipo al elemento que ha de recorrerse.

 

Anuncios

Java desde Cero – Arreglos 1 y ForEach

Bueno ya hemos revisado la mayoría de los bucles, y quizá quede el último que es el forEach; sin embargo, este fue creado para ser empleado en arreglos, eso implica que tenemos que definir que es un arreglo, un arreglo o también conocido como Array, es una estructura de datos del mismo tipo y es empleado para almacenar valores que tienen alguna relación entre sí. Definir un arreglo en Java es como definir una variable o atributo, pero al especificar el tipo lo que hacemos es colocar un par de corchetes [ ] para indicar que estamos definiendo un arreglo, entonces su sintaxis es de la siguiente forma:

tipo[]  nombre=new tipo[cantidad];
double[] tuMatriz=new double[10];

La cantidad (que es la cantidad de elementos que contiene el arreglo) es también denominada longitud; otra característica de los arreglos que estos están ordenados en función de un índice el cual nos permite poder acceder y/o modificar a cada uno de los elementos del arreglo, este índice inicia en la posición 0, en el gráfico podemos observar que si bien es cierto que el arreglo tiene 10 elementos, la última posición es 9, podemos decir entonces que la posición siempre es uno menos que la cantidad de elementos que contenga el arreglo. objects-tenelementarray

Un arreglo también puede inicializarse de forma extensiva, es decir, en la misma línea de la declaración del mismo, podemos enumerar sus elementos:

double[] tuMatriz2={2,3,4,5,6};

 

O luego de haberla inicializado podemos agregar los elementos haciendo referencia a su posición:

double[] tuMatriz3=new double[4];
tuMatriz3[0]=1;
tuMatriz3[1]=2;
tuMatriz3[2]=3;
tuMatriz3[3]=4;

Definitivamente este tipo de procesamiento puede resultar engorroso y es por ello que se hace uso del bucle for, tal como hemos revisado la estructura for, requiere de un inicio una finalización y un paso (incremento o decremento), podemos hacer entonces de la siguiente forma haciendo uso del bucle for:

for(int i=0;i<tuMatriz3.length;i++){
       System.out.println(tuMatriz3[i]);

}

Observemos esta estructura, estamos inicializando en i=0 y establecemos la finalización evaluando si i es menor que la longitud del arreglo, nosotros podemos obtener la longitud del arreglo a través de su propiedad length, el cual nos devuelve un entero, es decir tuMatriz3.length=4, podemos colocar el valor exacto dentro de la estructura, pero ello sería una mala práctica (hard-code) ya que estaríamos incrustando los datos directamente en el código y siendo que si por necesidad del programa cambiamos la longitud del arreglo, tendríamos que buscar la línea exacta donde este se modificó.

El uso del bucle for, también aplica para la inicialización de los elementos que componen un arreglo, esto se da de la siguiente forma:

for(int i =0; i < tuMatriz.length; i++){
     tuMatriz[i]=i;
     System.out.println(tuMatriz[i]);

}

Nosotros ya hemos definido el arreglo y también hemos determinado su longitud (10), y lo que hacemos es que a cada posición i le asignamos el valor de i, luego de esta asignación se imprime el valor ahora contenido en dicha posición.

Dicho esto, podemos ahora poder abordar el bucle foreach, veamos su estructura con los arreglos que ya hemos construido:

for (double elemento : tuMatriz3) {
       System.out.println(elemento);
}

Su estructura se puede traducir  como “por cada elemento de tuMatriz3 hacer:“, se puede observar que el código es más corto siendo el separador el “:“, a lado izquierdo del separador se coloca el elemento que pertenece al arreglo y que debe ser del mismo tipo que el arreglo (en nuestro caso de tipo double) y al lado derecho el arreglo que se ha de recorrer, los beneficiamos más resaltantes son que ya no nos preocupamos de donde partimos y hasta donde llegamos, el bucle ya sabe hasta donde debe llegar. Este tipo de bucle se aprecia más cuando contemplemos los tópicos de colecciones. Bueno eso es todo por el momento.

Java desde Cero – Estructura de Control de Flujo – Bucles 3

Anteriormente hemos revisado la estructura de control while:

Entonces ahora nos toca revisar la siguiente estructura denominada Do-While, ¿Cuándo se requiere hacer uso de esta estructura?, pues en situaciones donde requiramos que el código que ha de iterar de forma indefinida al menos sea ejecutado una vez antes de ser evaluado (esto quiere decir que incluso cuando la condición pueda ser falsa se ejecute una vez), esto operativamente se diferencia de la estructura while en que While la condición es evaluada al inicio del ciclo mientras que en Do-While es a su salida (razón por la cuál se permite al menos una primera iteración). La estructura Do-While es la siguiente:

do{
    sentencias...
}while(condiciones);

Procedamos a realizar un ejemplo, anteriormente habíamos observado nuestro programa de acierto de números en el cual íbamos contabilizando los intentos hasta encontrar el número aleatorio en cuestión, el sistema nos informaba que si estábamos demasiado bajo o demasiado alto, este programa lo traducimos en:

import java.util.Scanner;

public class do_while{

   publicstaticvoidmain(String[]args){

      Scanner entrada=newScanner(System.in);
      int numero=0;
      int aleatorio=(int)(Math.random()*100);
      int contador=0;

      do{

        System.out.println("ingrese un número");
        numero=entrada.nextInt();
        if(numero>aleatorio){System.out.println("Demasiado alto");}
        elseif(numero<aleatorio){System.out.println("Demasiado bajo");}
        contador++;

        }while(numero!=aleatorio);

        System.out.println("Es correcto, el número de veces que lo intentaste fue: "+contador);

        entrada.close();




}

}

Ya que estamos tratando a nivel de consola, debemos de usar la clase Scanner, esto ya lo hemos detallado en el anterior post, bueno, hemos creado un flujo, la instancia de Scanner se pone a la escucha recibiendo un input y parseando a un tipo entero que luego es evaluado para saber si es más alto o bajo que el número buscado, el único detalle es que la condición es evaluada al final.

Otro detalle que debes evaluar sobre este programa, si te haz dado cuenta es que hemos estado jugando a la suerte, ¿Qué hubiese ocurrido si el número aleatorio fuese cero y estuviésemos en una condición while, pues que el programa jamás se hubiese ejecutado al menos una vez, ya que la condición inicial que es evaluada al inicio, no se hubiera cumplido (tienen que ser diferentes para iterar), con Do While solucionamos dicho problema.

 

Teoría de Colas – Colas Markovianas – de 1 solo canal

INTRODUCCIÓN

Todos alguna vez hemos hecho una cola, en un banco, supermercado, o un trámite donde muchas personas se congregan y existen definitivamente menos centros de atención que usuarios que desean realizar algún trámite. Las colas son un tópico de la investigación de operaciones que se aborda con la finalidad de optimizar el sistema, esto ocurre por lo siguiente pongámonos  en la situación que tenemos un banco en la cual tenemos un solo cajero en atención, estamos reduciendo costos pues al menos tenemos un cajero, pero no estamos pensando que podríamos perder clientes por los tiempos de espera prolongados, lo cual repercute en el rendimiento de las operaciones, ahora podemos ir al otro extremo en que colocamos muchos cajeros tal que cada cliente sea atendido inmediatamente por un cajero, esto ocasionaría un sobre costo aun cuando el cliente se sienta totalmente satisfecho, pero no resulta conveniente, es por ello que se busca la optimización en el equilibrio del sistema. Entonces tenemos un sistema de colas que puede ser de un solo canal (cajero) o multi-canal:

1canal
Un solo canal
multicanal
Multicanal

COMPONENTES

Tal como se puede observar en los gráficos, se pueden distinguir componentes que conforman el modelo de colas, estos son:

modelo

  • Fuente de Entrada:  Toma especial interés el tamaño de la población que puede requerir servicio en determinado momento, a esta población de clientes potenciales se le conoce como “población de entrada”, esta población puede ser de tamaño finito o infinito; sin embargo, y  por la facilidad de cálculo se suele tomar que es infinito, aun cuando se trate de un problema real que definitivamente tiene un tamaño finito se toma como supuesto que es infinito a menos que se establezca lo contrario. Así como el tamaño se debe de especificar  el patrón estadístico por el cual se generan los clientes, por lo general se asume que estos siguen una distribución de Poisson.
  • Cola: La cola es donde los clientes esperan antes de recibir servicio, se caracteriza por el número máximo de clientes que puede admitir, estas también pueden ser finitas o infinitas, el supuesto de infinito se aplica como un estándar de la mayoría de modelos, incluso cuando en la realidad existe una cota superior.
  • Disciplina de la Cola:  Se refiere al orden en el que sus miembros se seleccionan para recibir el servicio, puede ser: “primero en entrar, primero en salir -(FIFO)“, “último en entrar, primero en salir-(LIFO)” , aleatoria o algún otro procedimiento.
  • Mecanismo de Servicio: Consiste  en uno o más estaciones de servicio denominados servidores, en un modelo de colas siempre se debe especificar el arreglo de las estaciones y el número de los servidores. El tiempo que transcurre desde el inicio del servicio para un cliente hasta su terminación en una estación se llama tiempo de servicio.

NOTACIÓN  Y DISTRIBUCIÓN

En la notación se sigue la notación Kendall que se indica de la siguiente forma:

A/B/C

Donde:

  • A: Especifica el tipo de distribución en la llegada.
  • B: Especifica el proceso de servicio
  • C: Indica el número de servidores

Los códigos empleados son:

  • M: para Markoviano (las tasas de llegada siguen una distribución de Poisson), significando una distribución exponencial para los tiempos de llegada (un banco, cola de supermercado, etc.).
  • D: para unos tiempos deterministas, es decir, los tiempos de llegada no son probabilísticos  y son a intervalos constantes (una planta con un proceso automatizado en línea).
  • G: para una distribución general de los tiempos de llegada, es decir permite cualquier distribución arbitraria.

TERMINOLOGÍA

Se tiende a una terminología aunque cada autor podría diferir en la definición de los términos o símbolos que hace uso:

  • Estado del sistema: número de clientes en el sistema.
  • Longitud de la cola: número de clientes que esperan servicio o estado del sistema menos número de clientes a quiénes se les da el servicio.
  • N(t): número de clientes en el sistema de colas en el tiempo t (t≥0).
  • Pn(t): probabilidad de que exactamente n clientes estén en el sistema en el tiempo t dado el número en el tiempo 0.
  • s: número de servidores (canales de servicio en paralelo) en el sistema de colas.
  • λn: tasa media de llegadas (número esperado de llegadas por unidad de tiempo) de nuevos clientes cuando hay n clientes en el sistema.
  • μn: tasa media de servicio en todo el sistema (número esperado de clientes que completan su servicio por unidad de tiempo).

MEDIDAS DE RENDIMIENTO

Centradas en el cliente:

  • Wq: tiempo promedio de espera, en la cual un cliente llega y es atendido.
  • W: tiempo promedio total del sistema, que incluye el tiempo promedio de espera y el tiempo promedio del servicio.

Cuantitativas sobre el número de clientes:

  • P0: probabilidad de que no haya clientes en el sistema, puede ser empleado cuando se requiera la probabilidad de que haya n elementos en el sistema.

Relacionadas al costo:

  • Costo promedio por unidad de tiempo de operación del sistema
  • Cantidad de estaciones de trabajo necesarias para obtener la mayor efectividad en términos de costos.

RELACIONES ENTRE MEDIDAS DE RENDIMIENTO

El tiempo promedio del sistema, es el tiempo de espera y el tiempo de servicio, sí  “μ” es la cantidad de clientes atendidos por unidad de tiempo, la inversa será el tiempo que demore en atender a un cliente en una unidad de tiempo, entonces:

Tiempo total de un cliente en el sistema:form1

Sea que el tiempo que pasa el cliente en el sistema es W, y λ  por definición es la cantidad de clientes que llegan al sistema por unidad de tiempo, entonces podemos decir que la cantidad de clientes en el sistema  en cualquier tiempo dado será:

L=W*λ

Podemos hacer una analogía, para determinar la cantidad de clientes esperando en cualquier tiempo dado de la siguiente forma:

Cantidad de clientes en cola: Lq=Wq

ANÁLISIS DE COSTOS DEL SISTEMA DE COLAS

Para determinar el costo total debemos de hallar el costo total del personal:

Costo total de personal=(Costoxhoraxservidor) * (Cantidad de personal)

El costo total de los clientes en espera:

Costo total por la espera=(Costoxhoraxcliente_en_cola) * (Cantidad de clientes en cola)

Tal que el costo total es:

Costo total=Costo_total_personal + Costo_total_por_la_espera

ANÁLISIS DE UN SISTEMA DE COLAS DE TIPO (M/M/1)

Las fórmulas de rendimiento por lo general se han derivado a través del uso de las variables λ y μ tal que se llega a la expresión de la intensidad de tráfico o también denominado factor de uso (ρ)  que tiene la siguiente forma:

 Factor de uso: ρ=λ/μ

Si el factor de uso mientras más cerca a 1 significará que el sistema estará más cargado lo cual trae como resultados colas más largas y tiempos de espera más largos. Sí el factor de uso mide la intensidad de clientes en el sistema,  su complemento determina la probabilidad de que no exista clientes en el sistema:

Probabilidad de cero clientes en el sistema: P0=1-ρ

Esta probabilidad indica que un cliente que llega no tendrá que esperar a que se le proporcione servicio ya que la cola estará vacía.

Podemos de similar forma obtener la cantidad de clientes en espera o en la cola en función de ρ o de λ y μ.

Número de clientes en espera:col1

Este último resultado sirven de base para obtener el Wq y W acorde a las fórmulas planteadas líneas arriba.

Si deseamos determinar la probabilidad de que el sistema tenga exactamente “n” cantidad de clientes:

Cantidad n exacta de clientes en el sistema:col2

Esta última ecuación nos permite responder a las preguntas tales como: ¿Cuál es la probabilidad que no haya más de  n clientes en el sistema? , para ello debemos de tomar la suma desde 0 a n de las probabilidades:

col3

Y si en caso la pregunta fuera ¿Cuál es la probabilidad de encontrar hasta n clientes en el sistema?, se tomará el complemento, es decir:

1-Ptotal

EJEMPLOS DE APLICACIÓN

Ejercicio 1

Si la tasa de llegada a una estación de servicio es de 12 unidades por hora y el tiempo de atención por unidad es de 4 minutos siendo además que se pierde por unidad parada la cantidad de $80 por hora y que el costo por día del servicio es de $50, se pide:

  • La probabilidad de encontrar hasta 3 unidades en el sistema.
  • El costo total por día del sistema.
  • Determine si conviene contratar un ayudante por $20 diario si la tasa de atención mejora en 30%.

Resolución:

Tenemos que el tiempo de llegada es de λ: 12 unidades por hora, y la cantidad de unidades por unidad de tiempo es de  μ: 15 unidades por hora ya que cada unidad tarda 4 minutos en un servidor. Nos piden hallar la probabilidad de encontrar hasta 3 unidades en el sistema, para ello usaremos  1-Ptotal,entonces hallamos el total desde i=0 hasta i=n=3 en:

col2

Tenemos que λ/μ=0.8, entonces en P0=(0.8)0(0.2)=0.2, P1=(0.8)1(0.2)=0.16, P2=(0.8)2(0.2)=0.128 y P3=(0.8)3(0.2)=0.1024; la suma total es 0.5904, entonces la probabilidad de encontrar hasta 3 unidades es 1-0.5904=0.4096.

El costo total del sistema, tenemos como datos el costo del día del servicio que es de $50, tomaremos que el día está compuesto de  8 horas laborales, entonces debemos de hallar cuántos clientes se encuentran en cola cada hora; debemos de hallar la cantidad de elementos en cola, sabemos que Lq:

col1

tenemos que la cola cada hora está compuesta por 3.2 unidades, y el costo por unidad por hora es de $80, entonces el costo total de espera por hora es de $256 por hora, pero como son 8 horas laborales tenemos que el costo diario es de $2048, el costo del servicio es de $50 y la cantidad de servidores es de 1, finalmente el costo total será:

Costo total=$50+$2,048=$2098

Ahora debemos de evaluar que sucede si se incluye un ayudante que mejora la tasa de atención es un 30%, esto se traduce en 1.3μ, entonces el nuevo μ será de 19.5 unidades por hora con lo cual debemos de revisar el costo, para ello el nuevo Lq es 0.985 unidades en cola en cada hora, entonces el nuevo costo será:

Costo total=$50+$20+8*80*0.985=$700.154 teniendo como conclusión que sí resulta conveniente.

Ejercicio 2

El departamento de sistemas trata de determinar si alquila una copiadora lenta o rápida. El tiempo de un empleado vale 15 soles la hora, el alquiler de la copiadora lenta cuesta 4 soles la hora y un empleado tarda en promedio 10 minutos en terminar un trabajo, la copiadora rápida cuesta 15 soles la hora en arrendamiento y un empleado tarda un promedio de 6 minutos en terminar un trabajo, al departamento llegan en promedio 4 trabajos de copiado por  hora y el costo de la espera por cada uno de estos trabajos es de 7 soles por  hora. Se pide:

  • La probabilidad de que no haya trabajos en el sistema con copiadora lenta.
  • La probabilidad de que haya al menos dos trabajos en el sistema con copiadora rápida.
  • ¿Cuál es el costo total si se alquila la máquina lenta?
  • ¿Cuál es el costo total si se alquila la máquina rápida?
  • Si el promedio de llegadas de trabajos es de 7 por hora, ¿Cuál es la máquina que deberá utilizar?

Resolución:

Por los datos del problema sabemos que λ=4 trabajos por hora y μ0= 6 trabajos por hora y μ1= 10 trabajos por hora, siendo los sub-índices 0 y 1 para la copiadora lenta y rápida respectivamente, entonces para hallar el primer punto (con la copiadora lenta), debemos de usar:

Probabilidad de cero clientes en el sistema: P0=1-ρ

Entonces ρ=4/6 y P0=1-4/6=1/3=0.333.

Para el segundo punto, nos piden la probabilidad de al menos 2 trabajos para la copiadora rápida, con lo cual debemos de hallar las probabilidades desde 0 a 2, hacer su suma y luego obtener su complemento a 1. Tenemos que λ/μ=0.4 (copiadora rápida), entonces en P0=(0.4)0(0.6)=0.6, P1=(0.4)1(0.6)=0.24 y P2=(0.4)2(0.6)=0.096; la suma total es 0.936, entonces la probabilidad de encontrar hasta 3 unidades es 1-0.936=0.064.

El tercer punto sobre el costo con la copiadora rápida, tomaremos como unidad de tiempo la hora, sabemos que el costo del personal es de S/.15 por hora y el costo por alquiler de copiadora por hora es de S/. 4, con lo cual debemos de hallar cuántos clientes hay en promedio en la cola en la unidad de tiempo, entonces Lq=4/3 y el costo por trabajo por hora es de S/.7, con lo que obtenemos:

Costo total=4+15+(4/3)*7=S/.28.333 

El cuarto punto de forma similar solo que se usará los datos de la copiadora rápida, Lq=4/15, entonces:

Costo total=15+15+(4/15)*7=S/.31.867 

En el quinto punto, si tomamos que λ=7 al resolver Lq con la copiadora lenta nos saldrá un valor negativo, por lo cual queda descartado siendo finalmente la conclusión hacer uso de la copiadora rápida.

El Perceptrón – Aprendizajes hacia la IA – Parte 1

 Nuevamente con el aprendizaje hacia la Inteligencia Artificial, para ello, uno de los tópicos a revisar son las redes neuronales artificiales, estas básicamente son una representación computacional de las redes neuronales “naturales” en términos de su comportamiento; una red neuronal está compuesta por neuronas, pero ¿Qué es una neurona?, por definición:

“Célula del sistema nervioso formada por un núcleo y una serie de prolongaciones, una de las cuáles es más larga que las demás”

300px-Neurona.svg

Podríamos decir que la función básica de la neurona es un procesamiento que se da a través de recibir un input (estímulos eléctricos), realizar un procesamiento y transmitir un resultado hacia la siguiente neurona, McCulloch  y Pitts crearon la neurona que lleva su nombre y que es una unidad de cálculo que intenta modelar el comportamiento descrito de una neurona “natural“:

neuronaa

PLANTEANDO

Si describimos esta neurona las Xi representan las entradas y las Wij representan el peso asignado a cada una de las entradas que tenemos, la sumatoria representa la neurona y el axón inicialmente sin tomar el f() sería la salida, hago esto con el fin de explicarles de la misma forma que entendí la conformación de la neurona, entonces podemos decir lo siguiente:

1
Primer acercamiento

Para todas las entradas posibles la salida Y sería la suma de cada entrada multiplicada con su ponderada, pero esta ecuación no está completa aunque si ya nos permite esbozar que una red neuronal será una aproximación a una función matemática de pesos, al ser matemática implica que podemos hacer uso de toda la matemática disponible para su resolución, al expresarlo mediante una función hemos “modelado” el comportamiento, ahora tenemos que poner a prueba nuestro modelo.

Cuando deseamos comprobar si nuestro modelo es adecuado lo primero que se hace es poner a prueba nuestro modelo y que pueda responder a las funciones lógicas más básicas, entonces:

Primera Prueba – La función NOT

Una función de ese tipo en una tabla se expresa de la siguiente forma:

2

Podemos representarla de la siguiente forma:

3

 

Cuando reemplazamos los valores a la función que hemos obtenido nos queda:

4

Entonces este primer acercamiento no es correcto y debe de modificarse, ¿Cómo debe de modificarse?, pues si observamos  seria muy conveniente el agregar un término constante b (en el gráfico es θ) por cada neurona de la siguiente forma:

6
Segundo acercamiento

Entonces se puede representar de la

5

 

Resolvemos según la tabla y obtenemos:

7

Vemos que esto nos funciona cuando hacemos uso de un NOT, ahora veamos si es posible en un OR.

Segunda Prueba – función OR

La tabla de una función lógica OR es:

8

Podemos expresarlo de la siguiente forma:

9

Reemplazando tenemos:

10.png

Tal como podemos observar vamos a obtener una contradicción en el que los pesos “W” son 1 y en la última ecuación ambos suman 2 pero el resultado es 1.

REPLANTEANDO NUEVAMENTE!!! 

Si resolvemos con las demás funciones lógicas simples veríamos que tampoco se cumple, entonces ¿Qué es a lo que se llegó?, debía de implementarse una función, a la que llamaron función no lineal, para este caso desarrollaron la función step, tal que su representación final sea la del inicio:

neuronaa

Tal que la función step es:

11

Entonces validamos la función NOT:

12

Y si cumple, ahora validemos la función OR:

13

¿Qué ocurre entonces con la función AND?

Se cumple la tabla:

14

¿Cómo podemos interpretar una función AND?, pues una AND se expresa en la negación de la función OR; tal como está nuestra función no se adapta, para ello debemos de aumentar en 2 neuronas y  de hacer un cambio en nuestro parámetro y revisar si nuestro modelo actual sigue adaptándose, entonces tomaremos el valor -0.5 para el “OR” y vemos que cumple, finalmente esto se puede graficar de la siguiente forma:

16.png

Es factible usando el mismo modelo expresarlo con una sola neurona si el valor del parámetro fuese -1.5

Tercera Prueba función XOR:

El problema que XOR a de implicar el uso de una neurona más, veamos la tabla:

15

 

Esta función se expresa de la siguiente forma:

17

Si construimos la gráfica:

18.png

 

Matplotlib – Generador de Gráficos en Python

Una imagen es mejor que mil palabras, es un término recurrente cuando se desea resumir o explicar algún tópico, las imágenes pueden ser solo el sujeto que hemos de cambiar por un diagrama o cuadros o gráficos, imaginemos que tenemos una cantidad considerable de datos y queremos mostrar el comportamiento que estos siguen, para ello existe la librería matplotlib, el cual es una librería para la generación de gráficos a partir de datos contenidos en listas  y es usado por lo general a través de numpy, para esta breve descripción usaremos a VSCODE como editor de código, sin más que decir. empecemos:

INSTALACIÓN E IMPLEMENTACIÓN

La instalación se realiza a través del terminal (CMD si es que tu python está dentro del path) incorporado en VSCODE con la instrucción siguiente:

pip install matplotlib

Ahora debemos de abrir un fichero y en este debemos de importar la librería, se estila que la librería sea importada de la siguiente forma:

import matplotlib.pyplot as plt

matplotlib.pyplot es una colección de funciones que asemejan al estilo de comandos que tiene MATLAB, que supongo tendrá especial significancia para aquellos que ya están familiarizados con dicho software, en lo particular yo no, pero te encontrarás con muchos tutoriales que hacen referencia a este tipo de importación.

HACIENDO UNA LÍNEA RECTA

Hacer una línea recta es muy sencillo en esta librería, pues en su forma más básica debemos de tener dos listas que representen el eje X e Y y colocarlos dentro del método plot(), plot tiene un constructor amplio, pero por el momento vamos a reducirlo a la realización de un recta simple en donde requerimos tanto los elementos de las coordenadas X e Y y una etiqueta, entonces plot hace la recta pero cuando creamos un gráfico necesitamos saber que representan cada uno de los ejes, supongamos que tenemos intenciones de presentar la relación entre los metros cuadrados de una habitación con su precio de alquiler, para ello debemos de hacer uso de los métodos xlabel() y ylabel(), los  cuáles reciben como parámetro obligatorio  la cadena de texto que representa el eje en cuestión, podemos agregar un título a nuestro gráfico con title() y la leyenda que corresponde a la recta que se toma de la etiqueta al momento de su creación con el método legend(), finalmente debemos de mostrar la gráfica, y esta se muestra con el método show(), entonces:

import matplotlib.pyplot as plt

#creamos dos listas
x=[1,2,3]
y=[5,7,9]

plt.plot(x,y,label="linea1") # creación de la recta
plt.xlabel("Metros cuadrados") #etiqueta eje X
plt.ylabel("Costo en miles de soles") #etiqueta eje Y
plt.title("Relación Costo y m2") #Agregamos un título
plt.legend() #agregamos la leyenda
plt.show() #desplegamos el gráfico
El resultados es el siguiente:
mat1.png

HACIENDO UNA DIAGRAMA DE BARRAS

Para realizar un diagrama de barras es tan sencillo, ya que solo se requiere del método bar(), como requisito debemos de indicarle la serie en el eje X y en Y, una etiqueta, todo lo demás se mantiene de forma similar:

x=[2,4,6,8,10]
y=[6,7,8,2,4]

x2=[1,3,5,9,11]
y2=[7,8,2,4,2]

plt.bar(x,y,label="Bar 1")
plt.bar(x2,y2,label="Bar 2")

plt.xlabel("x")
plt.ylabel("y")

plt.title("Gráfica de Barras")
plt.legend()
plt.show()

Así de forma sucesiva podemos hacer una serie de gráficas, personalmente no creo que requiera mayor análisis que el que implique revisar la misma API de la librería.

Matrices en Python uso de Numpy

Numpy es la librería casi por defecto cuando hemos de tratar con matrices, y específicamente en el uso de big data por su menor consumo de tiempo de procesamiento computacional dando paso a una mayor cantidad de procesamiento, entonces en esta ocasión revisaremos las operaciones con matrices que se pueden realizar:

INSTALACIÓN

En primera instancia este tutorial asume que estás usando VSCODE  y que tu sistema operativo o distribución ya tiene instalado python, abrimos el terminal incorporado de VSCODE, abrimos el terminal y hacemos la siguiente instrucción:

pip install numpy

DECLARACIÓN DE UNA MATRIZ

Cuando hemos de usar numpy debemos de importar la librería en el top del fichero, entonces:

import numpy as np

 Esto significa que todo lo relacionado a la invocación de los métodos que pertenecen a numpy lo hemos de realizar haciendo “np.nombre_metodo“, como si métodos estáticos se trataran en su sintaxis (java ¿huh?).

Ahora bien, ¿Cómo se implementa una matriz en un lenguaje de programación?, pues esta se implementa a través de los arreglos, un arreglo es una estructura de datos que nos permiten almacenar elementos que dependiendo del lenguaje pueden ser del mismo tipo o no, java por ejemplo permite los arreglos de un mismo tipo y solo de primitivos si son de tipo referenciados pues tienen otros nombres; sin embargo, python considera que los elementos que conformen un arreglo no necesariamente tienen que ser todos del mismo tipo de dato (no hacemos referencia a primitivos pues todo es un objeto en python).

Python agrupa los arreglos de la siguiente forma:

Para las matrices en numpy se organiza la estructura de forma muy similar a las listas, aunque no son lo mismo, entonces hecha esta aclaración, una matriz se define de la siguiente forma:

a=np.array([1,2,3])#1 dimensión
b=np.array([[1,2,3],[4,5,6]]) #2 dimensiones
c=np.array([[1,2,3],[4,5,6],[7,8,9]]) # 3 dimensiones

El objeto principal en numpy es ndarray el cual representa un arreglo que puede ser multidimensional y es homogéneo en términos del tipo de objeto. Una de las formas de crear una matriz se realiza con el método array, y que su constructor es de la siguiente forma:

numpy.array(objectdtype=Nonecopy=Trueorder='K'subok=Falsendmin=0)

Aunque los demás términos ya están descritos en su definición, el parámetro obligatorio es un objeto el cual tal como se ha mostrado divide sus dimensiones siguiendo una estructura tipo lista. Podemos también transformar desde listas o tuplas (bueno en esencia es un objeto ¿no?), entonces sea:

arreglo=[1,2,3,4,5,6,7,8,9]
arreglo2=(1,2,3,4,5,6,7,8,9)

x=np.array(arreglo)
y=np.array(arreglo2)

y=np.reshape(y,(3,3))
x=np.reshape(x,(3,3))

Si ingresamos una lista o tupla, esta quedará como una matriz de una sola dimensión, si deseamos dar un ordenamiento específico como una matriz de 3×3, debemos de hacer uso del método reshape:

numpy.reshape(anewshapeorder='C')

Este método nos devuelve una matriz con el ordenamiento deseado, y es tal como la hemos usado, el tipo de orden debe indicar a través de una tupla, en nuestro caso de (3,3). Dicho esto como parte básica para la creación de las matrices, vamos a realizar las operaciones con ellas.

OPERACIONES BÁSICAS

Sean 2 matrices de 2×2 A y B que las obtenemos a través de listas, pero vamos a generarlo todo en una sola línea:

a=[1,2,3,4,]
b=[7,8,9,10]

a=np.reshape(np.array(a),(2,2))
b=np.reshape(np.array(b),(2,2))

La suma entonces:

c=b+a
print(c)

La resta:

c=b-a

Podemos hacer que todos los elementos de la matriz se eleven a un exponente determinado de la siguiente forma:

c=b**exponente
c=np.power(b,exponente)

Multiplicación

Las matrices tienen una particularidad al momento de la multiplicación, ya que siguen la forma de filas por columna, para realizarla podemos hacerlo de dos formas:

c=np.dot(a,b) #recibe las 2 matrices a multiplicar
d=a@b

La División

¿Por qué no tomamos la división?, pues por teoría la división de una matriz no es una operación que se realice como con los números reales, una división en una matriz se puede determinar a través de la multiplicación con la inversa de la matriz que estaría en el denominador, es decir:

A.B-1

Podemos obtener la inversa de una matriz a través del método inv, el cual pertenece a la subclase linalg, inv recibe como parámetro a la matriz  y devuelve su matriz inversa, entonces:

e=np.linalg.inv(b)

Ahora bien haciendo uso de las matrices de ejemplo a y b:

f=np.dot(a,np.linalg.inv(b))

DETERMINANTE DE UNA MATRIZ 

El determinante de una matriz podemos hallarlo haciendo uso del método det, que tiene como parámetro la matriz cuadrada que se desea hallar su determinante (no olvidar que el determinante siempre es un escalar y nunca un vector):

determinante=np.linalg.det(a)

MATRIZ TRANSPUESTA

La transpuesta de una matriz es la transformación en que las filas pasan a las columnas y viceversa, para realizar la transpuesta debemos de usar el método transpose, este es un método asociado directamente a la matriz, entonces:

g=a.transpose()

Por lo pronto es todo lo que podemos observar de las operaciones con matrices