rust 0.9 → 0.12
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/bin/ruby-rust +1 -1
- data/lib/rust/core/csv.rb +21 -0
- data/lib/rust/core/rust.rb +65 -1
- data/lib/rust/core/types/dataframe.rb +146 -0
- data/lib/rust/core/types/datatype.rb +34 -0
- data/lib/rust/core/types/factor.rb +27 -0
- data/lib/rust/core/types/language.rb +45 -12
- data/lib/rust/core/types/list.rb +16 -0
- data/lib/rust/core/types/matrix.rb +29 -6
- data/lib/rust/core/types/s4class.rb +19 -0
- data/lib/rust/core/types/utils.rb +14 -1
- data/lib/rust/external/ggplot2/core.rb +171 -0
- data/lib/rust/external/ggplot2/geoms.rb +83 -0
- data/lib/rust/external/ggplot2/helper.rb +122 -0
- data/lib/rust/external/ggplot2/plot_builder.rb +188 -0
- data/lib/rust/external/ggplot2/themes.rb +435 -0
- data/lib/rust/external/ggplot2.rb +5 -0
- data/lib/rust/external/robustbase.rb +44 -0
- data/lib/rust/models/anova.rb +17 -0
- data/lib/rust/models/regression.rb +54 -1
- data/lib/rust/plots/basic-plots.rb +32 -0
- data/lib/rust/plots/core.rb +90 -0
- data/lib/rust/plots/distribution-plots.rb +13 -0
- data/lib/rust/stats/correlation.rb +43 -0
- data/lib/rust/stats/descriptive.rb +29 -0
- data/lib/rust/stats/effsize.rb +21 -0
- data/lib/rust/stats/probabilities.rb +141 -33
- data/lib/rust/stats/tests.rb +97 -5
- data/lib/rust.rb +19 -0
- metadata +9 -2
@@ -0,0 +1,435 @@
|
|
1
|
+
require 'json'
|
2
|
+
require_relative 'core'
|
3
|
+
|
4
|
+
module Rust::Plots::GGPlot
|
5
|
+
class Theme < Layer
|
6
|
+
def self.from_h(options)
|
7
|
+
starting = options.delete('_starting')
|
8
|
+
options = options.map do |key, value|
|
9
|
+
if value.is_a?(Hash)
|
10
|
+
case value.delete('_type').split("::").last
|
11
|
+
when 'TextElement'
|
12
|
+
[key, TextElement.new(**value)]
|
13
|
+
when 'RectElement'
|
14
|
+
[key, RectElement.new(**value)]
|
15
|
+
when 'TextElement'
|
16
|
+
[key, TextElement.new(**value)]
|
17
|
+
when 'LineElement'
|
18
|
+
[key, LineElement.new(**value)]
|
19
|
+
end
|
20
|
+
else
|
21
|
+
[key, value]
|
22
|
+
end
|
23
|
+
end.to_h
|
24
|
+
|
25
|
+
return Theme.new(starting, **options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.load(filename)
|
29
|
+
json = JSON.parse(File.read(filename))
|
30
|
+
return self.from_h(json.to_h)
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(starting, **options)
|
34
|
+
super("theme", **options)
|
35
|
+
if starting
|
36
|
+
@starting = "theme_" + starting
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_R
|
41
|
+
result = super do |options, arguments|
|
42
|
+
[
|
43
|
+
options.map { |k, v| [k.to_s.gsub("_", "."), v] }.to_h,
|
44
|
+
arguments
|
45
|
+
]
|
46
|
+
end
|
47
|
+
|
48
|
+
result = Rust::Function.new(@starting).to_R + " + " + result if @starting
|
49
|
+
|
50
|
+
return result
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_h
|
54
|
+
options = @options.clone
|
55
|
+
|
56
|
+
options['_starting'] = @starting.sub("theme_", "")
|
57
|
+
options = options.map do |key, value|
|
58
|
+
[key, value.is_a?(Theme::Element) ? value.to_h : value]
|
59
|
+
end.to_h
|
60
|
+
|
61
|
+
return options
|
62
|
+
end
|
63
|
+
|
64
|
+
def save(path, force = false)
|
65
|
+
if !force && FileTest.exist?(path)
|
66
|
+
raise "File already existing."
|
67
|
+
end
|
68
|
+
|
69
|
+
File.open(path, "w") do |f|
|
70
|
+
f.write(
|
71
|
+
JSON.pretty_generate(
|
72
|
+
self.to_h
|
73
|
+
)
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
return true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class Theme::Element
|
82
|
+
attr_reader :options
|
83
|
+
|
84
|
+
def initialize(**options)
|
85
|
+
@options = options
|
86
|
+
end
|
87
|
+
|
88
|
+
def r_function
|
89
|
+
raise "Not implemented for generic theme element"
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_R
|
93
|
+
options = @options.map { |k, v| [k.to_s.gsub("_", "."), v] }.to_h
|
94
|
+
|
95
|
+
function = Rust::Function.new(self.r_function)
|
96
|
+
function.options = Rust::Options.from_hash(options)
|
97
|
+
|
98
|
+
return function.to_R
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_h
|
102
|
+
hash = @options.clone
|
103
|
+
hash['_type'] = self.class.name
|
104
|
+
return hash
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class Theme::TextElement < Theme::Element
|
109
|
+
def r_function
|
110
|
+
return "element_text"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class Theme::LineElement < Theme::Element
|
115
|
+
def r_function
|
116
|
+
return "element_line"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class Theme::RectElement < Theme::Element
|
121
|
+
def r_function
|
122
|
+
return "element_rect"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class Theme::BlankElement < Theme::Element
|
127
|
+
def r_function
|
128
|
+
return "element_blank"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class ThemeComponentBuilder
|
133
|
+
def initialize(namespace=nil)
|
134
|
+
@namespace = namespace
|
135
|
+
@options = {}
|
136
|
+
end
|
137
|
+
|
138
|
+
def option(key, value)
|
139
|
+
key = "#@namespace.#{key}" if @namespace
|
140
|
+
@options[key] = value
|
141
|
+
|
142
|
+
return self
|
143
|
+
end
|
144
|
+
|
145
|
+
def [](key)
|
146
|
+
key = "#@namespace.#{key}" if @namespace
|
147
|
+
return @options[key]
|
148
|
+
end
|
149
|
+
|
150
|
+
def line_el(value)
|
151
|
+
if value.is_a?(Theme::LineElement) || value.is_a?(Theme::BlankElement)
|
152
|
+
return value
|
153
|
+
elsif value.is_a?(Hash)
|
154
|
+
return Theme::LineElement.new(**value)
|
155
|
+
else
|
156
|
+
raise "Expected line or hash"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def rect_el(value)
|
161
|
+
if value.is_a?(Theme::RectElement) || value.is_a?(Theme::BlankElement)
|
162
|
+
return value
|
163
|
+
elsif value.is_a?(Hash)
|
164
|
+
return Theme::RectElement.new(**value)
|
165
|
+
else
|
166
|
+
raise "Expected rect or hash"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def text_el(value)
|
171
|
+
if value.is_a?(Theme::TextElement) || value.is_a?(Theme::BlankElement)
|
172
|
+
return value
|
173
|
+
elsif value.is_a?(Hash)
|
174
|
+
return Theme::TextElement.new(**value)
|
175
|
+
else
|
176
|
+
raise "Expected text or hash"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def unit_el(value)
|
181
|
+
numeric = nil
|
182
|
+
unit = nil
|
183
|
+
|
184
|
+
if input.is_a?(String)
|
185
|
+
numeric, unit = *input.scan(/^([0-9.]+)([A-Za-z]+)/).flatten
|
186
|
+
|
187
|
+
raise "Unclear numeric part in #{input}" unless numeric
|
188
|
+
raise "Unclear unit part in #{input}" unless unit
|
189
|
+
elsif input.is_a?(Numeric)
|
190
|
+
numeric = input
|
191
|
+
unit = "npc"
|
192
|
+
end
|
193
|
+
|
194
|
+
raise "Unable to handle #{input}" unless numeric && unit
|
195
|
+
|
196
|
+
function = Rust::Function.new("units")
|
197
|
+
function.arguments = Rust::Arguments.new([numeric, unit])
|
198
|
+
|
199
|
+
return function.to_R
|
200
|
+
end
|
201
|
+
|
202
|
+
def alignment_el(value)
|
203
|
+
if value.is_a?(String) || value.is_a?(Symbol)
|
204
|
+
case value.to_s.downcase
|
205
|
+
when 'left'
|
206
|
+
value = 1
|
207
|
+
when 'right'
|
208
|
+
value = 0
|
209
|
+
else
|
210
|
+
value = 1
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
return value
|
215
|
+
end
|
216
|
+
|
217
|
+
def numeric_el(value)
|
218
|
+
raise "Expected number" unless value.is_a?(Numeric)
|
219
|
+
return value
|
220
|
+
end
|
221
|
+
|
222
|
+
def build
|
223
|
+
@options
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
class ThemeBuilder < ThemeComponentBuilder
|
228
|
+
def initialize(starting = 'bw')
|
229
|
+
super("plot")
|
230
|
+
@starting = starting
|
231
|
+
end
|
232
|
+
|
233
|
+
def background(value)
|
234
|
+
self.option('background', rect_el(value))
|
235
|
+
end
|
236
|
+
|
237
|
+
def title(value)
|
238
|
+
self.option('title', text_el(value))
|
239
|
+
end
|
240
|
+
|
241
|
+
def axis
|
242
|
+
builder = ThemeAxisBuilder.new
|
243
|
+
yield builder
|
244
|
+
|
245
|
+
@options.merge!(builder.build)
|
246
|
+
return self
|
247
|
+
end
|
248
|
+
|
249
|
+
def legend
|
250
|
+
builder = ThemeLegendBuilder.new
|
251
|
+
yield builder
|
252
|
+
|
253
|
+
@options.merge!(builder.build)
|
254
|
+
return self
|
255
|
+
end
|
256
|
+
|
257
|
+
def panel
|
258
|
+
builder = ThemePanelBuilder.new
|
259
|
+
yield builder
|
260
|
+
|
261
|
+
@options.merge!(builder.build)
|
262
|
+
return self
|
263
|
+
end
|
264
|
+
|
265
|
+
def build
|
266
|
+
return Theme.new(@starting, **@options)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
class ThemeAxisBuilder < ThemeComponentBuilder
|
271
|
+
def initialize
|
272
|
+
super("axis")
|
273
|
+
end
|
274
|
+
|
275
|
+
def line(value)
|
276
|
+
self.option('line', line_el(value))
|
277
|
+
end
|
278
|
+
|
279
|
+
def text(value)
|
280
|
+
self.option('text', text_el(value))
|
281
|
+
end
|
282
|
+
|
283
|
+
def text_x(value)
|
284
|
+
self.option('text.x', text_el(value))
|
285
|
+
end
|
286
|
+
|
287
|
+
def text_y(value)
|
288
|
+
self.option('text.y', text_el(value))
|
289
|
+
end
|
290
|
+
|
291
|
+
def title(value)
|
292
|
+
self.option('title', text_el(value))
|
293
|
+
end
|
294
|
+
|
295
|
+
def title_x(value)
|
296
|
+
self.option('title.x', text_el(value))
|
297
|
+
end
|
298
|
+
|
299
|
+
def title_y(value)
|
300
|
+
self.option('title.y', text_el(value))
|
301
|
+
end
|
302
|
+
|
303
|
+
def ticks(value)
|
304
|
+
self.option('ticks', line_el(value))
|
305
|
+
end
|
306
|
+
|
307
|
+
def ticks_length(value)
|
308
|
+
self.option('ticks.length', unit_el(value))
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
class ThemeLegendBuilder < ThemeComponentBuilder
|
313
|
+
def initialize
|
314
|
+
super("legend")
|
315
|
+
end
|
316
|
+
|
317
|
+
def position(value)
|
318
|
+
self.option('position', value)
|
319
|
+
end
|
320
|
+
|
321
|
+
def justification(value)
|
322
|
+
self.option('justification', value)
|
323
|
+
end
|
324
|
+
|
325
|
+
def background(value)
|
326
|
+
self.option('background', rect_el(value))
|
327
|
+
end
|
328
|
+
|
329
|
+
def key_background(value)
|
330
|
+
self.option('key', rect_el(value))
|
331
|
+
end
|
332
|
+
|
333
|
+
def key_size(value)
|
334
|
+
self.option('key.size', unit_el(value))
|
335
|
+
end
|
336
|
+
|
337
|
+
def key_height(value)
|
338
|
+
self.option('key.height', unit_el(value))
|
339
|
+
end
|
340
|
+
|
341
|
+
def key_width(value)
|
342
|
+
self.option('key.width', unit_el(value))
|
343
|
+
end
|
344
|
+
|
345
|
+
def margin(value)
|
346
|
+
self.option('margin', unit_el(value))
|
347
|
+
end
|
348
|
+
|
349
|
+
def text(value)
|
350
|
+
self.option('text', text_el(value))
|
351
|
+
end
|
352
|
+
|
353
|
+
def text_align(value)
|
354
|
+
self.option('text.align', alignment_el(value))
|
355
|
+
end
|
356
|
+
|
357
|
+
def title(value)
|
358
|
+
self.option('title', text_el(value))
|
359
|
+
end
|
360
|
+
|
361
|
+
def title_align(value)
|
362
|
+
self.option('key.size', alignment_el(value))
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
class ThemePanelBuilder < ThemeComponentBuilder
|
367
|
+
def initialize
|
368
|
+
super("panel")
|
369
|
+
end
|
370
|
+
|
371
|
+
def background(value)
|
372
|
+
self.option('background', rect_el(value))
|
373
|
+
end
|
374
|
+
|
375
|
+
def border(value)
|
376
|
+
self.option('border', rect_el(value))
|
377
|
+
end
|
378
|
+
|
379
|
+
def grid_major(value)
|
380
|
+
self.option('grid.major', line_el(value))
|
381
|
+
end
|
382
|
+
|
383
|
+
def grid_major_x(value)
|
384
|
+
self.option('grid.major.x', line_el(value))
|
385
|
+
end
|
386
|
+
|
387
|
+
def grid_major_y(value)
|
388
|
+
self.option('grid.major.y', line_el(value))
|
389
|
+
end
|
390
|
+
|
391
|
+
def grid_minor(value)
|
392
|
+
self.option('grid.minor', line_el(value))
|
393
|
+
end
|
394
|
+
|
395
|
+
def grid_minor_x(value)
|
396
|
+
self.option('grid.minor.x', line_el(value))
|
397
|
+
end
|
398
|
+
|
399
|
+
def grid_minor_y(value)
|
400
|
+
self.option('grid.minor.y', line_el(value))
|
401
|
+
end
|
402
|
+
|
403
|
+
def aspect_ratio(value)
|
404
|
+
self.option('aspect.ratio', numeric_el(value))
|
405
|
+
end
|
406
|
+
|
407
|
+
def margin(value)
|
408
|
+
self.option('margin', unit_el(value))
|
409
|
+
end
|
410
|
+
|
411
|
+
def margin_x(value)
|
412
|
+
self.option('margin.x', unit_el(value))
|
413
|
+
end
|
414
|
+
|
415
|
+
def margin_y(value)
|
416
|
+
self.option('margin.y', unit_el(value))
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
self.default_theme = ThemeBuilder.new.
|
421
|
+
title(face: 'bold', size: 12).
|
422
|
+
legend do |legend|
|
423
|
+
legend.background(fill: 'white', size: 4, colour: 'white')
|
424
|
+
legend.position([0, 1])
|
425
|
+
legend.justification([0, 1])
|
426
|
+
end.
|
427
|
+
axis do |axis|
|
428
|
+
axis.ticks(colour: 'grey70', size: 0.2)
|
429
|
+
end.
|
430
|
+
panel do |panel|
|
431
|
+
panel.grid_major(colour: 'grey70', size: 0.2)
|
432
|
+
panel.grid_minor(Theme::BlankElement.new)
|
433
|
+
end.
|
434
|
+
build
|
435
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rust'
|
2
|
+
|
3
|
+
Rust.prerequisite('robustbase')
|
4
|
+
|
5
|
+
module Rust::Plots
|
6
|
+
class AdjustedBoxplot < DistributionPlot
|
7
|
+
protected
|
8
|
+
def _show()
|
9
|
+
function = Rust::Function.new("adjbox")
|
10
|
+
|
11
|
+
names = []
|
12
|
+
@series.each_with_index do |data, i|
|
13
|
+
series, options = *data
|
14
|
+
varname = "plotter.series#{i}"
|
15
|
+
Rust[varname] = series
|
16
|
+
function.arguments << Rust::Variable.new(varname)
|
17
|
+
names << (options[:name] || (i+1).to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
function.options = self._augmented_options({'names' => names})
|
21
|
+
|
22
|
+
function.call
|
23
|
+
|
24
|
+
return self
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module Rust::RBindings
|
30
|
+
def adjbox(*args, **options)
|
31
|
+
result = Rust::Plots::AdjustedBoxplot.new
|
32
|
+
options.each do |k, v|
|
33
|
+
result[k] = v
|
34
|
+
end
|
35
|
+
|
36
|
+
result._do_not_override_options!
|
37
|
+
|
38
|
+
args.each do |s|
|
39
|
+
result.series(s)
|
40
|
+
end
|
41
|
+
|
42
|
+
result.show
|
43
|
+
end
|
44
|
+
end
|
data/lib/rust/models/anova.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
require_relative '../core'
|
2
2
|
|
3
3
|
module Rust
|
4
|
+
|
5
|
+
##
|
6
|
+
# Mirror for an ANOVA model type in R. To create a new ANOVA model (aov), call the #generate method.
|
7
|
+
|
4
8
|
class ANOVAModel < RustDatatype
|
5
9
|
def self.can_pull?(type, klass)
|
6
10
|
return type == "list" && [klass].flatten.include?("aov")
|
@@ -16,6 +20,10 @@ module Rust
|
|
16
20
|
@model.load_in_r_as(variable_name)
|
17
21
|
end
|
18
22
|
|
23
|
+
##
|
24
|
+
# Generates a new ANOVA model with a given +formula+, +data+. +options+ can be specified and directly passed
|
25
|
+
# to the aov function in R.
|
26
|
+
|
19
27
|
def self.generate(formula, data, **options)
|
20
28
|
mapped = ""
|
21
29
|
if options.size > 0
|
@@ -32,14 +40,23 @@ module Rust
|
|
32
40
|
end
|
33
41
|
end
|
34
42
|
|
43
|
+
##
|
44
|
+
# Creates a new +model+.
|
45
|
+
|
35
46
|
def initialize(model)
|
36
47
|
@model = model
|
37
48
|
end
|
38
49
|
|
50
|
+
##
|
51
|
+
# Returns the model.
|
52
|
+
|
39
53
|
def model
|
40
54
|
@model
|
41
55
|
end
|
42
56
|
|
57
|
+
##
|
58
|
+
# Returns a summary of the ANOVA model through the summary function in R.
|
59
|
+
|
43
60
|
def summary
|
44
61
|
unless @summary
|
45
62
|
Rust.exclusive do
|
@@ -5,7 +5,14 @@ require_relative '../stats/correlation'
|
|
5
5
|
module Rust::Models
|
6
6
|
end
|
7
7
|
|
8
|
+
##
|
9
|
+
# Contains classes that allow to run regression models.
|
10
|
+
|
8
11
|
module Rust::Models::Regression
|
12
|
+
|
13
|
+
##
|
14
|
+
# Generic regression model in R.
|
15
|
+
|
9
16
|
class RegressionModel < Rust::RustDatatype
|
10
17
|
def self.can_pull?(type, klass)
|
11
18
|
# Can only pull specific sub-types
|
@@ -16,6 +23,11 @@ module Rust::Models::Regression
|
|
16
23
|
@model.load_in_r_as(variable_name)
|
17
24
|
end
|
18
25
|
|
26
|
+
##
|
27
|
+
# Generates a new regression model. +object_type+ is the Ruby class of the model object; +model_type+ represents
|
28
|
+
# the type of model at hand; +dependent_variable+ and +independent_variables+ are directly used as part of the
|
29
|
+
# model formula. +data+ represents the dataset to be used. +options+ can be specified and directly passed to the
|
30
|
+
# model.
|
19
31
|
|
20
32
|
def self.generate(object_type, model_type, dependent_variable, independent_variables, data, **options)
|
21
33
|
mapped = ""
|
@@ -36,6 +48,9 @@ module Rust::Models::Regression
|
|
36
48
|
return result
|
37
49
|
end
|
38
50
|
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Creates a new +model+.
|
39
54
|
|
40
55
|
def initialize(model)
|
41
56
|
raise StandardError if model.is_a?(RegressionModel)
|
@@ -46,6 +61,9 @@ module Rust::Models::Regression
|
|
46
61
|
@model
|
47
62
|
end
|
48
63
|
|
64
|
+
##
|
65
|
+
# Returns the residuals of the model.
|
66
|
+
|
49
67
|
def residuals
|
50
68
|
Rust.exclusive do
|
51
69
|
@residuals = Rust["residuals(#{self.r_mirror})"] unless @residuals
|
@@ -54,6 +72,9 @@ module Rust::Models::Regression
|
|
54
72
|
return @residuals
|
55
73
|
end
|
56
74
|
|
75
|
+
##
|
76
|
+
# Returns the fitted values of the model.
|
77
|
+
|
57
78
|
def fitted
|
58
79
|
Rust.exclusive do
|
59
80
|
@fitted = Rust["fitted(#{self.r_mirror})"] unless @fitted
|
@@ -62,22 +83,37 @@ module Rust::Models::Regression
|
|
62
83
|
return @fitted
|
63
84
|
end
|
64
85
|
|
86
|
+
##
|
87
|
+
# Returns the actual values in the dataset.
|
88
|
+
|
65
89
|
def actuals
|
66
90
|
return self.fitted.zip(self.residuals).map { |couple| couple.sum }
|
67
91
|
end
|
68
92
|
|
93
|
+
##
|
94
|
+
# Returns the r-squared of the model.
|
95
|
+
|
69
96
|
def r_2
|
70
97
|
return self.summary|"r.squared"
|
71
98
|
end
|
72
99
|
|
100
|
+
##
|
101
|
+
# Returns the adjusted r-squared of the model.
|
102
|
+
|
73
103
|
def r_2_adjusted
|
74
104
|
return self.summary|"adj.r.squared"
|
75
105
|
end
|
76
106
|
|
107
|
+
##
|
108
|
+
# Returns the mean squared error of the model.
|
109
|
+
|
77
110
|
def mse
|
78
111
|
Rust::Descriptive.variance(self.residuals)
|
79
112
|
end
|
80
113
|
|
114
|
+
##
|
115
|
+
# Returns the coefficients of the model.
|
116
|
+
|
81
117
|
def coefficients
|
82
118
|
a = self.summary|"coefficients"
|
83
119
|
end
|
@@ -86,6 +122,9 @@ module Rust::Models::Regression
|
|
86
122
|
return model|name.to_s
|
87
123
|
end
|
88
124
|
|
125
|
+
##
|
126
|
+
# Returns a summary for the model using the summary function in R.
|
127
|
+
|
89
128
|
def summary
|
90
129
|
unless @summary
|
91
130
|
Rust.exclusive do
|
@@ -101,6 +140,9 @@ module Rust::Models::Regression
|
|
101
140
|
end
|
102
141
|
end
|
103
142
|
|
143
|
+
##
|
144
|
+
# Represents a linear regression model in R.
|
145
|
+
|
104
146
|
class LinearRegressionModel < RegressionModel
|
105
147
|
def self.can_pull?(type, klass)
|
106
148
|
return type == "list" && klass == "lm"
|
@@ -112,6 +154,10 @@ module Rust::Models::Regression
|
|
112
154
|
return LinearRegressionModel.new(model)
|
113
155
|
end
|
114
156
|
|
157
|
+
##
|
158
|
+
# Generates a linear regression model, given its +dependent_variable+ and +independent_variables+ and its +data+.
|
159
|
+
# +options+ can be specified and directly passed to the model.
|
160
|
+
|
115
161
|
def self.generate(dependent_variable, independent_variables, data, **options)
|
116
162
|
RegressionModel.generate(
|
117
163
|
LinearRegressionModel,
|
@@ -124,6 +170,9 @@ module Rust::Models::Regression
|
|
124
170
|
end
|
125
171
|
end
|
126
172
|
|
173
|
+
##
|
174
|
+
# Represents a linear mixed effects model in R.
|
175
|
+
|
127
176
|
class LinearMixedEffectsModel < RegressionModel
|
128
177
|
def self.can_pull?(type, klass)
|
129
178
|
return type == "S4" && klass == "lmerModLmerTest"
|
@@ -152,6 +201,10 @@ module Rust::Models::Regression
|
|
152
201
|
return @summary
|
153
202
|
end
|
154
203
|
|
204
|
+
##
|
205
|
+
# Generates a linear mixed effects model, given its +dependent_variable+ and +independent_variables+ and its +data+.
|
206
|
+
# +options+ can be specified and directly passed to the model.
|
207
|
+
|
155
208
|
def self.generate(dependent_variable, fixed_effects, random_effects, data, **options)
|
156
209
|
Rust.prerequisite("lmerTest")
|
157
210
|
Rust.prerequisite("rsq")
|
@@ -169,7 +222,7 @@ module Rust::Models::Regression
|
|
169
222
|
end
|
170
223
|
|
171
224
|
def r_2
|
172
|
-
|
225
|
+
Rust.exclusive do
|
173
226
|
Rust._eval("tmp.rsq <- rsq(#{self.r_mirror}, adj=F)")
|
174
227
|
return Rust['tmp.rsq']
|
175
228
|
end
|