Página 3 de 4

[How to… Usar Table Controller]

[Entrada recuperada de Mono-Hispano]

En esta entrada vamos a ver cómo podemos crear un Table Controller. El Table Controller grosso modo es el equivalente a un GRID. Lo primero que debemos hacer, como viene siendo costumbre, es crear un proyecto nuevo al que denominaremos ProbandoTableController. Una vez tenemos nuestra solución, añadimos al proyecto un IphoneViewController y lo llamamos TableViewControllerMain. Vamos a TableViewControllerMain.cs y sustituimos la clase de la que deriva por UITableViewController: public partial class TableViewControllerMain : UITableViewController

A continuación, nos dirigimos al AppDelegate.cs y en el método FinishedLaunching agregamos el siguiente código:

TableViewControllerMain tvcm = new TableViewControllerMain();

window.RootViewController=tvcm;

Creo que a estas alturas no hace falta explicar este código, pero por si acaso: En la primera línea instanciamos nuestro TableViewController y en la segunda línea se lo asignamos como vista principal a nuestra ventana, recordemos que TableViewControllerMain hereda de UITableViewController y ésta a su vez de UIViewController . Abrimos el TableViewController.xib y en el diseñador de Xcode borramos la vista que está creada por defecto, seleccionándola y pulsando suprimir. A continuación, vamos a la librería de objetos y arrastramos un UITableView que reemplazará a la que hemos eliminado. Por último, botón derecho sobre la vista que acabamos de agregar y arrastramos -tal y como se ve en la imagen- el círculo de New Referencing Outlet sobre File´s Owner. Esto conectará añadirá

clip_image002

la vista a nuestra tabla. Si ejecutamos ahora veremos algo así, la tabla sin contenido:

clip_image004

Vamos a añadirle contenido para ello volemos a MonoDevelop y creamos la siguiente clase:

   1:  using System;
   2:   
   3:  using System.Collections.Generic;
   4:   
   5:  using MonoTouch.Foundation;
   6:   
   7:  using MonoTouch.UIKit;
   8:   
   9:  namespace ProbandoTableViewController
  10:   
  11:  {
  12:   
  13:  //Se establece la herencia de UITableViewSource
  14:   
  15:  public class TableSourceMain: UITableViewSource
  16:   
  17:  {
  18:   
  19:  private List<string> _datos;
  20:   
  21:  private string _cellID;
  22:   
  23:  public TableSourceMain ()
  24:   
  25:  {
  26:   
  27:  this._datos = new List<string>(){"Primer elemento","Segundo elemento", "Tercer elemento"} ;
  28:   
  29:  this._cellID="CellId";
  30:   
  31:  }
  32:   
  33:  //Retorna el objeto que vamos a mostrar por pantalla. Es decir, cada celda.
  34:   
  35:  public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
  36:   
  37:  {
  38:   
  39:  UITableViewCell cell = tableView.DequeueReusableCell(this._cellID);
  40:   
  41:  if(cell==null)
  42:   
  43:  cell = new UITableViewCell(UITableViewCellStyle.Default,this._cellID);
  44:   
  45:  cell.TextLabel.Text=_datos[indexPath.Row];
  46:   
  47:  return cell;
  48:   
  49:  }
  50:   
  51:  //Debe devolver el numero de elementos que queremos mostrar.
  52:   
  53:  public override int RowsInSection (UITableView tableview, int section)
  54:   
  55:  {
  56:   
  57:  return this._datos.Count;
  58:   
  59:  }
  60:   
  61:  }
  62:   
  63:  }
  64:   

Con la ayuda de los comentarios podemos ver que hace en general la clase. Sin embargo, vamos a repasarla: La clase hereda de UITableViewSource que es el origen de datos que tomará nuestra TableViewContollerMain, más adelante veremos como asignársela. La clase que acabamos de crear tiene una simple lista de string y un cellID (que nos permitirá recuperar nuestra celda). Centrándonos en el método GetCell, lo que hacemos es llamar al método tableView.DequeueReusableCell que nos devuelve una celda que hayamos usado ya (por eso usamos el identificador) esto nos permite ser más eficientes y no crearlas una y otra vez, ya que este método devuelve null si no se ha creado. A continuación, asignamos al label que viene por defecto el texto que queremos mostrar, y devolvemos la celda. Si nos fijamos cuando creamos la celda pasamos un Style por parámetro, esto es la plantilla que utilizará nuestra celda para mostrarse. En una continuación de esta entrada (que si no queda muy larga y no es la finalidad) veremos como crear nuestras propias plantillas, sólo comentar que hay más de un estilo por defecto y que se pueden probar cambian el default por algún otro valor.

Para terminar, abrimos el TableViewControllerMain y en el método ViewDidLoad asignamos a nuestra tabla, el tableSource que acabamos de crear: this.TableView.Source = new TableSourceMain();

Una introducción a los estilos arquitectónicos

Si te interesa la arquitectura del software, hoy traigo un documento An Introduction to Software Architecture

que es una buena introducción a los distintos estilos arquitectónicos. Dejo algunos ejemplos de estilos de los que se tratan en el texto:

Pipes and Filters

Creo que el ejemplo más claro proviene del mundo de los sistemas operativos, y son los comandos de consola. Por ejemplo de UNIX. ¿Quién no ha usado alguna vez una “tubería”? 

Data Abstraction and Object-Oriented Organization

Lenguajes orientados a objetos y también no orientados a objetos, ya que se pueden construir estructuras abstractas de datos con ellos. La orientación a objetos, en el sentido de tratar a un lenguaje como orientado a objetos, “sólo” facilita el trabajo.

Event-based, Implicit Invocation

Editor de código, procesador de texto (p.e. comprobación ortográfica), GUI

Layered Systems

El ejemplo del modelo OSI que citan en el texto, es bastante bueno. Uno más enfocado al mundo de la arquitectura, es el archiconocido MVC e incluso la evolución que desarrolló el principal arquitecto de Silverlight, MVVM, el cual incluso lo combina con un enfoque de Event-based a través de interfaces.

Table Driven Interpreters

Prácticamente cualquier intérprete de un lenguaje de alto nivel.

 

 

 

 

Vici CoolStorage un ORM ligero Cross Platform para MonoTouch, WP7 y MonoDroid

Sin duda una de las tecnologías que como desarrollador han mejorado mi productividad son los ORM. Hoy vengo a hablaros de Vici.CoolStorage un ORM cross platform para MonoTouch, MonoDroid y WP7 (y seguramente W8). Podéis descargarlo desde la página del proyecto.

Voy a ilustrar un ejemplo con MonoTouch en el que tendremos una clase persona:

[MapTo("Persona")]

public class Persona : CSObject<Persona,int>{

public int Id {

get;

set;

}

public string Nombre {

get;

set;

}

public string Apellidos {

get;

set;

}

}

Este código sería válido para MonoDroid y WindowsPhone pero, puesto que en el caso de MonoTouch no se soporta Reflection.Emmit, y CoolStorage la utiliza para su funcionamiento, debemos añadir el siguiente código en los getters/Setters:

[MapTo("Persona")]

public class Persona : CSObject<Persona,int>{

public int Id {

get { return (int)GetField("Id"); }

}

public string Nombre {

get { return (string)GetField("Nombre"); }

set { SetField("Nombre",value); }

}

public string Apellidos {

get { return (string)GetField("Apellidos"); }

set { SetField("Apellidos",value); }

}

}

Una vez hemos definido la clase, debemos conectarnos a la base de datos y, sólo en caso de que no exista previamente, crearla. Para ello hemos preparado el siguiente método:

void ComprobarYCrearLaDB{

string dbNombre = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.Personal), "db");

CSConfig.SetDB (dbNombre,SqliteOption.CreateIfNotExists, () => {

CSDatabase.ExecuteNonQuery (

"CREATE TABLE Persona (Id INTEGER PRIMARY KEY AUTOINCREMENT," +

"Nombre text, Apellidos text)");

//Datos de ejemplo

Persona p = new Persona(){ Nombre="Jose", Apellidos="Gónzalez"} ;

p.Save();

p = new Persona(){ Nombre="Antonio", Apellidos="Gónzalez"} ;

p.Save();

} );

}

Con CSConfig.SetDb indicamos que se cree la base de datos, y el método que se ejecutará cuando se cree. En nuestro ejemplo creamos la tabla Persona en la base de datos, para a continuación crear unos datos de prueba que guardamos gracias al método Save.

Finalmente, creamos la interfaz de usuario en el punto de entrada de la aplicación:

public override bool FinishedLaunching (UIApplication app, NSDictionary options)
        {
            window = new UIWindow (UIScreen.MainScreen.Bounds);


            ComprobarYCrearLaDB();
            //Se crea la interfaz de usuario

            var root = new RootElement("Personas");
            var section = new Section("Personas");
            foreach (var p in Persona.List()) {
                section.Add(new StringElement(string.Format("{0} {1}",p.Nombre,p.Apellidos)));
            }
            root.Add(section);
            var dialog = new DialogViewController(UITableViewStyle.Plain,root);
            dialog.Root=root;


            window.RootViewController = dialog;
            window.MakeKeyAndVisible ();

            return true;
        }

Como veis es muy fácil comenzar con este ligero ORM. Además aunque no lo hemos visto, soporta transacciones y relaciones.  Aquí encontrareis el fichero de código completo.

[MonoTouch How To…] Usar UITabBarViewController

[Entrada original publicada en www.mono-hispano.org]

Paralelamente a la serie MonoTouch N que quizá tiene más componente de tutorial que esta, he decidido crear una serie que muestre cómo realizar acciones concretas, aunque es muy recomendable tener unos conocimientos básicos sobre MonoTouch para llevarla a cabo.

Para comenzar la serie, nada mejor que comenzar con algo bastante práctico y útil, como es la interfaz de usuario, en concreto, con el componente TabBar. Que permite navegar entre pantallas de forma bastante fluida.

tab_bar_icons_closeup

 

En primer lugar, crearemos un nuevo proyecto en MonoDevelop File->New->Solution->MonoTouch->iPhone->Empty Project y le ponemos de nombre, ProbandoTabBar.

Lo primero que debemos hacer es dirigirnos a la clase AppDelegate y crear una variable con ámbito de clase del tipo UITabBarController la llamaremos tabBar.

Lo primero que debemos hacer es agregamos dos ViewController al proyecto que serán las pantallas entre las que navegaremos. Para ello: Botón derecho sobre el proyecto->Add->New File…-> iPhoneViewController y la denominamos MainView. Repetimos el proceso para la segunda, y la denominamos OtherView.

Una vez creadas, hacemos doble click sobre el .Xib que nos ha generado, abrirá XCode y ponemos un elemento distintivo, como puede ser un Label con un texto cualquiera.

clip_image004
Repetimos el proceso con la segunda, y volvemos a Xcode.

De vuelta en MonoDevelop, nos digirimos a la clase AppDelegate y crear una variable con ámbito de clase del tipo UITabBarController la llamaremos tabBar

Dento del método FinishedLaunching, creamos el siguiente código:

   1:  public override bool FinishedLaunching (UIApplication app, NSDictionary options)
   2:   
   3:  {
   4:   
   5:  // create a new window instance based on the screen size
   6:   
   7:  window = new UIWindow (UIScreen.MainScreen.Bounds);
   8:   
   9:  //Se instancian las pantallas:
  10:   
  11:  MainView mainView = new MainView();
  12:   
  13:  OtherView otherView = new OtherView();
  14:   
  15:  //Se establece el contenido del titulo que se mostrarテ。 en el tabBar.
  16:   
  17:  mainView.TabBarItem.Title = "MainView";
  18:   
  19:  otherView.TabBarItem.Title = "OtherView";
  20:   
  21:  //Se instancia el tabBar
  22:   
  23:  tabBar = new UITabBarController();
  24:   
  25:  //Se agregan las pantallas al tabBar
  26:   
  27:  tabBar.SetViewControllers(new UIViewController[]{mainView,otherView},false);
  28:   
  29:  //Se asigna el tabBar como vista principal
  30:   
  31:  window.RootViewController=tabBar;
  32:   
  33:  // make the window visible
  34:   
  35:  window.MakeKeyAndVisible ();
  36:   
  37:  return true;
  38:   
  39:  }

El código queda explicado por sí mismo además de por los comentarios. Compilamos:

clip_image006

 

Como último detalle quisiera comentar que para añadir una imagen en el TabBarItem se puede acceder desde cualquier instancia de UIViewController o derivadas como en nuestro caso, MainView u OtherView, a través de la propidad de la misma UIViewController.TabBarItem.Image. Otra cuestión que puede resultar útil es implementar el evento de UITabBarController ViewControllerSelected que nos permitirá acceder al ViewController seleccionado cuando cambie.

Pues esto es todo, cualquier duda no dudéis en comentarla.

¡Orchard 1.6 estable!

Ya está, es oficial, la tan esperada versión de Orchard acaba de ser publicada. Entre sus nuevas features encontramos:

  • MVC 4
  • Web API
  • Soporte para MySql out of the box.
  • NHibernate 3.3
  • Razor 2
  • Mejoras de rendimiento en general.

Aquí os dejo la lista de completa

Ahora toca ir actualizando los proyectos e ir jugando con la nueva versión, próximamente tendremos entradas de desarrollo de Módulos y Themes, ¡a ver si le damos algo más de vida a la comunidad Hispana de este excelente proyecto!

Marketing recipes: Orientación al marketing (o cliente)

Después de deliberar durante algunos días y a pesar de que no tengo todo el tiempo que quisiera para mantener el blog actualizado, he decidido incorporar una nueva rama a las ya variopintas tratadas en el blog (programación web y móvil, .net, productividad, IA…), la rama de marketing. El principal motivo es que soy egoísta. Como buen cuaderno de notas técnicas (o de ingeniería) muchas veces uso el blog como sistema para reforzar conocimiento adquirido. Aunque realmente, el principal motivo es que como es fundamental tener algunos conceptos de Marketing si queremos de verdad inventarnos nuestro trabajo (un emprendedor debería ser un ingeniero del trabajo 😉 ) .
Entrando un poco en materia, hoy vamos a ver un concepto que curiosamente razoné sin haber sabido de su existencia hace no mucho tiempo atrás, y es el concepto de Orientación al Marketing (o al cliente).

¿Qué fue primero, el producto o la necesidad?

 

Para entender mejor la Orientación al Marketing, me gustaría definir primero la orientación al producto: “una empresa orientada al producto es aquella que centra sus esfuerzos en mejorar sus productos” ¿Os suena? ¡Claro! Es lo que hacemos los desarrolladores, centrarnos principalmente, en mejorar nuestros desarrollos/productos. Esto es, primero el producto y luego el cliente, creo que prácticamente todo el mundo que he conocido que ha lanzado productos al mercado, lo ha hecho así, eligiendo el producto y en base a su producto a los clientes. Si eres desarrollador para una gran empresa (o pequeña) esto seguramente no te diga nada y tu enfoque es el adecuado. Sin embargo si lo que buscas es un hueco en el mercado, en un nicho, esto es lo mismo que ir a jugar al bingo. ¡A ver si tenemos suerte y sale nuestro cartón! Creo que es evidente que este enfoque es contraproducente.

Orientación al cliente

Una empresa orientada al marketing es aquella que tiene en cuenta a la hora de tomar decisiones estratégicas los deseos y necesidades de sus clientes reales y potenciales. Esto significa que primero busca el mercado/nicho/necesidades y luego crea el producto en base a ello y no al revés. Por ello, lo primero no es la idea, ¡lo primero es encontrar la necesidad!

[IA Aprendizaje] Probabilidad: El método clásico II Clasificación bayesiana ingenua

En primer lugar pido disculpas por haber dejado tanto espacio entre una entrada y otra, pero es que estoy en un momento de mi vida bastante complicado, no he parado de estudiar (en el ámbito universitario, que todos los que andamos por aquí siempre estamos estudiando nuevos frameworks constantemente) y por otra parte ha sido un verano muy ajetreado porque además, he vuelto a emprender 😀
Hoy vamos a hablar de la clasificación bayesiana ingenua, que no es más que un clasificador probabilístico basado en la aplicación del teorema de Bayes. La coletilla de ingenuo viene porque al crear el clasificador asumimos que las variables que utilizaremos son totalmente independientes unas de otras (esto es, recordemos,  ausencia de correlación o P(A,B)=P(A)*P(B)). Como anécdota mencionar que una de las razones por las que se abandonó el método clásico de probabilidad en IA fue, en parte, por la introducción de esta hipótesis. Quizá más adelante (en función de mi tiempo y vuestra aceptación, feedback por favor), veremos que con las redes bayesianas no tenemos este inconveniente.

Teorema de Bayes



Recordemos que el teorema de bayes nos dice que P(A|B) = P(A|B)*P(A) / P(B) donde A se puede interpretar como «causa» y B como «efecto», es decir, A es una reacción a la acción de B o lo que es lo mismo, A tendría dependencia causal de B.
Por ejemplo, en el caso de los diagnósticos clínicos del campo de Medicina Basada en le Evidencia, tenemos que: P(síntoma|enfermedad) = 0.6 P(síntoma) = 0.15 y P(enfermedad) =0.05
A partir de estos datos podemos preguntarnos por la probabilidad de que la causa del síntoma de un paciente sea la enfermedad, y vendría dada por (teorema de Bayes):

P(enfermedad|síntoma)=P(sintoma|enfermedad)*P(enfermedad)/P(síntoma)  = 0.7*0.05/0.15 = 0.233.
Como se puede ver en el ejemplo, dada una serie de efectos se puede clasificar y, por definición, encontrar la causa que los provoca. Un ejemplo típico (aunque hay muchísimas aplicaciones,
sobre todo en el campo de la minería de datos) es el filtrado de Spam o correo basura. Así que nos ponemos manos a la obra para construir nuestro propio y simple, filtro de Spam.

Filtro de Spam


Para comenzar, utilizaremos la fórmula de Bayes de la siguiente manera: P(palabra|categoria)=P(categoria|palabra) * P(palabra) / P(categoria)
Donde la categoría puede tomar los siguientes valores: SPAM y NO_SPAM. Cuando tenemos calculada la probabilidad de cada palabra condicionada, faltaría multiplicar sus probabilidades para cada categoría: P(categoria|palabra1,palabra2,…,palabran) = P(categoria) SIGMA_POR P(palabra|categoria) Es decir, multiplicamos cada probabilidad P(palabrai|categoria) del texto que queremos
clasificar y además, también P(categoria).
Antes de poder clasificar un texto, tendremos que poder analizar una serie de datos previos, algo así como un entrenamiento. Necesitaremos ejemplos de correos clasificados como SPAM o NO_SPAM, cuantos más ejemplos proveamos, más probabilidad de acertar tendrá nuestro clasificador.
En el próximo ejemplo utilizaremos la función training() para realizar el entrenamiento. La función espera una lista con un campo para el texto y otro que indica si es SPAM o NO_SPAM:
[«Esto es un ejemplo de frase»,NO_SPAM]
Se utilizará la función auxiliar wordList() que devuelve una lista con todas las palabras del texto mayores de dos caracteres, en minúscula y sin repeticiones.
La función training genera cuatro variables que almacenan los parámetros para su posterior clasificación.
La variable cWords es una lista con las palabras del texto y el número de veces que aparece en cada categoría. La variable cCategories almacena las categorías con el número de textos que pertenecen a ella. {«SPAM»:2,»NO_SPAM»:3} y por último, las variables cTexts y cTotalWords guardan el número de textos totales que hay en el ejemplo y el número de palabras totales.
La función Classify() es la que hace los cálculos y determina a qué categoría pertenece el texto que le pasamos como parámetro. También espera que le pasemos las cuatro variables anteriores.

 

   1:  namespace Clasificador_de_Spam
   2:  {
   3:      class Program
   4:      {
   5:   
   6:          class Message
   7:          {
   8:              public string Text { get; set; }
   9:              public string CategoryName { get; set; }
  10:          }
  11:          class Category
  12:          {
  13:              public string Name { get; set; }
  14:              public int Total { get; set; }
  15:   
  16:          }
  17:          class WordPerCategory
  18:          {
  19:             
  20:              public string Word { get; set; }
  21:              public List<Category>CategoryPerWord { get; set; }
  22:          
  23:              
  24:              public Category this[string value]
  25:              {
  26:                  get
  27:                  {
  28:                      return this.CategoryPerWord.FirstOrDefault(c => c.Name.Equals(value));
  29:                  }
  30:              }
  31:          }
  32:   
  33:   
  34:          class Classify
  35:          {
  36:              public Classify()
  37:              {
  38:                  cWords = new List<WordPerCategory>();
  39:                  cCategories = new List<Category>();
  40:                  cTotalTexts = 0;
  41:                  cTotalWords = 0;
  42:              }
  43:              public List<WordPerCategory> cWords { get; set; }
  44:              public List<Category> cCategories { get; set; }
  45:              public int cTotalTexts { get; set; }
  46:              public int cTotalWords { get; set; }
  47:   
  48:   
  49:   
  50:              public List<string> WordList(string text)
  51:              {
  52:                  var wordsTemp = text.ToLower().Split(' ');
  53:                  var words = new List<string>();
  54:                  foreach (var word in wordsTemp)
  55:                      if (word.Count() > 2 && !words.Contains(word))
  56:                          words.Add(word);
  57:   
  58:                  return words;
  59:              }
  60:   
  61:              public void Training(List<Message> texts)
  62:              {
  63:   
  64:   
  65:                  foreach (var message in texts)
  66:                  {
  67:                      cTotalTexts++;
  68:                      if (cCategories.Any(c => c.Name.Equals(message.CategoryName)))
  69:                          cCategories.First(c => c.Name.Equals(message.CategoryName)).Total++;
  70:                      else
  71:                          cCategories.Add(new Category() { Name = message.CategoryName, Total = 1 });
  72:   
  73:                  }
  74:   
  75:                  foreach (var message in texts)
  76:                  {
  77:                      var words = WordList(message.Text);
  78:                      foreach (var word in words)
  79:                      {
  80:                         
  81:                          if (!cWords.Any(w => w.Word.Equals(word)))
  82:                          {
  83:                              cTotalWords++;
  84:                              var wordPerCategory = new WordPerCategory() { Word = word, CategoryPerWord = new List<Category>()};
  85:                              foreach (var cat in cCategories)                     
  86:                                  wordPerCategory.CategoryPerWord.Add(new Category(){Name = cat.Name, Total = 0});
  87:                          
  88:                              cWords.Add(wordPerCategory);
  89:                          }
  90:                          cWords.First(w => w.Word.Equals(word))[message.CategoryName].Total++;
  91:   
  92:                      }
  93:   
  94:                  }
  95:   
  96:   
  97:              }
  98:   
  99:   
 100:              public Category Classifier(string texto)
 101:              {
 102:                  Category category = new Category();
 103:                  double probCategory = 0.0;
 104:   
 105:                  foreach (var c in cCategories)
 106:                  {
 107:                      //Prob of the category
 108:                      double probC = (double) c.Total / cTotalTexts;
 109:                      var words = WordList(texto);
 110:                      double probTotal = probC;
 111:                      foreach (var w in words)
 112:                      {
 113:                          //Prob of the  word
 114:                          if (cWords.Any(word => word.Word.Equals(w)))
 115:                          {
 116:                              var word = cWords.First(wrd => wrd.Word.Equals(w));
 117:                              double probWord = (double)word[c.Name].Total / cTotalWords;
 118:                              //P(cat|word)
 119:                              double probCond = (double)probWord / probC;
 120:                              //P(word|cat)
 121:                              double prob = (double)(probCond * probWord) / probC;
 122:                              probTotal *= (double)prob;
 123:                          }
 124:                      }
 125:                      if (probCategory < probTotal)
 126:                      {
 127:                          category = c;
 128:                          probCategory = probTotal;
 129:                      }
 130:                  }
 131:   
 132:                  return category;
 133:              }
 134:          }
 135:   
 136:          static void Main(string[] args)
 137:          {
 138:             List<Message> text = new List<Message>()
 139:                                       {
 140:                                           new Message(){CategoryName = "SPAM",Text = "Juega al poker online"},
 141:                                           new Message(){CategoryName = "NO_SPAM",Text = "Mañana vamos al cine"},
 142:                                           new Message(){CategoryName = "SPAM",Text = "Juega en los mejores casinos de poker"},
 143:                                           new Message(){CategoryName = "SPAM",Text = "Felicidades usted ha sido seleccionado para ganar un Microsoft Surface"},
 144:                                           new Message(){CategoryName = "NO_SPAM",Text = "La IA es una gran disciplina, es el punto de convergencia perfecto entre las mates y la program"},
 145:                                       };
 146:              Classify antiSpam = new Classify();
 147:              antiSpam.Training(text);
 148:              Category category = antiSpam.Classifier("Juega al poker y gana");
 149:              Console.WriteLine("Se trata de {0}.",category.Name);
 150:   
 151:              Console.Read();
 152:          }
 153:      }
 154:  }

 

 

Pues ya tenemos nuestro filtro anti spam definido. Hay que tener en cuenta que el entrenamiento ha sido con muy pocos datos, aunque aun así es relativamente fiable. Por otra parte, lo hemos definido para N categorías, cambiando dichas categorías podríamos clasificar cualquier otra cosa (por ejemplo qué palabras pertenecen a qué lenguaje).

 
Bibliografía:

Francisco Javier Díez, Probabilidad y teoría de la decisión en medicina

Alberto Garcia Serrano, Inteligencia Artificial Fundamentos, práctica y aplicaciones.

Stuart Russell, Peter Norvig Inteligencia Artificial: Un enfoque moderno.

Referencias

[IA Aprendizaje] Probabilidad: El método clásico I

Serializar y deserializar en .NET con C#

NOTA: Esta es una entrada extraída de mi anterior blog (de hecho la primera que he escrito), la he decidido publicar porque me consta que ha sido útil.

Muchas veces surge la necesidad de almacenar objetos en ficheros, en memoria, como cadena de caracteres, en una base de datos, etc. Para ello .NET nos facilita la vida primero debemos marcar la clase como “Serializable” y posteriormente proceder a realizar la serialización.

Veremos un ejemplo sencillo:

Serializar un objeto en memoria:

Primero definimos un array de bytes con una longitud estimada (superior a la que va a tener el objeto en cuestión).

byte[] flujosBytes = new byte[LONGITUD];



A continuación, se especifica el formato de la serialización y una nueva instancia de la clase donde lo vamos a serializar (en memoria) pasando por parámetro el array que acabamos de crear.

 

IFormatter formatter = new BinaryFormatter();

Stream stream = new MemoryStream(flujosBytes, true);

Se ejecuta el método Serialize con el flujo y el objeto a serializar (recordad que debe estar marcado como serializable)  y finalmente se cierra el flujo.

formatter.Serialize(stream, objeto);

stream.Close();

Ya tenemos el objeto en forma de array de bytes,  a partir de aquí guardarlo por ejemplo, en un fichero es trivial:

Stream stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);

stream.Write(flujo, 0,flujo.Length);

stream.Close();

Bien,  ya tenemos el objeto serializado y almacenado en un fichero, pero, ¿cómo desserializamos? Pues muy sencillo:

Primero -y siguiendo con el ejemplo- se debe rescatar el flujo de bytes del fichero que acabamos de crear:

Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

byte[] flujo = new byte[LONGITUD];

stream.Read(flujo, 0, flujo.Length);

stream.Close();

Volvemos a tener el flujo del principio, ahora procedemos a convertir el flujo de bytes al objeto inicial:

IFormatter formatter = new BinaryFormatter();

Stream stream = new MemoryStream(flujo, true);

object objectD = (object)formatter.Deserialize(stream);

stream.Close();

[IA Aprendizaje] Probabilidad: El método clásico I.

 

Vale, no es el tema más adecuado para escribir en un blog de programación pero si pensamos en aplicaciones en la IA, que a su vez se tendrán que representar programáticamente, seguro que ya nos parece algo más acertado. De todas formas, la intención no es perdernos en formalidades matemáticas, sino intentar desde el principio buscar un enfoque práctico. Intentaré partir las entradas y hacerlas lo más amenas posible.

Si lanzamos un dado al aire, podemos preguntarnos, por ejemplo, ¿cuál es la probabilidad de sacar un 2? o ¿cuál es la probabilidad de sacar un número impar?

Cuando lanzamos un dado de seis caras podremos obtener, evidentemente, seis resultados distintos. El conjunto de estos posibles resultados ({1,2,3,4,5,6}) se denomina espacio muestral o número de casos posibles. Un suceso o número de casos favorables es un subconjunto de nuestro espacio muestral, para nuestro caso particular:

¿Cuál es la probabilidad de sacar un 2?

A={2}

¿Cuál es la probabilidad de sacar un número impar?
B={1,3,5}


Se pueden realizar distintas operaciones con los sucesos, un poco más abajo dejo una hoja a modo de resumen.

Por otra parte, la regla de Laplace nos dice que:


 

Para nuestros casos:
P(A)=1/6=0.1667 Es decir, el 16% de las veces sacaremos un 2.
P(B)=3/6=0.5 La mitad de la veces sacaremos un número par.

Se puede observar que el valor de ambos sucesos está entre 0 y 1 y siempre será así, ya que cuanto más próximo a 1 quiere decir que tenemos más casos favorables.

A continuación os dejo una captura con algunas leyes básicas:

 

Accediendo a la API de Google Weather desde c#.

Buenas a todos,

dejando un poco de lado MonoTouch hoy vamos a ver cómo acceder a la API de Google Weather desde .NET. En mi caso particular tuve que hacerlo para una App que estoy desarrollando para WP7. Pero dado que a penas hay cambios he decidido hacer la entrada de un modo más general.

Lo primero que necesitaremos es definir la clase más simple que contendrá la información a mostrar al usuario:

   1:  

   2:     public class Tiempo

   3:     {

   4:        public ExtendedImage Icon {get;set;} //Puede ser una imagen o un String depende del tipo de App. 

   5:        public string Dia { get; set; }

   6:        public string Min { get; set; }

   7:        public string Max { get; set; }

   8:        public string Condicion { get; set; }

   9:  

  10:     }

A continuación, crearemos la clase que contiene el acceso a la API:

   1: public delegate void DownloadComplete ();

   2:  

   3:    public class GoogleWeather

   4:    {

   5:    public event DownloadComplete EDownloadComplete;

   6:           

   7:    public List<Tiempo> Temperaturas { get; set; }

   8:  

   9:  

  10:        public GoogleWeather(string localizacion, string cod)

  11:        {

  12:            WebClient webclient = new WebClient();

  13:            webclient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(WebClient_DownloadCompleted);

  14:            webclient.DownloadStringAsync(new Uri("http://www.google.com/ig/api?weather=" + localizacion + "&hl="+cod+"&oe=utf-8")); // weather location

  15:  

  16:        

  17:  

  18:        }

  19:      

  20:  

  21:  

  22:        protected void WebClient_DownloadCompleted(object sender, DownloadStringCompletedEventArgs e)

  23:        {

  24:            if (e.Error != null)

  25:                throw new Exception("Ha ocurrido un error");//TODO Cambiar al idioma correspondiente.

  26:  

  27:            Temperaturas = new List<Tiempo>();

  28:  

  29:            XElement XMLTemperatura = XElement.Parse(e.Result);

  30:            foreach (var elemento in XMLTemperatura.Descendants("forecast_conditions"))

  31:            {

  32:                Tiempo t = new Tiempo();

  33:                t.Dia = (string)elemento.Element("day_of_week").Attribute("data").Value;

  34:                t.Max = (string)elemento.Element("high").Attribute("data").Value;

  35:                t.Min = (string)elemento.Element("low").Attribute("data").Value;

  36:                t.Condicion = (string)elemento.Element("condition").Attribute("data").Value;

  37:  

  38:                ImageTools.IO.Decoders.AddDecoder<GifDecoder>();

  39:                ImageTools.ExtendedImage image = new ImageTools.ExtendedImage();

  40:                string  gifUrl = "http://www.google.com/" + (string)elemento.Element("icon").Attribute("data").Value;

  41:                image.UriSource = new Uri(gifUrl, UriKind.Absolute);

  42:                t.Icon = image;

  43:  

  44:                Temperaturas.Add(t);

  45:            }

  46:  

  47:            EDownloadComplete();

  48:  

  49:        }

  50:  

  51:  

  52:  

  53:  

  54:  

  55:  

  56:    }

 

Como se puede ver en el código, la clase se compone de:

  • Una lista de Tiempo que es la clase que hemos creado anteriormente.
  • Un evento que permite comunicarnos con el exterior para saber que se han descargado los datos o que ha ocurrido algún tipo de error. Recordemos que la carga se realiza de forma asíncrona.
  • El método que se subscribe al Webclient (hablaremos algo más de él a continuación).
  • El constructor de la clase. En el constructor se establece la localización y el idioma utilizado. Por defecto el idioma es inglés, que viene representado por “en”. Cabe destacar que Google nos devuelve la información con el sistema métrico utilizado para cada idioma. Como sabemos los países anglosajones utilizan Fahrenheit y el resto, Celsius. Por otra parte, la localización puede ser un código postal, una ciudad, un municipio, etc.

Como hemos visto, en WebClient_DownloadCompleted es dónde esta el meollo de la cuestión. En primer lugar comprobamos si ha ocurrido un error. A continuación solamente tenemos que acceder a los datos (son devueltos en XML) e ir rellenando la lista. Como veréis en este caso cambio el formato de la imagen. Y es que Google devuelve la imagen en formato GIF y como sabemos, Silverlight no soporta este formato de forma nativa. Por ello he utilizado herramientas de terceros para convertir la imagen. Podéis acceder al proyecto aquí.

Finalmente, se genera el evento y la clase que va a estar subscrita al mismo mostrará los datos al usuario.

Hasta la próxima!

« Siguientes entradas Recientes entradas »