loess 0.0.4 → 1.0.0

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: 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: []