rust 0.2 → 0.3

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
  SHA256:
3
- metadata.gz: a39315e623da717c4f035a11fbe7363bf3aae0d8885f922c4f0fca689bc7b90a
4
- data.tar.gz: e0a1ec7e485a0f9521a42191f6a97d833df8eb35c961d31c9ba67f0a6f0c0c22
3
+ metadata.gz: 985f7e940ab123fa452dae63792bde90613b134176ff4eaf5b59a719dd8a1ed5
4
+ data.tar.gz: bef0bb5028c99cb43c8e5453fdbbaf687bad65f8e6b54b06f949e5df6fb61bda
5
5
  SHA512:
6
- metadata.gz: eaffc66a8a3250f7f687bdf1dec96421681f25ff394010f0c15d7e65b5ed87a9deb25111c7f56baa60b19a53a4849bd92a665bfe507f9ba9b096b722cddeed53
7
- data.tar.gz: c5fc8ce8b55347ca402783ab352310719fcdd008eaa2f1ed3b00ca93137736ca6a2d8c9d9b2169865212e7a09ca955e5909d7983b0461bda0c539b51f1c0e379
6
+ metadata.gz: 418181b9357665ecc654e9a765e24aa792d6287dd5998b1b1bd8f3278e6951d785fff8afe9594c6c95e1f7a384cb08f844939728b62a96ab416259de1c14512b
7
+ data.tar.gz: 810f14821924bd1b0cebf4fbf9f52e510abc0e935be6cc2852294fd374d54411bcd2a1943f5b60d2ce93501abcaff9cac25dd458e1a8b354b665aab199705a4a
@@ -0,0 +1,126 @@
1
+ require_relative 'rust-core'
2
+
3
+ module Rust:: Correlation
4
+ class Pearson
5
+ def self.test(d1, d2)
6
+ raise TypeError, "Expecting Array of numerics" if !d1.is_a?(Array) || !d1.all? { |e| e.is_a?(Numeric) }
7
+ raise TypeError, "Expecting Array of numerics" if !d2.is_a?(Array) || !d2.all? { |e| e.is_a?(Numeric) }
8
+
9
+ Rust.exclusive do
10
+ Rust['correlation.a'] = d1
11
+ Rust['correlation.b'] = d2
12
+
13
+ Rust._eval("correlation.result <- cor.test(correlation.a, correlation.b, method='p')")
14
+
15
+ result = Result.new
16
+ result.name = "Pearson's product-moment correlation"
17
+ result.statistics['t'] = Rust._pull('correlation.result$statistic')
18
+ result.pvalue = Rust._pull('correlation.result$p.value')
19
+ result.correlation = Rust._pull('correlation.result$estimate')
20
+
21
+ return result
22
+ end
23
+ end
24
+
25
+ def self.estimate(d1, d2)
26
+ self.test(d1, d2).correlation
27
+ end
28
+ end
29
+
30
+ class Spearman
31
+ def self.test(d1, d2)
32
+ raise TypeError, "Expecting Array of numerics" if !d1.is_a?(Array) || !d1.all? { |e| e.is_a?(Numeric) }
33
+ raise TypeError, "Expecting Array of numerics" if !d2.is_a?(Array) || !d2.all? { |e| e.is_a?(Numeric) }
34
+
35
+ Rust.exclusive do
36
+ Rust['correlation.a'] = d1
37
+ Rust['correlation.b'] = d2
38
+
39
+ Rust._eval("correlation.result <- cor.test(correlation.a, correlation.b, method='s')")
40
+
41
+ result = Result.new
42
+ result.name = "Spearman's rank correlation rho"
43
+ result.statistics['S'] = Rust._pull('correlation.result$statistic')
44
+ result.pvalue = Rust._pull('correlation.result$p.value')
45
+ result.correlation = Rust._pull('correlation.result$estimate')
46
+
47
+ return result
48
+ end
49
+ end
50
+
51
+ def self.estimate(d1, d2)
52
+ self.test(d1, d2).correlation
53
+ end
54
+ end
55
+
56
+ class Kendall
57
+ def self.test(d1, d2)
58
+ raise TypeError, "Expecting Array of numerics" if !d1.is_a?(Array) || !d1.all? { |e| e.is_a?(Numeric) }
59
+ raise TypeError, "Expecting Array of numerics" if !d2.is_a?(Array) || !d2.all? { |e| e.is_a?(Numeric) }
60
+
61
+ Rust.exclusive do
62
+ Rust['correlation.a'] = d1
63
+ Rust['correlation.b'] = d2
64
+
65
+ Rust._eval("correlation.result <- cor.test(correlation.a, correlation.b, method='p')")
66
+
67
+ result = Result.new
68
+ result.name = "Kendall's rank correlation tau"
69
+ result.statistics['T'] = Rust._pull('correlation.result$statistic')
70
+ result.pvalue = Rust._pull('correlation.result$p.value')
71
+ result.correlation = Rust._pull('correlation.result$estimate')
72
+
73
+ return result
74
+ end
75
+ end
76
+
77
+ def self.estimate(d1, d2)
78
+ self.test(d1, d2).correlation
79
+ end
80
+ end
81
+
82
+ class Result
83
+ attr_accessor :name
84
+ attr_accessor :statistics
85
+ attr_accessor :pvalue
86
+ attr_accessor :correlation
87
+
88
+ alias :estimate :correlation
89
+
90
+ def initialize
91
+ @statistics = {}
92
+ end
93
+
94
+ def [](name)
95
+ return @statistics[name.to_sym]
96
+ end
97
+
98
+ def []=(name, value)
99
+ @statistics[name.to_sym] = value
100
+ end
101
+
102
+ def to_s
103
+ return "#{name}. Correlation = #{correlation}, P-value = #{pvalue} " +
104
+ "#{ statistics.map { |k, v| k.to_s + " -> " + v.to_s }.join(", ") }."
105
+ end
106
+ end
107
+ end
108
+
109
+ module Rust::RBindings
110
+ def cor(d1, d2, **options)
111
+ return cor_test(d1, d2, **options).correlation
112
+ end
113
+
114
+ def cor_test(d1, d2, **options)
115
+ method = options[:method].to_s.downcase
116
+ if "pearson".start_with?(method)
117
+ return Rust::Correlation::Pearson.test(d1, d2)
118
+ elsif "spearman".start_with?(method)
119
+ return Rust::Correlation::Spearman.test(d1, d2)
120
+ elsif "kendall".start_with?(method)
121
+ return Rust::Correlation::Kendall.test(d1, d2)
122
+ else
123
+ raise "Unsupported method #{method}"
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,69 @@
1
+ require_relative 'rust-core'
2
+
3
+ module Rust
4
+ class Function
5
+ attr_reader :name
6
+ attr_reader :arguments
7
+ attr_reader :options
8
+
9
+ def initialize(name)
10
+ @function = name
11
+ @arguments = Arguments.new
12
+ @options = Options.new
13
+ end
14
+
15
+ def options=(options)
16
+ raise TypeError, "Expected Options" unless options.is_a?(Options)
17
+
18
+ @options = options
19
+ end
20
+
21
+ def arguments=(arguments)
22
+ raise TypeError, "Expected Arguments" unless options.is_a?(Arguments)
23
+
24
+ @arguments = arguments
25
+ end
26
+
27
+ def to_R
28
+ params = [@arguments.to_R, @options.to_R].select { |v| v != "" }.join(",")
29
+ return "#@function(#{params})"
30
+ end
31
+
32
+ def call
33
+ Rust._eval(self.to_R)
34
+ end
35
+ end
36
+
37
+ class Variable
38
+ def initialize(name)
39
+ @name = name
40
+ end
41
+
42
+ def to_R
43
+ @name
44
+ end
45
+ end
46
+
47
+ class Arguments < Array
48
+ def to_R
49
+ return self.map { |v| v.to_R }.join(", ")
50
+ end
51
+ end
52
+
53
+ class Options < Hash
54
+ def to_R
55
+ return self.map { |k, v| "#{k}=#{v.to_R}" }.join(", ")
56
+ end
57
+
58
+ def self.from_hash(hash)
59
+ options = Options.new
60
+ hash.each do |key, value|
61
+ options[key.to_s] = value
62
+ end
63
+ return options
64
+ end
65
+ end
66
+ end
67
+
68
+ module Rust::RBindings
69
+ end
@@ -9,8 +9,17 @@ module Rust
9
9
 
10
10
  R_ENGINE = RinRuby.new(echo: false)
11
11
 
12
+ private_constant :R_ENGINE
13
+ private_constant :R_MUTEX
14
+ private_constant :CLIENT_MUTEX
15
+
16
+ @@debugging = false
12
17
  @@in_client_mutex = false
13
18
 
19
+ def self.debug
20
+ @@debugging = true
21
+ end
22
+
14
23
  def self.exclusive
15
24
  result = nil
16
25
  CLIENT_MUTEX.synchronize do
@@ -27,7 +36,7 @@ module Rust
27
36
  elsif value.is_a?(String) || value.is_a?(Numeric) || value.is_a?(Array)
28
37
  R_ENGINE.assign(variable, value)
29
38
  else
30
- raise "Given #{variable.class}, expected RustDatatype, String, Numeric, or Array"
39
+ raise "Given #{value.class}, expected RustDatatype, String, Numeric, or Array"
31
40
  end
32
41
 
33
42
  end
@@ -66,6 +75,7 @@ module Rust
66
75
  end
67
76
 
68
77
  def self._rexec(r_command, return_warnings = false)
78
+ puts "Calling _rexec with command: #{r_command}" if @@debugging
69
79
  R_MUTEX.synchronize do
70
80
  assert("This command must be executed in an exclusive block") { @@in_client_mutex }
71
81
 
@@ -120,41 +130,85 @@ module Rust
120
130
  @labels.each { |label| @data[label] = [] }
121
131
  elsif labels_or_data.is_a? Hash
122
132
  @labels = labels_or_data.keys.map { |l| l.to_s }
123
- @labels.each { |label| @data[label] = [] }
124
- for i in 0...labels_or_data.values[0].size
125
- self.add_row(labels_or_data.map { |k, v| [k, v[i]] }.to_h)
126
- end
133
+ @data = labels_or_data.clone
127
134
  end
128
135
  end
129
136
 
130
137
  def row(i)
131
- return @data.map { |label, values| [label, values[i]] }.to_h
138
+ if i < 0 || i >= self.rows
139
+ return nil
140
+ else
141
+ return @data.map { |label, values| [label, values[i]] }.to_h
142
+ end
143
+ end
144
+
145
+ def shuffle(*args)
146
+ result = DataFrame.new(@labels)
147
+
148
+ buffer = []
149
+ self.each do |row|
150
+ buffer << row
151
+ end
152
+ buffer.shuffle!(*args).each do |row|
153
+ result << row
154
+ end
155
+
156
+ return result
157
+ end
158
+
159
+ def [](rows, cols=nil)
160
+ raise "You must specify either rows or columns to select" if !rows && !cols
161
+ result = self
162
+ if rows && (rows.is_a?(Range) || rows.is_a?(Array))
163
+ result = result.select_rows { |row, i| rows.include?(i) }
164
+ end
165
+
166
+ if cols && cols.is_a?(Array)
167
+ cols = cols.map { |c| c.to_s }
168
+ result = result.select_columns(cols)
169
+ end
170
+
171
+ return result
132
172
  end
133
- alias :[] :row
134
173
 
135
174
  def column(name)
136
175
  return @data[name]
137
176
  end
138
177
 
178
+ def rename_column!(old_name, new_name)
179
+ raise "This DataFrame does not contain a column named #{old_name}" unless @labels.include?(old_name)
180
+ raise "This DataFrame already contains a column named #{new_name}" if @labels.include?(new_name)
181
+
182
+ @data[new_name.to_s] = @data.delete(old_name)
183
+ @labels[@labels.index(old_name)] = new_name
184
+ end
185
+
139
186
  def transform_column!(column)
140
187
  @data[column].map! { |e| yield e }
141
188
  end
142
189
 
143
190
  def select_rows
144
191
  result = DataFrame.new(self.column_names)
145
- self.each do |row|
146
- result << row if yield row
192
+ self.each_with_index do |row, i|
193
+ result << row if yield row, i
147
194
  end
148
195
  return result
149
196
  end
150
197
 
151
- def select_cols
198
+ def select_columns(cols=nil)
199
+ raise "You must specify either the columns you want to select or a selection block" if !cols && !block_given?
200
+
152
201
  result = self.clone
153
202
  @labels.each do |label|
154
- result.delete_column(label) unless yield label
203
+ if cols
204
+ result.delete_column(label) unless cols.include?(label)
205
+ else
206
+ result.delete_column(label) unless yield label
207
+ end
155
208
  end
156
209
  return result
157
210
  end
211
+ alias :select_cols :select_columns
158
212
 
159
213
  def delete_column(column)
160
214
  @labels.delete(column)
@@ -162,70 +216,18 @@ module Rust
162
216
  end
163
217
 
164
218
  def column_names
165
- return @data.keys.map { |k| k.to_s }
219
+ return @labels.map { |k| k.to_s }
166
220
  end
167
221
  alias :colnames :column_names
168
222
 
169
- def merge(other, by, first_alias = "x", second_alias = "y")
170
- raise TypeError, "Expected Rust::DataFrame" unless other.is_a?(DataFrame)
171
- raise TypeError, "Expected list of strings" if !by.is_a?(Array) || !by.all? { |e| e.is_a?(String) }
172
- raise "This dataset should have all the columns in #{by}" unless (by & self.column_names).size == by.size
173
- raise "The passed dataset should have all the columns in #{by}" unless (by & other.column_names).size == by.size
174
- raise "The aliases can not have the same value" if first_alias == second_alias
175
-
176
- my_keys = {}
177
- self.each_with_index do |row, i|
178
- key = []
179
- by.each do |colname|
180
- key << row[colname]
181
- end
182
-
183
- my_keys[key] = i
184
- end
185
-
186
- merged_column_self = (self.column_names - by)
187
- merged_column_other = (other.column_names - by)
188
-
189
- first_alias = first_alias + "." if first_alias.length > 0
190
- second_alias = second_alias + "." if second_alias.length > 0
191
-
192
- merged_columns = merged_column_self.map { |colname| "#{first_alias}#{colname}" } + merged_column_other.map { |colname| "#{second_alias}#{colname}" }
193
- columns = by + merged_columns
194
- result = DataFrame.new(columns)
195
- other.each do |other_row|
196
- key = []
197
- by.each do |colname|
198
- key << other_row[colname]
199
- end
200
-
201
- my_row_index = my_keys[key]
202
- if my_row_index
203
- my_row = self[my_row_index]
204
-
205
- to_add = {}
206
- by.each do |colname|
207
- to_add[colname] = my_row[colname]
208
- end
209
-
210
- merged_column_self.each do |colname|
211
- to_add["#{first_alias}#{colname}"] = my_row[colname]
212
- end
213
-
214
- merged_column_other.each do |colname|
215
- to_add["#{second_alias}#{colname}"] = other_row[colname]
216
- end
217
-
218
- result << to_add
219
- end
220
- end
221
-
222
- return result
223
- end
224
-
225
223
  def rows
226
224
  @data.values[0].size
227
225
  end
228
226
 
227
+ def columns
228
+ @labels.size
229
+ end
230
+
229
231
  def add_row(row)
230
232
  if row.is_a?(Array)
231
233
  raise "Expected an array of size #{@data.size}" unless row.size == @data.size
@@ -249,6 +251,22 @@ module Rust
249
251
  end
250
252
  alias :<< :add_row
251
253
 
254
+ def add_column(name, values=nil)
255
+ raise "Column already exists" if @labels.include?(name)
256
+ raise "Values or block required" if !values && !block_given?
257
+ raise "Number of values not matching" if values && values.size != self.rows
258
+
259
+ @labels << name
260
+ if values
261
+ @data[name] = values.clone
262
+ else
263
+ @data[name] = []
264
+ self.each_with_index do |row, i|
265
+ @data[name][i] = yield row
266
+ end
267
+ end
268
+ end
269
+
252
270
  def each
253
271
  self.each_with_index do |element, i|
254
272
  yield element
@@ -276,9 +294,7 @@ module Rust
276
294
  command << "#{variable_name} <- data.frame()"
277
295
  row_index = 1
278
296
  self.each do |row|
279
- keys = row.keys.map { |v| v.inspect }.join(",")
280
- values = row.values.map { |v| v.inspect }.join(",")
281
- command << "#{variable_name}[#{row_index}, c(#{keys})] <- c(#{values})"
297
+ command << "#{variable_name}[#{row_index.to_R}, #{row.keys.to_R}] <- #{row.values.to_R}"
282
298
 
283
299
  row_index += 1
284
300
  end
@@ -289,20 +305,140 @@ module Rust
289
305
  def inspect
290
306
  separator = " | "
291
307
  col_widths = self.column_names.map { |colname| [colname, ([colname.length] + @data[colname].map { |e| e.inspect.length }).max] }.to_h
292
- col_widths[:rowscol] = self.rows.inspect.length + 3
308
+ col_widths[:rowscol] = (self.rows - 1).inspect.length + 3
293
309
 
294
310
  result = ""
295
311
  result << "-" * (col_widths.values.sum + ((col_widths.size - 1) * separator.length)) + "\n"
296
312
  result << (" " * col_widths[:rowscol]) + self.column_names.map { |colname| (" " * (col_widths[colname] - colname.length)) + colname }.join(separator) + "\n"
297
313
  result << "-" * (col_widths.values.sum + ((col_widths.size - 1) * separator.length)) + "\n"
298
314
  self.each_with_index do |row, i|
299
- result << "[#{i}] " + row.map { |colname, value| (" " * (col_widths[colname] - value.inspect.length)) + value.inspect }.join(separator) + "\n"
315
+ index_part = "[" + (" " * (col_widths[:rowscol] - i.inspect.length - 3)) + "#{i}] "
316
+ row_part = row.map { |colname, value| (" " * (col_widths[colname] - value.inspect.length)) + value.inspect }.join(separator)
317
+
318
+ result << index_part + row_part + "\n"
300
319
  end
301
320
 
302
321
  result << "-" * (col_widths.values.sum + ((col_widths.size - 1) * separator.length))
303
322
 
304
323
  return result
305
324
  end
325
+
326
+ def head(n=10)
327
+ result = DataFrame.new(self.column_names)
328
+ self.each_with_index do |row, i|
329
+ result << row if i < n
330
+ end
331
+ return result
332
+ end
333
+
334
+ def merge(other, by, first_alias = "x", second_alias = "y")
335
+ raise TypeError, "Expected Rust::DataFrame" unless other.is_a?(DataFrame)
336
+ raise TypeError, "Expected list of strings" if !by.is_a?(Array) || !by.all? { |e| e.is_a?(String) }
337
+ raise "This dataset should have all the columns in #{by}" unless (by & self.column_names).size == by.size
338
+ raise "The passed dataset should have all the columns in #{by}" unless (by & other.column_names).size == by.size
339
+
340
+ if first_alias == second_alias
341
+ if first_alias == ""
342
+ my_columns = self.column_names - by
343
+ other_columns = other.column_names - by
344
+ intersection = my_columns & other_columns
345
+ raise "Cannot merge because the following columns would overlap: #{intersection}" if intersection.size > 0
346
+ else
347
+ raise "The aliases can not have the same value"
348
+ end
349
+ end
350
+
351
+ my_keys = {}
352
+ self.each_with_index do |row, i|
353
+ key = []
354
+ by.each do |colname|
355
+ key << row[colname]
356
+ end
357
+
358
+ my_keys[key] = i
359
+ end
360
+
361
+ merged_column_self = (self.column_names - by)
362
+ merged_column_other = (other.column_names - by)
363
+
364
+ first_alias = first_alias + "." if first_alias.length > 0
365
+ second_alias = second_alias + "." if second_alias.length > 0
366
+
367
+ merged_columns = merged_column_self.map { |colname| "#{first_alias}#{colname}" } + merged_column_other.map { |colname| "#{second_alias}#{colname}" }
368
+ columns = by + merged_columns
369
+ result = DataFrame.new(columns)
370
+ other.each do |other_row|
371
+ key = []
372
+ by.each do |colname|
373
+ key << other_row[colname]
374
+ end
375
+
376
+ my_row_index = my_keys[key]
377
+ if my_row_index
378
+ my_row = self.row(my_row_index)
379
+
380
+ to_add = {}
381
+ by.each do |colname|
382
+ to_add[colname] = my_row[colname]
383
+ end
384
+
385
+ merged_column_self.each do |colname|
386
+ to_add["#{first_alias}#{colname}"] = my_row[colname]
387
+ end
388
+
389
+ merged_column_other.each do |colname|
390
+ to_add["#{second_alias}#{colname}"] = other_row[colname]
391
+ end
392
+
393
+ result << to_add
394
+ end
395
+ end
396
+
397
+ return result
398
+ end
399
+
400
+ def bind_rows!(dataframe)
401
+ raise TypeError, "DataFrame expected" unless dataframe.is_a?(DataFrame)
402
+ raise "The columns are not compatible: #{self.column_names - dataframe.column_names} - #{dataframe.column_names - self.column_names}" unless (self.column_names & dataframe.column_names).size == self.columns
403
+
404
+ dataframe.each do |row|
405
+ self << row
406
+ end
407
+
408
+ return true
409
+ end
410
+ alias :rbind! :bind_rows!
411
+
412
+ def bind_columns!(dataframe)
413
+ raise TypeError, "DataFrame expected" unless dataframe.is_a?(DataFrame)
414
+ raise "The number of rows are not compatible" if self.rows != dataframe.rows
415
+ raise "The dataset would override some columns" if (self.column_names & dataframe.column_names).size > 0
416
+
417
+ dataframe.column_names.each do |column_name|
418
+ self.add_column(column_name, dataframe.column(column_name))
419
+ end
420
+
421
+ return true
422
+ end
423
+ alias :cbind! :bind_columns!
424
+
425
+ def bind_rows(dataframe)
426
+ result = self.clone
427
+ result.bind_rows!(dataframe)
428
+ return result
429
+ end
430
+ alias :rbind :bind_rows
431
+
432
+ def bind_columns(dataframe)
433
+ result = self.clone
434
+ result.bind_columns!(dataframe)
435
+ return result
436
+ end
437
+ alias :cbind :bind_columns
438
+
439
+ def clone
440
+ DataFrame.new(@data)
441
+ end
306
442
  end
307
443
 
308
444
  class Matrix < RustDatatype
@@ -344,36 +480,104 @@ module Rust
344
480
  end
345
481
  end
346
482
 
347
- class CSV
348
- def self.read(filename, **options)
349
- hash = {}
350
- labels = nil
351
- ::CSV.parse(File.read(filename), **options) do |row|
352
- labels = row.headers || (1..row.size).to_a.map { |e| "X#{e}" } unless labels
353
-
354
- labels.each do |label|
355
- hash[label] = [] unless hash[label]
356
- hash[label] << row[label]
357
- end
483
+ class Sequence
484
+ attr_reader :min
485
+ attr_reader :max
486
+
487
+ def initialize(min, max, step=1)
488
+ @min = min
489
+ @max = max
490
+ @step = step
491
+ end
492
+
493
+ def step(step)
494
+ @step = step
495
+ end
496
+
497
+ def each
498
+ (@min..@max).step(@step) do |v|
499
+ yield v
358
500
  end
359
-
360
- return Rust::DataFrame.new(hash)
361
501
  end
362
502
 
363
- def self.write(filename, dataframe, **options)
364
- raise TypeError, "Expected Rust::DataFrame" unless dataframe.is_a?(Rust::DataFrame)
365
-
366
- x[:headers] = dataframe.column_names if x[:headers]
367
-
368
- hash = {}
369
- labels = nil
370
- ::CSV.open(filename, 'w', write_headers: (x[:headers] ? true : false), **options) do |csv|
371
- dataframe.each do |row|
372
- csv << row
373
- end
503
+ def to_a
504
+ result = []
505
+ self.each do |v|
506
+ result << v
374
507
  end
375
-
376
- return true
508
+ return result
377
509
  end
510
+
511
+ def to_R
512
+ "seq(from=#@min, to=#@max, by=#@step)"
513
+ end
514
+ end
515
+ end
516
+
517
+ class TrueClass
518
+ def to_R
519
+ "TRUE"
520
+ end
521
+ end
522
+
523
+ class FalseClass
524
+ def to_R
525
+ "FALSE"
526
+ end
527
+ end
528
+
529
+ class Object
530
+ def to_R
531
+ raise TypeError, "Unsupported type for #{self.class}"
532
+ end
533
+ end
534
+
535
+ class NilClass
536
+ def to_R
537
+ return "NULL"
538
+ end
539
+ end
540
+
541
+ class Numeric
542
+ def to_R
543
+ self.inspect
544
+ end
545
+ end
546
+
547
+ class Float
548
+ def to_R
549
+ return self.nan? ? "NA" : super
550
+ end
551
+ end
552
+
553
+ class Array
554
+ def to_R
555
+ return "c(#{self.map { |e| e.to_R }.join(",")})"
556
+ end
557
+ end
558
+
559
+ class String
560
+ def to_R
561
+ return self.inspect
562
+ end
563
+ end
564
+
565
+ class Range
566
+ def to_R
567
+ [range.min, range.max].to_R
568
+ end
569
+ end
570
+
571
+ module Rust::RBindings
572
+ def read_csv(filename, **options)
573
+ Rust::CSV.read(filename, **options)
574
+ end
575
+
576
+ def write_csv(filename, dataframe, **options)
577
+ Rust::CSV.write(filename, dataframe, **options)
578
+ end
579
+
580
+ def data_frame(*args)
581
+ Rust::DataFrame.new(*args)
378
582
  end
379
583
  end