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
}

Instance Method Summary collapse

Constructor Details

#initialize(data, type: nil) ⇒ Vector

Returns a new instance of Vector.

Raises:

  • (ArgumentError)


24
25
26
27
# File 'lib/rover/vector.rb', line 24

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



147
148
149
150
151
152
153
# File 'lib/rover/vector.rb', line 147

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

#-@Object



155
156
157
# File 'lib/rover/vector.rb', line 155

def -@
  self * -1
end

#[](v) ⇒ Object



86
87
88
89
90
91
92
# File 'lib/rover/vector.rb', line 86

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

#[]=(k, v) ⇒ Object



94
95
96
97
# File 'lib/rover/vector.rb', line 94

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

#absObject



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

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

#all?(&block) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#any?(&block) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#clamp(min, max) ⇒ Object



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

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

#clamp!(min, max) ⇒ Object



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

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

#crosstab(other) ⇒ Object



283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/rover/vector.rb', line 283

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



81
82
83
84
# File 'lib/rover/vector.rb', line 81

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

#each(&block) ⇒ Object



204
205
206
# File 'lib/rover/vector.rb', line 204

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

#each_with_index(&block) ⇒ Object



208
209
210
# File 'lib/rover/vector.rb', line 208

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

#first(n = 1) ⇒ Object



262
263
264
265
266
267
268
# File 'lib/rover/vector.rb', line 262

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

#head(n = 5) ⇒ Object



296
297
298
299
# File 'lib/rover/vector.rb', line 296

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

#in?(values) ⇒ Boolean

Returns:

  • (Boolean)


133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/rover/vector.rb', line 133

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

#inspectObject Also known as: to_s

TODO add type and size?



321
322
323
324
325
# File 'lib/rover/vector.rb', line 321

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

#last(n = 1) ⇒ Object



270
271
272
273
274
275
276
# File 'lib/rover/vector.rb', line 270

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

#map(&block) ⇒ Object



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

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

#map!(&block) ⇒ Object



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

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

#maxObject



212
213
214
# File 'lib/rover/vector.rb', line 212

def max
  @data.max
end

#meanObject



220
221
222
223
224
# File 'lib/rover/vector.rb', line 220

def mean
  # currently only floats have mean in Numo
  # https://github.com/ruby-numo/numo-narray/issues/79
  @data.cast_to(Numo::DFloat).mean
end

#medianObject



226
227
228
229
230
# File 'lib/rover/vector.rb', line 226

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

#minObject



216
217
218
# File 'lib/rover/vector.rb', line 216

def min
  @data.min
end

#missingObject



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

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)


52
53
54
# File 'lib/rover/vector.rb', line 52

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

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

Raises:

  • (ArgumentError)


306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/rover/vector.rb', line 306

def one_hot(drop: false, prefix: nil)
  raise ArgumentError, "All elements must be strings" unless all? { |vi| vi.is_a?(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



232
233
234
# File 'lib/rover/vector.rb', line 232

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

#reject(&block) ⇒ Object



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

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

#select(&block) ⇒ Object



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

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

#sizeObject Also known as: length, count



56
57
58
# File 'lib/rover/vector.rb', line 56

def size
  @data.size
end

#sortObject



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

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



241
242
243
# File 'lib/rover/vector.rb', line 241

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

#sumObject



236
237
238
# File 'lib/rover/vector.rb', line 236

def sum
  @data.sum
end

#tail(n = 5) ⇒ Object



301
302
303
304
# File 'lib/rover/vector.rb', line 301

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

#take(n) ⇒ Object

Raises:

  • (ArgumentError)


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

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

#tallyObject



187
188
189
190
191
192
193
194
# File 'lib/rover/vector.rb', line 187

def tally
  result = Hash.new(0)
  @data.each do |v|
    result[v] += 1
  end
  result.default = nil
  result
end

#to(type) ⇒ Object



33
34
35
# File 'lib/rover/vector.rb', line 33

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

#to!(type) ⇒ Object



37
38
39
40
# File 'lib/rover/vector.rb', line 37

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

#to_aObject



46
47
48
49
50
# File 'lib/rover/vector.rb', line 46

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

#to_htmlObject

for IRuby



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

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



42
43
44
# File 'lib/rover/vector.rb', line 42

def to_numo
  @data
end

#typeObject



29
30
31
# File 'lib/rover/vector.rb', line 29

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

#uniqObject



62
63
64
# File 'lib/rover/vector.rb', line 62

def uniq
  Vector.new(to_a.uniq)
end

#varObject

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



246
247
248
# File 'lib/rover/vector.rb', line 246

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

#zip(other, &block) ⇒ Object



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

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