Class: GroupedFrame

Inherits:
Object
  • Object
show all
Defined in:
lib/carray/frame/group.rb

Overview

GroupedFrame — the result of CAFrame#group_by (memo §11.6, §16).

Holds the grouping categorical once (grouping is per-key, computed once and shared across every column). Three surfaces:

grp["col"]   -> the CArray group iterator (raw exposure)
aggregate    -> declarative per-column reductions into a new frame
table { |g| }-> cross-column Ruby escape, g is a per-group view-frame

Instance Method Summary collapse

Constructor Details

#initialize(frame, cat, axis_name, key_names = []) ⇒ GroupedFrame

key_names are the frame columns the grouping was keyed on. They become the result's index, so the reduction shortcuts must not also return them as reduced columns; an external CArray key contributes no name.



69
70
71
72
73
74
75
# File 'lib/carray/frame/group.rb', line 69

def initialize(frame, cat, axis_name, key_names = [])
  @frame     = frame
  @cat       = cat
  @axis_name = axis_name
  @key_names = key_names
  @labels    = cat.labels          # group values, in code order
end

Instance Method Details

#[](name) ⇒ Object

Raw exposure: the CArray group iterator for one column (memo §11.6).



88
89
90
# File 'lib/carray/frame/group.rb', line 88

def [](name)
  @frame[name].group_by_category(@cat)
end

#aggregate(spec) ⇒ Object

Declarative aggregation (memo §11.6). Spec maps an output column name to [input_column, reduction], where reduction is a Symbol (vectorized, applied through the group iterator) or a Proc (per-group custom, called with the group's column slice).



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/carray/frame/group.rb', line 96

def aggregate(spec)
  cols = {}
  spec.each do |out_name, (in_name, reduction)|
    out = out_name.to_s
    cols[out] =
      case reduction
      when Symbol
        self[in_name].public_send(reduction)
      when Proc
        per_group_column(in_name, reduction)
      else
        raise ArgumentError,
              "reduction must be a Symbol or Proc (got #{reduction.class})"
      end
  end
  CAFrame.new(cols, axis_name: @axis_name, index: label_index)
end

#inspect ⇒ String

Returns:

  • (String)


160
161
162
# File 'lib/carray/frame/group.rb', line 160

def inspect
  "#<GroupedFrame ngroup=#{ngroup} by=#{@axis_name.inspect}>"
end

#labels ⇒ Object

Group key values (one per group), as an Array.



83
84
85
# File 'lib/carray/frame/group.rb', line 83

def labels
  @labels.dup
end

#max ⇒ CAFrame

Returns a frame of the per-group maximum of every numeric one-dimensional column, as #sum does.

Returns:



155
156
157
# File 'lib/carray/frame/group.rb', line 155

[:sum, :mean, :min, :max].each do |red|
  define_method(red) { reduce_numeric(red) }
end

#mean ⇒ CAFrame

Returns a frame of the per-group arithmetic mean of every numeric one-dimensional column, as #sum does.

Returns:



155
156
157
# File 'lib/carray/frame/group.rb', line 155

[:sum, :mean, :min, :max].each do |red|
  define_method(red) { reduce_numeric(red) }
end

#min ⇒ CAFrame

Returns a frame of the per-group minimum of every numeric one-dimensional column, as #sum does.

Returns:



155
156
157
# File 'lib/carray/frame/group.rb', line 155

[:sum, :mean, :min, :max].each do |red|
  define_method(red) { reduce_numeric(red) }
end

#ngroup ⇒ Object

Number of groups.



78
79
80
# File 'lib/carray/frame/group.rb', line 78

def ngroup
  @labels.size
end

#sum ⇒ CAFrame

Returns a frame of the per-group sum of every numeric one-dimensional column. Non-numeric and multi-dimensional columns are left out.

Returns:

  • (CAFrame) —

    one row per group, indexed by the group labels.



155
156
157
# File 'lib/carray/frame/group.rb', line 155

[:sum, :mean, :min, :max].each do |red|
  define_method(red) { reduce_numeric(red) }
end

#table ⇒ Object

Cross-column Ruby escape (memo §11.6). The block receives a per-group view-frame and returns a Hash of output-name => value; the values are collected column-wise across groups into a new frame.



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/carray/frame/group.rb', line 117

def table
  collected = {}
  order = nil
  each_group_frame do |g|
    out = yield(g)
    unless out.is_a?(Hash)
      raise ArgumentError, "table block must return a Hash (got #{out.class})"
    end
    order ||= out.keys.map(&:to_s)
    out.each { |k, v| (collected[k.to_s] ||= []) << v }
  end
  cols = {}
  (order || []).each do |name|
    vals = collected[name]
    cols[name] = CArray.object(vals.size) { |i| vals[i] }
  end
  CAFrame.new(cols, axis_name: @axis_name, index: label_index)
end