slope_one 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Manifest.txt ADDED
@@ -0,0 +1,9 @@
1
+ Manifest.txt
2
+ README.markdown
3
+ Rakefile
4
+ lib/slope_one.rb
5
+ script/console
6
+ script/destroy
7
+ script/generate
8
+ test/test_helper.rb
9
+ test/test_slope_one.rb
data/README.markdown ADDED
@@ -0,0 +1,58 @@
1
+ # Slope One (Recommendation Algorithm)
2
+
3
+ ## DESCRIPTION:
4
+
5
+ Implementation of the [Slope One](http://en.wikipedia.org/wiki/Slope_One) collaborative filtering/recommendation algorithm.
6
+
7
+ Ported to Ruby from Bryan O’Sullivan's [Python implementation](http://www.serpentine.com/blog/2006/12/12/collaborative-filtering-made-easy/). All credit goes to him.
8
+
9
+ ## SYNOPSIS:
10
+
11
+ user_data = {
12
+ "rob" => {
13
+ "24" => 9.5,
14
+ "Lost" => 8.2,
15
+ "House" => 6.8
16
+ },
17
+
18
+ "bob" => {
19
+ "24" => 3.7,
20
+ "Big Bang Theory" => 2.1,
21
+ "House" => 8.3
22
+ },
23
+
24
+ "tod" => {
25
+ "24" => 9.5,
26
+ "Lost" => 3.4,
27
+ "House" => 5.5,
28
+ "Big Bang Theory" => 9.3
29
+ },
30
+
31
+ "dod" => {
32
+ "24" => 7.2,
33
+ "Lost" => 5.1,
34
+ "House" => 8.4,
35
+ "The Event" => 7.8,
36
+ }
37
+ }
38
+
39
+ slope_one = SlopeOne.new
40
+ slope_one.update(user_data)
41
+ puts slope_one.predict({"House" => 3, "Big Bang Theory" => 7.5}).inspect
42
+
43
+ ## INSTALL:
44
+
45
+ gem install slope_one
46
+
47
+ or in your Gemfile:
48
+
49
+ gem 'slope_one'
50
+
51
+ ## LICENSE:
52
+
53
+ Copyright 2006 Bryan O'Sullivan <bos@serpentine.com> (Original implementation)
54
+ Copyright 2010 Ashley Williams <hi@ashleyw.co.uk> (Ruby port)
55
+
56
+ This software may be used and distributed according to the terms
57
+ of the GNU General Public License, version 2 or later, which is
58
+ incorporated herein by reference.
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/slope_one'
6
+
7
+ Hoe.plugin :newgem
8
+
9
+ $hoe = Hoe.spec 'slope_one' do
10
+ self.developer 'Ashley Williams', 'hi@ashleyw.co.uk'
11
+ self.rubyforge_name = self.name # TODO this is default value
12
+ end
13
+
14
+ require 'newgem/tasks'
15
+ Dir['tasks/**/*.rake'].each { |t| load t }
data/lib/slope_one.rb ADDED
@@ -0,0 +1,52 @@
1
+ VERSION = '0.1'
2
+
3
+ class SlopeOne
4
+ attr_accessor :diffs, :freqs
5
+
6
+ def initialize
7
+ self.diffs = {}
8
+ self.freqs = {}
9
+ end
10
+
11
+ def insert(user_data)
12
+ user_data.each do |name, ratings|
13
+ ratings.each do |item1, rating1|
14
+ self.freqs[item1] ||= {}
15
+ self.diffs[item1] ||= {}
16
+ ratings.each do |item2, rating2|
17
+ self.freqs[item1][item2] ||= 0
18
+ self.diffs[item1][item2] ||= 0.0
19
+ self.freqs[item1][item2] += 1
20
+ self.diffs[item1][item2] += (rating1 - rating2)
21
+ end
22
+ end
23
+ end
24
+
25
+ self.diffs.each do |item1, ratings|
26
+ ratings.each do |item2, rating2|
27
+ ratings[item2] = ratings[item2] / self.freqs[item1][item2]
28
+ end
29
+ end
30
+ end
31
+
32
+ def predict(user)
33
+ preds, freqs = {}, {}
34
+
35
+ user.each do |item, rating|
36
+ self.diffs.each do |diff_item, diff_ratings|
37
+ next if self.freqs[diff_item].nil? or diff_ratings[item].nil?
38
+ freq = self.freqs[diff_item][item]
39
+ preds[diff_item] ||= 0.0
40
+ freqs[diff_item] ||= 0
41
+ preds[diff_item] += freq * (diff_ratings[item] + rating)
42
+ freqs[diff_item] += freq
43
+ end
44
+ end
45
+
46
+ results = {}
47
+ preds.each do |item, value|
48
+ results[item] = sprintf('%.3f', (value / freqs[item])).to_f unless user.include?(item) && freqs[item] > 0
49
+ end
50
+ return results
51
+ end
52
+ end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/slope_one.rb'}"
9
+ puts "Loading slope_one gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,3 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/slope_one'
@@ -0,0 +1,60 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestSlopeOne < Test::Unit::TestCase
4
+ def setup
5
+ user_data = {
6
+ "rob" => {
7
+ "24" => 9.5,
8
+ "Lost" => 8.2,
9
+ "House" => 6.8
10
+ },
11
+
12
+ "bob" => {
13
+ "24" => 3.7,
14
+ "Big Bang Theory" => 2.1,
15
+ "House" => 8.3
16
+ },
17
+
18
+ "tod" => {
19
+ "24" => 9.5,
20
+ "Lost" => 3.4,
21
+ "House" => 5.5,
22
+ "Big Bang Theory" => 9.3
23
+ },
24
+
25
+ "dod" => {
26
+ "24" => 7.2,
27
+ "Lost" => 5.1,
28
+ "House" => 8.4,
29
+ "The Event" => 7.8,
30
+ }
31
+ }
32
+
33
+ @slope_one = SlopeOne.new
34
+ @slope_one.insert(user_data)
35
+ end
36
+
37
+ def input_test(input, output)
38
+ assert @slope_one.predict(input) == output
39
+ end
40
+
41
+ def test_predict
42
+ input = {"House" => 3, "Big Bang Theory" => 7.5}
43
+ output = {"24"=>4.95, "Lost"=>1.65, "The Event"=>2.4}
44
+ input_test(input, output)
45
+ end
46
+
47
+ def test_irrelevent_input
48
+ input = {"Eastenders" => 7.25}
49
+ output = {}
50
+ input_test(input, output)
51
+ end
52
+
53
+ def test_insufficient_data
54
+ @slope_one = SlopeOne.new
55
+ # < here there nay be data insertion >
56
+ input = {"Eastenders" => 7.25}
57
+ output = {}
58
+ input_test(input, output)
59
+ end
60
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: slope_one
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - Ashley Williams
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2010-12-13 00:00:00 +00:00
17
+ default_executable:
18
+ dependencies: []
19
+
20
+ description: Implementation of the weighted Slope One collaborative filtering/recommendation algorithm.
21
+ email:
22
+ - hi@ashleyw.co.uk
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - Manifest.txt
31
+ - README.markdown
32
+ - Rakefile
33
+ - lib/slope_one.rb
34
+ - script/console
35
+ - script/destroy
36
+ - script/generate
37
+ - test/test_helper.rb
38
+ - test/test_slope_one.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/ashleyw/slope_one
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options: []
45
+
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ segments:
62
+ - 1
63
+ - 3
64
+ - 6
65
+ version: 1.3.6
66
+ requirements: []
67
+
68
+ rubyforge_project: slope_one
69
+ rubygems_version: 1.3.7
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Implementation of the Slope One recommendation algorithm.
73
+ test_files: []
74
+