Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

Ruby NLP: เชี่ยวชาญ N-gram Analysis สำหรับ Text Mining ที่ลึกซึ้ง

จะทำไงถ้ามี text collection ใหญ่ๆ และอยากดึง meaning ออกมา? เริ่มต้นที่ดีคือแบ่ง text เป็น n-grams

คำอธิบาย:

ใน computational linguistics และ probability n-gram คือ contiguous sequence ของ n items จาก sequence ของ text ที่ให้มา — Wikipedia

เช่น: phrase "Hello there, how are you?" unigrams (ngrams 1 element): "Hello", "there", "how", "are", "you" bigrams (2 elements): ["Hello", "there"], ["there", "how"], ["how", "are"], ["are", "you"]

เรียนรู้ด้วยภาพดีกว่า นี่คือรูป:

Ruby NLP: เชี่ยวชาญ N-gram Analysis สำหรับ Text Mining ที่ลึกซึ้ง

มาดู implementation ใน Ruby!

Downloading Sample Data

ก่อนลงมือต้องมี sample data ถ้าไม่มี download Wikipedia หรือ blog articles บางอย่าง กรณีนี้ผม download IRC logs จาก #ruby freenode channel

Logs อยู่ที่: irclog.whitequark.org/ruby

Note on data formats: ถ้า plain text version ไม่มี ใช้ Nokogiri parse หน้าและ extract data IRC logs มี plain text โดย append .txt ท้าย URL ใช้ได้เลย

Class นี้ download และ save data:

require 'restclient'
class LogParser
  LOG_DIR = 'irc_logs'
  def initialize(date)
    @date = date
    @log_name = "#{LOG_DIR}/irc-log-#{@date}.txt"
  end
  def download_page(url)
    return log_contents if File.exist? @log_name
    RestClient.get(url).body
  end
  def save_page(page)
    File.open(@log_name, "w+") { |f| f.puts page }
  end
  def log_contents
    File.readlines(@log_name).join
  end
  def get_messages
    page = download_page("https://irclog.whitequark.org/ruby/#{@date}.txt")
    save_page(page)
    page
  end
end
log = LogParser.new("2015-04-15")
msg = log.get_messages

Class straightforward ใช้ RestClient เป็น HTTP client save results ไฟล์ เพื่อไม่ request ซ้ำขณะ modify โปรแกรม

Analyzing The Data

ตอนมี data แล้ว มาวิเคราะห์ นี่คือ Ngram class ใช้ Array#each_cons ผลิต ngrams เพราะ return Enumerator ต้อง to_a ได้ Array

class Ngram
  def initialize(input)
    @input = input
  end
  def ngrams(n)
    @input.split.each_cons(n).to_a
  end
end

รวมทั้งหมดด้วย loop, Hash#merge! และ Enumerable#sort_by

แบบนี้:

# Filter words ที่ปรากฏน้อยกว่านี้
MIN_REPETITIONS = 20
total = {}
# Get logs 15 วันแรกของเดือน return trigrams
(1..15).each do |n|
  day = '%02d' % [n]
  total.merge!(get_trigrams_for_date "2015-04-#{day}") { |k, old, new| old + new }
end
# Sort descending
total = total.sort_by { |k, v| -v }.reject { |k, v| v < MIN_REPETITIONS }
total.each { |k, v| puts "#{v} => #{k}" }

Note: get_trigrams_for_date method ไม่อยู่ที่นี่ เพื่อความกระชับ หาได้ที่ github

Output 长得像这样:

112 => i want to
83 => link for more
82 => is there a
71 => you want to
66 => i don't know
66 => i have a
65 => i need to

เห็นได้ว่า "อยากทำอะไร" เป็นประเด็夯ใน #ruby 🙂

สรุป

ตาคุณลองเล่น n-gram analysis! อีกวิธีดู n-grams คือ Google Ngram Viewer

Natural language processing (NLP) เรื่องน่าสนใจ Wikipedia มี overview ดี

โค้ดครบที่นี่: https://github.com/matugm/ngram-analysis/blob/master/irc_histogram.rb