Mostrando entradas con la etiqueta grafos. Mostrar todas las entradas
Mostrando entradas con la etiqueta grafos. Mostrar todas las entradas

domingo, 20 de enero de 2013

Métricas del grafo de hash tags

Tutorial de Grafos
Anterior        Índice       

El programa que extrae la información usando la API de Twitter está usando exploración aleatoria. Es decir, selecciona aleatoriamente el siguiente hash tag a solicitar. Este enfoque resulta muy práctico y nos permite descubrir muchos hash tags. Por ejemplo, después de haber ejecutado el programa algunas horas, este ha visitado alrededor de 3,000 nodos pero ha descubierto alrededor de 150,000. Esto nos da un grafo bastante incompleto, lo cual puede ser frustrante al momento de ejecutar algoritmos como el de encontrar la ruta más corta, ya que es muy probable que si seleccionamos dos nodos al azar sólo haya una ruta entre ellos. Lo ideal sería poder visitar la mayoría de los nodos que conocemos; el problema es que el realizar las peticiones de tweets es una operación costosa.

Por ello es que decidí modificar el programa para visitar sólo aquellos hash tags que luzcan más “relevantes”. La definición de relevancia es un tanto arbitraria y la definí intuitivamente. Obtuve algunas métricas con los nodos que he visitado hasta el momento para obtener un parámetro que no fuera del todo subjetivo.

NOTA: las siguientes conclusiones están basadas en los aproximadamente 3,000 hash tags que visite usando el programa descrito en secciones anteriores. Por lo que estás conclusiones pueden ser incompletas e incluso incorrectas, pero son un buen inicio para los propósitos de este tutorial.

El término hash tag y nodo son equivalentes en la siguiente discusión.

La primer métrica es el número de vecinos de un nodo: en promedio tienen 133 vecinos. En la siguiente gráfica observamos que más del 40% de los nodos tienen 90 o más vecinos. Esto concuerda con nuestros resultados (sólo 3,000 visitados pero ya llevamos 150.000 descubiertos); es decir, el universo de nodos descubiertos crece muy rápidamente conforme vamos visitando más nodos.

Es interesante ver como hay también un buen porcentaje de nodos con muy pocos vecinos, tal vez esto se deba a hash tags esporádicos.

Bueno, regresando a la pregunta de qué es un nodo relevante, decidí ver la fortaleza entre dos hash tags, y esto es simplemente cuantas veces aparece un hash tag en la búsqueda de otro. Por ejemplo, cuando buscamos #Toluca, de los 400 tweets obtenidos, el hash tag #futbol apareció 20 veces; en este caso digo que la fortaleza de #Toluca a #futbol es 20.

La siguiente gráfica muestra la distribución de las fortalezas de los enlaces. Noten como el 70% de los enlaces sólo tienen fortaleza 1, pareciera que la mayoría de las relaciones entre hash tags son esporádicas. Sin embargo, existe un porcentaje considerable de enlaces con fortaleza igual o mayor a 9.

Precisamente está es la métrica que utilicé para decidir que nodos visitar. Sólo visitaremos aquellos nodos que estén muy conectados a alguno de los nodos que hayamos visitado. Obviamente hay que cuidar no ser muy restrictivo que lleguemos al punto de no encontrar más nodos. Para ello obtuve la siguiente gráfica donde podemos ver que aproximadamente la mitad de los nodos están conectados a por lo menos otro nodo con fortaleza 9 o mayor. Lo cual es un buen indicador que aún cuando estamos reduciendo el espacio de búsqueda, seguiremos encontrando nuevos nodos.

Primero probé con enlaces de fortaleza 4, pero aún así el número de nodos conocidos crecía muy rápidamente. Así que ajuste este valor a 10.

El código lo pueden encontrar aquí. El archivo tweets_old.zip contiene la información usada para las métricas. El archivo tweet_graph.py calcula y despliega las métricas. Tweet_search.py es el programa de extracción de tweets con las modificaciones mencionadas.

Tutorial de Grafos
Anterior        Índice       

sábado, 12 de enero de 2013

Creación del grafo de hash tags

Tutorial de Grafos
Anterior        Índice        Siguiente

Ahora que ya tenemos datos podemos empezar a crear nuestro grafo. Existen dos formas principales de representar un grafo: matriz de adyacencia o lista de adyacencia. Aquí usaremos una lista de adyacencia, en particular, usaremos un diccionario de adyacencia.

El programa twitter_graph.py contiene un ciclo doble donde construye el grafo. Después entra a un cliclo donde podemos teclear un hash tag y despliega los 10 hash tags vecinos más frecuentes.

Nuestro grafo lo representamos con un diccionario de diccionarios. En el diccionario externo las llaves son los nodos del grafo y los valores son los vecinos de este nodo. Siendo más precisos, un valor es otro diccionario, donde las llaves son los vecinos y los valores representan el número de veces que un hash tag apareció.

Veamos un ejemplo de la variable que apunta al grafo en el programa usando los resultados de la imagen anterior.

  • graph["#cozumel"]
    : contiene los vecinos del hash tag #cozumel.
  • graph["#cozumel"]["#cancun"]
    : regresa el número de veces que #cancun apareció en la búsqueda de #cozumel, en este caso 10 veces.

Vale la pena mencionar dos funciones de los diccionarios en python que ayudan a hacer código más compacto. El siguiente fragmento de código agrega el hash tag al grafo en caso de ser necesario.

if hash_tag not in graph: 
  graph[hash_tag] = dict() 
links = graph[hash_tag]

Esto es equivalente a usar la función setdefault, la cual regresa el valor asociado con la llave (primer parámetro), en caso de no existir, inserta la llave con el segundo parámetro en el diccionario y por último regresa ese nuevo valor.

links = graph.setdefault(hash_tag, dict()) 

El siguiente código inicializa e incrementa el número de ocurrencias de un vecino.

if neighbor not in links: 
  links[neighbor] = 1 
else: 
  links[neighbor] = links[neighbor] + 1

Esto se puede reemplazar por la siguiente línea de código:

links[neighbor] = links.get(neighbor,0) + 1

La función get regresa el valor asociado con la llave o en caso de no existir regresa el segundo parámetro.

El código lo pueden encontrar aquí. Para ejecutarlo sólo recibe la carpeta donde están guardados los tweets:

python twitter_graph.py ./tweets

También incluí un archivo zip que contiene alrededor de 3,000 hash tags consultados, sólo tienen que descomprimir este archivo. AVISO: algunos de los hash tags pueden resultar ofensivos, pero eso es lo que encontró el programa.

En el siguiente post veremos algunas métricas de este grafo.

Tutorial de Grafos
Anterior        Índice        Siguiente

domingo, 2 de diciembre de 2012

Reiniciar peticiones de tweets

Tutorial de Grafos
Anterior        Índice        Siguiente

En este post volveremos a visitar el programa que obtiene la información de los hash tags. Agregué dos nuevas funcionalidades.

La primera mejora tiene que ver con qué pasa si queremos volver a ejecutar búsquedas y guárdalas en la misma carpeta de tweets de una ejecución anterior. Sin ninguna modificación al programa, lo que pasaría es que los nuevos archivos de salida se agregan sin problema aún cuando volvamos a visitar un mismo hash tag, ya que el nombre del archivo esta formado por un “timestamp” y el hash tag (por ejemplo: 1351987950#felicidad). Y tal vez ese sea un comportamiento deseado.

Sin embargo, decidí modificar el programa para evitar visitar hash tags que hayan sido visitados en ejecuciones anteriores. Esto es muy sencillo, ya que el nombre del archivo contiene el hash tag, por lo que sólo tuve que extraerlos y agregarlos al conjunto de hash tags visitados.

Un efecto secundario de este cambio es cuando nuestro hash tag inicial ya lo habíamos visitado anteriormente, el resultado es que el programa termina inmediatamente. Esto nos lleva a el segundo cambio, inicializar automáticamente la búsqueda cuando pasemos “##” como hash tag inicial en la línea de comandos.

En caso de que hayamos ejecutado el programa previamente, entonces tendremos un conjunto de archivos de los hash tags visitados. Los hash tags dentro de los archivos no necesariamente han sido visitados, por lo que inicializaré los hash tags a visitar con todos aquellos hash tags que no se visitaron en ejecuciones anteriores. El siguiente comando visitará otros 2,000 hash tags, tomando como base la información en "../tweets" de los hash tags visitados anteriormente.

python twitter_search.py "##" 100 5 2000 ../tweets

El código lo pueden encontrar en la siguiente liga.

Creo que por el momento el programa de extracción de datos está bastante completo, en el siguiente post veremos cómo construir nuestro grafo de hash tags con esta información.

Tutorial de Grafos
Anterior        Índice        Siguiente

viernes, 23 de noviembre de 2012

Grafo de hash tags (parte 3)

Tutorial de Grafos
Anterior        Índice        Siguiente

Hasta el momento podemos obtener un número de tweets deseados para un hash tag. El objetivo es obtener la relación entre hash tags. El programa de este post, analiza cada tweet y extrae los hash tags para poder construir más búsquedas. De esta forma podemos obtener más tweets de otros tópicos.

Al mismo tiempo de obtener tweets y extraer hash tags, iremos guardando la información. Usaremos la siguiente convención para guardar los datos. Por cada hash tag que consultemos crearemos un archivo, cuyo nombre es el resultado de concatenar un “timestamp” con el hash tag. El archivo contiene un hash tag por línea, estos son los hash tags encontrados en los tweets que regreso la búsqueda. Por ejemplo, después de consultar #Mexico, obtuvimos el siguiente archivo:

Nombre del archivo: 1351385380#mexico

Contenido del archivo:

#musica 
#cancun 
#guadalajara 
...
#instagram 
#instagramhub 
...
#saltillo 
#torreon 
...
#saltillo 
#argentina 
#colombia 
#bolivia 
#brasil 
...
#reforma 
#instagram
...

Como pueden ver, algunos hash tags aparecen más de una vez; esto se debe a que el mismo hash tag está en varios tweets. Decidí dejar los duplicados ya que considero que son un muy buen indicador de qué tan relacionados están los tópicos.

Esta versión del programa recibe cinco parámetros, por ejemplo:

python twitter_search.py "#Mexico" 50 5 500 ./tweets
  1. El hash tag inicial, es decir, con el que iniciaremos las búsquedas.
  2. El número de resultados por petición. En este ejemplo cada petición a Twitter regresará a lo más 50 tweets.
  3. El número de peticiones por hash tag. En el ejemplo, para cada hash tag que busquemos realizaremos a los más 5 peticiones. Este parámetro junto con el anterior nos da el máximo número de tweets por hash tag. En este caso a lo más 250 tweets por hash tag. Puede ser menor, ya que algunos tópicos son poco populares.
  4. El número de hash tags a visitar. Por ejemplo, buscaremos 500 hash tags.
  5. El directorio donde queremos guardar los resultados. Después de que se termine de ejecutar el comando anterior, tendremos 500 archivos en el directorio ./tweets

La lógica del programa es la siguiente:

Mientras no hayamos visitado el número de hash tags

  1. Obtener los tweets de un hash tag que aún no hayamos visitado.
  2. Extraer los hash tags de los tweets.
  3. Guardar los hash tags asociados al hash tag consultado.
  4. Actualizar la información de los hash tags a visitar con los hash tags obtenidos en el paso 2. En este paso sólo agregamos hash tags que no hayamos visitado y que no estén ya en la lista por visitar.

El código lo pueden encontrar en la siguiente liga.

Tutorial de Grafos
Anterior        Índice        Siguiente

domingo, 18 de noviembre de 2012

Grafo de hash tags (parte 2)

Tutorial de Grafos
Anterior        Índice        Siguiente

Ahora modificaremos el programa del post anterior para obtener más de 15 tweets; que es lo que regresa una petición sin parámetros. El programa recibe dos parámetros, además del hash tag inicial, también espera el número de tweets que se desean obtener. Por ejemplo:

python twitter_search.py "#Toluca" 35

Obtiene 35 tweets que contienen el hash tag #Toluca. El programa realiza peticiones hasta que obtiene los tweets deseados.

Sin embargo hay un punto a considerar, la documentación de Twitter menciona que para la API de búsqueda existe un límite en la frecuencia con la que se pueden realizar peticiones, pero no publican dicho límite. En caso de que excedamos este límite simplemente obtendremos algo como:

{"error":"..."}

Por lo que antes de iniciar una nueva petición, espero 5 segundos, si la petición resulta en un error, espero el doble. Quizá tengamos que modificar estos valores.

El siguiente es un ejemplo de la salida del programa.

El código lo pueden encontrar aquí. En el siguiente post comenzaremos a navegar entre hash tags.

Tutorial de Grafos
Anterior        Índice        Siguiente

sábado, 3 de noviembre de 2012

Grafo de hash tags (parte 1)

Tutorial de Grafos
Índice        Siguiente

Realizar una búsqueda usando la API de twitter es tan sencillo como construir la siguiente URL:

http://search.twitter.com/search.json?q=%23Toluca

Esta consulta regresa tweets recientes que contienen el hash tag #Toluca. De hecho si pegan esta URL en su navegado pueden observar el formato de la respuesta. La respuesta viene en formato JSON. Los signos de llaves indican un objeto y los corchetes indican un arreglo.

{
 "completed_in":0.089,
 "max_id":259679677768151040,
 "max_id_str":"259679677768151040",
 "next_page":"?page=2&max_id=259679677768151040&q=%23Toluca",
 "page":1,
 "query":"%23Toluca",
 "refresh_url":"?since_id=259679677768151040&q=%23Toluca",
 "results":
  [
   {
    "created_at":"Sat, 20 Oct 2012 15:18:54 +0000",
    "from_user":"tlcweather",
    "from_user_id":461072765,
    "from_user_id_str":"461072765",
    "from_user_name":"Toluca Weather",
    "geo":null,
    "id":259675063110995968,
    "id_str":"259675063110995968",
    "iso_language_code":"es",
    "metadata":{"result_type":"recent"},
    "profile_image_url":"http:\/\/a0.twimg.com\/profile_...",
    "profile_image_url_https":"https:\/\/si0.twimg.com\/...",
    "source":"<a href="http:\/\/www.google.com\/">Google<\/a>",
    "text":"Toluca, MEXICO Weather :: 13C Mist ... #Toluca #Mexico",
    "to_user":null,
    "to_user_id":0,
    "to_user_id_str":"0",
    "to_user_name":null
   },
   {...}
  ],
 "results_per_page":15,
 "since_id":0,
 "since_id_str":"0"
}

Analicemos algunas variables de la respuesta JSON que utilizaremos. Como podemos ver en la variable results_per_page, cada consulta regresa sólo 15 tweets. Para obtener los siguientes 15 tweets utilizaremos la variable next_page.

La variable results es un arreglo de objetos. Cada objeto de results contiene el usuario que creó el tweet, si está dirigido a alguien, cuándo fue creado y por supuesto el texto del tweet.

El programa en python recibe el hash tag que deseamos buscar:

python twitter_search.py "#Toluca"

El programa construye y realiza la petición de búsqueda. Después de parsear el resultado, obtenemos un mapa de llaves y valores. Por ejemplo, para acceder a la variable next_page usamos algo como search_result["next_page"]. El programa despliega todos los elementos del resultado de búsqueda, todos los elementos de un tweet y finalmente sólo los textos de los 15 tweets.

En el siguiente post extenderemos este ejemplo para obtener más de 15 tweets.

Tutorial de Grafos
Índice        Siguiente

Tutorial de Grafos

Una de las estructuras de datos que más ha llamado mi atención son los grafos. Y no sólo por la parte teórica, sino por su presencia en diversas situaciones. Uno de los ejemplos más claros son las redes sociales. Este es el primer post de una serie en la que hablaremos de grafos y algunos algoritmos.

El primer paso será construir un grafo. Resulta un tanto aburrido el estudiar grafos donde los nodos son simplemente letras y las conexiones entre ellos no tienen un significado real. Algunos libros cuando hablan de encontrar rutas usan ejemplos donde los nodos son ciudades y las conexiones son caminos entre ellas. Intentaré usar algo más atractivo para esta serie.

Después de investigar un poco las APIs de Facebook y Twitter, decidí que utilizaremos el servicio de búsqueda de Twitter, ya que no requiere autenticación, así que es muy fácil de empezar a usar. Como lenguaje de programación usaremos Python y el código estará en mercurial.

En el siguiente post comenzaremos a investigar cómo construir nuestro grafo usando la API de Twitter.

Todos los post de esta serie se irán listando a continuación:

sábado, 20 de octubre de 2012

Grafo de Lenguajes de Programación

La siguiente página muestra una red de lenguajes de programación, donde las conexiones significan que un lenguaje influenció a otro. Entre más grande sea un nodo significa que ese lenguaje ha influenciado a más lenguajes de programación.

Cuando posicionas el cursor sobre un lenguaje muestra en un color los lenguajes que lo han influenciado y en otro color los que ha influenciado. Dando clic en el nodo despliega más información acerca del lenguaje.

Esta visualización resulta muy interesante. Además, si en algún momento deseamos aprender un nuevo lenguaje, puede ser una buena guía. Por ejemplo, tal vez resulte de más utilidad aprender un lenguaje que tiene mucha influencia, porque nos puede ayudar a aprender fácilmente más lenguajes.

En la página también explican como fue generado el grafo y tiene enlaces al código.

Programming Languages Influence Network