Class: Rover::Vector

Inherits:
Object
  • Object
show all
Defined in:
lib/rover/vector.rb

Constant Summary collapse

TYPE_CAST_MAPPING =

if a user never specifies types, the defaults are bool, float64, int64, and object

{
  bool: Numo::Bit,
  float32: Numo::SFloat,
  float64: Numo::DFloat,
  int8: Numo::Int8,
  int16: Numo::Int16,
  int32: Numo::Int32,
  int64: Numo::Int64,
  object: Numo::RObject,
  uint8: Numo::UInt8,
  uint16: Numo::UInt16,
  uint32: Numo::UInt32,
  uint64: Numo::UInt64,
  # legacy - must come last
  float: Numo::DFloat,
  int: Numo::Int64,
  uint: Numo::UInt64
}
NOT_SET =
Object.new

Instance Method Summary collapse

Constructor Details

#initialize(data, type: nil) ⇒ Vector

Returns a new instance of Vector.

Raises:

  • (ArgumentError)


26
27
28
29
# File 'lib/rover/vector.rb', line 26

def initialize(data, type: nil)
  @data = cast_data(data, type: type)
  raise ArgumentError, "Bad size: #{@data.shape}" unless @data.ndim == 1
end

Instance Method Details

#!Object



151
152
153
154
155
156
157
# File 'lib/rover/vector.rb', line 151

def !
  if @data.is_a?(Numo::Bit)
    Vector.new(@data.eq(0))
  else
    raise "Not implemented yet"
  end
end

#-@Object



159
160
161
# File 'lib/rover/vector.rb', line 159

def -@
  self * -1
end

#[](v) ⇒ Object



88
89
90
91
92
93
94
95
96
# File 'lib/rover/vector.rb', line 88

def [](v)
  if v.is_a?(Vector)
    Vector.new(v.to_numo.mask(@data))
  elsif v.is_a?(Numeric)
    @data[v]
  else
    Vector.new(@data[v])
  end
end

#[]=(k, v) ⇒ Object



98
99
100
101
# File 'lib/rover/vector.rb', line 98

def []=(k, v)
  k = k.to_numo if k.is_a?(Vector)
  @data[k] = v
end

#absObject



201
202
203
# File 'lib/rover/vector.rb', line 201

def abs
  Vector.new(@data.abs)
end

#all?Boolean

Returns:

  • (Boolean)


308
309
310
# File 'lib/rover/vector.rb', line 308

def all?(...)
  to_a.all?(...)
end

#any?Boolean

Returns:

  • (Boolean)


312
313
314
# File 'lib/rover/vector.rb', line 312

def any?(...)
  to_a.any?(...)
end

#ceil(ndigits = 0) ⇒ Object



213
214
215
216
217
218
219
# File 'lib/rover/vector.rb', line 213

def ceil(ndigits = 0)
  if ndigits == 0
    Vector.new(@data.ceil)
  else
    Vector.new(@data.map { |v| v.ceil(ndigits) })
  end
end

#clamp(min, max) ⇒ Object



168
169
170
# File 'lib/rover/vector.rb', line 168

def clamp(min, max)
  dup.clamp!(min, max)
end

#clamp!(min, max) ⇒ Object



163
164
165
166
# File 'lib/rover/vector.rb', line 163

def clamp!(min, max)
  @data = @data.clip(min, max)
  self
end

#crosstab(other) ⇒ Object



353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/rover/vector.rb', line 353

def crosstab(other)
  index = uniq.sort
  index_pos = index.to_a.map.with_index.to_h
  df = DataFrame.new({"_" => index})
  other.uniq.sort.each do |k|
    df[k] = 0
  end
  to_a.zip(other.to_a) do |v1, v2|
    df[v2][index_pos[v1]] += 1
  end
  df
end

#diffObject

keep same number of rows as original to make it easy to add to original data frame



83
84
85
86
# File 'lib/rover/vector.rb', line 83

def diff
  diff = @data.cast_to(Numo::DFloat).diff
  Vector.new(diff.insert(0, Float::NAN))
end

#each(&block) ⇒ Object



263
264
265
# File 'lib/rover/vector.rb', line 263

def each(&block)
  @data.each(&block)
end

#each_with_index(&block) ⇒ Object



267
268
269
# File 'lib/rover/vector.rb', line 267

def each_with_index(&block)
  @data.each_with_index(&block)
end

#empty?Boolean

Returns:

  • (Boolean)


316
317
318
# File 'lib/rover/vector.rb', line 316

def empty?
  size == 0
end

#first(n = NOT_SET) ⇒ Object



328
329
330
331
332
333
334
335
336
# File 'lib/rover/vector.rb', line 328

def first(n = NOT_SET)
  if n == NOT_SET
    @data[0]
  elsif n >= size
    Vector.new(@data)
  else
    Vector.new(@data[0...n])
  end
end

#floor(ndigits = 0) ⇒ Object



221
222
223
224
225
226
227
# File 'lib/rover/vector.rb', line 221

def floor(ndigits = 0)
  if ndigits == 0
    Vector.new(@data.floor)
  else
    Vector.new(@data.map { |v| v.floor(ndigits) })
  end
end

#frexpObject



253
254
255
256
# File 'lib/rover/vector.rb', line 253

def frexp
  fraction, exponent = Numo::NMath.frexp(@data)
  [Vector.new(fraction), Vector.new(exponent)]
end

#head(n = 5) ⇒ Object



366
367
368
369
# File 'lib/rover/vector.rb', line 366

def head(n = 5)
  n += size if n < 0
  first(n)
end

#hypot(y) ⇒ Object



248
249
250
251
# File 'lib/rover/vector.rb', line 248

def hypot(y)
  y = y.to_numo if y.is_a?(Rover::Vector)
  Vector.new(Numo::NMath.hypot(@data, y))
end

#in?(values) ⇒ Boolean

Returns:

  • (Boolean)


137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/rover/vector.rb', line 137

def in?(values)
  ret = Numo::Bit.new(size).fill(false)
  values.each do |v|
    comp =
      if v.is_a?(Numeric) || v.is_a?(Numo::NArray)
        @data.eq(v)
      else
        Numo::Bit.cast(@data.map { |d| d == v })
      end
    ret |= comp
  end
  Vector.new(ret)
end

#include?(value) ⇒ Boolean

Returns:

  • (Boolean)


320
321
322
# File 'lib/rover/vector.rb', line 320

def include?(value)
  to_a.include?(value)
end

#inspectObject Also known as: to_s

TODO add type and size?



391
392
393
394
395
# File 'lib/rover/vector.rb', line 391

def inspect
  elements = first(5).to_a.map(&:inspect)
  elements << "..." if size > 5
  "#<Rover::Vector [#{elements.join(", ")}]>"
end

#last(n = NOT_SET) ⇒ Object



338
339
340
341
342
343
344
345
346
# File 'lib/rover/vector.rb', line 338

def last(n = NOT_SET)
  if n == NOT_SET
    @data[-1]
  elsif n >= size
    Vector.new(@data)
  else
    Vector.new(@data[-n..-1])
  end
end

#ldexp(exponent) ⇒ Object



258
259
260
261
# File 'lib/rover/vector.rb', line 258

def ldexp(exponent)
  exponent = exponent.to_numo if exponent.is_a?(Rover::Vector)
  Vector.new(Numo::NMath.ldexp(@data, exponent))
end

#lnObject



244
245
246
# File 'lib/rover/vector.rb', line 244

def ln
  log
end

#log(base = NOT_SET) ⇒ Object



235
236
237
238
239
240
241
242
# File 'lib/rover/vector.rb', line 235

def log(base = NOT_SET)
  if base == NOT_SET
    Vector.new(Numo::NMath.log(@data))
  else
    type = self.type == :float32 ? :float32 : :float64
    Vector.new(@data.to_a.map { |v| Math.log(v, base) }, type: type)
  end
end

#map(&block) ⇒ Object



172
173
174
175
176
177
# File 'lib/rover/vector.rb', line 172

def map(&block)
  # convert to Ruby first to cast properly
  # https://github.com/ruby-numo/numo-narray/issues/181
  # numo-narray-alt has same behavior
  Vector.new(@data.to_a.map(&block))
end

#map!(&block) ⇒ Object



179
180
181
182
# File 'lib/rover/vector.rb', line 179

def map!(&block)
  @data = cast_data(@data.to_a.map(&block))
  self
end

#maxObject



271
272
273
# File 'lib/rover/vector.rb', line 271

def max
  @data.max
end

#meanObject



279
280
281
# File 'lib/rover/vector.rb', line 279

def mean
  @data.mean
end

#medianObject



283
284
285
286
287
288
# File 'lib/rover/vector.rb', line 283

def median
  # need to cast to get correct result
  # https://github.com/ruby-numo/numo-narray/issues/165
  # numo-narray-alt has same behavior
  @data.cast_to(Numo::DFloat).median
end

#minObject



275
276
277
# File 'lib/rover/vector.rb', line 275

def min
  @data.min
end

#missingObject



68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/rover/vector.rb', line 68

def missing
  bit =
    if @data.is_a?(Numo::RObject)
      Numo::Bit.cast(@data.map(&:nil?))
    elsif @data.respond_to?(:isnan)
      @data.isnan
    else
      Numo::Bit.new(size).fill(0)
    end

  Vector.new(bit)
end

#numeric?Boolean

Returns:

  • (Boolean)


54
55
56
# File 'lib/rover/vector.rb', line 54

def numeric?
  ![:object, :bool].include?(type)
end

#one_hot(drop: false, prefix: nil) ⇒ Object

Raises:

  • (ArgumentError)


376
377
378
379
380
381
382
383
384
385
386
387
388
# File 'lib/rover/vector.rb', line 376

def one_hot(drop: false, prefix: nil)
  raise ArgumentError, "All elements must be strings" unless all?(String)

  new_vectors = {}
  # maybe sort values first
  values = uniq.to_a
  values.shift if drop
  values.each do |v2|
    # TODO use types
    new_vectors["#{prefix}#{v2}"] = (self == v2).to_numo.cast_to(Numo::Int64)
  end
  DataFrame.new(new_vectors)
end

#percentile(q) ⇒ Object



290
291
292
# File 'lib/rover/vector.rb', line 290

def percentile(q)
  @data.percentile(q)
end

#reject(&block) ⇒ Object



188
189
190
# File 'lib/rover/vector.rb', line 188

def reject(&block)
  Vector.new(@data.to_a.reject(&block))
end

#round(ndigits = 0) ⇒ Object



205
206
207
208
209
210
211
# File 'lib/rover/vector.rb', line 205

def round(ndigits = 0)
  if ndigits == 0
    Vector.new(@data.round)
  else
    Vector.new(@data.map { |v| v.round(ndigits) })
  end
end

#select(&block) ⇒ Object



184
185
186
# File 'lib/rover/vector.rb', line 184

def select(&block)
  Vector.new(@data.to_a.select(&block))
end

#sizeObject Also known as: length, count



58
59
60
# File 'lib/rover/vector.rb', line 58

def size
  @data.size
end

#sortObject



197
198
199
# File 'lib/rover/vector.rb', line 197

def sort
  Vector.new(@data.respond_to?(:sort) ? @data.sort : @data.to_a.sort)
end

#stdObject

uses Bessel’s correction for now since that’s all Numo supports



299
300
301
# File 'lib/rover/vector.rb', line 299

def std
  @data.cast_to(Numo::DFloat).stddev
end

#sumObject



294
295
296
# File 'lib/rover/vector.rb', line 294

def sum
  @data.sum
end

#tail(n = 5) ⇒ Object



371
372
373
374
# File 'lib/rover/vector.rb', line 371

def tail(n = 5)
  n += size if n < 0
  last(n)
end

#take(n) ⇒ Object

Raises:

  • (ArgumentError)


348
349
350
351
# File 'lib/rover/vector.rb', line 348

def take(n)
  raise ArgumentError, "attempt to take negative size" if n < 0
  first(n)
end

#tallyObject

use Ruby tally for performance



193
194
195
# File 'lib/rover/vector.rb', line 193

def tally
  @data.to_a.tally
end

#to(type) ⇒ Object



35
36
37
# File 'lib/rover/vector.rb', line 35

def to(type)
  dup.to!(type)
end

#to!(type) ⇒ Object



39
40
41
42
# File 'lib/rover/vector.rb', line 39

def to!(type)
  @data = cast_data(@data, type: type)
  self
end

#to_aObject



48
49
50
51
52
# File 'lib/rover/vector.rb', line 48

def to_a
  a = @data.to_a
  a.map! { |v| !v.zero? } if @data.is_a?(Numo::Bit)
  a
end

#to_htmlObject

for IRuby



399
400
401
402
403
404
405
406
407
408
# File 'lib/rover/vector.rb', line 399

def to_html
  require "iruby"

  if size > 7
    # pass 8 rows so maxrows is applied
    IRuby::HTML.table(first(4).to_a + last(4).to_a, maxrows: 7)
  else
    IRuby::HTML.table(to_a)
  end
end

#to_numoObject



44
45
46
# File 'lib/rover/vector.rb', line 44

def to_numo
  @data
end

#typeObject



31
32
33
# File 'lib/rover/vector.rb', line 31

def type
  TYPE_CAST_MAPPING.find { |_, v| @data.is_a?(v) }[0]
end

#uniqObject



64
65
66
# File 'lib/rover/vector.rb', line 64

def uniq
  Vector.new(to_a.uniq)
end

#varObject

uses Bessel’s correction for now since that’s all Numo supports



304
305
306
# File 'lib/rover/vector.rb', line 304

def var
  @data.cast_to(Numo::DFloat).var
end

#zip(other, &block) ⇒ Object



324
325
326
# File 'lib/rover/vector.rb', line 324

def zip(other, &block)
  to_a.zip(other.to_a, &block)
end