daru 0.1.5 → 0.3
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 +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
|