Интеллектуальный анализ данных с применением Ruby и Twitter

Интересные возможности API Twitter

Twitter - не только фантастический инструмент общения в режиме реального времени, но и богатый источник информации, созревший для интеллектуального анализа данных. Пользователи Twitter создают в среднем 140 млн твитов в день на самые разные темы. Данная статья знакомит читателя со способами интеллектуального анализа этих данных и демонстрирует концепцию объектно-ориентированного языка программирования Ruby.

M. Тим Джонс, инженер-консультант, Emulex Corp.

М. Тим ДжонсМ. Тим Джонс - архитектор встроенного ПО и, кроме того, автор книг Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming (выдержавшей на данный момент второе издание), AI Application Programming (второе издание) и BSD Sockets Programming from a Multilanguage Perspective. Он имеет обширный опыт разработки ПО в самых разных предметных областях - от ядер специальных ОС для геосинхронных космических аппаратов до архитектур встраиваемых систем и сетевых протоколов. Тим - инженер-консультант Emulex Corp., Лонгмонт, Колорадо.



15.06.2012

В октябре 2008 года, как и многие другие, я из любопытства завел учетную запись Twitter. Как большинство пользователей, я общался с друзьями и иногда проводил тот или иной поиск, чтобы лучше понять эту службу. Собщения длиной 140 символов не казались идеей, которая завоюет популярность. Но некоторые случайные события помогли мне оценить реальное значение Twitter.

В начале июля 2009 года отключился мой поставщик услуг Web-хостинга. Покопавшись в сети, я обнаружил, что виноват пожар в бизнес-центре Fisher Plaza в Сиэтле. Информация из традиционных Web-источников поступала медленно и не давала никаких указаний на то, когда сервис может быть восстановлен. Зато в Twitter я нашел всю информацию об инциденте, в том числе о том, что происходит в данный момент. Например, незадолго до восстановления моей службы хостинга появился твит о том, что за пределами здания есть дизель-генераторы.

Тогда-то я и понял, что истинная сила Twitter – в открытом обмене информацией в режиме реального времени между отдельными людьми и группами. Между тем под поверхностью лежат целые сокровища информации о поведении пользователей и о тенденциях на местном и глобальном уровнях. Я исследую возможность их реализации в контексте простых сценариев на языке Ruby и Twitter gem, API-оболочки для Twitter. Я также показываю, как создать простые мэшапы для визуализации данных с помощью других Web-сервисов и приложений.

Знание Ruby

Те, кто не обладает базовыми знаниями в области замечательного языка Ruby, могут найти ссылки разделе Ресурсы. Приведенные здесь примеры демонстрируют значение Ruby и его способность заключать большую мощь в ограниченном количестве строк исходного кода.

Twitter и API

Если ранний Web был сосредоточен на взаимодействии человека и машины, то сегодня это средство машино-машинного взаимодействия с использование Web-сервисов. Такие сервисы существуют для наиболее популярных сайтов – от разнообразных проектов Google до LinkedIn, Facebook и Twitter. Web-сервисы создают интерфейсы, через которые внешние приложения могут запрашивать контент на Web-сайтах или манипулировать им.

Web-сервисы реализованы разными способами. Сегодня одним из наиболее популярных является Representational State Transfer, или REST. Одна из реализаций REST использует известный протокол HTTP, что позволяет HTTP служить средой для архитектуры RESTful (с помощью стандартных операций HTTP, таких как GET, PUT, POST и DELETE). API для Twitter развивается как уровень абстракции поверх этой среды. Таким образом, не нужно знать REST, HTTP или такие форматы данных, как XML или JSON, а достаточно объектно-ориентированного интерфейса, который гладко объединяет все это в языке Ruby.


Краткий обзор Ruby и Twitter

Давайте посмотрим, как можно использовать Twitter API с Ruby. Во-первых, нужно получить необходимые ресурсы. Если вы используете Ubuntu Linux®, как я, то вам подойдет среда apt.

Чтобы получить последнюю версию полного дистрибутива Ruby (загрузка примерно 13 МБ), используйте следующую команду:

$ sudo apt-get install ruby1.9.1-full

Далее, установите пакет Twitter с помощью утилиты gem:

$ sudo gem install twitter

Теперь у вас есть все необходимое для испытания оболочки Twitter. Для этой демонстрации мы используем оболочку Interactive Ruby Shell (IRB). Она позволяет выполнять команды Ruby и экспериментировать с языком в режиме реального времени. IRB обладает широкими возможностями, но мы используем ее для простых экспериментов.

В листинге 1 показан сеанс работы с IRB, разбитый для удобочитаемости на три части. В первой части (строки 001 и 002) просто подготавливается среда путем импорта необходимых элементов времени выполнения (загружается метод require и выполняется указанная библиотека). В следующей строке (003) показано, как использовать Twitter gem для отображения последних твитов IBM® developerWorks®. Как видите, для отображения твитов используется метод user_timeline модуля Client::Timeline. Этот первый пример демонстрирует так называемую "цепочку методов" Ruby. Метод user_timeline возвращает последовательность из 20 твитов, которая направляется в метод first. Тот извлекает первый твит из последовательности (first - это метод класса Array). Из этого твита извлекается текстовое поле, которое выводится посредством метода puts.

В следующей части (строка 004) используется определяемое пользователем поле location произвольной формы, в которое пользователь может поместить как полезную, так и бесполезную информацию о местоположении. В данном примере модуль User вводит информацию о пользователе, ограниченную полем location.

В заключительной части (строки, начиная с 005) используется модуль Twitter::Search. Модуль search предоставляет чрезвычайно богатый интерфейс, позволяющий выполнять поиск в Twitter. В данном примере сначала создается экземпляр search (строка 005), затем, в строке 006, определяются параметры поиска. Мы ищем последние твиты, содержащие слово why, адресованные пользователю LulzSec. Полученный список сокращен и отредактирован. Поиск предвзят в том смысле, что экземпляр search использует определенные фильтры. Их можно удалить, выполнив команду search.clear.

Листинг 1. Экспериментирование с Twitter API посредством 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>

Теперь посмотрим на схему для пользователя в Twitter. Это можно сделать и через IRB, но я переформатирую результат, чтобы нагляднее показать анатомию пользователя Twitter. В листинге 2 показан результат распечатки структуры пользователя, которая в Ruby называется Hashie::Mash. Эта структура полезна тем, что позволяет объекту иметь метод доступа к хэш-ключам (открытый объект). Как видно из листинга 2, этот объект содержит большой объем информации (относящейся к пользователю и к способу обработки), включая текущий статус пользователя (с геокодированной информацией). Твит тоже содержит большое количество информации, и процесс ее создания можно легко визуализировать, используя класс user_timeline.

Листинг 2. Анатомия пользователя Twitter (с точки зрения 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>

На этом наш краткий обзор окончен. Теперь рассмотрим некоторые простые сценарии, которые можно использовать для сбора и визуализации данных с помощью Ruby и Twitter API. В процессе вы познакомитесь с некоторыми идеями Twitter, такими как аутентификация и ограничение частоты обращений.


Добыча данных в Twitter

В следующих разделах приведено несколько сценариев сбора и представления данных, доступных через Twitter API. Эти сценарии упрощены, но для создания новых возможностей их можно расширять и объединять. Кроме того, этот раздел затрагивает API Twitter gem, который предоставляет много других возможностей.

Важно отметить, что API Twitter позволяет клиентам делать лишь ограниченное число вызовов в течение часа, то есть Twitter ограничивает частоту запросов (в настоящее время ― не более 150 в час), что означает, что через некоторое время вы получите сообщение об ошибке, и для подачи новых запросов придется обождать.

Информация о пользователе

Как следует из листинга 2, Twitter содержит большое количество информации о каждом пользователе. Эта информация доступна только в том случае, если пользователь не защищен. Давайте посмотрим, как извлечь данные о пользователе и представить их в наиболее удобной форме.

В листинге 3 приведен простой сценарий Ruby для получения информации о пользователе (по его псевдониму) и выделения некоторых полезных элементов. Для преобразования значений в строку по мере необходимости используется метод Ruby to_s. Обратите внимание, что сначала нужно убедиться, что пользователь не защищен, в противном случае, эти данные будут недоступны.

Листинг 3. Простой сценарий для извлечения данных о пользователе 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

Чтобы запустить этот сценарий, убедимся, что он исполняем (chmod +х user.rb), и применим его к пользователю. В листинге 4 показан результат для пользователя developerWorks, содержащий информацию о пользователе и его текущем состоянии (информация последнего твита). Имейте в виду, что Twitter определяет последователей (followers) как людей, которые следуют за вами; люди же, за которыми следуете вы, называются друзьями (friends).

Листинг 4. Пример результата работы 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

Популярность друзей

Давайте соберем данные о друзьях оценим их популярность. Для этого мы выберем друзей и отсортируем их по числу их последователей. Этот простой сценарий показан в листинге 5.

Найдя пользователя, которого нужно проанализировать (по его псевдониму), вы создаете хэш этого пользователя. Хэш Ruby (или ассоциативный массив) представляет собой структуру данных, которая позволяет определить ключ хранения (вместо простого числового индекса). Затем хэш индексируется по псевдониму в Twitter, и полученное значение – это число последователей пользователя. Процесс просто перебирает друзей и хэширует число их последователей. Затем мы сортируем хэш (в порядке убывания) и выводим его.

Листинг 5. Сценарий для определения популярности друзей (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}" }

Пример результата работы сценария из листинга 5 показан в листинге 6. Я обрезал его для экономии места, но, как видите, в моей прямой сети популярны пользователи ReadWriteWeb (RWW) и Playstation Twitter.

Листинг 6. Пример результата работы сценария из листинга 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

Где находятся мои последователи?

Как было показано в листинге 2, Twitter предоставляет огромное количество информации о местоположении. Там есть определяемое пользователем поле location произвольной формы и дополнительные данные геокодирования. Однако на фактическое местонахождение последователя может указывать и определяемый пользователем часовой пояс.

В этом примере мы создадим мэшап, который извлекает данные о часовых поясах ваших последователей Twitter, а затем визуализирует эти данные с помощью Google Charts. Google Charts – это интересный проект, который позволяет создавать диаграммы разного типа по данным из Интернета, определяя тип диаграммы и данные в качестве HTTP-запроса, результат которого обрабатывается прямо в браузере. Чтобы установить Ruby gem для Google Charts, используйте следующую команду:

$ gem install gchartrb

В листинге 7 приведен сценарий для извлечения данных о часовых поясах с последующим построением запроса Google Charts. В отличие от предыдущих сценариев, этот сценарий требует прохождения аутентификации в Twitter. Для этого необходимо зарегистрировать приложение в Twitter, который предоставит вам набор ключей и маркеров. Для успешного извлечения данных эти маркеры нужно применить к сценарию из листинга 7. описание этого простого процесса можно найти в разделе Ресурсы.

Этот сценарий принимает псевдоним, а затем перебирает последователей пользователя по той же схеме. Для текущего последователя извлекается часовой пояс и сохранятся в хэше tweetlocation. Обратите внимание, что сначала мы проверяем, присутствует ли данный ключ в этом хэше, и если да, то увеличиваем счетчик для этого ключа. Кроме того, ведется учет общего количества часовых поясов для последующего вычисления процентного отношения.

Последняя часть сценария представляет собой построение диаграммы Google Pie Chart URL. Вы можете создать новую диаграмму PieChart и задать некоторые параметры (размер, название и формат - 2D или 3D). Затем мы перебираем хэш часовых поясов, выдавая данные для вычисления строки часовых поясов диаграммы (с удалением символа &) и отношения числа пользователей в данном часовом поясе к их общему числу.

Листинг 7. Создание круговой диаграммы часовых поясов последователей 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

Чтобы запустить сценарий из листинга 7, введите в него псевдоним Twitter, а затем скопируйте и вставьте полученный URL в браузер. Этот процесс вместе с результирующим сгенерированным URL показан в листинге 8.

Листинг 8. Вызов сценария определения местонахождения последователей (результат в одну строку)
$ ./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
$

Вставив URL из листинга 8 в браузер, вы получите результат, показанный на рисунке 1.

Рисунок 1. Круговая диаграмма местонахождения последователей Twitter
Круговая диаграмма местонахождения последователей Twitter

Поведение пользователей Twitter

Twitter содержит большое количество данных, которые можно использовать для выявления некоторых элементов поведения пользователя. Два простых примера: анализ времени составления пользователем его твитов и приложений, в котором он это делает. Для извлечения и визуализации этой информации можно использовать следующие два простых сценария.

В листинге 9 представлен сценарий, который перебирает твиты определенного пользователя (с помощью метода user_timeline), а затем извлекает из каждого твита день недели, в который тот составлен. Для накопления дней недели опять можно использовать простой хэш, а затем сгенерировать гистограмму с помощью Google Charts, как в предыдущем примере для часовых поясов. Отметим также, что для хэша используется значение по умолчанию, которое определяет точку возврата для неопределенных хэшей.

Листинг 9. Построение гистограммы дней недели для твитов (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

Рисунок 2 иллюстрирует результат выполнения сценария tweet-days из листинга 9 для пользователя developerWorks. Как видите, наиболее продуктивным днем создания твитов является среда, а наименее продуктивными - суббота и воскресенье.

Рисунок 2. Гистограмма распределения твитов по дням недели
Гистограмма показывает деятельность по дням недели

Следующий сценарий определяет источники твитов определенного пользователя. Есть несколько способов создания твитов, и этот сценарий не учитывает их все. Как показано в листинге 10, аналогичную модель можно использовать для извлечения графика работы данного пользователя, а затем попытаться определить источник твита в хэше. Затем этот хэш можно использовать для построения простой круговой диаграммы с помощью Google Charts с целью визуализации данных.

Листинг 10. Построение круговой диаграммы источников твитов пользователя (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

На рисунке 3 представлена визуализация для пользователя Twitter с интересным набором источников твитов. Чаще всего он использует традиционный Web-сайт Twitter, за которым следует приложение для мобильного телефона.

Рисунок 3. Круговая диаграмма источников твитов
Круговая диаграмма источников твитов

Граф последователей

Twitter представляет собой обширную сеть пользователей, которая образует граф. Как видно из приведенных сценариев, легко перебрать свои контакты, а затем ― их контакты. Это создает основу для построения большого графа, даже на этом уровне.

Чтобы отобразить граф, я решил использовать программное обеспечение визуализации графов GraphViz. В Ubuntu этот инструмент легко установить с помощью следующей команды:

$ sudo apt-get install graphviz

Сценарий, приведенный в листинге 11, перебирает последователей пользователя, а затем их последователей. Единственная особенность этой модели ― построение файла в формате GraphViz. GraphViz использует простой формат сценария для определения графа, который создается при перечислении пользователей Twitter. Как видно из листинга, для определения графа достаточно описать отношения между узлами.

Листинг 11. Визуализация графа последователей 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 "}"

Выполнение сценария, приведенного в листинге 11, для пользователя дает dot-файл, по которому затем строится изображение с помощью GraphViz. Сначала вызовем сценарий Ruby для сбора данных графа (сохраняется как graph.dot), а затем, используя GraphViz, построим граф (в данном случае, используя модель circo, которая определяет круговую схему). Процесс формирования этого изображения определяется следующим образом:

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

Полученное изображение показано на рисунке 4. Обратите внимание, что графы Twitter, как правило, получаются большими, и я ограничил наш граф, минимизировав количество пользователей и их последователей (параметр :count в листинге 11).

Рисунок 4. Пример графа последователей Twitter (предельно сокращенный)
Граф изображает последователей в виде связанных между собой центров, как на сетевой диаграмме

Информация о местоположении

Если это разрешено, Twitter собирает данные о местоположении пользователя и местах создания его твитов. Эти данные содержат широту и долготу и могут использоваться для точного определения местонахождения пользователя или места, откуда исходят его твиты. Затем эту информацию можно включать в поиск, чтобы находить достопримечательности или людей в определенном месте или рядом с вами.

Не все пользователи или твиты допускают геолокацию (по причинам конфиденциальности), но эта информация - интересный аспект общего опыта работы с Twitter. Рассмотрим сценарий, который позволяет визуализировать данные геолокации, и еще один, который позволяет вести поиск с использованием этой информации.

В первом сценарии (листинг 12) мы извлекаем данные о широте и долготе для пользователя (вспомните bounding box из листинга 2). Bounding box ― это многоугольник, определяющий область местонахождения пользователя, но я для простоты использую только одну точку данных. С помощью этих данных можно создать простую функцию JavaScript в простом HTML-файле. Этот код JavaScript взаимодействует с Google Maps, представляя вид данной местности со спутника (по данным широты и долготы, полученным от пользователя Twitter).

Листинг 12. Сценарий Ruby для построения карты местонахождения пользователя (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

Сценарий из листинга 12 выполняется просто:

$ ./where-am-i.rb MTimJones

Результирующий HTML-файл отображается с помощью браузера:

$ firefox test.html

Этот сценарий может не работать, если информация о местоположении недоступна; но если он работает, то создается HTML-файл, который может прочесть браузер и изобразить карту. На рисунке 5 показано результирующее изображение карты участка Передового хребта в северной части штата Колорадо, США.

Рисунок 5. Пример изображения, полученного с помощью сценария из листинга 12
Пример изображения, полученного с помощью сценария из листинга 12

С помощью данных геолокации можно также выполнять поиск пользователей Twitter и твитов, связанных с определенным местом. API Twitter Search допускает геокодирование информации для ограничения результатов поиска. Следующий пример, приведенный в листинге 13, извлекает данные о широте и долготе пользователя, а затем применяет эти данные для сбора твитов в радиусе 5 км от этого места.

Листинг 13. Поиск местных твитов по данным о широте и долготе (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

Результат работы сценария из листинга 13 приведен в листинге 14. Это подмножество твитов с учетом активности твитеров.

Листинг 14. Местные твиты в радиусе 5 км от меня
$ ./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
$

Заключение

В данной статье представлен ряд простых сценариев для извлечения данных из Twitter с использованием языка Ruby. Акцент сделан на разработку и представление простых сценариев для иллюстрации основных идей, но имеющиеся возможности гораздо шире. Например, API можно использовать для изучения сетей своих друзей и определения наиболее популярных из интересующих вас пользователей Twitter. Еще одна интересная область применения ― разработка самих твитов с использованием данных геолокации для изучения поведения местных пользователей или событий (например, вспышки гриппа). Эта статья дает лишь поверхностное представление, но не стесняйтесь приводить в комментариях к ней свои собственные примеры. Рубин и Twitter gem упрощают разработку полезных мэшапов или информационных панелей для анализа данных.

Ресурсы

Научиться

  • Оригинал статьи
  • Официальный Web-сайт языка Ruby ― единый источник новостей, информации, версий, документации и поддержки сообщества по языку Ruby. Ruby все чаще используется в Web-средах (таких, как Ruby on Rails), и здесь можно также узнать о последних угрозах для безопасности и средствах защиты от них.
  • Сайт социального программирования Github ― официальный источник Twitter gem. На этом сайте можно получить доступ к исходному коду, документации и спискам рассылки по Twitter gem.
  • При регистрации приложения Twitter необходимо использовать определенные элементы API Twitter. Этот бесплатный процесс позволяет получить доступ к некоторым из наиболее полезных элементов API.
  • Руководство по Google Maps JavaScript API показывает, как использовать Google Maps для отображения различных карт с использованием предоставляемых пользователями данных геолокации. Код JavaScript, используемый в этой статье, основан на примере "Hello World" из этого руководства.
  • developerWorks в Твиттере: следуйте за нами и за автором этой статьи: M. Tim Jones.

Получить продукты и технологии

  • Модель Twitter Ruby gem, разработанная Джоном Нунмейкером (John Nunemaker), обеспечивает удобный интерфейс для сервиса Twitter, гладко интегрированный в язык Ruby.
  • Google Chart API - полезный сервис, который позволяет создавать сложные и богатые графики с использованием различных стилей и параметров. Этот сервис предоставляет API, через который результирующий URL обрабатывается на сайте Google.
  • Ruby-оболочка Google Chart API обеспечивает Ruby-интерфейс для Google Charts API, позволяющий строить полезные диаграммы в Ruby.

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Open source
ArticleID=821343
ArticleTitle=Интеллектуальный анализ данных с применением Ruby и Twitter
publish-date=06152012