red_amber 0.1.8 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,35 +1,55 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RedAmber
4
- # data frame class
5
- # @table : holds Arrow::Table object
4
+ # Class to represent a data frame.
5
+ # Variable @table holds an Arrow::Table object.
6
6
  class DataFrame
7
7
  # mix-in
8
8
  include DataFrameDisplayable
9
9
  include DataFrameIndexable
10
+ include DataFrameReshaping
10
11
  include DataFrameSelectable
11
12
  include DataFrameVariableOperation
12
13
  include Helper
13
14
 
15
+ # Creates a new RedAmber::DataFrame.
16
+ #
17
+ # @overload initialize(hash)
18
+ #
19
+ # @params hash [Hash]
20
+ #
21
+ # @overload initialize(table)
22
+ #
23
+ # @params table [Arrow::Table]
24
+ #
25
+ # @overload initialize(dataframe)
26
+ #
27
+ # @params dataframe [RedAmber::DataFrame, Rover::DataFrame]
28
+ #
29
+ # @overload initialize(null)
30
+ #
31
+ # @params null [NilClass] No arguments.
32
+ #
14
33
  def initialize(*args)
15
34
  @variables = @keys = @vectors = @types = @data_types = nil
16
- if args.empty? || args[0] == [] || args[0] == {} || args[0].nil?
35
+ case args
36
+ in nil | [nil] | [] | {} | [[]] | [{}]
17
37
  # DataFrame.new, DataFrame.new([]), DataFrame.new({}), DataFrame.new(nil)
18
38
  # returns empty DataFrame
19
39
  @table = Arrow::Table.new({}, [])
20
- elsif args.size > 1
21
- @table = Arrow::Table.new(*args)
40
+ in [Arrow::Table => table]
41
+ @table = table
42
+ in [DataFrame => dataframe]
43
+ @table = dataframe.table
44
+ in [rover_or_hash]
45
+ begin
46
+ # Accepts Rover::DataFrame or Hash
47
+ @table = Arrow::Table.new(rover_or_hash.to_h)
48
+ rescue StandardError
49
+ raise DataFrameTypeError, "invalid argument: #{rover_or_hash}"
50
+ end
22
51
  else
23
- arg = args[0]
24
- @table =
25
- case arg
26
- when Arrow::Table then arg
27
- when DataFrame then arg.table
28
- when Rover::DataFrame then Arrow::Table.new(arg.to_h)
29
- when Hash then Arrow::Table.new(arg)
30
- else
31
- raise DataFrameTypeError, "invalid argument: #{arg}"
32
- end
52
+ @table = Arrow::Table.new(*args)
33
53
  end
34
54
  name_unnamed_keys
35
55
  end
@@ -48,56 +68,101 @@ module RedAmber
48
68
  @table.save(output, options)
49
69
  end
50
70
 
71
+ # Returns the number of rows.
72
+ #
73
+ # @return [Integer] Number of rows.
51
74
  def size
52
75
  @table.n_rows
53
76
  end
54
77
  alias_method :n_rows, :size
55
78
  alias_method :n_obs, :size
56
79
 
80
+ # Returns the number of columns.
81
+ #
82
+ # @return [Integer] Number of columns.
57
83
  def n_keys
58
84
  @table.n_columns
59
85
  end
60
86
  alias_method :n_cols, :n_keys
61
87
  alias_method :n_vars, :n_keys
62
88
 
89
+ # Returns the numbers of rows and columns.
90
+ #
91
+ # @return [Array]
92
+ # Number of rows and number of columns in an array.
93
+ # Same as [size, n_keys].
63
94
  def shape
64
95
  [size, n_keys]
65
96
  end
66
97
 
98
+ # Returns a Hash of key and Vector pairs in the columns.
99
+ #
100
+ # @return [Hash]
101
+ # key => Vector pairs for each columns.
67
102
  def variables
68
103
  @variables || @variables = init_instance_vars(:variables)
69
104
  end
70
105
  alias_method :vars, :variables
71
106
 
107
+ # Returns an Array of keys.
108
+ #
109
+ # @return [Array]
110
+ # Keys in an Array.
72
111
  def keys
73
112
  @keys || @keys = init_instance_vars(:keys)
74
113
  end
75
114
  alias_method :column_names, :keys
76
115
  alias_method :var_names, :keys
77
116
 
117
+ # Returns true if self has a specified key in the argument.
118
+ #
119
+ # @param key [Symbol, String] Key to test.
120
+ # @return [Boolean]
121
+ # Returns true if self has key in Symbol.
78
122
  def key?(key)
79
123
  keys.include?(key.to_sym)
80
124
  end
81
125
  alias_method :has_key?, :key?
82
126
 
127
+ # Returns index of specified key in the Array keys.
128
+ #
129
+ # @param key [Symbol, String] key to know.
130
+ # @return [Integer]
131
+ # Index of key in the Array keys.
83
132
  def key_index(key)
84
133
  keys.find_index(key.to_sym)
85
134
  end
86
135
  alias_method :find_index, :key_index
87
136
  alias_method :index, :key_index
88
137
 
138
+ # Returns abbreviated type names in an Array.
139
+ #
140
+ # @return [Array]
141
+ # Abbreviated Red Arrow data type names.
89
142
  def types
90
143
  @types || @types = @table.columns.map { |column| column.data.value_type.nick.to_sym }
91
144
  end
92
145
 
146
+ # Returns an Array of Classes of data type.
147
+ #
148
+ # @return [Array]
149
+ # An Array of Red Arrow data type Classes.
93
150
  def type_classes
94
151
  @data_types || @data_types = @table.columns.map { |column| column.data_type.class }
95
152
  end
96
153
 
154
+ # Returns Vectors in an Array.
155
+ #
156
+ # @return [Array]
157
+ # An Array of RedAmber::Vector s.
97
158
  def vectors
98
159
  @vectors || @vectors = init_instance_vars(:vectors)
99
160
  end
100
161
 
162
+ # Returns row indices (0...size) in an Array.
163
+ #
164
+ # @return [Array]
165
+ # An Array of all indices of rows.
101
166
  def indices
102
167
  (0...size).to_a
103
168
  end
@@ -126,6 +191,18 @@ module RedAmber
126
191
  variables.empty?
127
192
  end
128
193
 
194
+ def each_row
195
+ return enum_for(:each_row) unless block_given?
196
+
197
+ size.times do |i|
198
+ key_row_pairs =
199
+ vectors.each_with_object({}) do |v, h|
200
+ h[v.key] = v.data[i]
201
+ end
202
+ yield key_row_pairs
203
+ end
204
+ end
205
+
129
206
  def to_rover
130
207
  require 'rover'
131
208
  Rover::DataFrame.new(to_h)
@@ -7,15 +7,34 @@ module RedAmber
7
7
  module DataFrameDisplayable
8
8
  INDEX_KEY = :index_key_for_format_table
9
9
 
10
- def to_s
10
+ def to_s(width: 80)
11
11
  return '' if empty?
12
12
 
13
- format_table(width: 80)
13
+ format_table(width: width)
14
14
  end
15
15
 
16
- # def describe() end
17
-
18
- # def summary() end
16
+ # Show statistical summary by a new DatFrame.
17
+ # Make stats for numeric columns only.
18
+ # NaNs are ignored.
19
+ # Counts also show non-NaN counts.
20
+ #
21
+ # @return [DataFrame] a new dataframe.
22
+ def summary
23
+ num_keys = keys.select { |key| self[key].numeric? }
24
+
25
+ DataFrame.new(
26
+ variables: num_keys,
27
+ count: num_keys.map { |k| self[k].count },
28
+ mean: num_keys.map { |k| self[k].mean },
29
+ std: num_keys.map { |k| self[k].std },
30
+ min: num_keys.map { |k| self[k].min },
31
+ '25%': num_keys.map { |k| self[k].quantile(0.25) },
32
+ median: num_keys.map { |k| self[k].median },
33
+ '75%': num_keys.map { |k| self[k].quantile(0.75) },
34
+ max: num_keys.map { |k| self[k].max }
35
+ )
36
+ end
37
+ alias_method :describe, :summary
19
38
 
20
39
  def inspect
21
40
  if ENV.fetch('RED_AMBER_OUTPUT_MODE', 'Table') == 'TDR'
@@ -133,11 +152,7 @@ module RedAmber
133
152
  a
134
153
  end
135
154
 
136
- def format_table(width: 80)
137
- head = 5
138
- tail = 3
139
- n_digit = 1
140
-
155
+ def format_table(width: 80, head: 5, tail: 3, n_digit: 2)
141
156
  original = self
142
157
  indices = size > head + tail ? [*0...head, *(size - tail)...size] : [*0...size]
143
158
  df = slice(indices).assign do
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RedAmber
4
+ # mix-ins for the class DataFrame
5
+ module DataFrameReshaping
6
+ # Transpose a wide DataFrame.
7
+ #
8
+ # @param key [Symbol, FalseClass] key of the index column
9
+ # to transepose into keys.
10
+ # If it is false, keys[0] is used.
11
+ # @param new_key [Symbol, FalseClass] key name of transposed index column.
12
+ # If it is false, :name is used. If it already exists, :name1.succ is used.
13
+ # @return [DataFrame] trnsposed DataFrame
14
+ def transpose(key: keys.first, new_key: :name)
15
+ raise DataFrameArgumentError, "Not include: #{key}" unless keys.include?(key)
16
+
17
+ # Find unused name
18
+ new_keys = self[key].to_a.map { |e| e.to_s.to_sym }
19
+ new_key = (:name1..).find { |k| !new_keys.include?(k) } if new_keys.include?(new_key)
20
+
21
+ hash = { new_key => (keys - [key]) }
22
+ i = keys.index(key)
23
+ each_row do |h|
24
+ k = h.values[i]
25
+ hash[k] = h.values - [k]
26
+ end
27
+ DataFrame.new(hash)
28
+ end
29
+
30
+ # Reshape wide DataFrame to a longer DataFrame.
31
+ #
32
+ # @param keep_keys [Array] keys to keep.
33
+ # @param name [Symbol, String] key of the column which is come **from values**.
34
+ # @param value [Symbol, String] key of the column which is come **from values**.
35
+ # @return [DataFrame] long DataFrame.
36
+ def to_long(*keep_keys, name: :name, value: :value)
37
+ not_included = keep_keys - keys
38
+ raise DataFrameArgumentError, "Not have keys #{not_included}" unless not_included.empty?
39
+
40
+ name = name.to_sym
41
+ raise DataFrameArgumentError, "Invalid key: #{name}" if keep_keys.include?(name)
42
+
43
+ value = value.to_sym
44
+ raise DataFrameArgumentError, "Invalid key: #{value}" if keep_keys.include?(value)
45
+
46
+ hash = Hash.new { |h, k| h[k] = [] }
47
+ l = keys.size - keep_keys.size
48
+ each_row do |row|
49
+ row.each do |k, v|
50
+ if keep_keys.include?(k)
51
+ hash[k].concat([v] * l)
52
+ else
53
+ hash[name] << k
54
+ hash[value] << v
55
+ end
56
+ end
57
+ end
58
+ DataFrame.new(hash)
59
+ end
60
+
61
+ # Reshape long DataFrame to a wide DataFrame.
62
+ #
63
+ # @param name [Symbol, String] key of the column which will be expanded **to key names**.
64
+ # @param value [Symbol, String] key of the column which will be expanded **to values**.
65
+ # @return [DataFrame] wide DataFrame.
66
+ def to_wide(name: :name, value: :value)
67
+ name = name.to_sym
68
+ raise DataFrameArgumentError, "Invalid key: #{name}" unless keys.include?(name)
69
+
70
+ value = value.to_sym
71
+ raise DataFrameArgumentError, "Invalid key: #{value}" unless keys.include?(value)
72
+
73
+ hash = Hash.new { |h, k| h[k] = {} }
74
+ keep_keys = keys - [name, value]
75
+ each_row do |row|
76
+ keeps, converts = row.partition { |k, _| keep_keys.include?(k) }
77
+ h = converts.to_h
78
+ hash[keeps.to_h][h[name].to_s.to_sym] = h[value]
79
+ end
80
+ ks = hash.first[0].keys + hash.first[1].keys
81
+ vs = hash.map { |k, v| k.values + v.values }.transpose
82
+ DataFrame.new(ks.zip(vs))
83
+ end
84
+ end
85
+ end
@@ -44,64 +44,106 @@ module RedAmber
44
44
  raise DataFrameArgumentError, "Invalid argument #{args}"
45
45
  end
46
46
 
47
- # rename variables to create new DataFrame
48
- def rename(*args, &block)
49
- renamer = args
47
+ # rename variables to create a new DataFrame
48
+ def rename(*renamer, &block)
50
49
  if block
51
- raise DataFrameArgumentError, 'Must not specify both arguments and a block' unless args.empty?
50
+ raise DataFrameArgumentError, 'Must not specify both arguments and a block' unless renamer.empty?
52
51
 
53
- renamer = instance_eval(&block)
52
+ renamer = [instance_eval(&block)]
54
53
  end
55
- renamer = [renamer].flatten
56
- return self if renamer.empty?
54
+ case renamer
55
+ in [] | [nil] | [{}] | [[]]
56
+ return self
57
+ in [Hash => key_pairs]
58
+ # noop
59
+ in [ (Symbol | String) => from, (Symbol | String) => to]
60
+ key_pairs = { from => to }
61
+ in [Array => array_in_array]
62
+ key_pairs = try_convert_to_hash(array_in_array)
63
+ in [Array, *] => array_in_array1
64
+ key_pairs = try_convert_to_hash(array_in_array1)
65
+ else
66
+ raise DataFrameArgumentError, "Invalid argument #{renamer}"
67
+ end
68
+ rename_by_hash(key_pairs)
69
+ end
57
70
 
58
- return rename_by_hash([renamer].to_h) if renamer.size == 2 && sym_or_str?(renamer) # rename(from, to)
59
- return rename_by_hash(renamer[0]) if renamer.one? && renamer[0].is_a?(Hash) # rename({from => to})
71
+ # assign variables to create a new DataFrame
72
+ def assign(*assigner, &block)
73
+ appender, fields, arrays = assign_update(*assigner, &block)
74
+ return self if appender.is_a?(DataFrame)
60
75
 
61
- raise DataFrameArgumentError, "Invalid argument #{args}"
76
+ append_to_fields_and_arrays(appender, fields, arrays, append_to_left: false) unless appender.empty?
77
+
78
+ DataFrame.new(Arrow::Table.new(Arrow::Schema.new(fields), arrays))
79
+ end
80
+
81
+ def assign_left(*assigner, &block)
82
+ appender, fields, arrays = assign_update(*assigner, &block)
83
+ return self if appender.is_a?(DataFrame)
84
+
85
+ append_to_fields_and_arrays(appender, fields, arrays, append_to_left: true) unless appender.empty?
86
+
87
+ DataFrame.new(Arrow::Table.new(Arrow::Schema.new(fields), arrays))
62
88
  end
63
89
 
64
- # assign variables to create new DataFrame
65
- def assign(*args, &block)
66
- assigner = args
90
+ private
91
+
92
+ def assign_update(*assigner, &block)
67
93
  if block
68
- raise DataFrameArgumentError, 'Must not specify both arguments and a block' unless args.empty?
94
+ raise DataFrameArgumentError, 'Must not specify both arguments and a block' unless assigner.empty?
69
95
 
70
- assigner = instance_eval(&block)
96
+ assigner = [instance_eval(&block)]
97
+ end
98
+ case assigner
99
+ in [] | [nil] | [{}] | [[]]
100
+ return self
101
+ in [Hash => key_array_pairs]
102
+ # noop
103
+ in [(Symbol | String) => key, (Vector | Array | Arrow::Array) => array]
104
+ key_array_pairs = { key => array }
105
+ in [Array => array_in_array]
106
+ key_array_pairs = try_convert_to_hash(array_in_array)
107
+ in [Array, *] => array_in_array1
108
+ key_array_pairs = try_convert_to_hash(array_in_array1)
109
+ else
110
+ raise DataFrameArgumentError, "Invalid argument #{assigner}"
71
111
  end
72
- assigner = [assigner].flatten
73
- return self if assigner.empty? || assigner == [nil]
74
-
75
- raise DataFrameArgumentError, "Invalid argument #{args}" unless assigner.one? && assigner[0].is_a?(Hash)
76
112
 
77
113
  updater = {}
78
114
  appender = {}
79
- assigner[0].each do |key, value|
115
+ key_array_pairs.each do |key, array|
80
116
  if keys.include? key
81
- updater[key] = value
117
+ updater[key] = array
82
118
  else
83
- appender[key] = value
119
+ appender[key] = array
84
120
  end
85
121
  end
86
- fields, arrays = update_fields_and_arrays(updater)
87
- append_to_fields_and_arrays(appender, fields, arrays) unless appender.empty?
88
-
89
- DataFrame.new(Arrow::Table.new(Arrow::Schema.new(fields), arrays))
122
+ [appender, *update_fields_and_arrays(updater)]
90
123
  end
91
124
 
92
- private
125
+ def try_convert_to_hash(array)
126
+ array.to_h
127
+ rescue TypeError
128
+ [array].to_h
129
+ rescue TypeError # rubocop:disable Lint/DuplicateRescueException
130
+ raise DataFrameArgumentError, "Invalid argument in Array #{array}"
131
+ end
93
132
 
94
133
  def rename_by_hash(key_pairs)
95
- fields = keys.map do |key|
96
- new_key = key_pairs[key]
97
- if new_key
98
- Arrow::Field.new(new_key.to_sym, @table[key].data_type)
99
- else
100
- @table.schema[key]
134
+ not_existing_keys = key_pairs.keys - keys
135
+ raise DataFrameArgumentError, "Not existing: #{not_existing_keys}" unless not_existing_keys.empty?
136
+
137
+ fields =
138
+ keys.map do |key|
139
+ new_key = key_pairs[key]
140
+ if new_key
141
+ Arrow::Field.new(new_key.to_sym, @table[key].data_type)
142
+ else
143
+ @table.schema[key]
144
+ end
101
145
  end
102
- end
103
- schema = Arrow::Schema.new(fields)
104
- DataFrame.new(Arrow::Table.new(schema, @table.columns))
146
+ DataFrame.new(Arrow::Table.new(Arrow::Schema.new(fields), @table.columns))
105
147
  end
106
148
 
107
149
  def update_fields_and_arrays(updater)
@@ -120,13 +162,20 @@ module RedAmber
120
162
  [fields, arrays]
121
163
  end
122
164
 
123
- def append_to_fields_and_arrays(appender, fields, arrays)
124
- appender.each do |key, data|
165
+ def append_to_fields_and_arrays(appender, fields, arrays, append_to_left: false)
166
+ enum = append_to_left ? appender.reverse_each : appender.each
167
+ enum.each do |key, data|
125
168
  raise DataFrameArgumentError, "Data size mismatch (#{data.size} != #{size})" if data.size != size
126
169
 
127
170
  a = Arrow::Array.new(data.is_a?(Vector) ? data.to_a : data)
128
- fields << Arrow::Field.new(key.to_sym, a.value_data_type)
129
- arrays << Arrow::ChunkedArray.new([a])
171
+
172
+ if append_to_left
173
+ fields.unshift(Arrow::Field.new(key.to_sym, a.value_data_type))
174
+ arrays.unshift(Arrow::ChunkedArray.new([a]))
175
+ else
176
+ fields << Arrow::Field.new(key.to_sym, a.value_data_type)
177
+ arrays << Arrow::ChunkedArray.new([a])
178
+ end
130
179
  end
131
180
  end
132
181
 
@@ -3,6 +3,10 @@
3
3
  module RedAmber
4
4
  # group class
5
5
  class Group
6
+ # Creates a new Group object.
7
+ #
8
+ # @param dataframe [DataFrame] dataframe to be grouped.
9
+ # @param group_keys [Array<>] keys for grouping.
6
10
  def initialize(dataframe, *group_keys)
7
11
  @dataframe = dataframe
8
12
  @table = @dataframe.table
@@ -50,7 +54,7 @@ module RedAmber
50
54
  raise GroupArgumentError, "#{d} is not a key of\n #{@dataframe}." unless summary_keys.empty? || d.empty?
51
55
 
52
56
  df = RedAmber::DataFrame.new(@group.send(func, *summary_keys))
53
- df = df[df.keys[-1], df.keys[0...-1]]
57
+ df = df[@group_keys, df.keys - @group_keys]
54
58
  # if counts are the same (no nil included), aggregate count columns.
55
59
  df = df[df.keys[0..1]].rename(df.keys[1], :count) if func == :count && df.to_h.values[1..].uniq.size == 1
56
60
  df
@@ -39,9 +39,53 @@ module RedAmber
39
39
 
40
40
  # Returns other than value
41
41
  # - mode
42
- # - quantile
43
42
  # - tdigest
44
43
 
44
+ # Return quantile
45
+ # 0.5 quantile (median) is returned by default.
46
+ # Or return quantile for specified probability (prob).
47
+ # If quantile lies between two data points, interpolated value is
48
+ # returned based on selected interpolation method.
49
+ # Nils and NaNs are ignored.
50
+ # Nil is returned if there are no valid data point.
51
+ #
52
+ # @param prob [Float] probability.
53
+ # @param interpolation [Symbol] specifies interpolation method to use,
54
+ # when the quantile lies between the data i and j.
55
+ # - Default value is :linear, which returns i + (j - i) * fraction.
56
+ # - :lower returns i.
57
+ # - :higher returns j.
58
+ # - :nearest returns i or j, whichever is closer.
59
+ # - :midpoint returns (i + j) / 2.
60
+ # @param skip_nils [Boolean] wheather to ignore nil.
61
+ # @param min_count [Integer] min count.
62
+ # @return [Float] quantile.
63
+ def quantile(prob = 0.5, interpolation: :linear, skip_nils: true, min_count: 0)
64
+ raise VectorArgumentError, "Invalid: probability #{prob} must be between 0 and 1" unless (0..1).cover? prob
65
+
66
+ datum = find(:quantile).execute([data],
67
+ q: prob,
68
+ interpolation: interpolation,
69
+ skip_nulls: skip_nils,
70
+ min_count: min_count)
71
+ datum.value.to_a.first
72
+ end
73
+
74
+ # Return quantiles in a DataFrame
75
+ #
76
+ def quantiles(probs = [1.0, 0.75, 0.5, 0.25, 0.0], interpolation: :linear, skip_nils: true, min_count: 0)
77
+ if probs.empty? || !probs.all? { |q| (0..1).cover?(q) }
78
+ raise VectorArgumentError, "Invarid probavilities #{probs}"
79
+ end
80
+
81
+ DataFrame.new(
82
+ probs: probs,
83
+ quantiles: probs.map do |q|
84
+ quantile(q, interpolation: interpolation, skip_nils: skip_nils, min_count: min_count)
85
+ end
86
+ )
87
+ end
88
+
45
89
  # [Unary element-wise]: vector.func => vector
46
90
  unary_element_wise =
47
91
  %i[abs array_sort_indices atan bit_wise_not ceil cos fill_null_backward fill_null_forward floor is_finite
@@ -63,6 +107,7 @@ module RedAmber
63
107
 
64
108
  alias_method :sort_indexes, :array_sort_indices
65
109
  alias_method :sort_indices, :array_sort_indices
110
+ alias_method :sort_index, :array_sort_indices
66
111
 
67
112
  alias_method :uniq, :unique
68
113
 
@@ -111,7 +111,7 @@ module RedAmber
111
111
 
112
112
  index_array = Arrow::UInt64ArrayBuilder.build(normalized_indices.data) # round to integer array
113
113
 
114
- datum = find(:array_take).execute([data, index_array])
114
+ datum = find(:take).execute([data, index_array]) # :array_take will fail with ChunkedArray
115
115
  Vector.new(datum.value)
116
116
  end
117
117
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RedAmber
4
- VERSION = '0.1.8'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/red_amber.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'arrow'
4
- require 'rover-df'
5
4
 
6
5
  require_relative 'red_amber/helper'
7
6
  require_relative 'red_amber/data_frame_displayable'
8
7
  require_relative 'red_amber/data_frame_indexable'
8
+ require_relative 'red_amber/data_frame_reshaping'
9
9
  require_relative 'red_amber/data_frame_selectable'
10
10
  require_relative 'red_amber/data_frame_variable_operation'
11
11
  require_relative 'red_amber/data_frame'
data/red_amber.gemspec CHANGED
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
31
  spec.require_paths = ['lib']
32
32
 
33
- spec.add_dependency 'red-arrow', '>= 8.0.0'
33
+ spec.add_dependency 'red-arrow', '>= 9.0.0'
34
34
 
35
35
  # Development dependency has gone to the Gemfile (rubygems/bundler#7237)
36
36
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: red_amber
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hirokazu SUZUKI (heronshoes)
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-03 00:00:00.000000000 Z
11
+ date: 2022-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: red-arrow
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 8.0.0
19
+ version: 9.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 8.0.0
26
+ version: 9.0.0
27
27
  description: RedAmber is a simple dataframe library inspired by Rover-df and powered
28
28
  by Red Arrow.
29
29
  email:
@@ -69,6 +69,7 @@ files:
69
69
  - lib/red_amber/data_frame.rb
70
70
  - lib/red_amber/data_frame_displayable.rb
71
71
  - lib/red_amber/data_frame_indexable.rb
72
+ - lib/red_amber/data_frame_reshaping.rb
72
73
  - lib/red_amber/data_frame_selectable.rb
73
74
  - lib/red_amber/data_frame_variable_operation.rb
74
75
  - lib/red_amber/group.rb