measurable 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 66337383a6c25685893bb39f7caf5c7f0b40bcff
4
- data.tar.gz: 117a22bb28b1d36f14780d3a22bbad7211b279a0
3
+ metadata.gz: 8e94547914fc6532f23f86d4d8118100aad64398
4
+ data.tar.gz: f5eae04dfb5c5b2e041d59527921be80ba1b27bc
5
5
  SHA512:
6
- metadata.gz: 0d7aff51213d2f0ca31472d1d5f43b3ce99d58255b9d3d53485b0983e953866a365927734c1852c7040f7c23149455712af6357679e03ff63bf247709ac7e124
7
- data.tar.gz: 652066925d87d7d52656f87346c856d34296e4a98662e94a670d72e9612c568dd95bf758314c524501700b21b53484eaaf059e5b5fee315129fb1b0b90a170bd
6
+ metadata.gz: 8992dfff181353a0feb8d893f90c4705572f2706e158e6ee51f6d398c31ddd0b39f8f1153c123252eb064213984c11ec6d98cf720814065973a3d5a59884ebe7
7
+ data.tar.gz: 8643ac26d9471a6e1a78ca9b25c684196ad7fd61d7f930b0d2242b9d68d7b857ff7dd5c49da667517fd7a9ebf4593528947ebbb812ef9045026d381b5b76f978
data/Gemfile.lock CHANGED
@@ -1,13 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- measurable (0.0.5)
4
+ measurable (0.0.6)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
8
8
  specs:
9
9
  diff-lcs (1.1.3)
10
- rake (0.9.2.2)
10
+ rake (0.9.6)
11
11
  rspec (2.9.0)
12
12
  rspec-core (~> 2.9.0)
13
13
  rspec-expectations (~> 2.9.0)
data/README.md CHANGED
@@ -27,13 +27,12 @@ The following are the similarity measures supported at the moment:
27
27
  - Jaccard distance
28
28
  - Tanimoto distance
29
29
  - Haversine distance
30
+ - Minkowski (Cityblock or Manhattan) distance
31
+ - Chebyshev distance
32
+ - Hamming distance
30
33
 
31
34
  These still need to be implemented:
32
35
 
33
- - Cityblock distance
34
- - Chebyshev distance
35
- - Minkowski distance
36
- - Hamming distance
37
36
  - Correlation distance
38
37
  - Chi-square distance
39
38
  - Kullback-Leibler divergence
@@ -41,6 +40,8 @@ These still need to be implemented:
41
40
  - Mahalanobis distance
42
41
  - Squared Mahalanobis distance
43
42
 
43
+ I plan to update the specs to reflect that each method is (or isn't) a mathematical metric, but I want to finish implementing them first. Any help is appreciated! :)
44
+
44
45
  ## How to use
45
46
 
46
47
  The API I intend to support is something like this:
data/lib/measurable.rb CHANGED
@@ -2,11 +2,14 @@ require 'measurable/version'
2
2
 
3
3
  # Distance measures. The require order is important.
4
4
  require 'measurable/euclidean'
5
+ require 'measurable/minkowski'
5
6
  require 'measurable/cosine'
6
7
  require 'measurable/jaccard'
7
8
  require 'measurable/tanimoto'
8
- require 'measurable/haversine'
9
+ require 'measurable/chebyshev'
9
10
  require 'measurable/maxmin'
11
+ require 'measurable/haversine'
12
+ require 'measurable/hamming'
10
13
 
11
14
  module Measurable
12
15
  # PI / 180 degrees.
@@ -0,0 +1,23 @@
1
+ module Measurable
2
+
3
+ # call-seq:
4
+ # chebyshev(u, v) -> Float
5
+ #
6
+ #
7
+ #
8
+ # * *Arguments* :
9
+ # - +u+ -> An array of Numeric objects.
10
+ # - +v+ -> An array of Numeric objects.
11
+ # * *Returns* :
12
+ # - The L-infinite distance between +u+ and +v+.
13
+ # * *Raises* :
14
+ # - +ArgumentError+ -> The sizes of +u+ and +v+ don't match.
15
+ #
16
+ def chebyshev(u, v)
17
+ # TODO: Change this to a more specific, custom-made exception.
18
+ raise ArgumentError if u.size != v.size
19
+
20
+ abs_differences = u.zip(v).map { |a| (a[0] - a[1]).abs }
21
+ abs_differences.max
22
+ end
23
+ end
@@ -14,7 +14,7 @@ module Measurable
14
14
  # - The normalized dot product of +u+ and +v+, that is, the angle between
15
15
  # them in the n-dimensional space.
16
16
  # * *Raises* :
17
- # - +ArgumentError+ -> The sizes of +u+ and +v+ doesn't match.
17
+ # - +ArgumentError+ -> The sizes of +u+ and +v+ don't match.
18
18
  #
19
19
  def cosine(u, v)
20
20
  # TODO: Change this to a more specific, custom-made exception.
@@ -17,7 +17,7 @@ module Measurable
17
17
  # - The euclidean norm of +u+ or the euclidean distance between +u+ and
18
18
  # +v+.
19
19
  # * *Raises* :
20
- # - +ArgumentError+ -> The sizes of +u+ and +v+ doesn't match.
20
+ # - +ArgumentError+ -> The sizes of +u+ and +v+ don't match.
21
21
  #
22
22
  def euclidean(u, v = nil)
23
23
  # If the second argument is nil, the method should return the norm of
@@ -57,7 +57,7 @@ module Measurable
57
57
  # - The squared value of the euclidean norm of +u+ or of the euclidean
58
58
  # distance between +u+ and +v+.
59
59
  # * *Raises* :
60
- # - +ArgumentError+ -> The sizes of +u+ and +v+ doesn't match.
60
+ # - +ArgumentError+ -> The sizes of +u+ and +v+ don't match.
61
61
  #
62
62
  def euclidean_squared(u, v = nil)
63
63
  # If the second argument is nil, the method should return the norm of
@@ -0,0 +1,27 @@
1
+ module Measurable
2
+
3
+ # call-seq:
4
+ # hamming(s1, s2) -> Integer
5
+ #
6
+ #
7
+ #
8
+ # See: http://en.wikipedia.org/wiki/Cosine_similarity
9
+ #
10
+ # * *Arguments* :
11
+ # - +s1+ -> A String.
12
+ # - +s2+ -> A String with the same size of +s1+.
13
+ # * *Returns* :
14
+ # - The number of characters in which +s1+ and +s2+ differ.
15
+ # * *Raises* :
16
+ # - +ArgumentError+ -> The sizes of +s1+ and +s2+ don't match.
17
+ #
18
+ def hamming(s1, s2)
19
+ # TODO: Change this to a more specific, custom-made exception.
20
+ raise ArgumentError if s1.size != s2.size
21
+
22
+ s1.chars.zip(s2.chars).reduce(0) do |acc, c|
23
+ acc += 1 if c[0] != c[1]
24
+ acc
25
+ end
26
+ end
27
+ end
@@ -17,7 +17,7 @@ module Measurable
17
17
  # * *Returns* :
18
18
  # - Similarity between +u+ and +v+.
19
19
  # * *Raises* :
20
- # - +ArgumentError+ -> The sizes of +u+ and +v+ doesn't match.
20
+ # - +ArgumentError+ -> The sizes of +u+ and +v+ don't match.
21
21
  #
22
22
  def maxmin(u, v)
23
23
  # TODO: Change this to a more specific, custom-made exception.
@@ -0,0 +1,28 @@
1
+ module Measurable
2
+
3
+ # call-seq:
4
+ # minkowski(u, v) -> Numeric
5
+ #
6
+ # Calculate the sum of the absolute value of the differences between each
7
+ # coordinate of +u+ and +v+.
8
+ #
9
+ # * *Arguments* :
10
+ # - +u+ -> An array of Numeric objects.
11
+ # - +v+ -> An array of Numeric objects.
12
+ # * *Returns* :
13
+ # - The Minkowski (or L1) distance between +u+ and +v+.
14
+ # * *Raises* :
15
+ # - +ArgumentError+ -> The sizes of +u+ and +v+ don't match.
16
+ #
17
+ def minkowski(u, v)
18
+ # TODO: Change this to a more specific, custom-made exception.
19
+ raise ArgumentError if u.size != v.size
20
+
21
+ u.zip(v).reduce(0) do |acc, elem|
22
+ acc += (elem[0] - elem[1]).abs
23
+ end
24
+ end
25
+
26
+ alias :cityblock :minkowski
27
+ alias :manhattan :minkowski
28
+ end
@@ -21,7 +21,7 @@ module Measurable
21
21
  # * *Returns* :
22
22
  # - A measure of the similarity between +u+ and +v+.
23
23
  # * *Raises* :
24
- # - +ArgumentError+ -> The sizes of +u+ and +v+ doesn't match.
24
+ # - +ArgumentError+ -> The sizes of +u+ and +v+ don't match.
25
25
  #
26
26
  def tanimoto(u, v)
27
27
  # TODO: Change this to a more specific, custom-made exception.
@@ -1,3 +1,3 @@
1
1
  module Measurable
2
- VERSION = "0.0.5" # :nodoc:
2
+ VERSION = "0.0.6" # :nodoc:
3
3
  end
data/measurable.gemspec CHANGED
@@ -4,12 +4,13 @@ require 'measurable/version'
4
4
  require 'date'
5
5
 
6
6
  Gem::Specification.new do |gem|
7
- gem.name = "measurable"
7
+ gem.name = "measurable"
8
8
  gem.version = Measurable::VERSION
9
9
  gem.date = Date.today.to_s
10
+ gem.license = "MIT"
10
11
  gem.summary = %Q{A Ruby gem with a lot of distance measures for your projects.}
11
12
  gem.description = %Q{A Ruby gem with a lot of distance measures for your projects.}
12
-
13
+
13
14
  gem.authors = ["Carlos Agarie"]
14
15
  gem.email = "carlos.agarie@gmail.com"
15
16
  gem.homepage = "http://github.com/agarie/measurable"
@@ -0,0 +1,29 @@
1
+ describe "Chebyshev distance" do
2
+
3
+ before :all do
4
+ @u = [1.4, 2.5, 5.8]
5
+ @v = [2.2, 3.6, 2.7]
6
+ @w = [4.1, 5.7, 1.2]
7
+ end
8
+
9
+ it "accepts two arguments" do
10
+ expect { Measurable.chebyshev(@u, @v) }.to_not raise_error
11
+ expect { Measurable.chebyshev(@u, @v, @w) }.to raise_error(ArgumentError)
12
+ end
13
+
14
+ it "should be symmetric" do
15
+ x = Measurable.chebyshev(@u, @v)
16
+ y = Measurable.chebyshev(@v, @u)
17
+
18
+ x.should be_within(TOLERANCE).of(y)
19
+ end
20
+
21
+ it "should return the correct value" do
22
+ x = Measurable.chebyshev(@u, @v)
23
+ x.should be_within(TOLERANCE).of(3.1)
24
+ end
25
+
26
+ it "shouldn't work with vectors of different length" do
27
+ expect { Measurable.chebyshev(@u, [1, 3, 5, 7]) }.to raise_error(ArgumentError)
28
+ end
29
+ end
data/spec/cosine_spec.rb CHANGED
@@ -1,16 +1,16 @@
1
1
  describe "Cosine distance" do
2
-
2
+
3
3
  before :all do
4
4
  @u = [1, 2]
5
5
  @v = [2, 3]
6
6
  @w = [4, 5]
7
7
  end
8
-
8
+
9
9
  it "accepts two arguments" do
10
10
  expect { Measurable.cosine(@u, @v) }.to_not raise_error
11
11
  expect { Measurable.cosine(@u, @v, @w) }.to raise_error(ArgumentError)
12
12
  end
13
-
13
+
14
14
  it "should be symmetric" do
15
15
  x = Measurable.cosine(@u, @v)
16
16
  y = Measurable.cosine(@v, @u)
@@ -24,6 +24,6 @@ describe "Cosine distance" do
24
24
  end
25
25
 
26
26
  it "shouldn't work with vectors of different length" do
27
- expect { Measurable.cosine(@u, [1, 3, 5, 7]) }.to raise_error
27
+ expect { Measurable.cosine(@u, [1, 3, 5, 7]) }.to raise_error(ArgumentError)
28
28
  end
29
29
  end
@@ -1,22 +1,22 @@
1
1
  describe "Euclidean" do
2
-
2
+
3
3
  before :all do
4
4
  @u = [1, 3, 16]
5
5
  @v = [1, 4, 16]
6
6
  @w = [4, 5, 6]
7
7
  end
8
-
8
+
9
9
  context "Distance" do
10
10
  it "accepts two arguments" do
11
11
  expect { Measurable.euclidean(@u, @v) }.to_not raise_error
12
12
  expect { Measurable.euclidean(@u, @v, @w) }.to raise_error(ArgumentError)
13
13
  end
14
-
14
+
15
15
  it "accepts one argument and returns the vector's norm" do
16
16
  # Remember that 3^2 + 4^2 = 5^2.
17
17
  Measurable.euclidean([3, 4]).should == 5
18
18
  end
19
-
19
+
20
20
  it "should be symmetric" do
21
21
  Measurable.euclidean(@u, @v).should == Measurable.euclidean(@v, @u)
22
22
  end
@@ -25,27 +25,27 @@ describe "Euclidean" do
25
25
  Measurable.euclidean(@u, @u).should == 0
26
26
  Measurable.euclidean(@u, @v).should == 1
27
27
  end
28
-
28
+
29
29
  it "shouldn't work with vectors of different length" do
30
- expect { Measurable.euclidean(@u, [2, 2, 2, 2]) }.to raise_error
30
+ expect { Measurable.euclidean(@u, [2, 2, 2, 2]) }.to raise_error(ArgumentError)
31
31
  end
32
32
  end
33
-
33
+
34
34
  context "Squared Distance" do
35
35
  it "accepts two arguments" do
36
36
  expect { Measurable.euclidean_squared(@u, @v) }.to_not raise_error
37
37
  expect { Measurable.euclidean_squared(@u, @v, @w) }.to raise_error(ArgumentError)
38
38
  end
39
-
39
+
40
40
  it "accepts one argument and returns the vector's norm" do
41
41
  # Remember that 3^2 + 4^2 = 5^2.
42
42
  Measurable.euclidean_squared([3, 4]).should == 25
43
43
  end
44
-
44
+
45
45
  it "should be symmetric" do
46
46
  x = Measurable.euclidean_squared(@u, @v)
47
47
  y = Measurable.euclidean_squared(@v, @u)
48
-
48
+
49
49
  x.should == y
50
50
  end
51
51
 
@@ -53,9 +53,9 @@ describe "Euclidean" do
53
53
  Measurable.euclidean_squared(@u, @u).should == 0
54
54
  Measurable.euclidean_squared(@u, @v).should == 1
55
55
  end
56
-
56
+
57
57
  it "shouldn't work with vectors of different length" do
58
- expect { Measurable.euclidean_squared(@u, [2, 2, 2, 2]) }.to raise_error
59
- end
58
+ expect { Measurable.euclidean_squared(@u, [2, 2, 2, 2]) }.to raise_error(ArgumentError)
59
+ end
60
60
  end
61
61
  end
@@ -0,0 +1,30 @@
1
+ describe "Hamming distance" do
2
+
3
+ before :all do
4
+ @u = "Hi, I'm a test string!"
5
+ @v = "Hello, not a test omg."
6
+ @w = "Hey there, a test wtf!"
7
+ end
8
+
9
+ it "accepts two arguments" do
10
+ expect { Measurable.hamming(@u, @v) }.to_not raise_error
11
+ expect { Measurable.hamming(@u, @v, @w) }.to raise_error(ArgumentError)
12
+ end
13
+
14
+ it "should be symmetric" do
15
+ x = Measurable.hamming(@u, @v)
16
+ y = Measurable.hamming(@v, @u)
17
+
18
+ x.should be(y)
19
+ end
20
+
21
+ it "should return the correct value" do
22
+ x = Measurable.hamming(@u, @v)
23
+ x.should be(17)
24
+ end
25
+
26
+ it "shouldn't work with strings of different length" do
27
+ expect { Measurable.hamming(@u, "smallstring") }.to raise_error(ArgumentError)
28
+ expect { Measurable.hamming(@u, "largestring" * 20) }.to raise_error(ArgumentError)
29
+ end
30
+ end
@@ -32,6 +32,6 @@ describe "Haversine distance" do
32
32
  end
33
33
 
34
34
  it "should only work with [lat, long] vectors" do
35
- expect { Measurable.haversine([2, 4], [1, 3, 5, 7]) }.to raise_error
35
+ expect { Measurable.haversine([2, 4], [1, 3, 5, 7]) }.to raise_error(ArgumentError)
36
36
  end
37
37
  end
data/spec/jaccard_spec.rb CHANGED
@@ -26,7 +26,7 @@ describe "Jaccard" do
26
26
  end
27
27
 
28
28
  it "shouldn't work with vectors of different length" do
29
- expect { Measurable.jaccard_index(@u, [1, 2, 3, 4]) }.to raise_error
29
+ expect { Measurable.jaccard_index(@u, [1, 2, 3, 4]) }.to raise_error(ArgumentError)
30
30
  end
31
31
  end
32
32
 
@@ -56,7 +56,7 @@ describe "Jaccard" do
56
56
  end
57
57
 
58
58
  it "shouldn't work with vectors of different length" do
59
- expect { Measurable.jaccard(@u, [1, 2, 3, 4]) }.to raise_error
59
+ expect { Measurable.jaccard(@u, [1, 2, 3, 4]) }.to raise_error(ArgumentError)
60
60
  end
61
61
  end
62
62
  end
data/spec/maxmin_spec.rb CHANGED
@@ -25,6 +25,6 @@ describe "Max-min distance" do
25
25
  end
26
26
 
27
27
  it "shouldn't work with vectors of different length" do
28
- expect { Measurable.maxmin(@u, [1, 3, 5, 7]) }.to raise_error
28
+ expect { Measurable.maxmin(@u, [1, 3, 5, 7]) }.to raise_error(ArgumentError)
29
29
  end
30
30
  end
@@ -0,0 +1,28 @@
1
+ describe "Minkowski" do
2
+
3
+ before :all do
4
+ @u = [1, 3, 6]
5
+ @v = [1, 4, 7]
6
+ @w = [4, 5, 6]
7
+ end
8
+
9
+ context "Distance" do
10
+ it "accepts two arguments" do
11
+ expect { Measurable.minkowski(@u, @v) }.to_not raise_error
12
+ expect { Measurable.minkowski(@u, @v, @w) }.to raise_error(ArgumentError)
13
+ end
14
+
15
+ it "should be symmetric" do
16
+ Measurable.minkowski(@u, @v).should == Measurable.minkowski(@v, @u)
17
+ end
18
+
19
+ it "should return the correct value" do
20
+ Measurable.minkowski(@u, @u).should == 0
21
+ Measurable.minkowski(@u, @v).should == 2
22
+ end
23
+
24
+ it "shouldn't work with vectors of different length" do
25
+ expect { Measurable.minkowski(@u, [2, 2, 2, 2]) }.to raise_error(ArgumentError)
26
+ end
27
+ end
28
+ end
@@ -25,6 +25,6 @@ describe "Tanimoto distance" do
25
25
  end
26
26
 
27
27
  it "shouldn't work with vectors of different length" do
28
- expect { Measurable.tanimoto(@u, [1, 3, 5, 7]) }.to raise_error
28
+ expect { Measurable.tanimoto(@u, [1, 3, 5, 7]) }.to raise_error(ArgumentError)
29
29
  end
30
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: measurable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carlos Agarie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-24 00:00:00.000000000 Z
11
+ date: 2013-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,23 +66,30 @@ files:
66
66
  - README.md
67
67
  - Rakefile
68
68
  - lib/measurable.rb
69
+ - lib/measurable/chebyshev.rb
69
70
  - lib/measurable/cosine.rb
70
71
  - lib/measurable/euclidean.rb
72
+ - lib/measurable/hamming.rb
71
73
  - lib/measurable/haversine.rb
72
74
  - lib/measurable/jaccard.rb
73
75
  - lib/measurable/maxmin.rb
76
+ - lib/measurable/minkowski.rb
74
77
  - lib/measurable/tanimoto.rb
75
78
  - lib/measurable/version.rb
76
79
  - measurable.gemspec
80
+ - spec/chebyshev_spec.rb
77
81
  - spec/cosine_spec.rb
78
82
  - spec/euclidean_spec.rb
83
+ - spec/hamming_spec.rb
79
84
  - spec/haversine_spec.rb
80
85
  - spec/jaccard_spec.rb
81
86
  - spec/maxmin_spec.rb
87
+ - spec/minkowski_spec.rb
82
88
  - spec/spec_helper.rb
83
89
  - spec/tanimoto_spec.rb
84
90
  homepage: http://github.com/agarie/measurable
85
- licenses: []
91
+ licenses:
92
+ - MIT
86
93
  metadata: {}
87
94
  post_install_message:
88
95
  rdoc_options: []
@@ -100,15 +107,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
107
  version: '0'
101
108
  requirements: []
102
109
  rubyforge_project:
103
- rubygems_version: 2.0.3
110
+ rubygems_version: 2.0.6
104
111
  signing_key:
105
112
  specification_version: 4
106
113
  summary: A Ruby gem with a lot of distance measures for your projects.
107
114
  test_files:
115
+ - spec/chebyshev_spec.rb
108
116
  - spec/cosine_spec.rb
109
117
  - spec/euclidean_spec.rb
118
+ - spec/hamming_spec.rb
110
119
  - spec/haversine_spec.rb
111
120
  - spec/jaccard_spec.rb
112
121
  - spec/maxmin_spec.rb
122
+ - spec/minkowski_spec.rb
113
123
  - spec/spec_helper.rb
114
124
  - spec/tanimoto_spec.rb