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 +4 -4
- data/README.md +22 -10
- data/lib/loess.rb +17 -112
- data/lib/loess/version.rb +1 -1
- data/loess.gemspec +3 -1
- data/vendor/apache/commons-math3-3.3.jar +0 -0
- metadata +19 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 505e1cc10dcad7f56fd80a8743e51bf27c188a19
|
|
4
|
+
data.tar.gz: 2162e9cbf0faef7811692fa24e7523b4cc79fce7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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,
|
|
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::
|
|
26
|
-
regression = Loess::
|
|
29
|
+
regression = Loess::Interpolator.interpolate(data)
|
|
30
|
+
regression = Loess::Interpolator.new(data).interpolate
|
|
27
31
|
|
|
28
32
|
# Change your settings
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
37
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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.
|
|
137
|
-
new(data).
|
|
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
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
|
+
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-
|
|
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: []
|