loess 0.0.4 → 1.0.0

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: 57c70d6636f7fd381261a7af28fdb5a0765e8bc0
4
- data.tar.gz: c76458cf22700ecfbadad9582c9ae16a2f19d3b7
3
+ metadata.gz: 505e1cc10dcad7f56fd80a8743e51bf27c188a19
4
+ data.tar.gz: 2162e9cbf0faef7811692fa24e7523b4cc79fce7
5
5
  SHA512:
6
- metadata.gz: ea7dc5e99f00a2db6ceafc44f624e303b0c11a29f1beedb58e960fc66c56f766d52c5b2bb188387e08d376fd0260646ce82d711a178de989c866f165f69ef370
7
- data.tar.gz: 06fc4e3dab6612eeff5085d30ba2e850a0df7a62486cb1e4298d76e049e04df1c119863e8f648f9fa8a33d03f81d711faf64be4a0df6da51455c61721dc8823a
6
+ metadata.gz: c90e2002e56320470697d39a661dd8142bd347485c7404a1434adc087df3f2813aa8bfbb4416852c6dd5c94e507ee7f06c733510cb37969b598ff30293a40c98
7
+ data.tar.gz: e8b439a545b23f08e17c5e3bdf31d7255c328b4752444c0b4ec2d8afd8e4977e08ff06af854abeb4f3a0af918a52cd60ce4f52fa0ee9f27cbc6317fb9fba0401
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Loess
2
2
 
3
- Simple Loess / Lowess interpolator built in Ruby, based on Apache's [`LoessInterpolator`][1].
3
+ Simple Loess / Lowess interpolator built in Ruby, using Apache's [`LoessInterpolator`][1] through Rjb
4
4
 
5
5
  ## Installation
6
6
 
@@ -16,31 +16,41 @@ Or install it yourself as:
16
16
 
17
17
  $ gem install loess
18
18
 
19
+ ## Depencies
20
+
21
+ This gem depends on Rjb, which in turn depends on Java. [Rjb documentation][3] has more info.
22
+
19
23
  ## Usage
20
24
 
21
25
  ```Ruby
22
26
 
23
27
  data = 1000.times.map { |i| [i, rand(10_000)] }
24
28
 
25
- regression = Loess::Calculator.calculate(data)
26
- regression = Loess::Calculator.new(data).calculate
29
+ regression = Loess::Interpolator.interpolate(data)
30
+ regression = Loess::Interpolator.new(data).interpolate
27
31
 
28
32
  # Change your settings
29
33
 
30
- calculator = Loess::Calculator.new(data)
31
- calculator.bandwidth = 0.2
32
- calculator.robustness_factor = 10 # Go crazy
33
- calculator.calculate
34
+ interpolator = Loess::Interpolator.new(data)
35
+ interpolator.bandwidth = 0.2
36
+ interpolator.robustness_factor = 10 # Go crazy
37
+ interpolator.interpolate
34
38
 
35
39
  # Pass in settings through initialize
36
- calculator = Loess::Calculator.new(data, bandwidth: 0.2, accuracy: 1e-10)
37
- calculator.calculate
40
+ interpolator = Loess::Interpolator.new(data, bandwidth: 0.2, accuracy: 1e-10)
41
+ interpolator.interpolate
38
42
 
43
+ # Get a Spline Interpolator object
44
+ # Returns an instance of PolynomialSplineFunction, smoothed with the given data
45
+ # More documentation at [Apache Commons Maths][2]
46
+ interpolator.spline_interpolator
39
47
 
40
48
  ```
41
49
 
42
50
  ## Contributing
43
51
 
52
+ At this moment, there is little to contribute, but still:
53
+
44
54
  1. Fork it ( https://github.com/swanandp/loess.rb/fork )
45
55
  2. Create your feature branch (`git checkout -b my-new-feature`)
46
56
  3. Commit your changes (`git commit -am 'Add some feature'`)
@@ -48,4 +58,6 @@ calculator.calculate
48
58
  5. Create a new Pull Request
49
59
 
50
60
 
51
- [1]: http://commons.apache.org/proper/commons-math/jacoco/org.apache.commons.math3.analysis.interpolation/LoessInterpolator.java.html
61
+ [1]: http://commons.apache.org/proper/commons-math/jacoco/org.apache.commons.math3.analysis.interpolation/LoessInterpolator.java.html
62
+ [2]: http://commons.apache.org/proper/commons-math/jacoco/org.apache.commons.math3.analysis.polynomials/PolynomialSplineFunction.java.html
63
+ [3]: https://github.com/arton/rjb
data/lib/loess.rb CHANGED
@@ -1,10 +1,9 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ require 'rjb'
3
+ Rjb::add_jar(File.join(File.expand_path('../../', __FILE__), 'vendor', 'apache', 'commons-math3-3.3.jar').to_s)
2
4
 
3
- # A Ruby Port of Apache's LoessInterpolator
4
- # http://commons.apache.org/proper/commons-math/jacoco/org.apache.commons.math3.analysis.interpolation/LoessInterpolator.java.html
5
- #
6
5
  module Loess
7
- class Calculator
6
+ class Interpolator
8
7
  attr_accessor :data, :bandwidth, :robustness_factor, :accuracy
9
8
  # Sane Defaults as per Apache
10
9
  DEFAULT_ACCURACY = 1e-12
@@ -16,125 +15,31 @@ module Loess
16
15
  # For options, refer to defaults above
17
16
  def initialize(data = [], options = {})
18
17
  @xval, @yval = split_up(data)
19
- self.accuracy = options[:accuracy] || DEFAULT_ACCURACY
20
- self.bandwidth = options[:bandwidth] || DEFAULT_BANDWIDTH
21
- self.robustness_factor = options[:robustness_factor] || DEFAULT_ROBUSTNESS_FACTOR
18
+ self.accuracy = Float(options[:accuracy] || DEFAULT_ACCURACY)
19
+ self.bandwidth = Float(options[:bandwidth] || DEFAULT_BANDWIDTH)
20
+ self.robustness_factor = Integer(options[:robustness_factor] || DEFAULT_ROBUSTNESS_FACTOR)
21
+ @klass = Rjb::import('org.apache.commons.math3.analysis.interpolation.LoessInterpolator')
22
+ @interpolator = @klass.new(bandwidth, robustness_factor, accuracy)
22
23
  end
23
24
 
24
25
  # Accepts array of [x, y] pairs
25
26
  # e.g. [ [1, 2], [3, 4], [5, 6], [0, 42] ]
26
- def calculate(data = nil)
27
+ def interpolate(data = nil)
27
28
  @xval, @yval = split_up(data) if data
28
- smooth(@xval, @yval)
29
+ @interpolator.smooth(@xval, @yval)
29
30
  end
30
31
 
31
- def smooth(xval, yval, weights = [])
32
- xlength = xval.length
33
- return unless xlength > 0 && xlength == yval.length
34
- return yval if xlength == 1 || xlength == 2
35
- bandwidth_in_points = (bandwidth * xlength).to_i
36
- fail "bandwidth is way too small" if bandwidth_in_points < 2
37
- weights = Array(weights).length > 0 ? weights : [1.0] * xlength
38
-
39
- result = []
40
- residuals = []
41
- robustness_weights = [1] * xlength
42
-
43
- robustness_factor.times do |factor|
44
- xval.each_with_index do |x, i|
45
- bandwidth_interval = [0, bandwidth_in_points - 1]
46
- update_bandwidth_interval(xval, weights, i, bandwidth_interval) if i > 0
47
- ileft, iright = bandwidth_interval
48
- edge = if xval[i] - xval[ileft] > xval[iright] - xval[i]
49
- ileft
50
- else
51
- iright
52
- end
53
-
54
- sum_weights = 0
55
- sum_x = 0
56
- sum_x_squared = 0
57
- sum_y = 0
58
- sum_xy = 0
59
- denom = (1.0 / (xval[edge] - x)).abs
60
-
61
- xval[ileft..iright].each_with_index do |xk, k|
62
- next unless xk
63
- yk = yval[k]
64
- dist = (k < i) ? x - xk : xk - x
65
- w = tricube(dist * denom) * robustness_weights[k] * weights[k]
66
- xkw = xk * w
67
-
68
- # Intentionally avoiding multiple reduce calls here
69
- # On large data-sets, this severly impacts performance
70
- sum_weights += w
71
- sum_x += xkw
72
- sum_x_squared += xk * xkw
73
- sum_y += yk * w
74
- sum_xy += yk * xkw
75
- end
76
-
77
- mean_x = sum_x / sum_weights
78
- mean_y = sum_y / sum_weights
79
- mean_xy = sum_xy / sum_weights
80
- mean_x_squared = sum_x_squared / sum_weights
81
-
82
- beta = if Math.sqrt((mean_x_squared - mean_x * mean_x).abs) < accuracy
83
- 0
84
- else
85
- (mean_xy - mean_x * mean_y) / (mean_x_squared - mean_x * mean_x)
86
- end
87
-
88
- alpha = mean_y - beta * mean_x
89
- result[i] = beta * x + alpha
90
- residuals[i] = (yval[i] - result[i]).abs
91
- end
92
-
93
- break if factor == robustness_factor - 1
94
-
95
- sorted_residuals = residuals.sort
96
- median_residual = sorted_residuals[xlength / 2]
97
-
98
- break if median_residual.abs < accuracy
99
-
100
- xlength.times do |i|
101
- arg = residuals[i] / (6 * median_residual)
102
- if arg >= 1
103
- robustness_weights[i] = 0
104
- else
105
- robustness_weights[i] = (1 - arg * arg) ** 2
106
- end
107
- end
108
- end
109
- result
110
- end
111
-
112
- # http://en.wikipedia.org/wiki/Local_regression#Weight_function
113
- def tricube(x)
114
- (1 - x.abs ** 3) ** 3
115
- end
116
-
117
- def update_bandwidth_interval(xval, weights, i, bandwith_interval)
118
- left, right = bandwith_interval
119
- next_right = next_non_zero(weights, right)
120
- if next_right < xval.length &&
121
- xval[next_right] - xval[i] < xval[i] - xval[left]
122
- next_left = next_non_zero(weights, left)
123
- bandwith_interval[0] = next_left
124
- bandwith_interval[1] = next_right
125
- end
126
- end
127
-
128
- def next_non_zero(collection, index)
129
- collection.each_with_index.detect { |el, i|
130
- i > index && !el.zero?
131
- }[1]
32
+ # Accepts array of [x, y] pairs
33
+ # e.g. [ [1, 2], [3, 4], [5, 6], [0, 42] ]
34
+ def spline_interpolator(data = nil)
35
+ @xval, @yval = split_up(data) if data
36
+ @interpolator.interpolator(@xval, smooth(@xval, @yval))
132
37
  end
133
38
 
134
39
  # Accepts array of [x, y] pairs
135
40
  # e.g. [ [1, 2], [3, 4], [5, 6], [0, 42] ]
136
- def self.calculate(data)
137
- new(data).calculate
41
+ def self.interpolate(data, options = {})
42
+ new(data, options).interpolate
138
43
  end
139
44
 
140
45
  private
data/lib/loess/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Loess
2
- VERSION = "0.0.4"
2
+ VERSION = "1.0.0"
3
3
  end
data/loess.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Loess::VERSION
9
9
  spec.authors = ["Swanand Pagnis"]
10
10
  spec.email = ["swanand.pagnis@gmail.com"]
11
- spec.summary = %q{A Simple LOESS / LOWESS calculator built in Ruby}
11
+ spec.summary = %q{A Simple LOESS / LOWESS calculator built in Ruby, using Apache Commons Math through Rjb}
12
12
  spec.description = %q{Perfect if you want to plot a line graph or scatter plot and a loess regression}
13
13
  spec.homepage = "https://github.com/swanandp/loess.rb"
14
14
  spec.license = "MIT"
@@ -20,4 +20,6 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.6"
22
22
  spec.add_development_dependency "rake"
23
+
24
+ spec.add_runtime_dependency "rjb"
23
25
  end
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loess
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Swanand Pagnis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-05 00:00:00.000000000 Z
11
+ date: 2014-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rjb
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  description: Perfect if you want to plot a line graph or scatter plot and a loess
42
56
  regression
43
57
  email:
@@ -55,6 +69,7 @@ files:
55
69
  - lib/loess.rb
56
70
  - lib/loess/version.rb
57
71
  - loess.gemspec
72
+ - vendor/apache/commons-math3-3.3.jar
58
73
  homepage: https://github.com/swanandp/loess.rb
59
74
  licenses:
60
75
  - MIT
@@ -78,5 +93,6 @@ rubyforge_project:
78
93
  rubygems_version: 2.2.2
79
94
  signing_key:
80
95
  specification_version: 4
81
- summary: A Simple LOESS / LOWESS calculator built in Ruby
96
+ summary: A Simple LOESS / LOWESS calculator built in Ruby, using Apache Commons Math
97
+ through Rjb
82
98
  test_files: []