Simple item-based collaborative filtering with Rails

I suspect there is room for improvements with this, since it is really simplistic, and I certainly am not an expert in the subject. But it works ok for small numbers of items:

def Pair.from_items(items)
  Pair.transaction do
    res = []
    all = items.reject { |i| i.name == "" }.collect { |i|
            i.name.downcase }.sort
    all.collect { |i| ([i]*all.length).zip(all) }.each { |i| 
            i.each {|j| res << j} }
    res = res.each { |i| i.sort! }.uniq.reject { |p| 
            p[0] == p[1] }
    res.each do |pair|
      p = Pair.find(:first, :conditions => 
                            ['val1 = ? and val2 = ?', 
                             pair[0], pair[1]])
      p ||= Pair.new(:val1 => pair[0], :val2 => pair[1],
                     :num => 0)
      p.num += 1
      p.save!
    end
  end
end

Basically what happens is that for a list of items [A, B, C, D], it calculates and inserts into the database that A and B have been purchased/rated/viewed/whatevered together once. Same for A and C, A and D, B and C, and so on. After accumulating enough of these pairs, you can query the datbase for an item – B for instance – and see what it’s been purchased with the most times, and recommend that to people who have shown an interest in B. When someone purchases a group of items togehter, you call Pair.from_items(the_items) and it takes care of inserting the various combinations.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s