Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Ruby NLP: Thành thạo Phân tích N-gram để khai thác văn bản sâu sắc

Bạn sẽ làm gì nếu được cho một bộ sưu tập văn bản lớn và muốn trích xuất ý nghĩa từ nó?

Khởi đầu tốt là chia nhỏ văn bản thành n-gram.

Dưới đây là mô tả:

Trong lĩnh vực ngôn ngữ học tính toán và xác suất, n-gram là chuỗi liên tiếp n mục từ một chuỗi văn bản cho trước. – Wikipedia

Ví dụ:

Nếu chúng ta lấy cụm từ "Hello there, how are you?", thì unigram (n-gram một phần tử) sẽ là: "Hello", "there", "how", "are", "you", và bigram (n-gram hai phần tử): ["Hello", "there"], ["there", "how"], ["how", "are"], ["are", "you"].

Nếu bạn học tốt hơn với hình ảnh, đây là hình minh họa:

Ruby NLP: Thành thạo Phân tích N-gram để khai thác văn bản sâu sắc

Giờ hãy xem cách triển khai trong Ruby!

Tải dữ liệu mẫu

Trước khi bám tay vào việc, chúng ta cần dữ liệu mẫu.

Nếu bạn không có dữ liệu để làm việc, bạn có thể tải vài bài Wikipedia hoặc blog. Trong trường hợp này, tôi quyết định tải log IRC từ kênh #ruby của freenode.

Log có thể tìm thấy tại:

irclog.whitequark.org/ruby

Lưu ý về định dạng dữ liệu:

Nếu phiên bản văn bản thuần túy của tài nguyên bạn muốn phân tích không có sẵn, bạn có thể dùng Nokogiri để phân tích trang và trích xuất dữ liệu.

Log IRC có sẵn dạng văn bản thuần túy bằng cách thêm .txt cuối URL, nên chúng ta sẽ tận dụng điều đó.

Lớp này sẽ tải và lưu dữ liệu cho chúng ta:

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

Đây là một lớp khá đơn giản.

Chúng ta dùng RestClient làm HTTP client và lưu kết quả vào tệp để không phải yêu cầu nhiều lần khi sửa chương trình.

Phân tích dữ liệu

Giờ chúng ta có dữ liệu, có thể phân tích.

Đây là lớp Ngram đơn giản.

Trong lớp này, chúng ta dùng phương thức Array#each_cons tạo ra n-gram.

Vì phương thức này trả về Enumerator, chúng ta cần gọi to_a để lấy Array.

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

Sau đó, gắn mọi thứ lại dùng vòng lặp, Hash#merge! và Enumerable#sort_by.

Như thế này:

# Lọc từ xuất hiện ít hơn ngưỡng này
MIN_REPETITIONS = 20
total = {}
# Lấy log 15 ngày đầu tháng và trả về trigram
(1..15).each do |n|
  day = '%02d' % [n]
  total.merge!(get_trigrams_for_date "2015-04-#{day}") { |k, old, new| old + new }
end
# Sắp xếp giảm dần
total = total.sort_by { |k, v| -v }.reject { |k, v| v < MIN_REPETITIONS }
total.each { |k, v| puts "#{v} => #{k}" }

Lưu ý: phương thức get_trigrams_for_date không có ở đây cho gọn, nhưng bạn có thể tìm trên github.

Đây là giao diện đầu ra:

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

Như bạn thấy, "muốn làm điều gì đó" rất phổ biến trong #ruby 🙂

Kết luận

Giờ đến lượt bạn!

Mở editor và bắt đầu chơi với phân tích n-gram. Cách khác xem n-gram hoạt động là Google Ngram Viewer.

Xử lý ngôn ngữ tự nhiên (NLP) có thể là chủ đề thú vị, Wikipedia có tổng quan tốt về chủ đề này.

Bạn có thể tìm mã hoàn chỉnh cho bài viết này tại: https://github.com/matugm/ngram-analysis/blob/master/irc_histogram.rb