loess 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9923d89f3f15891ade1a13c26a8d5c309a5a42fb
4
+ data.tar.gz: 50a119394cf1d9a374800b2d243be2a725b9d07d
5
+ SHA512:
6
+ metadata.gz: 39d48d37c35570f12955495f41c785be21d240779e7e85deac3d90536f7775f7248adb1ac6d0bef97679604dc7bd64a8c3a1f258c1267eee36a382457344ad2c
7
+ data.tar.gz: 73eb8f680e859ee0b9a254de667c6db187f9e66b9d2110f045be6836ffa99fdc08c9e6953da9b6a015ee0ea03ffd46dd936216286e5d87f9e1f1f7994a7d02ec
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in loess.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Swanand Pagnis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Swanand Pagnis
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Loess
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'loess'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install loess
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/loess/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,151 @@
1
+ # -*- encoding : utf-8 -*-
2
+
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
+ module Loess
7
+ class Calculator
8
+ attr_accessor :data, :bandwidth, :robustness_factor, :accuracy
9
+ # Sane Defaults as per Apache
10
+ DEFAULT_ACCURACY = 1e-12
11
+ DEFAULT_BANDWIDTH = 0.3 # A sensible value is usually 0.25 to 0.5
12
+ DEFAULT_ROBUSTNESS_FACTOR = 2 # number of iterations to refine over 1 or 2 is usually good enough
13
+
14
+ # data: Accepts array of [x, y] pairs
15
+ # e.g. [ [1, 2], [3, 4], [5, 6], [0, 42] ]
16
+ # For options, refer to defaults above
17
+ def initialize(data = [], options = {})
18
+ @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
22
+ end
23
+
24
+ # Accepts array of [x, y] pairs
25
+ # e.g. [ [1, 2], [3, 4], [5, 6], [0, 42] ]
26
+ def calculate(data = nil)
27
+ @xval, @yval = split_up(data) if data
28
+ smooth(@xval, @yval)
29
+ end
30
+
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 = weights.present? ? 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]
132
+ end
133
+
134
+ # Accepts array of [x, y] pairs
135
+ # e.g. [ [1, 2], [3, 4], [5, 6], [0, 42] ]
136
+ def self.calculate(data)
137
+ new(data).calculate
138
+ end
139
+
140
+ private
141
+ # Given this: [ [1, 2], [3, 4], [5, 6], ['a', 'b'] ]
142
+ # Return this: [ [1, 3, 5, 'a'], [2, 4, 6, 'b'] ]
143
+ def split_up(data)
144
+ data.reduce([[], []]) { |memo, (x, y)|
145
+ memo[0] << x
146
+ memo[1] << y
147
+ memo
148
+ }
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,3 @@
1
+ module Loess
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'loess/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "loess"
8
+ spec.version = Loess::VERSION
9
+ spec.authors = ["Swanand Pagnis"]
10
+ spec.email = ["swanand.pagnis@gmail.com"]
11
+ spec.summary = %q{A Simple LOESS / LOWESS calculator built in Ruby}
12
+ spec.description = %q{Perfect if you want to plot a line graph or scatter plot and a loess regression}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: loess
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Swanand Pagnis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Perfect if you want to plot a line graph or scatter plot and a loess
42
+ regression
43
+ email:
44
+ - swanand.pagnis@gmail.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - Gemfile
51
+ - LICENSE
52
+ - LICENSE.txt
53
+ - README.md
54
+ - Rakefile
55
+ - lib/loess.rb
56
+ - lib/loess/version.rb
57
+ - loess.gemspec
58
+ homepage: ''
59
+ licenses:
60
+ - MIT
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 2.2.2
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: A Simple LOESS / LOWESS calculator built in Ruby
82
+ test_files: []