daru 0.1.5 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/ISSUE_TEMPLATE.md +18 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +21 -7
- data/.travis.yml +10 -5
- data/CONTRIBUTING.md +15 -10
- data/History.md +124 -2
- data/README.md +37 -9
- data/ReleasePolicy.md +20 -0
- data/benchmarks/db_loading.rb +34 -0
- data/benchmarks/statistics.rb +6 -6
- data/benchmarks/where_clause.rb +1 -1
- data/benchmarks/where_vs_filter.rb +1 -1
- data/daru.gemspec +17 -41
- data/lib/daru.rb +10 -13
- data/lib/daru/accessors/gsl_wrapper.rb +1 -1
- data/lib/daru/accessors/nmatrix_wrapper.rb +2 -0
- data/lib/daru/category.rb +29 -15
- data/lib/daru/configuration.rb +34 -0
- data/lib/daru/core/group_by.rb +158 -77
- data/lib/daru/core/merge.rb +12 -3
- data/lib/daru/core/query.rb +20 -4
- data/lib/daru/dataframe.rb +692 -118
- data/lib/daru/date_time/index.rb +14 -11
- data/lib/daru/date_time/offsets.rb +9 -1
- data/lib/daru/extensions/which_dsl.rb +55 -0
- data/lib/daru/formatters/table.rb +3 -5
- data/lib/daru/index/categorical_index.rb +4 -4
- data/lib/daru/index/index.rb +131 -42
- data/lib/daru/index/multi_index.rb +118 -10
- data/lib/daru/io/csv/converters.rb +21 -0
- data/lib/daru/io/io.rb +105 -33
- data/lib/daru/io/sql_data_source.rb +10 -0
- data/lib/daru/iruby/templates/dataframe.html.erb +4 -51
- data/lib/daru/iruby/templates/dataframe_mi.html.erb +3 -56
- data/lib/daru/iruby/templates/dataframe_mi_tbody.html.erb +35 -0
- data/lib/daru/iruby/templates/dataframe_mi_thead.html.erb +21 -0
- data/lib/daru/iruby/templates/dataframe_tbody.html.erb +28 -0
- data/lib/daru/iruby/templates/dataframe_thead.html.erb +21 -0
- data/lib/daru/iruby/templates/vector.html.erb +3 -25
- data/lib/daru/iruby/templates/vector_mi.html.erb +3 -34
- data/lib/daru/iruby/templates/vector_mi_tbody.html.erb +26 -0
- data/lib/daru/iruby/templates/vector_mi_thead.html.erb +8 -0
- data/lib/daru/iruby/templates/vector_tbody.html.erb +17 -0
- data/lib/daru/iruby/templates/vector_thead.html.erb +8 -0
- data/lib/daru/maths/arithmetic/vector.rb +38 -2
- data/lib/daru/maths/statistics/dataframe.rb +28 -30
- data/lib/daru/maths/statistics/vector.rb +295 -41
- data/lib/daru/plotting/gruff/dataframe.rb +13 -15
- data/lib/daru/plotting/nyaplot/category.rb +1 -1
- data/lib/daru/plotting/nyaplot/dataframe.rb +15 -4
- data/lib/daru/plotting/nyaplot/vector.rb +1 -2
- data/lib/daru/vector.rb +308 -96
- data/lib/daru/version.rb +1 -1
- data/profile/vector_new.rb +9 -0
- data/spec/accessors/gsl_wrapper_spec.rb +38 -35
- data/spec/accessors/nmatrix_wrapper_spec.rb +25 -22
- data/spec/category_spec.rb +24 -20
- data/spec/core/group_by_spec.rb +238 -4
- data/spec/core/merge_spec.rb +1 -1
- data/spec/core/query_spec.rb +65 -50
- data/spec/daru_spec.rb +22 -0
- data/spec/dataframe_spec.rb +473 -16
- data/spec/date_time/date_time_index_helper_spec.rb +72 -0
- data/spec/date_time/index_spec.rb +34 -16
- data/spec/date_time/offsets_spec.rb +14 -0
- data/spec/extensions/rserve_spec.rb +1 -1
- data/spec/extensions/which_dsl_spec.rb +38 -0
- data/spec/fixtures/boolean_converter_test.csv +5 -0
- data/spec/fixtures/duplicates.csv +32 -0
- data/spec/fixtures/eciresults.html +394 -0
- data/spec/fixtures/empty_rows_test.csv +17 -0
- data/spec/fixtures/macau.html +3691 -0
- data/spec/fixtures/macd_data.csv +150 -0
- data/spec/fixtures/matrix_test.csv +55 -55
- data/spec/fixtures/moneycontrol.html +6812 -0
- data/spec/fixtures/string_converter_test.csv +5 -0
- data/spec/fixtures/test_xls.xls +0 -0
- data/spec/fixtures/test_xls_2.xls +0 -0
- data/spec/fixtures/url_test.txt~ +0 -0
- data/spec/fixtures/valid_markup.html +62 -0
- data/spec/fixtures/wiki_climate.html +1243 -0
- data/spec/fixtures/wiki_table_info.html +631 -0
- data/spec/formatters/table_formatter_spec.rb +29 -0
- data/spec/index/categorical_index_spec.rb +33 -33
- data/spec/index/index_spec.rb +160 -41
- data/spec/index/multi_index_spec.rb +143 -33
- data/spec/io/io_spec.rb +246 -2
- data/spec/io/sql_data_source_spec.rb +31 -41
- data/spec/iruby/dataframe_spec.rb +17 -19
- data/spec/iruby/vector_spec.rb +26 -28
- data/spec/maths/arithmetic/dataframe_spec.rb +1 -1
- data/spec/maths/arithmetic/vector_spec.rb +18 -0
- data/spec/maths/statistics/vector_spec.rb +153 -15
- data/spec/plotting/gruff/category_spec.rb +3 -3
- data/spec/plotting/gruff/dataframe_spec.rb +14 -4
- data/spec/plotting/gruff/vector_spec.rb +9 -9
- data/spec/plotting/nyaplot/category_spec.rb +5 -9
- data/spec/plotting/nyaplot/dataframe_spec.rb +95 -47
- data/spec/plotting/nyaplot/vector_spec.rb +5 -11
- data/spec/shared/vector_display_spec.rb +12 -14
- data/spec/spec_helper.rb +30 -7
- data/spec/support/matchers.rb +5 -0
- data/spec/vector_spec.rb +306 -72
- metadata +96 -55
- data/spec/fixtures/stock_data.csv +0 -500
data/lib/daru/date_time/index.rb
CHANGED
@@ -93,11 +93,12 @@ module Daru
|
|
93
93
|
def infer_offset data
|
94
94
|
diffs = data.each_cons(2).map { |d1, d2| d2 - d1 }
|
95
95
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
96
|
+
return nil unless diffs.uniq.count == 1
|
97
|
+
|
98
|
+
return TIME_INTERVALS[diffs.first].new if TIME_INTERVALS.include?(diffs.first)
|
99
|
+
|
100
|
+
number_of_seconds = diffs.first / Daru::Offsets::Second.new.multiplier
|
101
|
+
Daru::Offsets::Second.new(number_of_seconds.numerator) if number_of_seconds.denominator == 1
|
101
102
|
end
|
102
103
|
|
103
104
|
def find_index_of_date data, date_time
|
@@ -226,7 +227,7 @@ module Daru
|
|
226
227
|
to_a.each(&block)
|
227
228
|
end
|
228
229
|
|
229
|
-
attr_reader :frequency, :offset, :periods
|
230
|
+
attr_reader :frequency, :offset, :periods, :keys
|
230
231
|
|
231
232
|
# Create a DateTimeIndex with or without a frequency in data. The constructor
|
232
233
|
# should be used for creating DateTimeIndex by directly passing in DateTime
|
@@ -253,6 +254,7 @@ module Daru
|
|
253
254
|
# DateTime.new(2012,4,11), DateTime.new(2012,4,12)], freq: :infer)
|
254
255
|
# #=>#<DateTimeIndex:84198340 offset=D periods=8 data=[2012-04-05T00:00:00+00:00...2012-04-12T00:00:00+00:00]>
|
255
256
|
def initialize data, opts={freq: nil}
|
257
|
+
super data
|
256
258
|
Helper.possibly_convert_to_date_time data
|
257
259
|
|
258
260
|
@offset =
|
@@ -343,7 +345,7 @@ module Daru
|
|
343
345
|
|
344
346
|
# Retreive a slice or a an individual index number from the index.
|
345
347
|
#
|
346
|
-
# @param [String, DateTime] Specify a date partially (as a String) or
|
348
|
+
# @param key [String, DateTime] Specify a date partially (as a String) or
|
347
349
|
# completely to retrieve.
|
348
350
|
def [] *key
|
349
351
|
return slice(*key) if key.size != 1
|
@@ -405,7 +407,7 @@ module Daru
|
|
405
407
|
@data
|
406
408
|
else
|
407
409
|
@data.sort_by(&:last)
|
408
|
-
end.transpose.first
|
410
|
+
end.transpose.first || []
|
409
411
|
end
|
410
412
|
|
411
413
|
# Size of index.
|
@@ -419,6 +421,7 @@ module Daru
|
|
419
421
|
|
420
422
|
def inspect
|
421
423
|
meta = [@periods, @frequency ? "frequency=#{@frequency}" : nil].compact.join(', ')
|
424
|
+
return "#<#{self.class}(#{meta})>" if @data.empty?
|
422
425
|
"#<#{self.class}(#{meta}) " \
|
423
426
|
"#{@data.first[0]}...#{@data.last[0]}>"
|
424
427
|
end
|
@@ -490,7 +493,7 @@ module Daru
|
|
490
493
|
# @return [Array<Integer>] Array containing minutes of each index.
|
491
494
|
# @!method sec
|
492
495
|
# @return [Array<Integer>] Array containing seconds of each index.
|
493
|
-
[
|
496
|
+
%i[year month day hour min sec].each do |meth|
|
494
497
|
define_method(meth) do
|
495
498
|
each_with_object([]) do |d, arr|
|
496
499
|
arr << d.send(meth)
|
@@ -528,7 +531,7 @@ module Daru
|
|
528
531
|
slice first, last
|
529
532
|
end
|
530
533
|
|
531
|
-
def slice_between_dates first, last # rubocop:disable Metrics/AbcSize
|
534
|
+
def slice_between_dates first, last # rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity
|
532
535
|
# about that ^ disable: I'm waiting for cleaner understanding
|
533
536
|
# of offsets logic. Reference: https://github.com/v0dro/daru/commit/7e1c34aec9516a9ba33037b4a1daaaaf1de0726a#diff-a95ef410a8e1f4ea3cc48d231bb880faR250
|
534
537
|
start = @data.bsearch { |d| d[0] >= first }
|
@@ -542,7 +545,7 @@ module Daru
|
|
542
545
|
st = @data.index(start)
|
543
546
|
en = after_en ? @data.index(after_en) - 1 : Helper.last_date(@data)[1]
|
544
547
|
return start[1] if st == en
|
545
|
-
DateTimeIndex.new(@data[st..en].transpose[0])
|
548
|
+
DateTimeIndex.new(@data[st..en].transpose[0] || []) # empty slice guard
|
546
549
|
end
|
547
550
|
end
|
548
551
|
|
@@ -86,7 +86,7 @@ module Daru
|
|
86
86
|
|
87
87
|
module Offsets
|
88
88
|
class DateOffsetType < DateOffset
|
89
|
-
#
|
89
|
+
# @!method initialize(n)
|
90
90
|
# Initialize one of the subclasses of DateOffsetType with the number of the times
|
91
91
|
# the offset should be applied, which is the supplied as the argument.
|
92
92
|
#
|
@@ -111,6 +111,14 @@ module Daru
|
|
111
111
|
def - date_time
|
112
112
|
date_time - @n*multiplier
|
113
113
|
end
|
114
|
+
|
115
|
+
def ==(other_obj)
|
116
|
+
other_obj.is_a?(Tick) && period == other_obj.period
|
117
|
+
end
|
118
|
+
|
119
|
+
def period
|
120
|
+
@n * multiplier
|
121
|
+
end
|
114
122
|
end
|
115
123
|
|
116
124
|
# Create a seconds offset
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# Support for a simple query DSL for accessing where(), inspired by gem "squeel"
|
2
|
+
|
3
|
+
module Daru
|
4
|
+
class DataFrame
|
5
|
+
# a simple query DSL for accessing where(), inspired by gem "squeel"
|
6
|
+
# e.g.:
|
7
|
+
# df.which{ `FamilySize` == `FamilySize`.max }
|
8
|
+
# equals
|
9
|
+
# df.where( df['FamilySize'].eq( df['FamilySize'].max ) )
|
10
|
+
#
|
11
|
+
# e.g.:
|
12
|
+
# df.which{ (`NameTitle` == 'Dr') & (`Sex` == 'female') }
|
13
|
+
# equals
|
14
|
+
# df.where( df['NameTitle'].eq('Dr') & df['Sex'].eq('female') )
|
15
|
+
def which(&block)
|
16
|
+
WhichQuery.new(self, &block).exec
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class WhichQuery
|
21
|
+
def initialize(df, &condition)
|
22
|
+
@df = df
|
23
|
+
@condition = condition
|
24
|
+
end
|
25
|
+
|
26
|
+
# executes a block of DSL code
|
27
|
+
def exec
|
28
|
+
query = instance_eval(&@condition)
|
29
|
+
@df.where(query)
|
30
|
+
end
|
31
|
+
|
32
|
+
def `(vector_name)
|
33
|
+
if !@df.has_vector?(vector_name) && @df.has_vector?(vector_name.to_sym)
|
34
|
+
vector_name = vector_name.to_sym
|
35
|
+
end
|
36
|
+
VectorWrapper.new(@df[vector_name])
|
37
|
+
end
|
38
|
+
|
39
|
+
class VectorWrapper < SimpleDelegator
|
40
|
+
{
|
41
|
+
:== => :eq,
|
42
|
+
:!= => :not_eq,
|
43
|
+
:< => :lt,
|
44
|
+
:<= => :lteq,
|
45
|
+
:> => :mt,
|
46
|
+
:>= => :mteq,
|
47
|
+
:=~ => :in
|
48
|
+
}.each do |opt, method|
|
49
|
+
define_method opt do |*args|
|
50
|
+
send(method, *args)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -10,15 +10,13 @@ module Daru
|
|
10
10
|
@data = data || []
|
11
11
|
@headers = (headers || []).to_a
|
12
12
|
@row_headers = (row_headers || []).to_a
|
13
|
+
@row_headers = [''] * @data.to_a.size if @row_headers.empty?
|
13
14
|
end
|
14
15
|
|
15
|
-
DEFAULT_SPACING = 10
|
16
|
-
DEFAULT_THRESHOLD = 15
|
17
|
-
|
18
16
|
def format threshold=nil, spacing=nil
|
19
|
-
rows = build_rows(threshold ||
|
17
|
+
rows = build_rows(threshold || Daru.max_rows)
|
20
18
|
|
21
|
-
formatter = construct_formatter rows, spacing ||
|
19
|
+
formatter = construct_formatter rows, spacing || Daru.spacing
|
22
20
|
|
23
21
|
rows.map { |r| formatter % r }.join("\n")
|
24
22
|
end
|
@@ -45,7 +45,7 @@ module Daru
|
|
45
45
|
# Returns positions given categories or positions
|
46
46
|
# @note If the argument does not a valid category it treats it as position
|
47
47
|
# value and return it as it is.
|
48
|
-
# @param [Array<object>]
|
48
|
+
# @param indexes [Array<object>] categories or positions
|
49
49
|
# @example
|
50
50
|
# x = Daru::CategoricalIndex.new [:a, 1, :a, 1, :c]
|
51
51
|
# x.pos :a, 1
|
@@ -145,7 +145,7 @@ module Daru
|
|
145
145
|
end
|
146
146
|
|
147
147
|
# Return subset given categories or positions
|
148
|
-
# @param [Array<object>]
|
148
|
+
# @param indexes [Array<object>] categories or positions
|
149
149
|
# @return [Daru::CategoricalIndex] subset of the self containing the
|
150
150
|
# mentioned categories or positions
|
151
151
|
# @example
|
@@ -161,7 +161,7 @@ module Daru
|
|
161
161
|
|
162
162
|
# Takes positional values and returns subset of the self
|
163
163
|
# capturing the categories at mentioned positions
|
164
|
-
# @param [Array<Integer>] positional values
|
164
|
+
# @param positions [Array<Integer>] positional values
|
165
165
|
# @return [object] index object
|
166
166
|
# @example
|
167
167
|
# idx = Daru::CategoricalIndex.new [:a, :b, :a, :b, :c]
|
@@ -178,7 +178,7 @@ module Daru
|
|
178
178
|
end
|
179
179
|
|
180
180
|
# Add specified index values to the index object
|
181
|
-
# @param [Array<object>]
|
181
|
+
# @param indexes [Array<object>] index values to add
|
182
182
|
# @return [Daru::CategoricalIndex] index object with added values
|
183
183
|
# @example
|
184
184
|
# idx = Daru::CategoricalIndex.new [:a, :b, :a, :b, :c]
|
data/lib/daru/index/index.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Daru
|
2
|
-
class Index
|
2
|
+
class Index # rubocop:disable Metrics/ClassLength
|
3
3
|
include Enumerable
|
4
4
|
# It so happens that over riding the .new method in a super class also
|
5
5
|
# tampers with the default .new method for class that inherit from the
|
@@ -44,30 +44,37 @@ module Daru
|
|
44
44
|
end
|
45
45
|
|
46
46
|
attr_reader :relation_hash, :size
|
47
|
+
attr_accessor :name
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
49
|
+
# @example
|
50
|
+
#
|
51
|
+
# idx = Daru::Index.new [:one, 'one', 1, 2, :two]
|
52
|
+
# => #<Daru::Index(5): {one, one, 1, 2, two}>
|
53
|
+
#
|
54
|
+
# # set the name
|
55
|
+
#
|
56
|
+
# idx.name = "index_name"
|
57
|
+
# => "index_name"
|
58
|
+
#
|
59
|
+
# idx
|
60
|
+
# => #<Daru::Index(5): index_name {one, one, 1, 2, two}>
|
61
|
+
#
|
62
|
+
# # set the name during initialization
|
63
|
+
#
|
64
|
+
# idx = Daru::Index.new [:one, 'one', 1, 2, :two], name: "index_name"
|
65
|
+
# => #<Daru::Index(5): index_name {one, one, 1, 2, two}>
|
66
|
+
def initialize index, opts={}
|
67
|
+
index = guess_index index
|
62
68
|
@relation_hash = index.each_with_index.to_h.freeze
|
63
69
|
@keys = @relation_hash.keys
|
64
70
|
@size = @relation_hash.size
|
71
|
+
@name = opts[:name]
|
65
72
|
end
|
66
73
|
|
67
74
|
def ==(other)
|
68
75
|
return false if self.class != other.class || other.size != @size
|
69
76
|
|
70
|
-
@
|
77
|
+
@keys == other.to_a &&
|
71
78
|
@relation_hash.values == other.relation_hash.values
|
72
79
|
end
|
73
80
|
|
@@ -83,7 +90,7 @@ module Daru
|
|
83
90
|
end
|
84
91
|
|
85
92
|
# Returns true if all arguments are either a valid category or position
|
86
|
-
# @param [Array<object>]
|
93
|
+
# @param indexes [Array<object>] categories or positions
|
87
94
|
# @return [true, false]
|
88
95
|
# @example
|
89
96
|
# idx.valid? :a, 2
|
@@ -97,7 +104,7 @@ module Daru
|
|
97
104
|
# Returns positions given indexes or positions
|
98
105
|
# @note If the arugent is both a valid index and a valid position,
|
99
106
|
# it will treated as valid index
|
100
|
-
# @param [Array<object>]
|
107
|
+
# @param indexes [Array<object>] indexes or positions
|
101
108
|
# @example
|
102
109
|
# x = Daru::Index.new [:a, :b, :c]
|
103
110
|
# x.pos :a, 1
|
@@ -106,27 +113,30 @@ module Daru
|
|
106
113
|
indexes = preprocess_range(indexes.first) if indexes.first.is_a? Range
|
107
114
|
|
108
115
|
if indexes.size == 1
|
109
|
-
|
116
|
+
numeric_pos indexes.first
|
110
117
|
else
|
111
|
-
indexes.map { |index|
|
118
|
+
indexes.map { |index| numeric_pos index }
|
112
119
|
end
|
113
120
|
end
|
114
121
|
|
115
122
|
def subset *indexes
|
116
123
|
if indexes.first.is_a? Range
|
117
|
-
|
124
|
+
start = indexes.first.begin
|
125
|
+
en = indexes.first.end
|
126
|
+
|
127
|
+
subset_slice start, en
|
118
128
|
elsif include? indexes.first
|
119
129
|
# Assume 'indexes' contain indexes not positions
|
120
130
|
Daru::Index.new indexes
|
121
131
|
else
|
122
132
|
# Assume 'indexes' contain positions not indexes
|
123
|
-
Daru::Index.new
|
133
|
+
Daru::Index.new(indexes.map { |k| key k })
|
124
134
|
end
|
125
135
|
end
|
126
136
|
|
127
137
|
# Takes positional values and returns subset of the self
|
128
138
|
# capturing the indexes at mentioned positions
|
129
|
-
# @param [Array<Integer>] positional values
|
139
|
+
# @param positions [Array<Integer>] positional values
|
130
140
|
# @return [object] index object
|
131
141
|
# @example
|
132
142
|
# idx = Daru::Index.new [:a, :b, :c]
|
@@ -143,10 +153,11 @@ module Daru
|
|
143
153
|
end
|
144
154
|
|
145
155
|
def inspect threshold=20
|
156
|
+
name_part = @name ? "#{@name} " : ''
|
146
157
|
if size <= threshold
|
147
|
-
"#<#{self.class}(#{size}): {#{to_a.join(', ')}}>"
|
158
|
+
"#<#{self.class}(#{size}): #{name_part}{#{to_a.join(', ')}}>"
|
148
159
|
else
|
149
|
-
"#<#{self.class}(#{size}): {#{to_a.first(threshold).join(', ')} ... #{to_a.last}}>"
|
160
|
+
"#<#{self.class}(#{size}): #{name_part}{#{to_a.first(threshold).join(', ')} ... #{to_a.last}}>"
|
150
161
|
end
|
151
162
|
end
|
152
163
|
|
@@ -154,12 +165,27 @@ module Daru
|
|
154
165
|
start = args[0]
|
155
166
|
en = args[1]
|
156
167
|
|
168
|
+
start_idx = @relation_hash[start]
|
169
|
+
en_idx = @relation_hash[en]
|
170
|
+
|
171
|
+
if start_idx.nil?
|
172
|
+
nil
|
173
|
+
elsif en_idx.nil?
|
174
|
+
Array(start_idx..size-1)
|
175
|
+
else
|
176
|
+
Array(start_idx..en_idx)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def subset_slice *args
|
181
|
+
start = args[0]
|
182
|
+
en = args[1]
|
183
|
+
|
157
184
|
if start.is_a?(Integer) && en.is_a?(Integer)
|
158
185
|
Index.new @keys[start..en]
|
159
186
|
else
|
160
187
|
start_idx = @relation_hash[start]
|
161
188
|
en_idx = @relation_hash[en]
|
162
|
-
|
163
189
|
Index.new @keys[start_idx..en_idx]
|
164
190
|
end
|
165
191
|
end
|
@@ -175,7 +201,7 @@ module Daru
|
|
175
201
|
end
|
176
202
|
|
177
203
|
def to_a
|
178
|
-
@
|
204
|
+
@keys
|
179
205
|
end
|
180
206
|
|
181
207
|
def key(value)
|
@@ -187,12 +213,33 @@ module Daru
|
|
187
213
|
@relation_hash.key? index
|
188
214
|
end
|
189
215
|
|
216
|
+
# @note Do not use it to check for Float::NAN as
|
217
|
+
# Float::NAN == Float::NAN is false
|
218
|
+
# Return vector of booleans with value at ith position is either
|
219
|
+
# true or false depending upon whether index value at position i is equal to
|
220
|
+
# any of the values passed in the argument or not
|
221
|
+
# @param indexes [Array] values to equate with
|
222
|
+
# @return [Daru::Vector] vector of boolean values
|
223
|
+
# @example
|
224
|
+
# dv = Daru::Index.new [1, 2, 3, :one, 'one']
|
225
|
+
# dv.is_values 1, 'one'
|
226
|
+
# # => #<Daru::Vector(5)>
|
227
|
+
# # 0 true
|
228
|
+
# # 1 false
|
229
|
+
# # 2 false
|
230
|
+
# # 3 false
|
231
|
+
# # 4 true
|
232
|
+
def is_values(*indexes) # rubocop:disable Style/PredicateName
|
233
|
+
bool_array = @keys.map { |r| indexes.include?(r) }
|
234
|
+
Daru::Vector.new(bool_array)
|
235
|
+
end
|
236
|
+
|
190
237
|
def empty?
|
191
|
-
@
|
238
|
+
@size.zero?
|
192
239
|
end
|
193
240
|
|
194
241
|
def dup
|
195
|
-
Daru::Index.new @
|
242
|
+
Daru::Index.new @keys, name: @name
|
196
243
|
end
|
197
244
|
|
198
245
|
def add *indexes
|
@@ -211,7 +258,7 @@ module Daru
|
|
211
258
|
|
212
259
|
# Provide an Index for sub vector produced
|
213
260
|
#
|
214
|
-
# @
|
261
|
+
# @option * [Array] the input by user to index the vector
|
215
262
|
# @return [Object] the Index object for sub vector produced
|
216
263
|
def conform(*)
|
217
264
|
self
|
@@ -222,8 +269,49 @@ module Daru
|
|
222
269
|
self.class.new(new_order.map { |i| from[i] })
|
223
270
|
end
|
224
271
|
|
272
|
+
# Sorts a `Index`, according to its values. Defaults to ascending order
|
273
|
+
# sorting.
|
274
|
+
#
|
275
|
+
# @param [Hash] opts the options for sort method.
|
276
|
+
# @option opts [Boolean] :ascending False, to get descending order.
|
277
|
+
#
|
278
|
+
# @return [Index] sorted `Index` according to its values.
|
279
|
+
#
|
280
|
+
# @example
|
281
|
+
# di = Daru::Index.new [100, 99, 101, 1, 2]
|
282
|
+
# # Say you want to sort in descending order
|
283
|
+
# di.sort(ascending: false) #=> Daru::Index.new [101, 100, 99, 2, 1]
|
284
|
+
# # Say you want to sort in ascending order
|
285
|
+
# di.sort #=> Daru::Index.new [1, 2, 99, 100, 101]
|
286
|
+
def sort opts={}
|
287
|
+
opts = {ascending: true}.merge(opts)
|
288
|
+
|
289
|
+
new_index = @keys.sort
|
290
|
+
new_index = new_index.reverse unless opts[:ascending]
|
291
|
+
|
292
|
+
self.class.new(new_index)
|
293
|
+
end
|
294
|
+
|
295
|
+
def to_df
|
296
|
+
Daru::DataFrame.new(name => to_a)
|
297
|
+
end
|
298
|
+
|
225
299
|
private
|
226
300
|
|
301
|
+
def guess_index index
|
302
|
+
case index
|
303
|
+
when nil
|
304
|
+
[]
|
305
|
+
when Integer
|
306
|
+
index.times.to_a
|
307
|
+
when Enumerable
|
308
|
+
index.to_a
|
309
|
+
else
|
310
|
+
raise ArgumentError,
|
311
|
+
"Cannot create index from #{index.class} #{index.inspect}"
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
227
315
|
def preprocess_range rng
|
228
316
|
start = rng.begin
|
229
317
|
en = rng.end
|
@@ -243,30 +331,21 @@ module Daru
|
|
243
331
|
end
|
244
332
|
|
245
333
|
def by_multi_key *key
|
246
|
-
|
247
|
-
Daru::Index.new key.map { |k| k }
|
248
|
-
else
|
249
|
-
# Assume the user is specifing values for index not keys
|
250
|
-
# Return index object having keys corresponding to values provided
|
251
|
-
Daru::Index.new key.map { |k| key k }
|
252
|
-
end
|
334
|
+
key.map { |k| by_single_key k }
|
253
335
|
end
|
254
336
|
|
255
337
|
def by_single_key key
|
256
338
|
if @relation_hash.key?(key)
|
257
339
|
@relation_hash[key]
|
258
|
-
elsif key.is_a?(Numeric) && key < size
|
259
|
-
key
|
260
340
|
else
|
261
|
-
|
341
|
+
nil
|
262
342
|
end
|
263
343
|
end
|
264
344
|
|
265
345
|
# Raises IndexError when one of the positions is an invalid position
|
266
346
|
def validate_positions *positions
|
267
|
-
positions = [positions] if positions.is_a? Integer
|
268
347
|
positions.each do |pos|
|
269
|
-
raise IndexError, "#{pos} is not a valid position." if pos >= size
|
348
|
+
raise IndexError, "#{pos} is not a valid position." if pos >= size || pos < -size
|
270
349
|
end
|
271
350
|
end
|
272
351
|
|
@@ -285,5 +364,15 @@ module Daru
|
|
285
364
|
positions
|
286
365
|
end
|
287
366
|
end
|
367
|
+
|
368
|
+
def numeric_pos key
|
369
|
+
if @relation_hash.key?(key)
|
370
|
+
@relation_hash[key]
|
371
|
+
elsif key.is_a?(Numeric) && (key < size && key >= -size)
|
372
|
+
key
|
373
|
+
else
|
374
|
+
raise IndexError, "Specified index #{key.inspect} does not exist"
|
375
|
+
end
|
376
|
+
end
|
288
377
|
end
|
289
378
|
end
|