cofi_cost 0.0.7 → 0.0.8

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/.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