recommendify_whosv 0.5.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.
- checksums.yaml +7 -0
- data/Gemfile +9 -0
- data/README.md +154 -0
- data/Rakefile +18 -0
- data/doc/example.png +0 -0
- data/doc/example.rb +87 -0
- data/doc/example_data.csv +120048 -0
- data/ext/cc_item.h +8 -0
- data/ext/cosine.c +3 -0
- data/ext/extconf.rb +18 -0
- data/ext/iikey.c +18 -0
- data/ext/jaccard.c +19 -0
- data/ext/output.c +22 -0
- data/ext/recommendify.c +214 -0
- data/ext/sort.c +23 -0
- data/ext/version.h +17 -0
- data/lib/recommendify/base.rb +88 -0
- data/lib/recommendify/cc_matrix.rb +51 -0
- data/lib/recommendify/cosine_input_matrix.rb +7 -0
- data/lib/recommendify/input_matrix.rb +52 -0
- data/lib/recommendify/jaccard_input_matrix.rb +62 -0
- data/lib/recommendify/neighbor.rb +19 -0
- data/lib/recommendify/recommendify.rb +25 -0
- data/lib/recommendify/similarity_matrix.rb +63 -0
- data/lib/recommendify/sparse_matrix.rb +53 -0
- data/lib/recommendify.rb +9 -0
- data/recommendify.gemspec +25 -0
- data/spec/base_spec.rb +188 -0
- data/spec/cc_matrix_shared.rb +89 -0
- data/spec/cosine_input_matrix_spec.rb +18 -0
- data/spec/input_matrix_shared.rb +27 -0
- data/spec/input_matrix_spec.rb +29 -0
- data/spec/jaccard_input_matrix_spec.rb +95 -0
- data/spec/recommendify_spec.rb +28 -0
- data/spec/similarity_matrix_spec.rb +93 -0
- data/spec/sparse_matrix_spec.rb +78 -0
- data/spec/spec_helper.rb +42 -0
- metadata +122 -0
@@ -0,0 +1,93 @@
|
|
1
|
+
require ::File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Recommendify::SimilarityMatrix do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
flush_redis!
|
7
|
+
@matrix = Recommendify::SimilarityMatrix.new(:redis_prefix => "recommendify-test", :key => "mymatrix")
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "sorted sets per item" do
|
11
|
+
|
12
|
+
it "should store member similarities" do
|
13
|
+
@matrix.update("item_foo", [["item_bar", 0.7], ["item_fnord", 0.3]])
|
14
|
+
@matrix.write_queue["item_foo"].length.should == 2
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should store member similarities uniquely" do
|
18
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3]])
|
19
|
+
@matrix.write_queue["item_fnord"].length.should == 1
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should store member similarities uniquely and sum the scores" do
|
23
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3]])
|
24
|
+
@matrix.write_queue["item_fnord"].should == {"item_bar" => 1.0}
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should store multiple member similarities uniquely and sum the scores" do
|
28
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3], ["item_foo", 0.75]])
|
29
|
+
@matrix.write_queue["item_fnord"].should == {"item_bar" => 1.0, "item_foo" => 0.75}
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should store multiple member similarities uniquely and sum the scores on multiple updates" do
|
33
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_foo", 0.75]])
|
34
|
+
@matrix.update("item_fnord", [["item_fnord", 0.3], ["item_bar", 0.3], ["item_foo", 0.75]])
|
35
|
+
@matrix.write_queue["item_fnord"].should == {"item_bar" => 1.0, "item_foo" => 1.5, "item_fnord" => 0.3}
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should retrieve the members" do
|
39
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3], ["item_foo", 0.75]])
|
40
|
+
@matrix["item_fnord"].should == {"item_bar" => 1.0, "item_foo" => 0.75}
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "serialization/loading to/from redis" do
|
46
|
+
|
47
|
+
it "should serialize a member of the write_queue correctly" do
|
48
|
+
@matrix.update("item_fnord", [["item_fnord", 0.3], ["item_bar", 0.3], ["item_foo", 0.75]])
|
49
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3]])
|
50
|
+
@matrix.send(:serialize_item, "item_fnord").should == "item_bar:1.3|item_foo:0.75|item_fnord:0.3"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should write the n-most similar members and scores to redis on commit_item!" do
|
54
|
+
@matrix.update("item_fnord", [["item_fnord", 0.3], ["item_bar", 0.3], ["item_foo", 0.75]])
|
55
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3]])
|
56
|
+
@matrix.commit_item!("item_fnord")
|
57
|
+
Recommendify.redis.hget("recommendify-test:mymatrix", "item_fnord").should == "item_bar:1.3|item_foo:0.75|item_fnord:0.3"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should not write more than max_neighbors scores to redis on commit_item!" do
|
61
|
+
60.times{ |n| @matrix.update("item_fnord", [["item_#{n}", n.to_f/100.0]]) }
|
62
|
+
@matrix.commit_item!("item_fnord")
|
63
|
+
Recommendify.redis.hget("recommendify-test:mymatrix", "item_fnord").split("|").length.should == 50
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not write more neighbors with zero-scores to redis on commit_item!" do
|
67
|
+
@matrix.update("item_fnord", [["item_fnord", 0.0], ["item_bar", 0.3], ["item_foo", 0.75]])
|
68
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3]])
|
69
|
+
@matrix.commit_item!("item_fnord")
|
70
|
+
Recommendify.redis.hget("recommendify-test:mymatrix", "item_fnord").split("|").length.should == 2
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should clear the item from the write_queue after commit_item!" do
|
74
|
+
60.times{ |n| @matrix.update("item_fnord", [["item_#{n}", n.to_f/100.0]]) }
|
75
|
+
@matrix.write_queue["item_fnord"].length.should == 60
|
76
|
+
@matrix.commit_item!("item_fnord")
|
77
|
+
@matrix.write_queue["item_fnord"].length.should == 0
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should retrieve the n-most similar neighbors after stored" do
|
81
|
+
Recommendify.redis.hset("recommendify-test:mymatrix", "item_fnord", "item_blubb:0.6|item_foo:0.4")
|
82
|
+
@matrix["item_fnord"].keys.should include("item_blubb")
|
83
|
+
@matrix["item_fnord"].keys.should include("item_foo")
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should retrieve the n-most similar neighbors after stored with scores" do
|
87
|
+
Recommendify.redis.hset("recommendify-test:mymatrix", "item_fnord", "item_blubb:0.6|item_foo:0.4")
|
88
|
+
@matrix["item_fnord"].should == {"item_blubb" => 0.6, "item_foo" => 0.4}
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require ::File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Recommendify::SparseMatrix do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
@sm = Recommendify::SparseMatrix.new(:redis_prefix => "recommendify-test", :key => "mysparsematrix")
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
flush_redis!
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should build the correct keys" do
|
14
|
+
@sm.redis_key.should == "recommendify-test:mysparsematrix"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should retrieve a value" do
|
18
|
+
Recommendify.redis.hset("recommendify-test:mysparsematrix", "bar:foo", 43)
|
19
|
+
@sm["bar", "foo"].to_i.should == 43
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should retrieve a value regardless of parameter order" do
|
23
|
+
Recommendify.redis.hset("recommendify-test:mysparsematrix", "one:two", 14)
|
24
|
+
@sm["one", "two"].to_i.should == 14
|
25
|
+
@sm["two", "one"].to_i.should == 14
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should store a value" do
|
29
|
+
@sm["bar", "foo"] = 123
|
30
|
+
Recommendify.redis.hget("recommendify-test:mysparsematrix", "bar:foo").to_i.should == 123
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should store a value regardless of parameter order" do
|
34
|
+
@sm["foo", "bar"] = 126
|
35
|
+
Recommendify.redis.hget("recommendify-test:mysparsematrix", "bar:foo").to_i.should == 126
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return 0 if the key is not found" do
|
39
|
+
@sm["not", "set"].should == 0
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should increment a value" do
|
43
|
+
@sm["foo", "bar"] = 1000
|
44
|
+
@sm.incr("foo", "bar")
|
45
|
+
Recommendify.redis.hget("recommendify-test:mysparsematrix", "bar:foo").to_i.should == 1001
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should increment a value regardless of parameter order" do
|
49
|
+
@sm["foo", "bar"] = 2000
|
50
|
+
@sm.incr("bar", "foo")
|
51
|
+
Recommendify.redis.hget("recommendify-test:mysparsematrix", "bar:foo").to_i.should == 2001
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should not create unneseccary keys" do
|
55
|
+
@sm["foo", "bar"] = 90
|
56
|
+
@sm["5asd6", "bar"] = 260
|
57
|
+
@sm["foo", "bar"] = 45
|
58
|
+
@sm["foo", "jefs"] = 26
|
59
|
+
Recommendify.redis.hkeys("recommendify-test:mysparsematrix").length.should == 3
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should create a key if the value is not 0" do
|
63
|
+
@sm["foo", "jefs"] = 26
|
64
|
+
Recommendify.redis.hkeys("recommendify-test:mysparsematrix").length.should == 1
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should not create a key if the value is 0" do
|
68
|
+
@sm["foo", "jefs"] = 0
|
69
|
+
Recommendify.redis.hkeys("recommendify-test:mysparsematrix").length.should == 0
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should delete a key if the value is set to 0" do
|
73
|
+
Recommendify.redis.hset("recommendify-test:mysparsematrix", "bar:foo", 43)
|
74
|
+
@sm["bar", "foo"] = 0
|
75
|
+
Recommendify.redis.hkeys("recommendify-test:mysparsematrix").length.should == 0
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "redis"
|
3
|
+
|
4
|
+
require ::File.expand_path('../../lib/recommendify', __FILE__)
|
5
|
+
|
6
|
+
require ::File.expand_path('../input_matrix_shared.rb', __FILE__)
|
7
|
+
require ::File.expand_path('../cc_matrix_shared.rb', __FILE__)
|
8
|
+
|
9
|
+
def flush_redis!
|
10
|
+
Recommendify.redis = Redis.new
|
11
|
+
Recommendify.redis.keys("recommendify-test*").each do |k|
|
12
|
+
Recommendify.redis.del(k)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Recommendify::Base
|
17
|
+
|
18
|
+
def redis_prefix
|
19
|
+
"recommendify-test"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
class TestRecommender < Recommendify::Base
|
26
|
+
|
27
|
+
input_matrix :jaccard_one,
|
28
|
+
:similarity_func => :jaccard
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class Recommendify::TestInputMatrix
|
33
|
+
|
34
|
+
def initialize(opts)
|
35
|
+
@opts = opts
|
36
|
+
end
|
37
|
+
|
38
|
+
def method_missing(method, *args)
|
39
|
+
@opts[method]
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: recommendify_whosv
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.8
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paul Asmuth
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: redis
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.2.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.2.2
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.8.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.8.0
|
41
|
+
description: Recommendify is a distributed, incremental item-based recommendation
|
42
|
+
engine for binary input ratings. It's based on ruby and redis and uses an approach
|
43
|
+
called "Collaborative Filtering"
|
44
|
+
email:
|
45
|
+
- paul@paulasmuth.com
|
46
|
+
executables: []
|
47
|
+
extensions:
|
48
|
+
- ext/extconf.rb
|
49
|
+
extra_rdoc_files: []
|
50
|
+
files:
|
51
|
+
- Gemfile
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- doc/example.png
|
55
|
+
- doc/example.rb
|
56
|
+
- doc/example_data.csv
|
57
|
+
- ext/cc_item.h
|
58
|
+
- ext/cosine.c
|
59
|
+
- ext/extconf.rb
|
60
|
+
- ext/iikey.c
|
61
|
+
- ext/jaccard.c
|
62
|
+
- ext/output.c
|
63
|
+
- ext/recommendify.c
|
64
|
+
- ext/sort.c
|
65
|
+
- ext/version.h
|
66
|
+
- lib/recommendify.rb
|
67
|
+
- lib/recommendify/base.rb
|
68
|
+
- lib/recommendify/cc_matrix.rb
|
69
|
+
- lib/recommendify/cosine_input_matrix.rb
|
70
|
+
- lib/recommendify/input_matrix.rb
|
71
|
+
- lib/recommendify/jaccard_input_matrix.rb
|
72
|
+
- lib/recommendify/neighbor.rb
|
73
|
+
- lib/recommendify/recommendify.rb
|
74
|
+
- lib/recommendify/similarity_matrix.rb
|
75
|
+
- lib/recommendify/sparse_matrix.rb
|
76
|
+
- recommendify.gemspec
|
77
|
+
- spec/base_spec.rb
|
78
|
+
- spec/cc_matrix_shared.rb
|
79
|
+
- spec/cosine_input_matrix_spec.rb
|
80
|
+
- spec/input_matrix_shared.rb
|
81
|
+
- spec/input_matrix_spec.rb
|
82
|
+
- spec/jaccard_input_matrix_spec.rb
|
83
|
+
- spec/recommendify_spec.rb
|
84
|
+
- spec/similarity_matrix_spec.rb
|
85
|
+
- spec/sparse_matrix_spec.rb
|
86
|
+
- spec/spec_helper.rb
|
87
|
+
homepage: http://github.com/paulasmuth/recommendify
|
88
|
+
licenses:
|
89
|
+
- MIT
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.2.2
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: ruby/redis based recommendation engine (collaborative filtering)
|
111
|
+
test_files:
|
112
|
+
- spec/base_spec.rb
|
113
|
+
- spec/cc_matrix_shared.rb
|
114
|
+
- spec/cosine_input_matrix_spec.rb
|
115
|
+
- spec/input_matrix_shared.rb
|
116
|
+
- spec/input_matrix_spec.rb
|
117
|
+
- spec/jaccard_input_matrix_spec.rb
|
118
|
+
- spec/recommendify_spec.rb
|
119
|
+
- spec/similarity_matrix_spec.rb
|
120
|
+
- spec/sparse_matrix_spec.rb
|
121
|
+
- spec/spec_helper.rb
|
122
|
+
has_rdoc:
|