suggestor 0.0.6 → 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/README.md +25 -7
- data/examples/playing_around.rb +18 -6
- data/lib/suggestor.rb +43 -1
- data/lib/suggestor/algorithms/euclidean_distance.rb +2 -12
- data/lib/suggestor/algorithms/pearson_correlation.rb +5 -4
- data/lib/suggestor/algorithms/recommendation_algorithm.rb +31 -62
- data/lib/suggestor/algorithms/records.rb +76 -0
- data/lib/suggestor/version.rb +1 -1
- data/test/suggestor_test.rb +26 -5
- metadata +36 -38
- data/lib/suggestor/engine.rb +0 -36
data/README.md
CHANGED
@@ -18,16 +18,19 @@ In the example, the user "Alvaro Pereyra Rabanal" has seen movies "Primer" and "
|
|
18
18
|
|
19
19
|
After loading the gem with the data:
|
20
20
|
|
21
|
-
|
21
|
+
suggestor = Suggestor::Suggestor.new(data)
|
22
22
|
|
23
23
|
We can start to get some results.
|
24
24
|
|
25
|
+
If using Ruby, you can also send Suggestor just a hash object and it'll take it aswell:
|
26
|
+
|
27
|
+
suggestor = Suggestor::Suggestor.new(JSON.parse(data))
|
25
28
|
|
26
29
|
### Similar items
|
27
30
|
|
28
31
|
For example, we can get similar users:
|
29
32
|
|
30
|
-
|
33
|
+
suggestor.similar_to("Alvaro Pereyra Rabanal")
|
31
34
|
|
32
35
|
Which will return an structure like
|
33
36
|
|
@@ -41,15 +44,15 @@ Thus, you can load the data and save their similarity scores for later use.
|
|
41
44
|
|
42
45
|
You can limit the data passing a "size" argument:
|
43
46
|
|
44
|
-
|
47
|
+
suggestor.similar_to("Alvaro Pereyra Rabanal", :size => 5)
|
45
48
|
|
46
49
|
Now, that fine and all, but what about Mr. Bob who always is ranking everything
|
47
50
|
higher. ID4 maybe is not that good after all. If that happens, Suggestor allows you to change the algorithm used:
|
48
51
|
|
49
52
|
algorithm = Suggestor::Algorithms::PearsonCorrelation
|
50
|
-
|
53
|
+
suggestor = Suggestor::Suggestor.new(data, algorithm)
|
51
54
|
|
52
|
-
|
55
|
+
suggestor.recommended_to("Alvaro Pereyra Rabanal")
|
53
56
|
|
54
57
|
There are two implemented methods, Euclidean Distance and Pearson Correlation.
|
55
58
|
|
@@ -64,7 +67,7 @@ take in mind if some user grades higher or lower and return more exact suggestio
|
|
64
67
|
Most interestingly, the gem allows you to get suggestions base on the data.
|
65
68
|
For example, which movies shoud user "2" watch based on his reviews, and similar other users tastes?
|
66
69
|
|
67
|
-
|
70
|
+
suggestor.recommended_to("Alvaro Pereyra Rabanal")
|
68
71
|
|
69
72
|
As before, the structure returned will be
|
70
73
|
|
@@ -79,6 +82,21 @@ We can also invert the data that the user has added, enableing us to get
|
|
79
82
|
similar related items. For example, let's say I'm on a Movie profile and
|
80
83
|
want to check which other movies are similar to it:
|
81
84
|
|
82
|
-
|
85
|
+
suggestor.similar_related_to("Batman Begins ", :size => 5)
|
86
|
+
|
87
|
+
### Suggested items for a set
|
88
|
+
|
89
|
+
Say that you have the list of the movies that you liked the most and you'd like to know what you should watch next. Suggestor has you covered:
|
90
|
+
|
91
|
+
suggestor.items_for_set ['Batman Begins', 'Cyrus']
|
92
|
+
# => [["Kung Fu Hustle", 0.5], ["Super 8 ", 0.5], ["Celda 211 ", 0.5], ... ]
|
93
|
+
|
94
|
+
Suggestor of course considers the whole set when recommending new items, so different sets will yield different results, even if they differ in only one item. Say you picked Super 8 from the previous query:
|
95
|
+
suggestor.items_for_set ['Batman Begins', 'Cyrus', 'Super 8 ']
|
96
|
+
# => [["Rapidos y Furiosos 5", 0.3333333333333333], ["Agente Salt", 0.3333333333333333], ["Mary and Max ", 0.3333333333333333], ... ]
|
97
|
+
|
98
|
+
But if you had picked Kung Fu Hustle:
|
99
|
+
suggestor.items_for_set ['Batman Begins', 'Cyrus', 'Kung Fu Hustle']
|
100
|
+
# => [["El mensajero ", 0.6666666666666666], ["El Club de la Pelea", 0.3333333333333333], ["Un tonto en el amor", 0.3333333333333333], ... ]
|
83
101
|
|
84
102
|
Now you can go and build your awesome recommendations web site :)
|
data/examples/playing_around.rb
CHANGED
@@ -4,12 +4,12 @@ require_relative '../lib/suggestor'
|
|
4
4
|
# Each user have a hash of their reviews with the movie and
|
5
5
|
# what they've rate them with
|
6
6
|
json = File.read("test/movies.json")
|
7
|
-
|
7
|
+
suggestor = Suggestor::Suggestor.new(json)
|
8
8
|
|
9
9
|
# Let's get some similar users
|
10
10
|
name = "Alvaro Pereyra Rabanal"
|
11
11
|
puts "Who is similar to #{name}"
|
12
|
-
puts
|
12
|
+
puts suggestor.similar_to(name, size: 5).inspect
|
13
13
|
|
14
14
|
puts
|
15
15
|
puts
|
@@ -17,7 +17,7 @@ puts
|
|
17
17
|
# So, after knowing them, why not having some recommendations?
|
18
18
|
puts "Interesting! But I want to see some stuff at the movies, what to watch?"
|
19
19
|
opts = {size: 5}
|
20
|
-
results =
|
20
|
+
results = suggestor.recommended_to("Alvaro Pereyra Rabanal", opts)
|
21
21
|
|
22
22
|
puts results.inspect
|
23
23
|
|
@@ -26,17 +26,29 @@ puts
|
|
26
26
|
|
27
27
|
# That's good, but let's take in mind bias while using Pearson Correlation:
|
28
28
|
puts "Adjust this results please"
|
29
|
-
|
29
|
+
suggestor = Suggestor::Suggestor.new(json,Suggestor::Algorithms::PearsonCorrelation)
|
30
30
|
|
31
31
|
ops = {size: 5}
|
32
|
-
results =
|
32
|
+
results = suggestor.recommended_to("Alvaro Pereyra Rabanal", opts)
|
33
33
|
puts results.inspect
|
34
34
|
|
35
35
|
puts
|
36
36
|
puts
|
37
37
|
|
38
|
+
puts "Adjust this results please"
|
39
|
+
suggestor = Suggestor::Suggestor.new(json)
|
40
|
+
|
38
41
|
name = "Batman Begins "
|
39
42
|
puts "Now that was nice. But which others are similar to '#{name}'"
|
40
43
|
ops = {size: 10}
|
41
|
-
results =
|
44
|
+
results = suggestor.similar_related_to(name, opts)
|
45
|
+
puts results.inspect
|
46
|
+
|
47
|
+
puts
|
48
|
+
puts
|
49
|
+
|
50
|
+
set = ['Batman Begins', 'Cyrus']
|
51
|
+
puts "Great! One more thing: if I've watched all these movies: #{set.inspect},
|
52
|
+
which should I watch next?"
|
53
|
+
results = suggestor.items_for_set set
|
42
54
|
puts results.inspect
|
data/lib/suggestor.rb
CHANGED
@@ -1,5 +1,47 @@
|
|
1
|
-
require_relative 'suggestor/
|
1
|
+
require_relative 'suggestor/algorithms/records'
|
2
2
|
require_relative 'suggestor/algorithms/recommendation_algorithm'
|
3
3
|
require_relative 'suggestor/algorithms/euclidean_distance'
|
4
4
|
require_relative 'suggestor/algorithms/pearson_correlation'
|
5
5
|
|
6
|
+
require 'json'
|
7
|
+
module Suggestor
|
8
|
+
class WrongInputFormat < Exception; end
|
9
|
+
|
10
|
+
class Suggestor
|
11
|
+
|
12
|
+
def initialize(input, algorithm = Algorithms::EuclideanDistance)
|
13
|
+
collection = load_from(input)
|
14
|
+
@algorithm = algorithm.new(collection)
|
15
|
+
end
|
16
|
+
|
17
|
+
def similar_to(item, opts={})
|
18
|
+
@algorithm.similar_to(item, opts)
|
19
|
+
end
|
20
|
+
|
21
|
+
def recommended_to(item, opts={})
|
22
|
+
@algorithm.recommended_to(item, opts)
|
23
|
+
end
|
24
|
+
|
25
|
+
def similar_related_to(item, opts={})
|
26
|
+
@algorithm.similar_related_to(item, opts)
|
27
|
+
end
|
28
|
+
|
29
|
+
def items_for_set(set, opts={})
|
30
|
+
@algorithm.items_for_set(set, opts)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def load_from(input)
|
36
|
+
return input if input.is_a? Hash
|
37
|
+
parse_from_json(input)
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_from_json(json)
|
41
|
+
JSON.parse(json)
|
42
|
+
rescue Exception => ex
|
43
|
+
raise WrongInputFormat, "Wrong Data format: #{ex.message}"
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -23,18 +23,8 @@ module Suggestor
|
|
23
23
|
include RecommendationAlgorithm
|
24
24
|
|
25
25
|
def similarity_score(first, second)
|
26
|
-
return 0.0 if nothing_shared?(first, second)
|
27
|
-
inverse_of_squares(first, second)
|
28
|
-
end
|
29
|
-
|
30
|
-
def inverse_of_squares(first, second)
|
31
|
-
1/(1+Math.sqrt(sum_squares(first, second)))
|
32
|
-
end
|
33
|
-
|
34
|
-
def sum_squares(first, second)
|
35
|
-
shared_items(first, second).inject(0.0) do |sum, item|
|
36
|
-
sum + ( values_for(first)[item] - values_for(second)[item] ) ** 2
|
37
|
-
end
|
26
|
+
return 0.0 if @collection.nothing_shared?(first, second)
|
27
|
+
@collection.inverse_of_squares(first, second)
|
38
28
|
end
|
39
29
|
|
40
30
|
end
|
@@ -34,11 +34,12 @@ module Suggestor
|
|
34
34
|
include RecommendationAlgorithm
|
35
35
|
|
36
36
|
def similarity_score(first, second)
|
37
|
-
return -1.0 if nothing_shared?(first, second)
|
37
|
+
return -1.0 if @collection.nothing_shared?(first, second)
|
38
38
|
|
39
39
|
process_values(first, second)
|
40
40
|
|
41
41
|
numerator = difference_from_values
|
42
|
+
|
42
43
|
denominator = square_root_from_differences
|
43
44
|
|
44
45
|
return 0.0 if denominator == 0
|
@@ -48,11 +49,11 @@ module Suggestor
|
|
48
49
|
private
|
49
50
|
|
50
51
|
def process_values(first, second)
|
51
|
-
items = shared_items(first, second)
|
52
|
+
items = @collection.shared_items(first, second)
|
52
53
|
@total_related_items = items.size.to_f
|
53
54
|
|
54
|
-
first_values = values_for(first)
|
55
|
-
second_values = values_for(second)
|
55
|
+
first_values = @collection.values_for(first)
|
56
|
+
second_values = @collection.values_for(second)
|
56
57
|
|
57
58
|
create_helper_variables
|
58
59
|
|
@@ -5,15 +5,16 @@ module Suggestor
|
|
5
5
|
attr_accessor :collection
|
6
6
|
|
7
7
|
def initialize(collection)
|
8
|
-
@collection = collection
|
8
|
+
@collection = Records.new(collection)
|
9
9
|
end
|
10
10
|
|
11
11
|
# Ex. Similar users based on their movies reviews
|
12
12
|
def similar_to(main, opts={})
|
13
13
|
opts.merge!(default_options)
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
|
15
|
+
cleaned = @collection.remove(main)
|
16
|
+
|
17
|
+
results = order_by_similarity_score(main, cleaned)
|
17
18
|
|
18
19
|
sort_results(results,opts[:size])
|
19
20
|
end
|
@@ -25,6 +26,7 @@ module Suggestor
|
|
25
26
|
@similarities = @totals = Hash.new(0)
|
26
27
|
|
27
28
|
create_similarities_totals(main)
|
29
|
+
|
28
30
|
results = generate_rankings
|
29
31
|
|
30
32
|
sort_results(results,opts[:size])
|
@@ -34,72 +36,43 @@ module Suggestor
|
|
34
36
|
def similar_related_to(main, opts={})
|
35
37
|
opts.merge!(default_options)
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
inverted_collection = @collection.invert
|
40
|
+
suggestor = self.class.new(inverted_collection)
|
39
41
|
|
40
|
-
|
42
|
+
suggestor.similar_to(main,opts)
|
41
43
|
end
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
related_keys_for(second).include? item
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
45
|
+
# Takes a set and returns suggestions based on the weighted average of
|
46
|
+
# the similarities to all of the items in it.
|
47
|
+
def items_for_set(set, opts={})
|
48
|
+
opts.merge!(default_options)
|
52
49
|
|
53
|
-
|
54
|
-
{size: 5}
|
55
|
-
end
|
50
|
+
suggestions = Hash.new(0.0)
|
56
51
|
|
57
|
-
|
58
|
-
|
59
|
-
|
52
|
+
set.each do |item|
|
53
|
+
related = similar_related_to(item, opts)
|
54
|
+
related.each { |rel| suggestions[rel[0]] += rel[1] unless
|
55
|
+
set.include? rel[0] }
|
56
|
+
end
|
60
57
|
|
61
|
-
|
62
|
-
|
63
|
-
cleaned.delete(main)
|
64
|
-
cleaned
|
58
|
+
suggestions = suggestions.map { |label, score| [label, score / set.length] }
|
59
|
+
suggestions.sort_by { |sug| sug[1] }.reverse
|
65
60
|
end
|
66
61
|
|
62
|
+
private
|
67
63
|
|
68
|
-
|
69
|
-
|
70
|
-
def invert_collection
|
71
|
-
results = {}
|
72
|
-
|
73
|
-
collection.keys.each do |main|
|
74
|
-
collection[main].keys.each do |item|
|
75
|
-
results[item] ||= {}
|
76
|
-
results[item][main] = collection[main][item]
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
results
|
64
|
+
def default_options
|
65
|
+
{size: 5}
|
81
66
|
end
|
82
67
|
|
83
|
-
def order_by_similarity_score(main,collection)
|
68
|
+
def order_by_similarity_score(main, collection)
|
84
69
|
result = collection.keys.inject({}) do |res, other|
|
85
70
|
res.merge!({other => similarity_score(main, other)})
|
86
71
|
end
|
87
72
|
end
|
88
|
-
|
89
|
-
def already_has?(main, related)
|
90
|
-
collection[main].has_key?(related)
|
91
|
-
end
|
92
73
|
|
93
|
-
def values_for(id)
|
94
|
-
collection[id.to_s]
|
95
|
-
end
|
96
|
-
|
97
|
-
def related_keys_for(id)
|
98
|
-
values_for(id).keys
|
99
|
-
end
|
100
|
-
|
101
74
|
def add_to_totals(other, item, score)
|
102
|
-
@totals[item] += collection[other][item]*score
|
75
|
+
@totals[item] += @collection[other][item] * score
|
103
76
|
@similarities[item] += score
|
104
77
|
end
|
105
78
|
|
@@ -123,23 +96,19 @@ module Suggestor
|
|
123
96
|
score > 0
|
124
97
|
end
|
125
98
|
|
126
|
-
def same_item?(main, other)
|
127
|
-
other == main
|
128
|
-
end
|
129
|
-
|
130
99
|
def create_similarities_totals(main)
|
131
100
|
|
132
|
-
collection.keys.each do |other|
|
101
|
+
@collection.keys.each do |other|
|
133
102
|
|
134
|
-
next if
|
103
|
+
next if other == main
|
135
104
|
|
136
105
|
score = similarity_score(main, other)
|
137
106
|
|
138
107
|
next unless something_in_common?(score)
|
139
108
|
|
140
|
-
collection[other].keys.each do |item|
|
109
|
+
@collection[other].keys.each do |item|
|
141
110
|
|
142
|
-
unless already_has?(main, item)
|
111
|
+
unless @collection.already_has?(main, item)
|
143
112
|
add_to_totals(other, item, score)
|
144
113
|
end
|
145
114
|
|
@@ -152,4 +121,4 @@ module Suggestor
|
|
152
121
|
|
153
122
|
end
|
154
123
|
end
|
155
|
-
end
|
124
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Suggestor
|
4
|
+
module Algorithms
|
5
|
+
class Records < DelegateClass(Hash)
|
6
|
+
|
7
|
+
def initialize(hash)
|
8
|
+
super(hash)
|
9
|
+
end
|
10
|
+
|
11
|
+
def dup
|
12
|
+
Marshal.load(Marshal.dump(self))
|
13
|
+
end
|
14
|
+
|
15
|
+
def remove(item)
|
16
|
+
cleaned = self.dup
|
17
|
+
cleaned.delete(item)
|
18
|
+
cleaned
|
19
|
+
end
|
20
|
+
|
21
|
+
def common_items(first, other)
|
22
|
+
values_for(first) && values_for(other)
|
23
|
+
end
|
24
|
+
|
25
|
+
def already_has?(main, related)
|
26
|
+
self[main].has_key?(related)
|
27
|
+
end
|
28
|
+
|
29
|
+
def values_for(id)
|
30
|
+
self[id.to_s]
|
31
|
+
end
|
32
|
+
|
33
|
+
def related_keys_for(id)
|
34
|
+
values_for(id).keys
|
35
|
+
end
|
36
|
+
|
37
|
+
def shared_items(first, other)
|
38
|
+
return [] unless common_items(first, other)
|
39
|
+
|
40
|
+
related_keys_for(first).select do |item|
|
41
|
+
related_keys_for(other).include? item
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def nothing_shared?(first, second)
|
46
|
+
shared_items(first, second).empty?
|
47
|
+
end
|
48
|
+
|
49
|
+
def inverse_of_squares(first, second)
|
50
|
+
1/(1+Math.sqrt(sum_squares(first, second)))
|
51
|
+
end
|
52
|
+
|
53
|
+
def sum_squares(first, second)
|
54
|
+
shared_items(first, second).inject(0.0) do |sum, item|
|
55
|
+
sum + ( values_for(first)[item] - values_for(second)[item] ) ** 2
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# changes { "Cat": {"1": 10, "2":20}, "Dog": {"1":5, "2": 15} }
|
60
|
+
# to {"1": {"Cat": 10, "Dog": 5}, "2": {"Cat": 20, "Dog": 15}
|
61
|
+
def invert
|
62
|
+
results = {}
|
63
|
+
|
64
|
+
self.keys.each do |main|
|
65
|
+
self[main].keys.each do |item|
|
66
|
+
results[item] ||= {}
|
67
|
+
results[item][main] = self[main][item]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
results
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/suggestor/version.rb
CHANGED
data/test/suggestor_test.rb
CHANGED
@@ -1,21 +1,37 @@
|
|
1
1
|
require 'minitest/autorun'
|
2
2
|
require_relative '../lib/suggestor'
|
3
3
|
|
4
|
-
describe Suggestor::
|
4
|
+
describe Suggestor::Suggestor do
|
5
5
|
before do
|
6
6
|
@data_string = File.read("test/numbers.json")
|
7
7
|
end
|
8
8
|
|
9
9
|
describe "when loading up the data structure" do
|
10
10
|
it "must raise an exception with invalid data" do
|
11
|
-
lambda{ Suggestor::
|
11
|
+
lambda{ Suggestor::Suggestor.new("GIBBERISH") }.must_raise Suggestor::WrongInputFormat
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
describe "when using a hash object for loading" do
|
16
|
+
|
17
|
+
before do
|
18
|
+
@data_string = File.read("test/numbers.json")
|
19
|
+
@data = JSON.parse(@data_string)
|
20
|
+
@suggestor = Suggestor::Suggestor.new(@data)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "must return similar items from the base one with euclidean distance" do
|
24
|
+
expected = [["3", 0.14285714285714285], ["2", 0.14285714285714285]]
|
25
|
+
@suggestor.similar_to("1").must_be :==, expected
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
end
|
30
|
+
|
15
31
|
describe "when accesing the data after load_dataing it" do
|
16
32
|
|
17
33
|
before do
|
18
|
-
@suggestor = Suggestor::
|
34
|
+
@suggestor = Suggestor::Suggestor.new(@data_string)
|
19
35
|
end
|
20
36
|
|
21
37
|
it "must return similar items from the base one with euclidean distance" do
|
@@ -24,7 +40,7 @@ require_relative '../lib/suggestor'
|
|
24
40
|
end
|
25
41
|
|
26
42
|
it "must return similar items from the base one with pearson correlation" do
|
27
|
-
@suggestor = Suggestor::
|
43
|
+
@suggestor = Suggestor::Suggestor.new(@data_string,Suggestor::Algorithms::PearsonCorrelation)
|
28
44
|
expected = [["2", 0.0], ["1", 0.0]]
|
29
45
|
@suggestor.similar_to("3").must_be :==, expected
|
30
46
|
end
|
@@ -39,5 +55,10 @@ require_relative '../lib/suggestor'
|
|
39
55
|
@suggestor.similar_related_to("2").must_be :==, expected
|
40
56
|
end
|
41
57
|
|
58
|
+
it "must return items that might follow a sequence" do
|
59
|
+
expected = [["5", 0.29166666666666663], ["3", 0.29166666666666663], ["4", 0.16666666666666666]]
|
60
|
+
@suggestor.items_for_set(['1', '2']).must_be :==, expected
|
61
|
+
end
|
62
|
+
|
42
63
|
end
|
43
|
-
end
|
64
|
+
end
|
metadata
CHANGED
@@ -1,38 +1,39 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: suggestor
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.8
|
4
5
|
prerelease:
|
5
|
-
version: 0.0.6
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Alvaro Pereyra
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2014-04-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
16
15
|
name: rake
|
17
|
-
|
18
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
19
17
|
none: false
|
20
|
-
requirements:
|
21
|
-
- -
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version:
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
24
22
|
type: :runtime
|
25
|
-
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
26
30
|
description: Suggestor allows you to get suggestions of related items in your data
|
27
|
-
email:
|
31
|
+
email:
|
28
32
|
- alvaro@xendacentral.com
|
29
33
|
executables: []
|
30
|
-
|
31
34
|
extensions: []
|
32
|
-
|
33
35
|
extra_rdoc_files: []
|
34
|
-
|
35
|
-
files:
|
36
|
+
files:
|
36
37
|
- .gitignore
|
37
38
|
- Gemfile
|
38
39
|
- README.md
|
@@ -42,7 +43,7 @@ files:
|
|
42
43
|
- lib/suggestor/algorithms/euclidean_distance.rb
|
43
44
|
- lib/suggestor/algorithms/pearson_correlation.rb
|
44
45
|
- lib/suggestor/algorithms/recommendation_algorithm.rb
|
45
|
-
- lib/suggestor/
|
46
|
+
- lib/suggestor/algorithms/records.rb
|
46
47
|
- lib/suggestor/version.rb
|
47
48
|
- suggestor.gemspec
|
48
49
|
- test/euclidean_test.rb
|
@@ -50,34 +51,31 @@ files:
|
|
50
51
|
- test/numbers.json
|
51
52
|
- test/pearson_correlation.rb
|
52
53
|
- test/suggestor_test.rb
|
53
|
-
homepage:
|
54
|
+
homepage: ''
|
54
55
|
licenses: []
|
55
|
-
|
56
56
|
post_install_message:
|
57
57
|
rdoc_options: []
|
58
|
-
|
59
|
-
require_paths:
|
58
|
+
require_paths:
|
60
59
|
- lib
|
61
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
61
|
none: false
|
63
|
-
requirements:
|
64
|
-
- -
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
version:
|
67
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
67
|
none: false
|
69
|
-
requirements:
|
70
|
-
- -
|
71
|
-
- !ruby/object:Gem::Version
|
72
|
-
version:
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
73
72
|
requirements: []
|
74
|
-
|
75
73
|
rubyforge_project: suggestor
|
76
|
-
rubygems_version: 1.8.
|
74
|
+
rubygems_version: 1.8.23.2
|
77
75
|
signing_key:
|
78
76
|
specification_version: 3
|
79
77
|
summary: Suggestor allows you to get suggestions of related items in your data
|
80
|
-
test_files:
|
78
|
+
test_files:
|
81
79
|
- test/euclidean_test.rb
|
82
80
|
- test/movies.json
|
83
81
|
- test/numbers.json
|
data/lib/suggestor/engine.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
module Suggestor
|
4
|
-
|
5
|
-
class WrongInputFormat < Exception; end
|
6
|
-
|
7
|
-
class Engine
|
8
|
-
|
9
|
-
def initialize(input, algorithm = Algorithms::EuclideanDistance)
|
10
|
-
@collection = parse_from_json(input)
|
11
|
-
@algorithm = algorithm.new(@collection)
|
12
|
-
end
|
13
|
-
|
14
|
-
def similar_to(item, opts={})
|
15
|
-
@algorithm.similar_to(item, opts)
|
16
|
-
end
|
17
|
-
|
18
|
-
def recommended_to(item, opts={})
|
19
|
-
@algorithm.recommended_to(item, opts)
|
20
|
-
end
|
21
|
-
|
22
|
-
def similar_related_to(item, opts={})
|
23
|
-
@algorithm.similar_related_to(item, opts)
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def parse_from_json(json)
|
29
|
-
JSON.parse(json)
|
30
|
-
rescue Exception => ex
|
31
|
-
raise WrongInputFormat, "Wrong Data format: #{ex.message}"
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|