measurable 0.0.5 → 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.
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