charty 0.1.4.dev → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +71 -0
- data/.github/workflows/nmatrix.yml +67 -0
- data/.github/workflows/pycall.yml +86 -0
- data/Dockerfile.dev +9 -1
- data/Gemfile +18 -0
- data/README.md +128 -9
- data/Rakefile +4 -5
- data/charty.gemspec +7 -2
- data/examples/Gemfile +1 -0
- data/examples/active_record.ipynb +34 -34
- data/examples/daru.ipynb +71 -29
- data/examples/iris_dataset.ipynb +12 -5
- data/examples/nmatrix.ipynb +30 -30
- data/examples/numo_narray.ipynb +245 -0
- data/examples/palette.rb +71 -0
- data/examples/sample.png +0 -0
- data/examples/sample_bokeh.ipynb +156 -0
- data/examples/sample_google_chart.ipynb +229 -68
- data/examples/sample_gruff.ipynb +148 -133
- data/examples/sample_images/bar_bokeh.html +85 -0
- data/examples/sample_images/barh_bokeh.html +85 -0
- data/examples/sample_images/barh_gruff.png +0 -0
- data/examples/sample_images/box_plot_bokeh.html +85 -0
- data/examples/sample_images/{boxplot_pyplot.png → box_plot_pyplot.png} +0 -0
- data/examples/sample_images/curve_bokeh.html +85 -0
- data/examples/sample_images/curve_with_function_bokeh.html +85 -0
- data/examples/sample_images/{errorbar_pyplot.png → error_bar_pyplot.png} +0 -0
- data/examples/sample_images/hist_gruff.png +0 -0
- data/examples/sample_images/scatter_bokeh.html +85 -0
- data/examples/sample_pyplot.ipynb +37 -35
- data/images/penguins_body_mass_g_flipper_length_mm_scatter_plot.png +0 -0
- data/images/penguins_body_mass_g_flipper_length_mm_species_scatter_plot.png +0 -0
- data/images/penguins_body_mass_g_flipper_length_mm_species_sex_scatter_plot.png +0 -0
- data/images/penguins_species_body_mass_g_bar_plot_h.png +0 -0
- data/images/penguins_species_body_mass_g_bar_plot_v.png +0 -0
- data/images/penguins_species_body_mass_g_box_plot_h.png +0 -0
- data/images/penguins_species_body_mass_g_box_plot_v.png +0 -0
- data/images/penguins_species_body_mass_g_sex_bar_plot_v.png +0 -0
- data/images/penguins_species_body_mass_g_sex_box_plot_v.png +0 -0
- data/lib/charty.rb +13 -7
- data/lib/charty/backend_methods.rb +8 -0
- data/lib/charty/backends.rb +80 -0
- data/lib/charty/backends/bokeh.rb +80 -0
- data/lib/charty/backends/google_charts.rb +267 -0
- data/lib/charty/backends/gruff.rb +104 -67
- data/lib/charty/backends/plotly.rb +549 -0
- data/lib/charty/backends/pyplot.rb +584 -86
- data/lib/charty/backends/rubyplot.rb +82 -74
- data/lib/charty/backends/unicode_plot.rb +79 -0
- data/lib/charty/index.rb +213 -0
- data/lib/charty/linspace.rb +1 -1
- data/lib/charty/missing_value_support.rb +14 -0
- data/lib/charty/plot_methods.rb +184 -0
- data/lib/charty/plotter.rb +57 -41
- data/lib/charty/plotters.rb +11 -0
- data/lib/charty/plotters/abstract_plotter.rb +156 -0
- data/lib/charty/plotters/bar_plotter.rb +216 -0
- data/lib/charty/plotters/box_plotter.rb +94 -0
- data/lib/charty/plotters/categorical_plotter.rb +380 -0
- data/lib/charty/plotters/count_plotter.rb +7 -0
- data/lib/charty/plotters/estimation_support.rb +84 -0
- data/lib/charty/plotters/random_support.rb +25 -0
- data/lib/charty/plotters/relational_plotter.rb +518 -0
- data/lib/charty/plotters/scatter_plotter.rb +115 -0
- data/lib/charty/plotters/vector_plotter.rb +6 -0
- data/lib/charty/statistics.rb +114 -0
- data/lib/charty/table.rb +82 -3
- data/lib/charty/table_adapters.rb +25 -0
- data/lib/charty/table_adapters/active_record_adapter.rb +63 -0
- data/lib/charty/table_adapters/base_adapter.rb +69 -0
- data/lib/charty/table_adapters/daru_adapter.rb +70 -0
- data/lib/charty/table_adapters/datasets_adapter.rb +49 -0
- data/lib/charty/table_adapters/hash_adapter.rb +224 -0
- data/lib/charty/table_adapters/narray_adapter.rb +76 -0
- data/lib/charty/table_adapters/nmatrix_adapter.rb +67 -0
- data/lib/charty/table_adapters/pandas_adapter.rb +81 -0
- data/lib/charty/vector.rb +69 -0
- data/lib/charty/vector_adapters.rb +183 -0
- data/lib/charty/vector_adapters/array_adapter.rb +109 -0
- data/lib/charty/vector_adapters/daru_adapter.rb +171 -0
- data/lib/charty/vector_adapters/narray_adapter.rb +187 -0
- data/lib/charty/vector_adapters/nmatrix_adapter.rb +37 -0
- data/lib/charty/vector_adapters/numpy_adapter.rb +168 -0
- data/lib/charty/vector_adapters/pandas_adapter.rb +200 -0
- data/lib/charty/version.rb +1 -1
- metadata +127 -13
- data/.travis.yml +0 -11
- data/examples/numo-narray.ipynb +0 -234
- data/lib/charty/backends/google_chart.rb +0 -167
- data/lib/charty/plotter_adapter.rb +0 -17
@@ -0,0 +1,81 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module Charty
|
4
|
+
module TableAdapters
|
5
|
+
class PandasDataFrameAdapter < BaseAdapter
|
6
|
+
TableAdapters.register(:pandas_data_frame, self)
|
7
|
+
|
8
|
+
extend Forwardable
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
def self.supported?(data)
|
12
|
+
defined?(Pandas::DataFrame) && data.is_a?(Pandas::DataFrame)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(data, columns: nil, index: nil)
|
16
|
+
@data = check_type(Pandas::DataFrame, data, :data)
|
17
|
+
|
18
|
+
self.columns = columns unless columns.nil?
|
19
|
+
self.index = index unless index.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :data
|
23
|
+
|
24
|
+
def columns
|
25
|
+
PandasIndex.new(data.columns)
|
26
|
+
end
|
27
|
+
|
28
|
+
def columns=(new_columns)
|
29
|
+
case new_columns
|
30
|
+
when PandasIndex
|
31
|
+
data.columns = new_columns.values
|
32
|
+
when Index
|
33
|
+
data.columns = new_columns.to_a
|
34
|
+
else
|
35
|
+
data.columns = new_columns
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def index
|
40
|
+
PandasIndex.new(data.index)
|
41
|
+
end
|
42
|
+
|
43
|
+
def index=(new_index)
|
44
|
+
case new_index
|
45
|
+
when PandasIndex
|
46
|
+
data.index = new_index.values
|
47
|
+
when Index
|
48
|
+
data.index = new_index.to_a
|
49
|
+
else
|
50
|
+
data.index = new_index
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def column_names
|
55
|
+
@data.columns.to_a
|
56
|
+
end
|
57
|
+
|
58
|
+
def compare_data_equality(other)
|
59
|
+
case other
|
60
|
+
when PandasDataFrameAdapter
|
61
|
+
data.equals(other.data)
|
62
|
+
else
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def [](row, column)
|
68
|
+
if row
|
69
|
+
@data[column][row]
|
70
|
+
else
|
71
|
+
Vector.new(@data[column])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private def check_type(type, data, name)
|
76
|
+
return data if data.is_a?(type)
|
77
|
+
raise TypeError, "#{name} must be a #{type}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module Charty
|
4
|
+
class Vector
|
5
|
+
extend Forwardable
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def self.try_convert(obj)
|
9
|
+
case obj
|
10
|
+
when self
|
11
|
+
obj
|
12
|
+
else
|
13
|
+
if VectorAdapters.find_adapter_class(obj, exception: false)
|
14
|
+
new(obj)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(data, index: nil, name: nil)
|
20
|
+
adapter_class = VectorAdapters.find_adapter_class(data)
|
21
|
+
@adapter = adapter_class.new(data)
|
22
|
+
self.index = index unless index.nil?
|
23
|
+
self.name = name unless name.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :adapter
|
27
|
+
|
28
|
+
def_delegators :adapter, :data
|
29
|
+
def_delegators :adapter, :index, :index=
|
30
|
+
def_delegators :adapter, :==, :[], :[]=
|
31
|
+
|
32
|
+
def_delegators :adapter, :length
|
33
|
+
def_delegators :adapter, :name, :name=
|
34
|
+
|
35
|
+
alias size length
|
36
|
+
|
37
|
+
def_delegators :adapter, :to_a
|
38
|
+
def_delegators :adapter, :each
|
39
|
+
def_delegators :adapter, :empty?
|
40
|
+
|
41
|
+
def_delegators :adapter, :boolean?, :numeric?, :categorical?
|
42
|
+
def_delegators :adapter, :categories
|
43
|
+
def_delegators :adapter, :unique_values
|
44
|
+
def_delegators :adapter, :group_by
|
45
|
+
def_delegators :adapter, :drop_na
|
46
|
+
def_delegators :adapter, :values_at
|
47
|
+
|
48
|
+
def_delegators :adapter, :eq, :notnull
|
49
|
+
|
50
|
+
alias completecases notnull
|
51
|
+
|
52
|
+
def_delegators :adapter, :mean, :stdev
|
53
|
+
|
54
|
+
# TODO: write test
|
55
|
+
def categorical_order(order=nil)
|
56
|
+
if order.nil?
|
57
|
+
case
|
58
|
+
when categorical?
|
59
|
+
order = categories
|
60
|
+
else
|
61
|
+
order = unique_values.compact
|
62
|
+
order.sort! if numeric?
|
63
|
+
end
|
64
|
+
order.compact!
|
65
|
+
end
|
66
|
+
order
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module Charty
|
4
|
+
module VectorAdapters
|
5
|
+
class UnsupportedVectorData < StandardError; end
|
6
|
+
|
7
|
+
@adapters = {}
|
8
|
+
|
9
|
+
def self.register(name, adapter_class)
|
10
|
+
@adapters[name] = adapter_class
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.find_adapter_class(data, exception: true)
|
14
|
+
@adapters.each_value do |adapter_class|
|
15
|
+
return adapter_class if adapter_class.supported?(data)
|
16
|
+
end
|
17
|
+
if exception
|
18
|
+
raise UnsupportedVectorData, "Unsupported vector data (#{data.class})"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class BaseAdapter
|
23
|
+
extend Forwardable
|
24
|
+
include Enumerable
|
25
|
+
include MissingValueSupport
|
26
|
+
|
27
|
+
def self.adapter_name
|
28
|
+
name[/:?(\w+)Adapter\z/, 1]
|
29
|
+
end
|
30
|
+
|
31
|
+
private def check_data(data)
|
32
|
+
return data if self.class.supported?(data)
|
33
|
+
raise UnsupportedVectorData, "Unsupported vector data (#{data.class})"
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :data
|
37
|
+
|
38
|
+
def_delegators :data, :length, :size
|
39
|
+
|
40
|
+
def ==(other)
|
41
|
+
case other.adapter
|
42
|
+
when BaseAdapter
|
43
|
+
return false if other.index != index
|
44
|
+
if respond_to?(:compare_data_equality)
|
45
|
+
compare_data_equality(other.adapter)
|
46
|
+
elsif other.adapter.respond_to?(:compare_data_equality)
|
47
|
+
other.adapter.compare_data_equality(self)
|
48
|
+
else
|
49
|
+
case other.adapter
|
50
|
+
when self.class
|
51
|
+
data == other.data
|
52
|
+
else
|
53
|
+
false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
else
|
57
|
+
super
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def_delegators :data, :[], :[]=
|
62
|
+
def_delegators :data, :each, :to_a, :empty?
|
63
|
+
|
64
|
+
def where_in_array(mask)
|
65
|
+
mask = check_mask_vector(mask)
|
66
|
+
masked_data = []
|
67
|
+
masked_index = []
|
68
|
+
mask.each_with_index do |f, i|
|
69
|
+
case f
|
70
|
+
when true, 1
|
71
|
+
masked_data << data[i]
|
72
|
+
masked_index << index[i]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
return masked_data, masked_index
|
76
|
+
end
|
77
|
+
|
78
|
+
private def check_mask_vector(mask)
|
79
|
+
# ensure mask is boolean vector
|
80
|
+
case mask
|
81
|
+
when Charty::Vector
|
82
|
+
unless mask.boolean?
|
83
|
+
raise ArgumentError, "Unable to lookup items by a nonboolean vector"
|
84
|
+
end
|
85
|
+
mask
|
86
|
+
else
|
87
|
+
Charty::Vector.new(mask)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def mean
|
92
|
+
Statistics.mean(data)
|
93
|
+
end
|
94
|
+
|
95
|
+
def stdev(population: false)
|
96
|
+
Statistics.stdev(data, population: population)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
module NameSupport
|
101
|
+
attr_reader :name
|
102
|
+
|
103
|
+
def name=(value)
|
104
|
+
@name = check_name(value)
|
105
|
+
end
|
106
|
+
|
107
|
+
private def check_name(value)
|
108
|
+
value = String.try_convert(value) || value
|
109
|
+
case value
|
110
|
+
when String, Symbol
|
111
|
+
value
|
112
|
+
else
|
113
|
+
raise ArgumentError,
|
114
|
+
"name must be a String or a Symbol (#{value.class} is given)"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
module IndexSupport
|
120
|
+
attr_reader :index
|
121
|
+
|
122
|
+
def [](key)
|
123
|
+
case key
|
124
|
+
when Charty::Vector
|
125
|
+
where(key)
|
126
|
+
else
|
127
|
+
super(key_to_loc(key))
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def []=(key, val)
|
132
|
+
super(key_to_loc(key), val)
|
133
|
+
end
|
134
|
+
|
135
|
+
private def key_to_loc(key)
|
136
|
+
loc = self.index.loc(key)
|
137
|
+
if loc.nil?
|
138
|
+
if key.respond_to?(:to_int)
|
139
|
+
loc = key.to_int
|
140
|
+
else
|
141
|
+
raise KeyError.new("key not found: %p" % key,
|
142
|
+
receiver: __method__, key: key)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
loc
|
146
|
+
end
|
147
|
+
|
148
|
+
def index=(values)
|
149
|
+
@index = check_and_convert_index(values, :index, length)
|
150
|
+
end
|
151
|
+
|
152
|
+
private def check_and_convert_index(values, name, expected_length)
|
153
|
+
case values
|
154
|
+
when Index, Range
|
155
|
+
else
|
156
|
+
unless (ary = Array.try_convert(values))
|
157
|
+
raise ArgumentError, "invalid object for %s: %p" % [name, values]
|
158
|
+
end
|
159
|
+
values = ary
|
160
|
+
end
|
161
|
+
if expected_length != values.size
|
162
|
+
raise ArgumentError,
|
163
|
+
"invalid length for %s (%d for %d)" % [name, values.size, expected_length]
|
164
|
+
end
|
165
|
+
case values
|
166
|
+
when Index
|
167
|
+
values
|
168
|
+
when Range
|
169
|
+
RangeIndex.new(values)
|
170
|
+
when Array
|
171
|
+
Index.new(values)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
require_relative "vector_adapters/array_adapter"
|
179
|
+
require_relative "vector_adapters/daru_adapter"
|
180
|
+
require_relative "vector_adapters/narray_adapter"
|
181
|
+
require_relative "vector_adapters/nmatrix_adapter"
|
182
|
+
require_relative "vector_adapters/numpy_adapter"
|
183
|
+
require_relative "vector_adapters/pandas_adapter"
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require "date"
|
2
|
+
|
3
|
+
module Charty
|
4
|
+
module VectorAdapters
|
5
|
+
class ArrayAdapter < BaseAdapter
|
6
|
+
VectorAdapters.register(:array, self)
|
7
|
+
|
8
|
+
extend Forwardable
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
def self.supported?(data)
|
12
|
+
case data
|
13
|
+
when Array
|
14
|
+
case data[0]
|
15
|
+
when Numeric, String, Time, Date, DateTime, true, false, nil
|
16
|
+
true
|
17
|
+
else
|
18
|
+
false
|
19
|
+
end
|
20
|
+
else
|
21
|
+
false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(data, index: nil)
|
26
|
+
@data = check_data(data)
|
27
|
+
self.index = index || RangeIndex.new(0 ... length)
|
28
|
+
end
|
29
|
+
|
30
|
+
include NameSupport
|
31
|
+
include IndexSupport
|
32
|
+
|
33
|
+
# TODO: Reconsider the return value type of values_at
|
34
|
+
def_delegators :data, :values_at
|
35
|
+
|
36
|
+
def where(mask)
|
37
|
+
masked_data, masked_index = where_in_array(mask)
|
38
|
+
Charty::Vector.new(masked_data, index: masked_index, name: name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def first_nonnil
|
42
|
+
data.drop_while(&:nil?).first
|
43
|
+
end
|
44
|
+
|
45
|
+
def boolean?
|
46
|
+
case first_nonnil
|
47
|
+
when true, false
|
48
|
+
true
|
49
|
+
else
|
50
|
+
false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def numeric?
|
55
|
+
case first_nonnil
|
56
|
+
when Numeric
|
57
|
+
true
|
58
|
+
else
|
59
|
+
false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def categorical?
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def categories
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
|
71
|
+
def_delegator :data, :uniq, :unique_values
|
72
|
+
|
73
|
+
def group_by(grouper)
|
74
|
+
groups = data.each_index.group_by {|i| grouper[i] }
|
75
|
+
groups.map { |g, vals|
|
76
|
+
vals.collect! {|i| self[i] }
|
77
|
+
[g, Charty::Vector.new(vals)]
|
78
|
+
}.to_h
|
79
|
+
end
|
80
|
+
|
81
|
+
def drop_na
|
82
|
+
if numeric?
|
83
|
+
Charty::Vector.new(data.reject { |x|
|
84
|
+
case x
|
85
|
+
when Float
|
86
|
+
x.nan?
|
87
|
+
else
|
88
|
+
x.nil?
|
89
|
+
end
|
90
|
+
})
|
91
|
+
else
|
92
|
+
Charty::Vector.new(data.compact)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def eq(val)
|
97
|
+
Charty::Vector.new(data.map {|x| x == val },
|
98
|
+
index: index,
|
99
|
+
name: name)
|
100
|
+
end
|
101
|
+
|
102
|
+
def notnull
|
103
|
+
Charty::Vector.new(data.map {|x| ! missing_value?(x) },
|
104
|
+
index: index,
|
105
|
+
name: name)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
module Charty
|
2
|
+
module VectorAdapters
|
3
|
+
class DaruVectorAdapter < BaseAdapter
|
4
|
+
VectorAdapters.register(:daru_vector, self)
|
5
|
+
|
6
|
+
def self.supported?(data)
|
7
|
+
defined?(Daru::Vector) && data.is_a?(Daru::Vector)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(data)
|
11
|
+
@data = check_data(data)
|
12
|
+
end
|
13
|
+
|
14
|
+
def_delegator :data, :size, :length
|
15
|
+
|
16
|
+
def index
|
17
|
+
DaruIndex.new(data.index)
|
18
|
+
end
|
19
|
+
|
20
|
+
def index=(new_index)
|
21
|
+
case new_index
|
22
|
+
when DaruIndex
|
23
|
+
data.index = new_index.values
|
24
|
+
when Index
|
25
|
+
data.index = new_index.to_a
|
26
|
+
else
|
27
|
+
data.index = new_index
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def_delegators :data, :name, :name=
|
32
|
+
|
33
|
+
def compare_data_equality(other)
|
34
|
+
case other
|
35
|
+
when DaruVectorAdapter
|
36
|
+
data == other.data
|
37
|
+
when ArrayAdapter
|
38
|
+
data.to_a == other.data
|
39
|
+
when NArrayAdapter, NMatrixAdapter, NumpyAdapter, PandasSeriesAdapter
|
40
|
+
other.compare_data_equality(self)
|
41
|
+
else
|
42
|
+
data == other.data.to_a
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def [](key)
|
47
|
+
case key
|
48
|
+
when Charty::Vector
|
49
|
+
where(key)
|
50
|
+
else
|
51
|
+
data[key]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def_delegators :data, :[]=, :to_a
|
56
|
+
|
57
|
+
def values_at(*indices)
|
58
|
+
indices.map {|i| data[i] }
|
59
|
+
end
|
60
|
+
|
61
|
+
def where(mask)
|
62
|
+
masked_data, masked_index = where_in_array(mask)
|
63
|
+
Charty::Vector.new(Daru::Vector.new(masked_data, index: masked_index), name: name)
|
64
|
+
end
|
65
|
+
|
66
|
+
def where_in_array(mask)
|
67
|
+
mask = check_mask_vector(mask)
|
68
|
+
masked_data = []
|
69
|
+
masked_index = []
|
70
|
+
mask.each_with_index do |f, i|
|
71
|
+
case f
|
72
|
+
when true, 1
|
73
|
+
masked_data << data[i]
|
74
|
+
masked_index << data.index.key(i)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
return masked_data, masked_index
|
78
|
+
end
|
79
|
+
|
80
|
+
def first_nonnil
|
81
|
+
data.drop_while(&:nil?).first
|
82
|
+
end
|
83
|
+
|
84
|
+
def boolean?
|
85
|
+
case
|
86
|
+
when numeric?, categorical?
|
87
|
+
false
|
88
|
+
else
|
89
|
+
case first_nonnil
|
90
|
+
when true, false
|
91
|
+
true
|
92
|
+
else
|
93
|
+
false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def_delegators :data, :numeric?
|
99
|
+
def_delegator :data, :category?, :categorical?
|
100
|
+
|
101
|
+
def categories
|
102
|
+
data.categories.compact if categorical?
|
103
|
+
end
|
104
|
+
|
105
|
+
def unique_values
|
106
|
+
data.uniq.to_a
|
107
|
+
end
|
108
|
+
|
109
|
+
def group_by(grouper)
|
110
|
+
case grouper
|
111
|
+
when Daru::Vector
|
112
|
+
if grouper.category?
|
113
|
+
# TODO: A categorical Daru::Vector cannot perform group_by well
|
114
|
+
grouper = Daru::Vector.new(grouper.to_a)
|
115
|
+
end
|
116
|
+
groups = grouper.group_by.groups
|
117
|
+
groups.map { |g, indices|
|
118
|
+
[g.first, Charty::Vector.new(data[*indices])]
|
119
|
+
}.to_h
|
120
|
+
when Charty::Vector
|
121
|
+
case grouper.data
|
122
|
+
when Daru::Vector
|
123
|
+
return group_by(grouper.data)
|
124
|
+
else
|
125
|
+
return group_by(Daru::Vector.new(grouper.to_a))
|
126
|
+
end
|
127
|
+
else
|
128
|
+
return group_by(Charty::Vector.new(grouper))
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def drop_na
|
133
|
+
values = data.reject do |x|
|
134
|
+
case
|
135
|
+
when x.nil?,
|
136
|
+
x.respond_to?(:nan?) && x.nan?
|
137
|
+
true
|
138
|
+
else
|
139
|
+
false
|
140
|
+
end
|
141
|
+
end
|
142
|
+
Charty::Vector.new(Daru::Vector.new(values))
|
143
|
+
end
|
144
|
+
|
145
|
+
def eq(val)
|
146
|
+
Charty::Vector.new(data.eq(val).to_a,
|
147
|
+
index: data.index.to_a,
|
148
|
+
name: name)
|
149
|
+
end
|
150
|
+
|
151
|
+
def notnull
|
152
|
+
notnull_data = data.map {|x| ! missing_value?(x) }
|
153
|
+
Charty::Vector.new(notnull_data, index: data.index.to_a, name: name)
|
154
|
+
end
|
155
|
+
|
156
|
+
def_delegator :data, :mean
|
157
|
+
|
158
|
+
def stdev(population: false)
|
159
|
+
if population
|
160
|
+
data.standard_deviation_sample
|
161
|
+
else
|
162
|
+
data.standard_deviation_population
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def percentile(q)
|
167
|
+
data.linear_percentile(q)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|