cofi_cost 0.0.4 → 0.0.6
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/lib/cofi_cost.rb +15 -33
- metadata +16 -6
data/lib/cofi_cost.rb
CHANGED
@@ -6,10 +6,10 @@ include GSL::MultiMin
|
|
6
6
|
|
7
7
|
class CofiCost
|
8
8
|
|
9
|
-
attr_accessor :ratings, :num_features, :cost, :
|
9
|
+
attr_accessor :ratings, :num_features, :cost, :regularization, :iterations, :features, :theta
|
10
10
|
attr_reader :boolean_rated, :num_tracks, :num_users, :ratings_mean, :ratings_norm, :predictions
|
11
11
|
|
12
|
-
def initialize(ratings, num_features = 2,
|
12
|
+
def initialize(ratings, num_features = 2, regularization = 1, iterations = 10, 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
|
@@ -24,7 +24,7 @@ class CofiCost
|
|
24
24
|
@ratings_mean = NArray.float(1, @num_tracks).fill(0.0)
|
25
25
|
@ratings_norm = NArray.float(@num_users, @num_tracks).fill(0.0)
|
26
26
|
@ratings_mean, @ratings_norm = normalize_ratings
|
27
|
-
@
|
27
|
+
@regularization = regularization
|
28
28
|
@predictions = nil
|
29
29
|
@iterations = iterations
|
30
30
|
end
|
@@ -32,7 +32,7 @@ class CofiCost
|
|
32
32
|
def normalize_ratings
|
33
33
|
for i in 0..@num_tracks-1 # sadly, @num_tracks.each_index does not work with NArray yet
|
34
34
|
track_rating = @ratings[true,i] # get all user ratings for track i (including unrated)
|
35
|
-
boolean_track_rating = boolean_rated[true,i] # get all user ratings that exist for track i
|
35
|
+
boolean_track_rating = @boolean_rated[true,i] # get all user ratings that exist for track i
|
36
36
|
track_rating_boolean = track_rating[boolean_track_rating]
|
37
37
|
if track_rating_boolean.size == 0
|
38
38
|
@ratings_mean[i] = 0
|
@@ -54,21 +54,15 @@ class CofiCost
|
|
54
54
|
return theta, features
|
55
55
|
end
|
56
56
|
|
57
|
-
def partial_cost_calc(theta,features)
|
57
|
+
def partial_cost_calc(theta=@theta,features=@features)
|
58
58
|
(NArray.ref(NMatrix.ref(features) * NMatrix.ref(theta.transpose(1,0))) - @ratings_norm) * @boolean_rated
|
59
59
|
end
|
60
60
|
|
61
61
|
def roll_up_theta_and_features
|
62
|
-
# roll up theta and features together
|
63
|
-
# (oddly, NArray objects created don't seem to recognize the hcat method
|
64
|
-
# added to the open class NArray
|
65
|
-
# x = GSL:: Vector.alloc(@theta.reshape(true).hcat(@features.reshape(true)))
|
66
|
-
# will fail)
|
67
|
-
# I don't understand why this is/how to fix it.
|
68
62
|
theta_reshaped = @theta.reshape(true)
|
69
63
|
features_reshaped = @features.reshape(true)
|
70
64
|
rolled = NArray.hcat(theta_reshaped,features_reshaped)
|
71
|
-
GSL::
|
65
|
+
GSL::Vector.alloc(rolled) # starting point
|
72
66
|
end
|
73
67
|
|
74
68
|
def unroll_params_init_shape(x)
|
@@ -79,22 +73,22 @@ class CofiCost
|
|
79
73
|
|
80
74
|
def min_cost
|
81
75
|
cost_f = Proc.new { |v|
|
82
|
-
|
76
|
+
theta_l, features_l = unroll_params(v)
|
83
77
|
# In octave:
|
84
|
-
# 1/2 * sum(sum(((X * Theta.transpose - Y).*R).^2)) +
|
85
|
-
(partial_cost_calc(
|
78
|
+
# 1/2 * sum(sum(((X * Theta.transpose - Y).*R).^2)) + regularization/2 * sum(sum((Theta).^2)) + regularization/2 * sum(sum((X).^2))
|
79
|
+
0.5 * (partial_cost_calc(theta_l,features_l)**2).sum + @regularization/2 * (features_l**2).sum
|
86
80
|
}
|
87
81
|
cost_df = Proc.new { |v, df|
|
88
|
-
|
82
|
+
theta_l, features_l = unroll_params(v)
|
89
83
|
# In octave:
|
90
|
-
# xgrad = ((X * Theta.transpose - Y).* R) * Theta +
|
91
|
-
# thetagrad = ((X * Theta.transpose - Y).* R).transpose * X +
|
84
|
+
# xgrad = ((X * Theta.transpose - Y).* R) * Theta + regularization * X # X_grad
|
85
|
+
# thetagrad = ((X * Theta.transpose - Y).* R).transpose * X + regularization * Theta
|
92
86
|
|
93
87
|
# I realize this is a hack. I'm not totally sure why or how but just setting
|
94
|
-
# df = NArray.hcat(dfzero,dfone) results in no steps being made in gradient descent.
|
88
|
+
# df = NArray.hcat(dfzero,dfone).to_gv results in no steps being made in gradient descent.
|
95
89
|
# ideas/suggestions welcome :)
|
96
|
-
dfzero = (NArray.ref(NMatrix.ref(partial_cost_calc(
|
97
|
-
dfone = (NArray.ref(NMatrix.ref((partial_cost_calc(
|
90
|
+
dfzero = (NArray.ref(NMatrix.ref(partial_cost_calc(theta_l,features_l)) * NMatrix.ref(theta_l)) + @regularization * features_l).flatten
|
91
|
+
dfone = (NArray.ref(NMatrix.ref((partial_cost_calc(theta_l,features_l)).transpose(1,0)) * NMatrix.ref(features_l)) + @regularization * theta_l).flatten
|
98
92
|
dfcomp = NArray.hcat(dfzero,dfone)
|
99
93
|
for i in 0..dfcomp.size-1 # again .each_index does not yet work with NArray
|
100
94
|
df[i] = dfcomp[i]
|
@@ -157,15 +151,3 @@ class NArray
|
|
157
151
|
def hcat(*narrays) ; cat(0, *narrays) end
|
158
152
|
end
|
159
153
|
end
|
160
|
-
|
161
|
-
##ratings = NArray.float(4,5).indgen(0,2)
|
162
|
-
#ratings = NArray[[1.0,4.0],[4.0,0.0],[0.0,0.0]]
|
163
|
-
#g = CofiCost.new(ratings, 5, 1, 10, nil, nil)
|
164
|
-
#puts g.theta.nil?
|
165
|
-
#g.min_cost
|
166
|
-
#puts "new theta"
|
167
|
-
#puts g.theta.to_a.to_s
|
168
|
-
#puts "new features"
|
169
|
-
#puts g.features.to_a.to_s
|
170
|
-
#puts "predictions"
|
171
|
-
#puts g.predictions.to_a.to_s
|
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.
|
4
|
+
version: 0.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-09-02 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: gsl
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: narray
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,7 +37,12 @@ dependencies:
|
|
32
37
|
version: '0'
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
36
46
|
description: Playground for collaborative filtering in Ruby using NArray and rb-gsl.
|
37
47
|
email: tomwolfe@gmail.com
|
38
48
|
executables: []
|
@@ -64,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
74
|
requirements:
|
65
75
|
- libgsl0-dev
|
66
76
|
rubyforge_project:
|
67
|
-
rubygems_version: 1.8.
|
77
|
+
rubygems_version: 1.8.23
|
68
78
|
signing_key:
|
69
79
|
specification_version: 3
|
70
80
|
summary: Collaborative filtering
|