cofi_cost 0.0.4 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|