Статьи

Code Safari: TWSS и Байесовская классификация поисков в Twitter

Возможно, мое любимое использование Ruby — это слесарное дело — маленькие сценарии для соединения больших библиотек таким образом, чтобы это было интересно. Быть способным поднять эти сценарии вечером — важный навык.

Сегодня я наткнулся на пример такой сантехники в драгоценном камне.

Потому что автоматизация не знает границ … в том числе и комедия.
TWSS — это простой класс Байеса, обученный по поиску в Твиттере #twss.

twss — это именно тот проект, который дает жизнь и характер экосистеме. Посмотрим, как это работает.

Поиск записи

Документация показывает нам потенциальную точку входа в изучение кода, в которой единственный открытый интерфейс — это один метод:

 require 'twss' TWSS("hey, did you resolve that ticket?") # => false TWSS("not yet, it's taking a while") # => false TWSS("well hurry up, you're not going fast enough") # => true 

Запрещенное имя метода выглядит странно для кода ruby, но полностью допустимо. Обычно это делается для «повторного использования» уже существующего имени класса или модуля, чтобы обеспечить поведение по умолчанию ( Hpricot — это еще один драгоценный камень, который делает это). Заглянув внутрь lib/twss.rb (обычно требуется lib/twss.rb с необходимого файла), мы увидим этот милый трюк: у вас действительно может быть метод с тем же именем, что и у Module.

 # lib/twss.rb module TWSS # ... end def TWSS(str) TWSS.classify(str) end 

Это отвлекает от нашей основной миссии. Давайте перейдем к внутренностям программы. Находя метод classify которому twss метод twss (используя ваш любимый инструмент поиска в файлах), мы анализируем первую основную подсистему этой сантехнической операции: гем classifier .

 # lib/twss/engine.rb require 'classifier' def initialize(options = {}) @data_file = options[:data_file] || DATA_FILE @threshold ||= options[:threshold] || 5.0 @classifier = load_classifier_from_file!(@data_file) || new_classifier end def classify(str) if basic_conditions_met?(str) c = @classifier.classifications(str) c[TRUE] - c[FALSE] > threshold else false end end def new_classifier Classifier::Bayes.new(TRUE, FALSE) end 

С домашней страницы драгоценного камня:

Классификатор является общим модулем, позволяющим байесовский и
другие виды классификаций.

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

Это только половина уравнения. Учитывая, что twss предоставляет предварительно подготовленный файл данных для классификатора, нам нужно сначала выяснить, как он создал этот файл. Совершенно очевидно, где находится этот код: только два других файла кода, которые мы не просмотрели, называются trainer.rb и tweet_collector.rb .

Выборка данных

Начнем с твиттера. Возможность собирать и обрабатывать твиты — это особенно удобная техника в вашем наборе инструментов.

 # lib/twss/tweet_collector.rb require 'twitter' # ... def run o = File.open(filename, 'a') page, per_page = 1, 100 begin Twitter::Search.new(search).per_page(per_page).page(page).each do |tweet| puts tweet.text o.puts tweet.text end page += 1 sleep 2 end while page * per_page < limit o.close end 

Это предполагает простой API, который мы можем использовать для наших собственных запросов в Twitter. Прыгайте в irb и мы можем поиграть.

 $ irb -rtwitter irb> Twitter::Search.new('#ruby').each {|x| puts x.text } TypeError: can't convert String into Hash from twitter-1.2.0/lib/twitter/api.rb:13:in `merge' 

… ну, это неловко. Похоже, код twss работает. Подобные вещи часто происходят в быстро меняющемся мире рубина, и первый шаг — не паниковать. Последний коммит для twss был в августе 2010 года, поэтому вполне возможно, что twitter изменил свой API с тех пор. В идеальном мире twss бы более узкий диапазон версий этого драгоценного камня, с которым, как было известно, работали (обычно основная и вспомогательная версия), но в этом случае нам придется провести некоторое исследование самостоятельно.

Я искал GitHub для «твиттера», чтобы найти исходный репозиторий для драгоценного камня . Сканируя README, кажется, что версия 1.0 нарушила обратную совместимость с более ранними версиями. В частности, это изменение выглядит точно соответствующим нашему коду:

Класс Twitter::Search остался в основном таким же, однако
он больше не принимает запрос в своем конструкторе. Вы можете указать
запрос с использованием метода #containing , который имеет псевдоним #q .

 # Pre-1.0 Twitter::Search.new("query").fetch.first.text # Post-1.0 Twitter::Search.new.q("query").fetch.first.text 

Давайте попробуем наш поиск снова с этой новой информацией.

 irb> Twitter::Search.new.q('#ruby').each {|x| puts x.text } #Ruby 1.9 is fast than #Python 2.7 so much................ The @bronxzooscobra was a big hit, maybe I'll do one for the snake in my house. Maybe #Zeus and #Ruby need their own twitter accounts too. Amanhã tem curso de #ruby com os mestres @caironoleto e @cleitonfco, acho que seria melhor manerar no café. #not RT @haacked: What's the gold standard in OSS project documentation? #Ruby #RoR #Python #PHP #Linux #GSoC2011 ANTIQUE RETRO DIAMOND 1.8ct RUBY WIDE RING 1940 size 10.5 #ring #ruby #diamond #gold #antique http://w.sns.ly/BQc0y4 http://www.pulist.net/max-amp-rubys-four-seasons-max-and-ruby.html #max #and #ruby #different Max &amp;amp; Ruby's Four Seasons (Max and Rub #hippa #pci #security #ruby do you guys have any ideas for #securesmsvoting. ? Does @americanidol do it? Let's scale it to the world. How many people have access to a cell phone for #voting? In the world? 75%? SecureSMS voting! #ruby #sms #twitter @twitter #g8 #un #egypt I'm watching @AJEnglish. Can't we fix world troubles with software? Secure voting for everyone. @AJListeningPost #sysadmin #ruby #facebook Wow, #Ruby'sMoney kicks ass!!! ICMembers - Firmen-Network http://bit.ly/bjsPkl #Firma #Network #Skript #Software #Mitgliedschaft #Ruby #On #Rails #2.0.2 #MySQL #Ruby Engagement Rings : Shop online Ruby Engagement Rings for Low Price. Compare Prices on Ruby Engagement Rings. find Sale items and more. Watchr – More Than An Automated Test Runner http://tinyurl.com/3vsvklm #ruby All this @antirez talk re #ruby perf has finally made me play w/ sinatra. Very cool, like #mojolicious which I love. Is mojo a #perl clone? RT @ruby2itter: georgi/rack_dav - GitHub: HTTPGit Read-OnlyThis URL has Read+Write accessDismissOctotip: You've activated ... http://bit.ly/fDDw7o #ruby 

Прекрасный. Мы узнали очень простой способ получить твиты из кода ruby.

Тренировка классификатора

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

 # lib/twss/trainer.rb # ... puts "Training NON-TWSS strings..." File.read(File.join(path, 'non_twss.txt')).each_line do |l| engine.train(TWSS::Engine::FALSE, strip_tweet(l)) end puts "Training TWSS strings..." File.read(File.join(path, 'twss.txt')).each_line do |l| engine.train(TWSS::Engine::TRUE, strip_tweet(l)) end # ... 

В этом случае есть только две категории (FALSE и TRUE, определенные как ‘0’ и ‘1’ в engine.rb ). Мы еще не видели файлы non_twss.txt и twss.txt , но если мы ищем их, мы находим некоторый код в каталоге script/ который заполняет их результатами поиска Twitter для «:)» и «#twss» соответственно ,

 # script/collect_twss.rb require File.join(File.dirname(__FILE__), '../lib/twss') require File.join(File.dirname(__FILE__), '../lib/twss/tweet_collector') TWSS::TweetCollector.new('#twss', File.join(File.dirname(__FILE__), '../data/twss.txt')).run 

Поиск «:)» — это интересный способ генерирования известного набора текста, не относящегося к twss, но, похоже, он работает адекватно для этого типа данных.

Положить его вместе

Мы #ruby список твитов с тегом #ruby , но многие из них были связаны с украшениями, а не с кодом. Давайте объединим две библиотеки, о которых мы только что узнали — classifier и twitter — чтобы попытаться отфильтровать твиты, которые не касаются кода. Самым сложным будет обучение нашего классификатора достоверным данным для категорий «код» и «ювелирные изделия». Давайте попробуем ту же технику, которую использует twss в качестве отправной точки, и просто воспользуемся поиском в твиттере для «#jewelery» и «#code».

 require 'twitter' require 'classifier' file_name = "classifier.dump" categories = %w(jewelery programming) classifier = Classifier::Bayes.new *categories categories.each do |category| Twitter::Search.new.q("##{category}").per_page(500).each do |x| classifier.train(category, x.text) end end Twitter::Search.new.q("#ruby").per_page(25).each do |x| puts x.text puts " => #{classifier.classifications(x.text)}" puts " => #{classifier.classify(x.text)}" puts end 

Мы объединили Twitter и байесовский классификатор всего в двадцать строк кода. Результаты многообещающие для первой попытки, хотя явно не идеальные:

 RT @haacked: What's the gold standard in OSS project documentation? #Ruby #RoR #Python #PHP #Linux #GSoC2011 => {"Jewelery"=>-48.675845247282666, "Programming"=>-46.948563939601286} => Programming ANTIQUE RETRO DIAMOND 1.8ct RUBY WIDE RING 1940 size 10.5 #ring #ruby #diamond #gold #antique http://w.sns.ly/BQc0y4 => {"Jewelery"=>-52.61580762140005, "Programming"=>-55.656377490626184} => Jewelery How many people have access to a cell phone for #voting? In the world? 75%? SecureSMS voting! #ruby #sms #twitter @twitter #g8 #un #egypt => {"Jewelery"=>-70.68382032808533, "Programming"=>-73.42867953661468} => Jewelery I'm watching @AJEnglish. Can't we fix world troubles with software? Secure voting for everyone. @AJListeningPost #sysadmin #ruby #facebook => {"Jewelery"=>-70.68382032808533, "Programming"=>-66.52092425763254} => Programming #Ruby Engagement Rings : Shop online Ruby Engagement Rings for Low Price. Compare Prices on Ruby Engagement Rings. find Sale items and more. => {"Jewelery"=>-94.997002062587, "Programming"=>-86.66119916641394} => Programming All this @antirez talk re #ruby perf has finally made me play w/ sinatra. Very cool, like #mojolicious which I love. Is mojo a #perl clone? => {"Jewelery"=>-107.46543897258468, "Programming"=>-101.50632914155935} => Programming 

Отсюда мы могли бы попробовать применить некоторые из алгоритмов качества данных, twss использует twss , такие как удаление не-слов и исключение коротких твитов, или мы могли бы посмотреть на улучшение наших базовых данных для обучающего набора.

Способность быстро и эффективно изучать и использовать новые библиотеки — это ценный навык для совершенствования. Практика объединения этих библиотек, даже для тривиальных приложений, сделает вас лучшим программистом.

Вот несколько идей для дальнейшей практики:

  • Изучите другие наборы обучающих данных для нашего идентификатора твита ruby.
  • twss и twss камень twss для работы с последней версией twitter .

Дайте нам знать, как вы идете в комментариях.