cofi_cost 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.txt
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,27 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cofi_cost (0.0.8)
5
+ gsl
6
+ narray
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ columnize (0.3.6)
12
+ debugger (1.6.2)
13
+ columnize (>= 0.3.1)
14
+ debugger-linecache (~> 1.2.0)
15
+ debugger-ruby_core_source (~> 1.2.3)
16
+ debugger-linecache (1.2.0)
17
+ debugger-ruby_core_source (1.2.3)
18
+ gsl (1.15.3)
19
+ narray (>= 0.5.9)
20
+ narray (0.6.0.8)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ cofi_cost!
27
+ debugger
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ task :default => [:test]
2
+
3
+ task :test do
4
+ ruby "test/unit/test_cofi_cost.rb"
5
+ end
data/cofi_cost.gemspec ADDED
@@ -0,0 +1,16 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'cofi_cost'
3
+ s.version = '0.0.8'
4
+ s.date = '2013-11-18'
5
+ s.summary = "Collaborative filtering"
6
+ s.description = "Playground for collaborative filtering in Ruby using NArray and rb-gsl."
7
+ s.authors = ["Thomas Wolfe"]
8
+ s.email = 'tomwolfe@gmail.com'
9
+ s.files = `git ls-files`.split("\n")
10
+ s.homepage = 'http://github.com/tomwolfe/cofi_cost'
11
+ s.add_runtime_dependency 'gsl'
12
+ s.add_runtime_dependency 'narray'
13
+ s.license = 'MIT'
14
+ s.required_ruby_version = '>= 1.9.2'
15
+ s.requirements << 'libgsl0-dev'
16
+ end
data/lib/cofi_cost.rb CHANGED
@@ -6,13 +6,14 @@ include GSL::MultiMin
6
6
 
7
7
  class CofiCost
8
8
 
9
- attr_accessor :ratings, :num_features, :cost, :regularization, :iterations, :features, :theta
10
- attr_reader :boolean_rated, :num_tracks, :num_users, :ratings_mean, :ratings_norm, :predictions
9
+ attr_accessor :ratings, :num_features, :regularization, :iterations, :features, :theta, :max_rating
10
+ attr_reader :boolean_rated, :num_tracks, :num_users, :ratings_mean, :ratings_norm, :predictions, :cost
11
11
 
12
- def initialize(ratings, num_features = 2, regularization = 1, iterations = 10, features = nil, theta = nil)
12
+ def initialize(ratings, num_features = 2, regularization = 1, iterations = 10, max_rating = 5, features = nil, theta = nil)
13
13
  @ratings = ratings.to_f # make sure it's a float for correct normalization
14
14
  @num_features = num_features
15
15
  @cost = 0
16
+ @max_rating = max_rating
16
17
  @boolean_rated = @ratings > 0 # return 0 for all rated and 1 for all unrated
17
18
  @boolean_unrated = @boolean_rated.eq 0 # return 1 for all unrated and 0 for all unrated
18
19
  @num_tracks = @ratings.shape[1] # @ratings is users x tracks
@@ -122,7 +123,14 @@ class CofiCost
122
123
  end
123
124
 
124
125
  def calc_predictions
125
- NArray.ref(NMatrix.ref(@features) * NMatrix.ref(@theta.transpose(1,0))) + @ratings_mean
126
+ predicts = NArray.ref(NMatrix.ref(@features) * NMatrix.ref(@theta.transpose(1,0))) + @ratings_mean
127
+ set_max_predictions(predicts)
128
+ end
129
+
130
+ def set_max_predictions(predicts)
131
+ a = predicts > @max_rating
132
+ predicts[a] = @max_rating
133
+ predicts
126
134
  end
127
135
 
128
136
  end
@@ -0,0 +1,77 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe CofiCost do
4
+ before :each do
5
+ ratings = NArray[[5.0,4.0,0.0,0.0],[3.0,0.0,0.0,0.0],[4.0,0.0,0.0,0.0],[3.0,0.0,0.0,0.0],[3.0,0.0,0.0,0.0]]
6
+ num_features = 3
7
+ regularization = 1
8
+ iterations = 10
9
+ max_rating = 5
10
+ theta = NArray[[0.28544,-1.68427,0.26294],[0.50501,-0.45465,0.31746],[-0.43192,-0.47880,0.84671],[0.72860,-0.27189,0.32684]]
11
+ features = NArray[[1.048686,-0.400232,1.194119],[0.780851,-0.385626,0.521198],[0.641509,-0.547854,-0.083796],[0.453618,-0.800218,0.680481],[0.937538,0.106090,0.361953]]
12
+ @cofi = CofiCost.new(ratings, num_features, regularization, iterations, max_rating, features, theta)
13
+ end
14
+
15
+ describe "#normalize_ratings" do
16
+ it "subtracts the mean rating of a track from each of the tracks ratings" do
17
+ # called in initilization
18
+ @cofi.ratings_mean.should == NArray[[4.5],[3.0],[4.0],[3.0],[3.0]]
19
+ @cofi.ratings_norm.should == NArray[[0.5,-0.5,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0]]
20
+ end
21
+ end
22
+
23
+ describe "#partial_cost_calc(theta,features)" do
24
+ it "calculates part of the cost" do
25
+ @cofi.partial_cost_calc.to_a.should == [[0.78741733234,1.5906474134,0.0,0.0],[1.00942821458,0.0,0.0,0.0],[1.0838130652999998,0.0,-0.0,0.0],[1.65618956692,0.0,0.0,0.0],[0.18409856424000004,0.0,-0.0,0.0]]
26
+ end
27
+ end
28
+
29
+ describe "#roll_up_theta_and_features" do
30
+ it "returns a vector of @theta + @features" do
31
+ @cofi.roll_up_theta_and_features.to_a.should == [0.28544,-1.68427,0.26294,0.50501,-0.45465,0.31746,-0.43192,-0.4788,0.84671,0.7286,-0.27189,0.32684,1.048686,-0.400232,1.194119,0.780851,-0.385626,0.521198,0.641509,-0.547854,-0.083796,0.453618,-0.800218,0.680481,0.937538,0.10609,0.361953]
32
+ end
33
+ end
34
+
35
+ describe "#unroll_params_init_shape(x)" do
36
+ before :each do
37
+ @rolled = @cofi.roll_up_theta_and_features
38
+ end
39
+ it "unrolls @theta and @features back into it's original shape" do
40
+ orig_theta, orig_features = @cofi.theta, @cofi.features
41
+ @cofi.unroll_params_init_shape(@rolled)
42
+ @cofi.theta.should == orig_theta
43
+ @cofi.features.should == orig_features
44
+ end
45
+ end
46
+
47
+ describe "#min_cost" do
48
+ it "finds the lowest cost" do
49
+ @cofi.min_cost
50
+ @cofi.cost.should == 0.9885618408659724
51
+ end
52
+ it "calls #calc_predictions" do
53
+ @cofi.should_receive(:calc_predictions)
54
+ @cofi.min_cost
55
+ end
56
+ end
57
+
58
+ describe "#calc_predictions" do
59
+ it "calculates predictions" do
60
+ @cofi.calc_predictions.to_a.should == [[5.0, 5.0, 5.0, 5.0], [4.00942821458, 3.73512194149, 3.28867612346, 3.84412424606], [5.0, 4.54644840303, 3.91428101676, 4.58897159682], [4.65618956692, 3.80892623814, 3.76338775935, 3.7704857568600003], [3.18409856424, 3.54013784626, 2.85073191967, 3.77254609522]]
61
+ end
62
+ end
63
+
64
+ describe "#unroll_params(v)" do
65
+ it "unrolls v back to it's original @theta and @features dimensions" do
66
+ @cofi.unroll_params(@cofi.roll_up_theta_and_features)[0].to_a.should == [[0.28544,-1.68427,0.26294],[0.50501,-0.45465,0.31746],[-0.43192,-0.4788,0.84671],[0.7286,-0.27189,0.32684]]
67
+ @cofi.unroll_params(@cofi.roll_up_theta_and_features)[1].to_a.should == [[1.048686,-0.400232,1.194119],[0.780851,-0.385626,0.521198],[0.641509,-0.547854,-0.083796],[0.453618,-0.800218,0.680481],[0.937538,0.10609,0.361953]]
68
+ end
69
+ end
70
+
71
+ describe "#set_max_predictions(predicts)" do
72
+ it "does not allow any prediction greater than self.max_rating" do
73
+ test = NArray[[6.0,4.0,0.0,0.0],[3.0,0.0,6.5,0.0],[4.0,0.0,0.0,0.0],[3.0,0.0,0.0,0.0],[3.0,0.0,0.0,0.0]]
74
+ @cofi.set_max_predictions(test).to_a.should == [[5.0,4.0,0.0,0.0],[3.0,0.0,5.0,0.0],[4.0,0.0,0.0,0.0],[3.0,0.0,0.0,0.0],[3.0,0.0,0.0,0.0]]
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,4 @@
1
+ require_relative '../lib/cofi_cost'
2
+
3
+ RSpec.configure do |config|
4
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cofi_cost
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-02 00:00:00.000000000 Z
12
+ date: 2013-11-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: gsl
@@ -49,9 +49,15 @@ executables: []
49
49
  extensions: []
50
50
  extra_rdoc_files: []
51
51
  files:
52
- - lib/cofi_cost.rb
52
+ - .gitignore
53
+ - Gemfile
54
+ - Gemfile.lock
53
55
  - README.textile
54
- - test/unit/test_cofi_cost.rb
56
+ - Rakefile
57
+ - cofi_cost.gemspec
58
+ - lib/cofi_cost.rb
59
+ - spec/cofi_cost_spec.rb
60
+ - spec/spec_helper.rb
55
61
  homepage: http://github.com/tomwolfe/cofi_cost
56
62
  licenses:
57
63
  - MIT
@@ -1,41 +0,0 @@
1
- require 'test/unit'
2
- require_relative '../../lib/cofi_cost.rb'
3
- require 'narray'
4
- require 'gsl'
5
- require 'matrix'
6
-
7
- class CofiCostTest < Test::Unit::TestCase
8
-
9
- def setup
10
- ratings = NArray[[5.0,4.0,0.0,0.0],[3.0,0.0,0.0,0.0],[4.0,0.0,0.0,0.0],[3.0,0.0,0.0,0.0],[3.0,0.0,0.0,0.0]]
11
- num_features = 2
12
- lambda = 1
13
- iterations = 10
14
- features = NArray[[0.139489,1.804804],[-0.501808,1.050885],[0.354079,-0.518884],[-0.015370,0.096253],[1.147623,-0.745562]]
15
- theta = NArray[[-0.079641,1.211386],[-0.130688,0.444762],[-0.789258,1.222232],[0.212132,-1.174545]]
16
- @c = CofiCost.new(ratings, num_features, lambda, iterations, features, theta)
17
- end
18
-
19
- def teardown
20
- @c = nil
21
- end
22
-
23
- def test_happy_case
24
- @c.min_cost
25
- assert_equal 0.07964723302994943, @c.cost
26
- # oddly the following fails, even though they are equal (not enough decimal places me thinks)
27
- # assert_equal NArray[[4.62547,3.91302,8.30084,1.59081],[2.96361,3.17939,1.88322,3.88434],[3.92356,4.32263,1.739,5.6172],[2.98132,3.06219,2.47359,3.3213],[2.93724,3.14111,1.33728,3.77855]], @c.predictions
28
- assert_equal 4.625468057637709, @c.predictions[0,0]
29
- end
30
-
31
- def test_normalize_ratings
32
- assert_equal NArray[[4.5],[3.0],[4.0],[3.0],[3.0]], @c.ratings_mean
33
- assert_equal NArray[[0.5,-0.5,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0]], @c.ratings_norm
34
- end
35
-
36
- def test_roll_up_theta_and_features
37
- rolled = @c.roll_up_theta_and_features
38
- assert_equal GSL:: Vector.alloc([-0.079641, 1.211386, -0.130688, 0.444762, -0.789258, 1.222232, 0.212132, -1.174545, 0.139489, 1.804804, -0.501808, 1.050885, 0.354079, -0.518884, -0.01537, 0.096253, 1.147623, -0.745562]), rolled
39
- end
40
-
41
- end