Minería de datos con Ruby y Twitter

El lado interesante hacia una API Twitter

Twitter no solo es una herramienta fantástica de redes sociales en tiempo real, también es una rica fuente de información que está madura para hacer minería de datos. En promedio, los usuarios de Twitter generan 140 millones de trinos por día en una variedad de temas. Este artículo le introduce a la minería de datos y demuestra el concepto con el lenguaje Ruby orientado a objetos.

M. Tim Jones, Independent author

M. Tim JonesM. Tim Jones es arquitecto de firmware integrado y el autor de Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming (ahora en su segunda edición), AI Application Programming (en su segunda edición) y de BSD Sockets Programming from a Multilanguage Perspective. Su experiencia en ingeniería va desde el desarrollo de kernels para vehículos espaciales geo-sincronizados hasta arquitectura de sistemas incorporados y desarrollo de protocolos de redes. Tim es arquitecto de plataforma para Intel y autor en Longmont, Colorado.



02-02-2012 (Primera publicación 04-10-2011)

En octubre del 2008, como muchos otros, creé una cuenta de Twitter por curiosidad. Como la mayoría de las personas, me conecté con amigos y realicé algunas búsquedas aleatorias para entender mejor el servicio. Comunicarse con solo 140 caracteres no me pareció una idea que pudiera ser popular. Un evento no relacionado me ayudó a entender el valor real de Twitter.

A principios de julio del 2009, mi proveedor de servicios Web se apagó. Después de una búsqueda al azar en la Web encontré información que señalaba que el culpable había sido un incendio en la Plaza Fisher de Seattle. La información de fuentes tradicionales basadas en la Web fue lenta y no daba ninguna indicación sobre cuándo se reanudaría el servicio. No obstante, después de buscar en Twitter, encontré cuentas personales sobre el incidente, incluyendo información en tiempo real sobre lo que estaba sucediendo en el sitio. Por ejemplo, poco después de que mi servicio Web retornara, recibí un trino que indicaba que había generadores eléctricos diesel afuera del edificio.

Allí fue cuando entendí que el verdadero poder de Twitter es la comunicación de información abierta y en tiempo real entre individuos y grupos. Aún así, debajo de la superficie, hay un tesoro oculto de información sobre los comportamientos de los usuarios y sobre tendencias a niveles locales y globales. Exploro este descubrimiento en el contexto de scripts simples usando el lenguaje Ruby y Twitter gem, un derivador de API para Twitter. También demuestro cómo construir mashups simples para virtualización de datos usando otros servicios y aplicaciones Web.

Conocimientos en Ruby

Si no tiene conocimientos básicos sobre el maravilloso lenguaje Ruby, encuentre referencias en la sección Recursos . Estos ejemplos demuestran el valor de Ruby y su capacidad para codificar una cantidad significativa de potencia en un número limitado de líneas de código fuente.

Twitter y APIs

Aunque la red temprana trataba sobre interacción entre hombres y máquinas, la red actual es sobre interacción máquina-máquina, que es posible mediante el uso de servicios Web. Estos servicios existen para los sitios Web más populares—desde varios servicios Google hasta LinkedIn, Facebook y Twitter. Los servicios Web crean APIs mediante las que las aplicaciones externas pueden consultar o manipular contenido en sitios Web.

Los servicios Web se implementan usando diversos estilos. Actualmente, uno de los más populares es el Representational State Transfer, o REST. Una implementación REST se hace sobre el bien conocido protocolo HTTP, permitiendo que el HTTP exista como medio para una arquitectura REST completa (usando operaciones HTTP estándar como GET, PUT, POST y DELETE). La API para Twitter se desarrolla como una abstracción para este medio. De esta forma, no hay conocimiento sobre REST, HTTP ni formatos de datos como XML o JSONH, sino una interfaz basada en objeto que se integra limpiamente en el lenguaje Ruby.


Un recorrido rápido por Ruby y Twitter

Exploremos cómo puede usted usar la API Twitter con Ruby. Primero, necesitamos obtener los recursos necesarios. Si como yo usted está usando Ubuntu Linux®, usted usa la infraestructura apt .

Para obtener la última distribución completa de Ruby (una descarga de aproximadamente 13MB), use esta línea de comando:

$ sudo apt-get install ruby1.9.1-full

Luego, tome el Twitter gem usando la herramienta gem :

$ sudo gem install twitter

Ahora tiene todo lo que necesita para este paso, así que continuemos con una prueba del derivador de Twitter. Para esta demostración, use un shell llamado Interactive Ruby Shell (IRB). Este shell le permite ejecutar comandos Ruby y experimentar con el lenguaje en tiempo real. El IRB tiene un gran número de capacidades, pero lo usaremos para experimentación simple.

El Listado 1 muestra una sesión con el IRB que ha sido descompuesta en tres secciones para facilitar la lectura. La primera sección (líneas 001 y 002) simplemente prepara el entorno importando los elementos de tiempo de ejecución necesarios (el método require carga y ejecuta la biblioteca nombrada). La siguiente línea (003) demuestra el uso de Twitter gem para mostrar el trino más reciente de IBM® developerWorks®. Como se muestra, usted usa el método user_timeline del módulo Client::Timeline para mostrar un trino. El primer ejemplo demuestra la capacidad de "métodos de cadena" de Ruby. El método user_timeline retorna una matriz de 20 trinos que usted encadena al método first . Hacer esto extrae el primer trino de la matriz (first es un método de la clase Array ). Desde este trino individual usted extrae el campo de texto emitido como resultado vía puts.

La siguiente sección (línea 004) usa el campo de ubicación definida por el usuario, un campo de formulario libre en el cual el usuario puede proporcionar información local útil y no útil. En este ejemplo, el módulo User captura la información, obligada en el campo de ubicación.

La sección final (desde la línea 005) explora el módulo Twitter::Search . El módulo de búsqueda proporciona una interfaz extremadamente rica con la cual hacer búsquedas en Twitter. En este ejemplo usted primero crea una instancia de búsqueda (line 005) y luego especifica una búsqueda en la línea 006. Usted estará buscando los trinos más recientes que contengan la palabrawhy que estén dirigidos al usuario LulzSec. La lista resultante ha sido reducida y editada. Las búsquedas son bochornosas en cuanto a que la instancia de búsqueda mantiene los filtros definidos. Usted puede limpiar estos filtros ejecutandosearch.clear.

Listado 1. Experimentando con la API Twitter mediante IRB
$ irb
irb(main):001:0> require "rubygems"
=> true
irb(main):002:0> require "twitter"
=> true

irb(main):003:0> puts Twitter.user_timeline("developerworks").first.text
dW Twitter is saving #IBM over $600K per month: will #Google+ add to that? > 
http://t.co/HiRwir7 #Tech #webdesign #Socialmedia #webapp #app
=> nil

irb(main):004:0> puts Twitter.user("MTimJones").location
Colorado, USA
=> nil

irb(main):005:0> search = Twitter::Search.new
=> #<Twitter::Search:0xb7437e04 @oauth_token_secret=nil, 
    @endpoint="https://api.twitter.com/1/", 
    @user_agent="Twitter Ruby Gem 1.6.0", 
    @oauth_token=nil, @consumer_secret=nil, 
    @search_endpoint="https://search.twitter.com/", 
    @query={:tude=>[], :q=>[]}, @cache=nil, @gateway=nil, @consumer_key=nil, 
    @proxy=nil, @format=:json, @adapter=:net_http<
irb(main):006:0> search.containing("why").to("LulzSec").
result_type("recent").each do |r| puts r.text end
@LulzSec why not stop posting <bleep> and get a full time job! MYSQLi isn't 
hacking you <bleep>.
...
irb(main):007:0>

Ahora, observemos el esquema para un usuario de Twitter. Usted también puede hacer esto mediante IRB, pero yo voy a reformatear el resultado para ilustrar más simplemente la anatomía de un usuario de Twitter. El Listado 2 muestra el resultado de imprimir la estructura de usuario, lo cual en Ruby es un Hashie::Mash. Esta estructura es útil porque permite que un objeto tenga accesos tipo método para claves hash (un objeto abierto). Como usted puede ver en el Listado 2, este objeto contiene una riqueza de información (información específica de usuario y de presentación), incluyendo estado actual de usuario (con información de geocódigo). Un trino también contiene una gran cantidad de información, y usted puede visualizar fácilmente esta información usando la clase user_timeline .

Listado 2. Anatomía de un usuario Twitter (perspectiva Ruby)
irb(main):007:0> puts Twitter.user("MTimJones")
<#Hashie::Mash 
  contributors_enabled=false 
  created_at="Wed Oct 08 20:40:53 +0000 2008" 
  default_profile=false default_profile_image=false 
  description="Platform Architect and author (Linux, Embedded, Networking, AI)."
  favourites_count=1 
  follow_request_sent=nil 
  followers_count=148 
  following=nil 
  friends_count=96 
  geo_enabled=true 
  id=16655901 id_str="16655901" 
  is_translator=false 
  lang="en" 
  listed_count=10 
  location="Colorado, USA" 
  name="M. Tim Jones" 
  notifications=nil 
  profile_background_color="1A1B1F" 
  profile_background_image_url="..."
  profile_background_image_url_https="..." 
  profile_background_tile=false 
  profile_image_url="http://a0.twimg.com/profile_images/851508584/bio_mtjones_normal.JPG" 
  profile_image_url_https="..." 
  profile_link_color="2FC2EF" 
  profile_sidebar_border_color="181A1E" profile_sidebar_fill_color="252429" 
  profile_text_color="666666" 
  profile_use_background_image=true 
  protected=false 
  screen_name="MTimJones" 
  show_all_inline_media=false 
  status=<#Hashie::Mash 
    contributors=nil coordinates=nil 
    created_at="Sat Jul 02 02:03:24 +0000 2011" 
    favorited=false 
    geo=nil 
    id=86978247602094080 id_str="86978247602094080" 
    in_reply_to_screen_name="AnonymousIRC" 
    in_reply_to_status_id=nil in_reply_to_status_id_str=nil 
    in_reply_to_user_id=225663702 in_reply_to_user_id_str="225663702" 
    place=<#Hashie::Mash 
      attributes=<#Hashie::Mash> 
      bounding_box=<#Hashie::Mash 
        coordinates=[[[-105.178387, 40.12596], 
                      [-105.034397, 40.12596], 
                      [-105.034397, 40.203495], 
                      [-105.178387, 40.203495]]] 
        type="Polygon"
      > 
      country="United States" country_code="US" 
      full_name="Longmont, CO" 
      id="2736a5db074e8201" 
      name="Longmont" place_type="city" 
      url="http://api.twitter.com/1/geo/id/2736a5db074e8201.json"
    > 
    retweet_count=0 
    retweeted=false 
    source="web" 
    text="@AnonymousIRC @anonymouSabu @LulzSec @atopiary @Anonakomis Practical reading 
          for future reference... LULZ \"Prison 101\" http://t.co/sf8jIH9" truncated=false
  >
  statuses_count=79 
  time_zone="Mountain Time (US & Canada)" 
  url="http://www.mtjones.com" 
  utc_offset=-25200 
  verified=false
>
=> nil
irb(main):008:0>

Eso es todo para el recorrido rápido. Ahora, exploremos algunos scripts simples que usted puede usar para recolectar y visualizar datos usando Ruby y la API Twitter. Durante el recorrido, usted conocerá algunos de los conceptos de Twitter, como la autenticación y la limitación de clasificación.


Minería de datos Twitter

las siguientes secciones presentan varios scripts para recolectar y presentar datos disponibles mediante la API Twitter. Estos scripts se enfocan en la simplicidad, pero usted puede extenderlos y combinarlos para crear nuevas capacidades. Además, esta sección toca la superficie de la API Twitter gem cuando muchas de las capacidades están disponibles.

Es importante notar que la API Twitter solo permite que los clientes hagan un número limitado de llamadas en una hora dada, esto es, Twitter clasifica-limita las solicitudes (actualmente no más de 150 por hora), lo cual significa que después de cierta cantidad de uso usted recibirá un mensaje de error y se le solicitará que espere antes de ingresar nuevas solicitudes.

Información de usuario

Recuerde del Listado 2 que hay una gran cantidad de información disponible sobre cada usuario de Twitter. A esta información solo se puede acceder si el usuario no está protegido. Observemos cómo puede usted extraer los datos de un usuario y presentarlos de la forma más conveniente.

El Listado 3 presenta un script Ruby simple para recuperar la información de un usuario (con base en su nombre en pantalla) y luego emitir algunos de los otros elementos útiles. Luego usted usa el método Ruby to_s para convertir el valor en una cadena de caracteres según sea necesario. Note que usted primero se asegura de que el usuario no esté protegido; en caso contrario, no se podrá acceder a estos datos.

Listado 3. Script simple para extraer datos de usuario de Twitter (user.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"

screen_name = String.new ARGV[0]

a_user = Twitter.user(screen_name)

if a_user.protected != true

  puts "Username   : " + a_user.screen_name.to_s
  puts "Name       : " + a_user.name
  puts "Id         : " + a_user.id_str
  puts "Location   : " + a_user.location
  puts "User since : " + a_user.created_at.to_s
  puts "Bio        : " + a_user.description.to_s
  puts "Followers  : " + a_user.followers_count.to_s
  puts "Friends    : " + a_user.friends_count.to_s
  puts "Listed Cnt : " + a_user.listed_count.to_s
  puts "Tweet Cnt  : " + a_user.statuses_count.to_s
  puts "Geocoded   : " + a_user.geo_enabled.to_s
  puts "Language   : " + a_user.lang
  if (a_user.url != nil)
    puts "URL        : " + a_user.url.to_s
  end
  if (a_user.time_zone != nil)
    puts "Time Zone  : " + a_user.time_zone
  end
  puts "Verified   : " + a_user.verified.to_s
  puts

  tweet = Twitter.user_timeline(screen_name).first

  puts "Tweet time : " + tweet.created_at
  puts "Tweet ID   : " + tweet.id.to_s
  puts "Tweet text : " + tweet.text

end

Para invocar este script, asegurando que es ejecutable (chmod +x user.rb), usted lo invoca como un usuario. El resultado de muestra en el Listado 4 para el usuario developerworks , mostrando la información de usuario y el estado actual (información del último trino). Note aquí que Twitter define followers como las personas que le siguen a usted; pero las personas a las que usted sigue son llamadas amigos.

Listado 4. Resultado de muestra de user.rb
$ ./user.rb developerworks
Username   : developerworks
Name       : developerworks
Id         : 16362921
Location   : 
User since : Fri Sep 19 13:10:39 +0000 2008
Bio        : IBM's premier Web site for Java, Android, Linux, Open Source, PHP, Social, 
Cloud Computing, Google, jQuery, and Web developer educational resources
Followers  : 48439
Friends    : 46299
Listed Cnt : 3801
Tweet Cnt  : 9831
Geocoded   : false
Language   : en
URL        : http://bit.ly/EQ7te
Time Zone  : Pacific Time (US & Canada)
Verified   : false

Tweet time : Sun Jul 17 01:04:46 +0000 2011
Tweet ID   : 92399309022167040
Tweet text : dW Twitter is saving #IBM over $600K per month: will #Google+ add to that? > 
http://t.co/HiRwir7 #Tech #webdesign #Socialmedia #webapp #app

Popularidad de los amigos

Observe a sus amigos (personas que usted sigue), y recolecte datos para entender su popularidad. En este caso, usted recolecta a sus amigos y los clasifica en orden según su número de seguidores. Este script simple se muestra en el Listado 5.

En este script, después de que usted entiende el usuario que desea analizar (con base en su nombre en pantalla), usted crea un hash de usuario. Un hash Ruby (o matriz asociativa) es una estructura de datos que le permite definir la clave para el almacenamiento (en lugar de un simple índice numérico). Luego su hash es indexado por el nombre en pantalla de Twitter y el valor asociado es el conteo de seguidores del usuario. El proceso es simplemente iterar a sus amigos y hacer hash al conteo de sus seguidores. Clasifique su hash (en orden descendente) y emítalo como resultado.

Listado 5. Script de popularidad de amigos (friends.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"
require 'google_chart'

name = String.new ARGV[0]

user = Hash.new

# Iterate friends, hash their followers
friends = Twitter.friend_ids(name)

friends.ids.each do |fid|

  f = Twitter.user(fid)

  # Only iterate if we can see their followers
  if (f.protected.to_s != "true")
    user[f.screen_name.to_s] = f.followers_count
  end

end

user.sort_by {|k,v| -v}.each { |user, count| puts "#{user}, #{count}" }

El resultado de muestra del script de los amigos del Listado 5 se muestra en el Listado 6. He recortado el resultado para ahorrar espacio, pero como puede ver, ReadWriteWeb (RWW) y Playstation son usuarios populares de Twitter en mi red directa.

Listado 6. Resultado en pantalla del script de amigos del Listado 5
$ ./friends.rb MTimJones
RWW, 1096862
PlayStation, 1026634
HarvardBiz, 541139
tedtalks, 526886
lifehacker, 146162
wandfc, 121683
AnonymousIRC, 117896
iTunesPodcasts, 82581
adultswim, 76188
forrester, 72945
googleresearch, 66318
Gartner_inc, 57468
developerworks, 48518

¿Dónde están mis seguidores?

Recuerde del Listado 2 que Twitter proporciona una riqueza de información de ubicación. Hay un campo de ubicación que es un formulario libre, definido por usuario y datos opcionales de geocodificación. No obstante, una zona horaria definida por el usuario también puede proporcionar información sobre la ubicación real del seguidor.

En este ejemplo, usted crea un mash-up que extrae datos de zona horaria de sus seguidores de Twitter y luego visualiza estos datos usando Google Charts. Google Charts es un proyecto interesante que le permite construir una variedad de diferentes tipos de gráficos en la Web, definiendo el tipo de gráfico y de datos como una solicitud HTTP, donde el resultado se presenta directamente en el navegador como respuesta. Para instalar el Ruby gem para Google Charts, use la siguiente línea de comandos:

$ gem install gchartrb

El Listado 7 proporciona el script para extraer los datos de zona horaria y luego construir la solicitud Google Charts. Primero, a diferencia de los scripts anteriores, este script requiere que usted esté autenticado en Twitter. Para hacer esto, usted necesita registrar una aplicación con Twitter, lo cual le proporciona un conjunto de claves y tokens. Esos tokens pueden aplicarse al script del Listado 7 para extraer los datos exitosamente. Consulte Recursos para detalles sobre este fácil proceso.

Siguiendo un patrón similar, este script acepta un nombre en pantalla y luego itera a los seguidores de ese usuario. La zona horaria es extraída del seguidor actual y almacenada en el hash tweetlocation . Note, que usted primero comprueba si esta clave está en el hash y, si lo está, aumenta el contador para esa clave. Usted también conserva una pestaña con el número de zonas horarias totales para la creación posterior de porcentajes.

La última porción del script es la construcción del Google Pie Chart URL. Usted crea un nuevo PieChart y especifica algunas opciones (tamaño, título, y si es en 3D). Luego, usted itera su hash de zona horaria, emitiendo datos para el gráfico para la cadena de caracteres de zona horaria (removiendo el símbolo & ) y el porcentaje de la zona horaria del total.

Listado 7. Construyendo una gráfica tipo pastel de las zonas horarias de los seguidores en Twitter (followers-location.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"
require 'google_chart'

screen_name = String.new ARGV[0]

tweetlocation = Hash.new
timezones = 0.0

# Authenticate
Twitter.configure do |config|
  config.consumer_key = '<consumer_key>'
  config.consumer_secret = '<consumer_secret>'
  config.oauth_token = '<oath_token>'
  config.oauth_token_secret = '<oath_token_secret>'
end

cursor = "-1"

# Loop through all pages
while cursor != 0 do

  # Iterate followers, hash their location
  followers = Twitter.follower_ids(screen_name, :cursor=>cursor)

  followers.ids.each do |fid|

    f = Twitter.user(fid)

    loc = f.time_zone.to_s

    if (loc.length > 0)

      if tweetlocation.has_key?(loc)
        tweetlocation[loc] = tweetlocation[loc] + 1
      else
        tweetlocation[loc] = 1
      end

      timezones = timezones + 1.0

end

end

cursor = followers.next_cursor

end

# Create a pie chart
GoogleChart::PieChart.new('650x350', "Time Zones", false ) do |pc|

  tweetlocation.each do |loc,count|
    pc.data loc.to_s.delete("&"), (count/timezones*100).round
  end

  puts pc.to_url

end

Para ejecutar el script del Listado 7, proporciónele un nombre en pantalla de Twitter y luego copie y pegue el URL resultante en un navegador. El Listado 8 muestra este proceso con el URL generado.

Listado 8. Invocando el script de ubicación de seguidores (el resultado es una sola línea)
$ ./followers-location.rb MTimJones
http://chart.apis.google.com/chart?chl=Seoul|Santiago|Paris|Mountain+Time+(US++Canada)|
Madrid|Central+Time+(US++Canada)|Warsaw|Kolkata|London|Pacific+Time+(US++Canada)|
New+Delhi|Pretoria|Quito|Dublin|Moscow|Istanbul|Taipei|Casablanca|Hawaii|Mumbai|
International+Date+Line+West|Tokyo|Ulaan+Bataar|Vienna|Osaka|Alaska|Chennai|Bern|
Brasilia|Eastern+Time+(US++Canada)|Rome|Perth|La+Paz
&chs=650x350&chtt=Time+Zones&chd=s:KDDyKcKDOcKDKDDDDDKDDKDDDDOKK9DDD&cht=p
$

Cuando usted pega el URL del Listado 8 en un navegador, obtendrá el resultado que se muestra en la Figura 1.

Figura 1. Gráfico tipo pastel de las ubicaciones de los seguidores en Twitter
Gráfico tipo pastel de las ubicaciones de los seguidores en Twitter

Comportamiento de usuario de Twitter

Twitter contiene una gran cantidad de datos a los que usted puede hacer minería para entender algunos elementos de comportamiento de usuario. Dos ejemplos simples para analizar cuando un usuario de Twitter trina y desde qué aplicación lo hace. Usted puede usar los dos scripts simples siguientes para extraer y visualizar esta información.

El Listado 9 presenta un script que itera los trinos de un usuario en particular (usando el método user_timeline ), y luego para cada trino, extrae el día particular en que se originó el trino. Usted nuevamente usa un hash simple para acumular sus conteos de la semana, luego genera un gráfico de barras usando Google Charts de forma similar al ejemplo de la zona horaria anterior. Note también que el uso de predeterminado para el hash, lo cual especifica el valor a retornar para hash indefinidos.

Listado 9. Construyendo un gráfico de barras de días de trinos (tweet-days.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"
require "google_chart"

screen_name = String.new ARGV[0]

dayhash = Hash.new

# Initialize to avoid a nil error with GoogleCharts (undefined is zero)
dayhash.default = 0

timeline = Twitter.user_timeline(screen_name, :count => 200 )
timeline.each do |t|

  tweetday = t.created_at.to_s[0..2]

  if dayhash.has_key?(tweetday)
    dayhash[tweetday] = dayhash[tweetday] + 1
  else
    dayhash[tweetday] = 1
  end

end

GoogleChart::BarChart.new('300x200', screen_name, :vertical, false) do |bc|
  bc.data "Sunday", [dayhash["Sun"]], '00000f'
  bc.data "Monday", [dayhash["Mon"]], '0000ff'
  bc.data "Tuesday", [dayhash["Tue"]], '00ff00'
  bc.data "Wednesday", [dayhash["Wed"]], '00ffff'
  bc.data "Thursday", [dayhash["Thu"]], 'ff0000'
  bc.data "Friday", [dayhash["Fri"]], 'ff00ff'
  bc.data "Saturday", [dayhash["Sat"]], 'ffff00'
  puts bc.to_url
end

La Figura 2 proporciona el resultado de la ejecución del script de días de trinos del Listado 9 para la cuenta developerWorks. Como se muestra, los miércoles tienden a ser el día más activo de trinos, siendo sábado y domingo los menos activos.

Figura 2. Gráfico de barras relativo de una actividad de trinos por día
Gráfico de barras relativo de una actividad de trinos por día

El siguiente script determina desde cuál fuente trina un usuario en particular. Hay varias formas en las que usted puede trinar y este script no las codifica todas. Como se muestra en el Listado 10, usted usa un patrón similar para extraer la línea de tiempo del usuario de un usuario dado y luego intenta decodificar la fuente del trino en un hash. Posteriormente usted usa el hash para crear un gráfico de tipo pastel para usar Google Charts para visualizar los datos.

Listado 10. Construyendo un gráfico tipo pastel de las fuentes de trinos de un usuario (tweet-source.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"
require 'google_chart'

screen_name = String.new ARGV[0]

tweetsource = Hash.new

timeline = Twitter.user_timeline(screen_name, :count => 200 )
timeline.each do |t|

  if (t.source.rindex('blackberry')) then
    src = 'Blackberry'
  elsif (t.source.rindex('snaptu')) then
    src = 'Snaptu'
  elsif (t.source.rindex('tweetmeme')) then
    src = 'Tweetmeme'
  elsif (t.source.rindex('android')) then
    src = 'Android'
  elsif (t.source.rindex('LinkedIn')) then
    src = 'LinkedIn'
  elsif (t.source.rindex('twitterfeed')) then
    src = 'Twitterfeed'
  elsif (t.source.rindex('twitter.com')) then
    src = 'Twitter.com'
  else
    src = t.source
  end

  if tweetsource.has_key?(src)
    tweetsource[src] = tweetsource[src] + 1
  else
    tweetsource[src] = 1
  end

end

GoogleChart::PieChart.new('320x200', "Tweet Source", false) do |pc|

  tweetsource.each do|source,count|
    pc.data source.to_s, count
  end

  puts "\nPie Chart"
  puts pc.to_url

end

La Figura 3 ofrece la visualización de un usuario de Twitter que tiene un conjunto interesante de fuentes de trinos. El sitio Web tradicional de Twitter es utilizado con más frecuencia, seguido con una aplicación de telefonía móvil.

Figura 3. Gráfico tipo pastel de las fuentes de trinos de un usuario de Twitter
Gráfico tipo pastel de las fuentes de trinos de un usuario de Twitter

Gráfica de seguidores

Twitter es una red masiva de usuarios que forma una gráfica. Como usted ha visto en los scripts, es fácil iterar sus contactos y luego iterar sus contactos. Hacer esto forma la base para una gráfica grande, incluso a este nivel.

Para visualizar la gráfica, he seleccionado el software de visualización de gráficas GraphViz. En Ubuntu, usted puede instalar fácilmente esta herramienta usando la siguiente línea de comandos:

$ sudo apt-get install graphviz

El script que se muestra en el Listado 11 itera a los seguidores de un usuario y luego itera los seguidores de ellos. LA única diferencia real en este patrón es la construcción de un archivo GraphViz con formato de puntos. GraphViz utiliza un formato de script simple para definir gráficas, el cual usted emite como parte de su enumeración de usuarios Twitter. Como se muestra, usted define una gráfica simple al especificar las relaciones de los nodos.

Listado 11. Visualizando una gráfica de los seguidores en Twitter (followers-graph.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"
require 'google_chart'

screen_name = String.new ARGV[0]

tweetlocation = Hash.new

# Authenticate
Twitter.configure do |config|
  config.consumer_key = '<consumer_key>'
  config.consumer_secret = '<consumer_secret>'
  config.oauth_token = '<oath_token>'
  config.oauth_token_secret = '<oath_token_secret>'
end

my_file = File.new("graph.dot", "w")

my_file.puts "graph followers {"
my_file.puts "  node [ fontname=Arial, fontsize=6, penwidth=4 ];"

# Get the first page of followers
followers = Twitter.follower_ids(screen_name, :cursor=> -1 )

# Iterate the followers returned in the Array (max 10).
followers.ids[0..[5,followers.ids.length].min].each do |fid|

  f = Twitter.user(fid)

  # Only iterate if we can see their followers
  if (f.protected.to_s != "true")

    my_file.puts "  \"" + screen_name + "\" -- \"" + f.screen_name.to_s + "\""

    # Get the first page of their followers
    followers2 = Twitter.follower_ids(f.screen_name, :cursor => -1 )

    # Iterate the followers returned in the Array (max 10).
    followers2.ids[0..[5,followers2.ids.length].min].each do |fid2|

      f2 = Twitter.user(fid2)

      my_file.puts "    \"" + f.screen_name.to_s + "\" -- \"" +
                    f2.screen_name.to_s + "\""

end

end

end

my_file.puts "}"

Ejecute el script del Listado 11 en un archivo dot que usted luego genera como imagen usando GraphViz. Primero, invoque el script Ruby para reunir los datos gráficos (almacenados como graph.dot); luego, use GraphViz para generar la imagen de gráfica (aquí, usando circo, el cual especifica su diseño circular). El proceso de generar esta imagen se define como sigue:

$ ./followers-graph.rb MTimJones
$ circo graph.dot -Tpng -o graph.png

La imagen resultante se muestra en la Figura 4. Note que las gráficas de Twitter tienden a ser bastante grandes, así que he limitado la gráfica minimizando el número de usuarios y de sus seguidores a enumerar (según la opción :count del Listado 11).

Figura 4. Gráfica de muestra de seguidores en Twitter (subconjunto extremo)
Gráfica de muestra de seguidores en Twitter (subconjunto extremo)

Información de ubicación

Cuando está habilitado, Twitter recolecta datos de ubicación geográfica sobre usted y sus trinos. Estos datos consisten en información de latitud y longitud que se pueden usar para señalar un usuario o desde dónde se generan un trino. Además, las búsquedas pueden incorporar esta información para que usted pueda identificar lugares o personas con base en una ubicación definida o en su ubicación.

No todos los usuarios ni trinos están activados geográficamente (por razones de seguridad), pero esta información sirve como una dimensión interesante de la experiencia Twitter general. Observemos un script que le permite visualizar datos de ubicación geográfica, así como otros que le permiten hacer búsquedas con esta información.

En el primer script (mostrado en el Listado 12), usted toma datos de latitud y de longitud de un usuario (recuerde el recuadro de vinculación del Listado 2). Aunque el recuadro de vinculación es un polígono que define el área representada para el usuario, yo simplifico y uso un punto de estos datos. Con estos datos, genero una función JavaScript simple en un archivo HTML simple. Este código JavaScript hace interfaz con Google Maps para presentar un mapa adelantado de su ubicación (dados los datos de latitud y de longitud extraídos del usuario de Twitter).

Listado 12. Script Ruby para construir un mapa de un usuario (where-am-i.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"
require 'google_chart'

Twitter.configure do |config|
  config.consumer_key = '<consumer_key>'
  config.consumer_secret = '<consumer_secret>'
  config.oauth_token = '<oauth_token>'
  config.oauth_token_secret = '<oauth_token_secret>'
end

screen_name = String.new ARGV[0]

a_user = Twitter.user(screen_name)

if a_user.geo_enabled == true

  long = a_user.status.place.bounding_box.coordinates[0][0][0];
  lat  = a_user.status.place.bounding_box.coordinates[0][0][1];

  my_file = File.new("test.html", "w")

  my_file.puts "<!DOCTYPE html>"
  my_file.puts "<html><head>"
  my_file.puts "<meta name=\"viewport\" content=\"initial-scale=1.0, "
  my_file.puts "user-scalable=no\" />"
  my_file.puts "<style type=\"text/css\">"
  my_file.puts "html { height: 100% }"
  my_file.puts "body { height: 100%; margin: 0px; padding: 0px }"
  my_file.puts "#map_canvas { height: 100% }"
  my_file.puts "<style>"
  my_file.puts "<script type=\"text/javascript\""
  my_file.puts "src=\"http://maps.google.com/maps/api/js?sensor=false\">"
  my_file.puts "<script>"
  my_file.puts "<script type=\"text/javascript\">"
  my_file.puts "function initialize() {"
  my_file.puts "var latlng = new google.maps.LatLng(" + lat.to_s + ", " + long.to_s + ");"
  my_file.puts "var myOptions = {"
  my_file.puts "zoom: 12,"
  my_file.puts "center: latlng,"
  my_file.puts "mapTypeId: google.maps.MapTypeId.HYBRID"
  my_file.puts "};"
  my_file.puts "var map = new google.maps.Map(document.getElementById(\"map_canvas\"),"
  my_file.puts "myOptions);"
  my_file.puts "}"
  my_file.puts "<script>"
  my_file.puts "<head>"
  my_file.puts "<body onload=\"initialize()\">"
  my_file.puts "<div id=\"map_canvas\" style=\"width:100%; height:100%\"<>/div>"
  my_file.puts "<body>"
  my_file.puts "<html>"

else

  puts "no geolocation data available."

end

El script del Listado 12 se ejecuta simplemente como:

$ ./where-am-i.rb MTimJones

El archivo HTML resultante es presentado mediante un navegador, como:

$ firefox test.html

Este script puede fallar si no hay información de ubicación disponible; pero si tiene éxito, se genera un archivo HTML que puede ser leído por un navegador para presentar el mapa. La Figura 5 presenta la imagen de mapa resultante, la cual muestra una porción de Front Range en el norte de Colorado, EE.UU.

Figura 5. Imagen de muestra presentada a partir del script del Listado 12
Imagen de muestra presentada a partir del script del Listado 12

Con la ubicación geográfica, usted también puede buscar en Twitter para identificar usuarios de Twitter y trinos relacionados con una ubicación en particular. La API de búsqueda de Twitter permite que la información de ubicación geográfica restrinja sus resultados. El siguiente ejemplo mostrado en el Listado 13 extrae datos de latitud y longitud para un usuario y luego utiliza estos datos para capturar trinos dentro de un radio de 5 millas de esa ubicación.

Listado 13. Búsqueda de trinos locales mediante datos de latitud y longitud(tweets-local.rb)
#!/usr/bin/env ruby
require "rubygems"
require "twitter"

Twitter.configure do |config|
  config.consumer_key = '<consumer_key>'
  config.consumer_secret = '<consumer_secret>'
  config.oauth_token = '<oauth_token>'
  config.oauth_token_secret = '<oauth_token_secret>'
end

screen_name = String.new ARGV[0]

a_user = Twitter.user(screen_name)

if a_user.geo_enabled == true

  long = a_user.status.place.bounding_box.coordinates[0][0][0]
  lat  = a_user.status.place.bounding_box.coordinates[0][0][1]

  Array tweets = Twitter::Search.new.geocode(lat, long, "5mi").fetch

  tweets.each do |t|

    puts t.from_user + " | " + t.text

  end

end

El resultado del script del Listado 13 se muestra en el Listado 14. Este es un subconjunto de trinos dada la frecuencia de trinos allí.

Listado 14. Vigilando trinos locales dentro de un radio de 5 millas de mi ubicación
$ ./tweets-local.rb MTimJones
Breesesummer | @DaltonOls did he answer u
LongmontRadMon | 60 CPM, 0.4872 uSv/h, 0.6368 uSv/h, 2 time(s) over natural radiation
graelston | on every street there is a memory; a time and place we can never be again.
Breesesummer | #I'minafight with @DaltonOls to see who will marry @TheCodySimpson I will 
marry him!!! :/
_JennieJune_ | ok I'm done, goodnight everyone!
Breesesummer | @DaltonOls same
_JennieJune_ | @sylquejr sleep well!
Breesesummer | @DaltonOls ok let's see what he says
LongmontRadMon | 90 CPM, 0.7308 uSv/h, 0.7864 uSv/h, 2 time(s) over natural radiation
Breesesummer | @TheCodySimpson would u marry me or @DaltonOls
natcapsolutions | RT hlovins: The scientific rebuttal to the silly Forbes release this 
morning: Misdiagnosis of Surface Temperatu... http://bit.ly/nRpLJl
$

Avanzando

Este artículo presentó numerosos scripts simples para extraer datos de Twitter usando lenguaje Ruby. El énfasis estuvo en el desarrollo y presentación de scripts simples para ilustrar estas ideas fundamentales, pero se puede hacer mucho más. Por ejemplo, usted también puede usar la API para explorar las redes de sus amigos y la identidad de los usuarios de Twitter más populares de su interés. Otra área interesante es la minería de trinos en sí mismos, usando datos de ubicación geográfica para entender comportamientos o eventos basados en ubicación (como brotes de gripa). Este artículo solo raspó la superficie, pero puede comentar libremente abajo sobre su propio mashup. Ruby y el Twitter gem simplifican el desarrollo de mash-ups o paneles de instrumentos útiles para sus necesidades de minería de datos.

Recursos

Aprender

  • El sitio Web oficial del lenguaje Ruby es la fuente única sobre noticias, información, releases, documentación y soporte comunitario para el lenguaje Ruby. Dado el crecimiento de Ruby en las infraestructuras Web (como Ruby on Rails), usted también puede aprender sobre las vulnerabilidades de seguridad más recientes y sobre sus soluciones.
  • El sitio Github de código social proporciona la fuente oficial del Twitter gem. En este sitio usted podrá lograr acceso a la fuente, documentación y a listas de correos electrónicos para el Ruby Twitter gem.
  • Registra una aplicación Twitter es necesario para utilizar ciertos elementos de la API Twitter. El proceso es gratuito y le permite acceder a algunos de los elementos más útiles de la API.
  • El tutorial Google Maps JavaScript API le muestra cómo usar Google Maps para mostrar mapas de varios tipos usando datos de ubicación geográfica proporcionados por usuario. El JavaScript usado en este artículo está basado en el código "Hello World" de ejemplo que se proporcionó aquí.
  • Zona de fuente abierta developerWorks proporciona rica información sobre herramientas de fuente abierta y sobre el uso de tecnologías de fuente abierta.
  • DeveloperWorks en Twitter: Síganos y siga a este autor en M. Tim Jones.
  • demostraciones developerWorks on-demand : Vigila y aprenda de demostrativos que van desde instalación y configuración de productos para principiantes, hasta funcionalidad avanzada para usuarios experimentados.

Obtener los productos y tecnologías

  • El Twitter Ruby gem, desarrollado por John Nunemaker, ofrece una interfaz útil para el servicios Twitter que se integra limpiamente con el lenguaje Ruby.
  • La API Google Chart es un servicio útil que proporciona la capacidad para construir gráficas ricas y complejas usando una variedad de estilos y opciones. Este servicio proporciona una API mediante la cual resulta un URL que es presentado por el sitio Google.
  • El derivador Google Chart API Ruby proporciona una interfaz Ruby para la API Google Charts para la construcción de gráficas útiles dentro de Ruby.
  • Evalúe productos de IBM de la forma que mejor se ajuste a usted: Descargue una prueba de producto, ensaye un producto en línea, use un producto en un entorno en nube, o pase algunas horas en el SOA Sandbox aprendiendo cómo implementar eficientemente la arquitectura orientada al servicio.

Comentar

  • Comunidad developerWorks: Conéctese a otros usuarios de developerWorks mientras explora los blogs, foros, grupos y wikis para desarrolladores.

Comentarios

developerWorks: Ingrese

Los campos obligatorios están marcados con un asterisco (*).


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. La información en su propio perfil (nombre, país/región y nombre de la empresa) se muestra al público y acompañará a cualquier contenido que publique, a menos que opte por la opción de ocultar el nombre de su empresa. Puede actualizar su cuenta de IBM en cualquier momento.

Toda la información enviada es segura.

Elija su nombre para mostrar



La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Los campos obligatorios están marcados con un asterisco (*).

(Por favor elija un nombre de 3 - 31 caracteres.)

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Toda la información enviada es segura.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=tecnologia Java
ArticleID=791672
ArticleTitle=Minería de datos con Ruby y Twitter
publish-date=02022012