Class: Daru::MultiIndex

Inherits:
Index show all
Defined in:
lib/daru/index/multi_index.rb

Instance Attribute Summary collapse

Attributes inherited from Index

#relation_hash

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Index

__new__, #_dump, _load, coerce, inherited, new, #slice

Constructor Details

#initialize(opts = {}) ⇒ MultiIndex

Returns a new instance of MultiIndex.

Raises:

  • (ArgumentError)

17
18
19
20
21
22
23
24
25
26
27
# File 'lib/daru/index/multi_index.rb', line 17

def initialize opts={}
  labels = opts[:labels]
  levels = opts[:levels]

  raise ArgumentError, 'Must specify both labels and levels' unless labels && levels
  raise ArgumentError, 'Labels and levels should be same size' if labels.size != levels.size
  raise ArgumentError, 'Incorrect labels and levels' if incorrect_fields?(labels, levels)

  @labels = labels
  @levels = levels.map { |e| e.map.with_index.to_h }
end

Instance Attribute Details

#labelsObject (readonly)

Returns the value of attribute labels


11
12
13
# File 'lib/daru/index/multi_index.rb', line 11

def labels
  @labels
end

Class Method Details

.from_arrays(arrays) ⇒ Object


37
38
39
40
41
42
43
44
45
46
# File 'lib/daru/index/multi_index.rb', line 37

def self.from_arrays arrays
  levels = arrays.map { |e| e.uniq.sort_by(&:to_s) }

  labels = arrays.each_with_index.map do |arry, level_index|
    level = levels[level_index]
    arry.map { |lvl| level.index(lvl) }
  end

  MultiIndex.new labels: labels, levels: levels
end

.from_tuples(tuples) ⇒ Object


48
49
50
# File 'lib/daru/index/multi_index.rb', line 48

def self.from_tuples tuples
  from_arrays tuples.transpose
end

.try_from_tuples(tuples) ⇒ Object


52
53
54
55
56
57
58
# File 'lib/daru/index/multi_index.rb', line 52

def self.try_from_tuples tuples
  if tuples.respond_to?(:first) && tuples.first.is_a?(Array)
    from_tuples(tuples)
  else
    nil
  end
end

Instance Method Details

#&(other) ⇒ Object


197
198
199
# File 'lib/daru/index/multi_index.rb', line 197

def & other
  MultiIndex.from_tuples(to_a & other.to_a)
end

#==(other) ⇒ Object


219
220
221
222
223
# File 'lib/daru/index/multi_index.rb', line 219

def == other
  self.class == other.class  &&
    labels   == other.labels &&
    levels   == other.levels
end

#[](*key) ⇒ Object


60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/daru/index/multi_index.rb', line 60

def [] *key
  key.flatten!
  case
  when key[0].is_a?(Range)
    retrieve_from_range(key[0])
  when key[0].is_a?(Integer) && key.size == 1
    try_retrieve_from_integer(key[0])
  else
    begin
      retrieve_from_tuples key
    rescue NoMethodError
      raise IndexError, "Specified index #{key.inspect} do not exist"
    end
  end
end

#add(*indexes) ⇒ Object


130
131
132
# File 'lib/daru/index/multi_index.rb', line 130

def add *indexes
  Daru::MultiIndex.from_tuples to_a << indexes
end

#at(*positions) ⇒ object

Takes positional values and returns subset of the self

capturing the indexes at mentioned positions

Examples:

idx = Daru::MultiIndex.from_tuples [[:a, :one], [:a, :two], [:b, :one], [:b, :two]]
idx.at 0, 1
# => #<Daru::MultiIndex(2x2)>
#   a one
#     two

Parameters:

  • positional (Array<Integer>)

    values

Returns:

  • (object)

    index object


120
121
122
123
124
125
126
127
128
# File 'lib/daru/index/multi_index.rb', line 120

def at *positions
  positions = preprocess_positions(*positions)
  validate_positions(*positions)
  if positions.is_a? Integer
    key(positions)
  else
    Daru::MultiIndex.from_tuples positions.map(&method(:key))
  end
end

#conform(input_indexes) ⇒ Object

Provide a MultiIndex for sub vector produced

Parameters:

  • input_indexes (Array)

    the input by user to index the vector

Returns:

  • (Object)

    the MultiIndex object for sub vector produced


247
248
249
250
# File 'lib/daru/index/multi_index.rb', line 247

def conform input_indexes
  return self if input_indexes[0].is_a? Range
  drop_left_level input_indexes.size
end

#drop_left_level(by = 1) ⇒ Object


189
190
191
# File 'lib/daru/index/multi_index.rb', line 189

def drop_left_level by=1
  MultiIndex.from_arrays to_a.transpose[by..-1]
end

#dupObject


185
186
187
# File 'lib/daru/index/multi_index.rb', line 185

def dup
  MultiIndex.new levels: levels.dup, labels: labels
end

#each(&block) ⇒ Object


3
4
5
# File 'lib/daru/index/multi_index.rb', line 3

def each(&block)
  to_a.each(&block)
end

#empty?Boolean

Returns:

  • (Boolean)

201
202
203
# File 'lib/daru/index/multi_index.rb', line 201

def empty?
  @labels.flatten.empty? && @levels.all?(&:empty?)
end

#include?(tuple) ⇒ Boolean

Returns:

  • (Boolean)

205
206
207
208
209
# File 'lib/daru/index/multi_index.rb', line 205

def include? tuple
  return false unless tuple.is_a? Enumerable
  tuple.flatten.each_with_index
       .all? { |tup, i| @levels[i][tup] }
end

#inspect(threshold = 20) ⇒ Object


233
234
235
236
# File 'lib/daru/index/multi_index.rb', line 233

def inspect threshold=20
  "#<Daru::MultiIndex(#{size}x#{width})>\n" +
    Formatters::Table.format([], row_headers: sparse_tuples, threshold: threshold)
end

#key(index) ⇒ Object

Raises:

  • (ArgumentError)

177
178
179
180
181
182
183
# File 'lib/daru/index/multi_index.rb', line 177

def key index
  raise ArgumentError, "Key #{index} is too large" if index >= @labels[0].size

  @labels
    .each_with_index
    .map { |label, i| @levels[i].keys[label[index]] }
end

#levelsObject


13
14
15
# File 'lib/daru/index/multi_index.rb', line 13

def levels
  @levels.map(&:keys)
end

#map(&block) ⇒ Object


7
8
9
# File 'lib/daru/index/multi_index.rb', line 7

def map(&block)
  to_a.map(&block)
end

#pos(*indexes) ⇒ Object

Note:

If the arugent is both a valid index and a valid position, it will treated as valid index

Returns positions given indexes or positions

Examples:

idx = Daru::MultiIndex.from_tuples [[:a, :one], [:a, :two], [:b, :one], [:b, :two]]
idx.pos :a
# => [0, 1]

Parameters:

  • *indexes (Array<object>)

    indexes or positions


92
93
94
95
96
97
98
99
100
# File 'lib/daru/index/multi_index.rb', line 92

def pos *indexes
  if indexes.first.is_a? Integer
    return indexes.first if indexes.size == 1
    return indexes
  end
  res = self[indexes]
  return res if res.is_a? Integer
  res.map { |i| self[i] }
end

#reorder(new_order) ⇒ Object


134
135
136
137
# File 'lib/daru/index/multi_index.rb', line 134

def reorder(new_order)
  from = to_a
  self.class.from_tuples(new_order.map { |i| from[i] })
end

#sizeObject


211
212
213
# File 'lib/daru/index/multi_index.rb', line 211

def size
  @labels[0].size
end

#sparse_tuplesObject

Return tuples with nils in place of repeating values, like this:

:a , :bar, :one
nil, nil , :two
nil, :foo, :one

258
259
260
261
262
263
264
# File 'lib/daru/index/multi_index.rb', line 258

def sparse_tuples
  tuples = to_a
  [tuples.first] + each_cons(2).map { |prev, cur|
    left = cur.zip(prev).drop_while { |c, p| c == p }
    [nil] * (cur.size - left.size) + left.map(&:first)
  }
end

#subset(*indexes) ⇒ Object


102
103
104
105
106
107
108
# File 'lib/daru/index/multi_index.rb', line 102

def subset *indexes
  if indexes.first.is_a? Integer
    MultiIndex.from_tuples(indexes.map { |index| key(index) })
  else
    self[indexes].conform indexes
  end
end

#to_aObject


225
226
227
# File 'lib/daru/index/multi_index.rb', line 225

def to_a
  (0...size).map { |e| key(e) }
end

#to_htmlObject


238
239
240
241
# File 'lib/daru/index/multi_index.rb', line 238

def to_html
  path = File.expand_path('../../iruby/templates/multi_index.html.erb', __FILE__)
  ERB.new(File.read(path).strip).result(binding)
end

#try_retrieve_from_integer(int) ⇒ Object


139
140
141
# File 'lib/daru/index/multi_index.rb', line 139

def try_retrieve_from_integer int
  @levels[0].key?(int) ? retrieve_from_tuples([int]) : int
end

#valid?(*indexes) ⇒ Boolean

Returns:

  • (Boolean)

76
77
78
79
80
81
82
# File 'lib/daru/index/multi_index.rb', line 76

def valid? *indexes
  # FIXME: This is perhaps not a good method
  pos(*indexes)
  return true
rescue IndexError
  return false
end

#valuesObject


229
230
231
# File 'lib/daru/index/multi_index.rb', line 229

def values
  Array.new(size) { |i| i }
end

#widthObject


215
216
217
# File 'lib/daru/index/multi_index.rb', line 215

def width
  @levels.size
end

#|(other) ⇒ Object


193
194
195
# File 'lib/daru/index/multi_index.rb', line 193

def | other
  MultiIndex.from_tuples(to_a | other.to_a)
end