daru 0.1.5 → 0.1.6

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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +20 -7
  3. data/CONTRIBUTING.md +1 -1
  4. data/History.md +48 -1
  5. data/README.md +3 -3
  6. data/benchmarks/statistics.rb +6 -6
  7. data/benchmarks/where_clause.rb +1 -1
  8. data/benchmarks/where_vs_filter.rb +1 -1
  9. data/daru.gemspec +3 -2
  10. data/lib/daru.rb +14 -6
  11. data/lib/daru/accessors/gsl_wrapper.rb +1 -1
  12. data/lib/daru/accessors/nmatrix_wrapper.rb +2 -0
  13. data/lib/daru/category.rb +1 -1
  14. data/lib/daru/core/group_by.rb +32 -15
  15. data/lib/daru/core/query.rb +4 -4
  16. data/lib/daru/dataframe.rb +196 -48
  17. data/lib/daru/date_time/index.rb +7 -5
  18. data/lib/daru/formatters/table.rb +1 -0
  19. data/lib/daru/index/index.rb +121 -33
  20. data/lib/daru/index/multi_index.rb +83 -3
  21. data/lib/daru/io/csv/converters.rb +18 -0
  22. data/lib/daru/io/io.rb +80 -11
  23. data/lib/daru/io/sql_data_source.rb +10 -0
  24. data/lib/daru/iruby/templates/dataframe.html.erb +3 -50
  25. data/lib/daru/iruby/templates/dataframe_mi.html.erb +3 -56
  26. data/lib/daru/iruby/templates/dataframe_mi_tbody.html.erb +35 -0
  27. data/lib/daru/iruby/templates/dataframe_mi_thead.html.erb +21 -0
  28. data/lib/daru/iruby/templates/dataframe_tbody.html.erb +28 -0
  29. data/lib/daru/iruby/templates/dataframe_thead.html.erb +21 -0
  30. data/lib/daru/iruby/templates/vector.html.erb +3 -25
  31. data/lib/daru/iruby/templates/vector_mi.html.erb +3 -34
  32. data/lib/daru/iruby/templates/vector_mi_tbody.html.erb +26 -0
  33. data/lib/daru/iruby/templates/vector_mi_thead.html.erb +8 -0
  34. data/lib/daru/iruby/templates/vector_tbody.html.erb +17 -0
  35. data/lib/daru/iruby/templates/vector_thead.html.erb +8 -0
  36. data/lib/daru/maths/statistics/dataframe.rb +9 -11
  37. data/lib/daru/maths/statistics/vector.rb +139 -32
  38. data/lib/daru/plotting/gruff/dataframe.rb +13 -15
  39. data/lib/daru/plotting/nyaplot/category.rb +1 -1
  40. data/lib/daru/plotting/nyaplot/dataframe.rb +4 -4
  41. data/lib/daru/plotting/nyaplot/vector.rb +1 -2
  42. data/lib/daru/vector.rb +169 -80
  43. data/lib/daru/version.rb +1 -1
  44. data/spec/category_spec.rb +19 -19
  45. data/spec/core/group_by_spec.rb +47 -0
  46. data/spec/core/query_spec.rb +55 -50
  47. data/spec/daru_spec.rb +22 -0
  48. data/spec/dataframe_spec.rb +118 -6
  49. data/spec/date_time/index_spec.rb +34 -16
  50. data/spec/extensions/rserve_spec.rb +1 -1
  51. data/spec/fixtures/boolean_converter_test.csv +5 -0
  52. data/spec/fixtures/eciresults.html +394 -0
  53. data/spec/fixtures/empty_rows_test.csv +17 -0
  54. data/spec/fixtures/macau.html +3691 -0
  55. data/spec/fixtures/macd_data.csv +150 -0
  56. data/spec/fixtures/moneycontrol.html +6812 -0
  57. data/spec/fixtures/url_test.txt~ +0 -0
  58. data/spec/fixtures/valid_markup.html +62 -0
  59. data/spec/fixtures/wiki_climate.html +1243 -0
  60. data/spec/fixtures/wiki_table_info.html +631 -0
  61. data/spec/formatters/table_formatter_spec.rb +29 -0
  62. data/spec/index/categorical_index_spec.rb +33 -33
  63. data/spec/index/index_spec.rb +134 -41
  64. data/spec/index/multi_index_spec.rb +115 -31
  65. data/spec/io/io_spec.rb +201 -0
  66. data/spec/io/sql_data_source_spec.rb +31 -41
  67. data/spec/iruby/dataframe_spec.rb +17 -19
  68. data/spec/iruby/vector_spec.rb +26 -28
  69. data/spec/maths/statistics/vector_spec.rb +136 -14
  70. data/spec/plotting/gruff/category_spec.rb +3 -3
  71. data/spec/plotting/gruff/dataframe_spec.rb +14 -4
  72. data/spec/plotting/gruff/vector_spec.rb +9 -9
  73. data/spec/plotting/nyaplot/category_spec.rb +5 -9
  74. data/spec/plotting/nyaplot/dataframe_spec.rb +72 -47
  75. data/spec/plotting/nyaplot/vector_spec.rb +5 -11
  76. data/spec/shared/vector_display_spec.rb +12 -14
  77. data/spec/spec_helper.rb +21 -0
  78. data/spec/support/matchers.rb +5 -0
  79. data/spec/vector_spec.rb +222 -72
  80. metadata +68 -23
  81. data/spec/fixtures/stock_data.csv +0 -500
@@ -20,7 +20,7 @@ module Daru
20
20
  #
21
21
  # == Arguments
22
22
  #
23
- # * path - Path of the file to load specified as a String.
23
+ # * path - Local path / Remote URL of the file to load specified as a String.
24
24
  #
25
25
  # == Options
26
26
  #
@@ -63,7 +63,7 @@ module Daru
63
63
 
64
64
  # Read a database query and returns a Dataset
65
65
  #
66
- # @param dbh [DBI::DatabaseHandle] A DBI connection to be used to run the query
66
+ # @param dbh [DBI::DatabaseHandle, String] A DBI connection OR Path to a SQlite3 database.
67
67
  # @param query [String] The query to be executed
68
68
  #
69
69
  # @return A dataframe containing the data resulting from the query
@@ -72,6 +72,11 @@ module Daru
72
72
  #
73
73
  # dbh = DBI.connect("DBI:Mysql:database:localhost", "user", "password")
74
74
  # Daru::DataFrame.from_sql(dbh, "SELECT * FROM test")
75
+ #
76
+ # #Alternatively
77
+ #
78
+ # require 'dbi'
79
+ # Daru::DataFrame.from_sql("path/to/sqlite.db", "SELECT * FROM test")
75
80
  def from_sql dbh, query
76
81
  Daru::IO.from_sql dbh, query
77
82
  end
@@ -112,6 +117,49 @@ module Daru
112
117
  Daru::IO.from_plaintext path, fields
113
118
  end
114
119
 
120
+ # Read the table data from a remote html file. Please note that this module
121
+ # works only for static table elements on a HTML page, and won't work in
122
+ # cases where the data is being loaded into the HTML table by Javascript.
123
+ #
124
+ # By default - all <th> tag elements in the first proper row are considered
125
+ # as the order, and all the <th> tag elements in the first column are
126
+ # considered as the index.
127
+ #
128
+ # == Arguments
129
+ #
130
+ # * path [String] - URL of the target HTML file.
131
+ # * fields [Hash] -
132
+ #
133
+ # +:match+ - A *String* to match and choose a particular table(s) from multiple tables of a HTML page.
134
+ #
135
+ # +:order+ - An *Array* which would act as the user-defined order, to override the parsed *Daru::DataFrame*.
136
+ #
137
+ # +:index+ - An *Array* which would act as the user-defined index, to override the parsed *Daru::DataFrame*.
138
+ #
139
+ # +:name+ - A *String* that manually assigns a name to the scraped *Daru::DataFrame*, for user's preference.
140
+ #
141
+ # == Returns
142
+ # An Array of +Daru::DataFrame+s, with each dataframe corresponding to a
143
+ # HTML table on that webpage.
144
+ #
145
+ # == Usage
146
+ # dfs = Daru::DataFrame.from_html("http://www.moneycontrol.com/", match: "Sun Pharma")
147
+ # dfs.count
148
+ # # => 4
149
+ #
150
+ # dfs.first
151
+ # #
152
+ # # => <Daru::DataFrame(5x4)>
153
+ # # Company Price Change Value (Rs
154
+ # # 0 Sun Pharma 502.60 -65.05 2,117.87
155
+ # # 1 Reliance 1356.90 19.60 745.10
156
+ # # 2 Tech Mahin 379.45 -49.70 650.22
157
+ # # 3 ITC 315.85 6.75 621.12
158
+ # # 4 HDFC 1598.85 50.95 553.91
159
+ def from_html path, fields={}
160
+ Daru::IO.from_html path, fields
161
+ end
162
+
115
163
  # Create DataFrame by specifying rows as an Array of Arrays or Array of
116
164
  # Daru::Vector objects.
117
165
  def rows source, opts={}
@@ -239,6 +287,48 @@ module Daru
239
287
  # # b 7 2
240
288
  # # c 8 3
241
289
  # # d 9 4
290
+ #
291
+ # df = Daru::DataFrame.new([[1,2,3,4],[6,7,8,9]], name: :bat_man)
292
+ #
293
+ # # =>
294
+ # # #<Daru::DataFrame: bat_man (4x2)>
295
+ # # 0 1
296
+ # # 0 1 6
297
+ # # 1 2 7
298
+ # # 2 3 8
299
+ # # 3 4 9
300
+ #
301
+ # # Dataframe having Index name
302
+ #
303
+ # df = Daru::DataFrame.new({a: [1,2,3,4], b: [6,7,8,9]}, order: [:b, :a],
304
+ # index: Daru::Index.new([:a, :b, :c, :d], name: 'idx_name'),
305
+ # name: :spider_man)
306
+ #
307
+ # # =>
308
+ # # <Daru::DataFrame:80766980 @name = spider_man @size = 4>
309
+ # # idx_name b a
310
+ # # a 6 1
311
+ # # b 7 2
312
+ # # c 8 3
313
+ # # d 9 4
314
+ #
315
+ #
316
+ # idx = Daru::Index.new [100, 99, 101, 1, 2], name: "s1"
317
+ # => #<Daru::Index(5): s1 {100, 99, 101, 1, 2}>
318
+ #
319
+ # df = Daru::DataFrame.new({b: [11,12,13,14,15], a: [1,2,3,4,5],
320
+ # c: [11,22,33,44,55]},
321
+ # order: [:a, :b, :c],
322
+ # index: idx)
323
+ # # =>
324
+ # #<Daru::DataFrame(5x3)>
325
+ # # s1 a b c
326
+ # # 100 1 11 11
327
+ # # 99 2 12 22
328
+ # # 101 3 13 33
329
+ # # 1 4 14 44
330
+ # # 2 5 15 55
331
+
242
332
  def initialize source, opts={} # rubocop:disable Metrics/MethodLength
243
333
  vectors, index = opts[:order], opts[:index] # FIXME: just keyword arges after Ruby 2.1
244
334
  @data = []
@@ -457,7 +547,7 @@ module Daru
457
547
  def dup vectors_to_dup=nil
458
548
  vectors_to_dup = @vectors.to_a unless vectors_to_dup
459
549
 
460
- src = vectors_to_dup.map { |vec| @data[@vectors[vec]].dup }
550
+ src = vectors_to_dup.map { |vec| @data[@vectors.pos(vec)].dup }
461
551
  new_order = Daru::Index.new(vectors_to_dup)
462
552
 
463
553
  Daru::DataFrame.new src, order: new_order, index: @index.dup, name: @name, clone: true
@@ -544,7 +634,7 @@ module Daru
544
634
  # b: [:a, :b, nil, Float::NAN, nil, 3, 5, 8],
545
635
  # c: ['a', Float::NAN, 3, 4, 3, 5, nil, 7]
546
636
  # }, index: 11..18)
547
- # df
637
+ # df.replace_values nil, Float::NAN
548
638
  # # => #<Daru::DataFrame(8x3)>
549
639
  # # a b c
550
640
  # # 11 1 a a
@@ -679,7 +769,7 @@ module Daru
679
769
  # * +axis+ - The axis to map over. Can be :vector (or :column) or :row.
680
770
  # Default to :vector.
681
771
  def map! axis=:vector, &block
682
- if axis == :vector || axis == :column
772
+ if %i[vector column].include?(axis)
683
773
  map_vectors!(&block)
684
774
  elsif axis == :row
685
775
  map_rows!(&block)
@@ -913,7 +1003,7 @@ module Daru
913
1003
 
914
1004
  # creates a new vector with the data of a given field which the block returns true
915
1005
  def filter_vector vec, &block
916
- Daru::Vector.new each_row.select(&block).map { |row| row[vec] }
1006
+ Daru::Vector.new(each_row.select(&block).map { |row| row[vec] })
917
1007
  end
918
1008
 
919
1009
  # Iterates over each row and retains it in a new DataFrame if the block returns
@@ -1031,7 +1121,7 @@ module Daru
1031
1121
  alias :vector_missing_values :missing_values_rows
1032
1122
 
1033
1123
  def has_missing_data?
1034
- !!@data.any? { |vec| vec.include_values?(*Daru::MISSING_VALUES) }
1124
+ @data.any? { |vec| vec.include_values?(*Daru::MISSING_VALUES) }
1035
1125
  end
1036
1126
  alias :flawed? :has_missing_data?
1037
1127
  deprecate :has_missing_data?, :include_values?, 2016, 10
@@ -1119,7 +1209,7 @@ module Daru
1119
1209
  # row[:a] < 3 and row[:b] == 'b'
1120
1210
  # end #=> true
1121
1211
  def any? axis=:vector, &block
1122
- if axis == :vector || axis == :column
1212
+ if %i[vector column].include?(axis)
1123
1213
  @data.any?(&block)
1124
1214
  elsif axis == :row
1125
1215
  each_row do |row|
@@ -1141,7 +1231,7 @@ module Daru
1141
1231
  # row[:a] < 10
1142
1232
  # end #=> true
1143
1233
  def all? axis=:vector, &block
1144
- if axis == :vector || axis == :column
1234
+ if %i[vector column].include?(axis)
1145
1235
  @data.all?(&block)
1146
1236
  elsif axis == :row
1147
1237
  each_row.all?(&block)
@@ -1377,7 +1467,7 @@ module Daru
1377
1467
  # df.rename_vectors :a => :alpha, :c => :gamma
1378
1468
  # df.vectors.to_a #=> [:alpha, :b, :gamma]
1379
1469
  def rename_vectors name_map
1380
- existing_targets = name_map.select { |k,v| k != v }.values & vectors.to_a
1470
+ existing_targets = name_map.reject { |k,v| k == v }.values & vectors.to_a
1381
1471
  delete_vectors(*existing_targets)
1382
1472
 
1383
1473
  new_names = vectors.to_a.map { |v| name_map[v] ? name_map[v] : v }
@@ -1408,19 +1498,16 @@ module Daru
1408
1498
  Daru::DataFrame.new(arry, clone: cln, order: order, index: @index)
1409
1499
  end
1410
1500
 
1411
- # Generate a summary of this DataFrame with ReportBuilder.
1412
- def summary(method=:to_text)
1413
- ReportBuilder.new(no_title: true).add(self).send(method)
1414
- end
1415
-
1416
- def report_building(b) # :nodoc: #
1417
- b.section(name: @name) do |g|
1418
- g.text "Number of rows: #{nrows}"
1419
- @vectors.each do |v|
1420
- g.text "Element:[#{v}]"
1421
- g.parse_element(self[v])
1422
- end
1501
+ # Generate a summary of this DataFrame based on individual vectors in the DataFrame
1502
+ # @return [String] String containing the summary of the DataFrame
1503
+ def summary
1504
+ summary = "= #{name}"
1505
+ summary << "\n Number of rows: #{nrows}"
1506
+ @vectors.each do |v|
1507
+ summary << "\n Element:[#{v}]\n"
1508
+ summary << self[v].summary(1)
1423
1509
  end
1510
+ summary
1424
1511
  end
1425
1512
 
1426
1513
  # Sorts a dataframe (ascending/descending) in the given pripority sequence of
@@ -1783,7 +1870,9 @@ module Daru
1783
1870
  end
1784
1871
 
1785
1872
  # Convert to html for IRuby.
1786
- def to_html threshold=30
1873
+ def to_html(threshold=30)
1874
+ table_thead = to_html_thead
1875
+ table_tbody = to_html_tbody(threshold)
1787
1876
  path = if index.is_a?(MultiIndex)
1788
1877
  File.expand_path('../iruby/templates/dataframe_mi.html.erb', __FILE__)
1789
1878
  else
@@ -1792,8 +1881,28 @@ module Daru
1792
1881
  ERB.new(File.read(path).strip).result(binding)
1793
1882
  end
1794
1883
 
1884
+ def to_html_thead
1885
+ table_thead_path =
1886
+ if index.is_a?(MultiIndex)
1887
+ File.expand_path('../iruby/templates/dataframe_mi_thead.html.erb', __FILE__)
1888
+ else
1889
+ File.expand_path('../iruby/templates/dataframe_thead.html.erb', __FILE__)
1890
+ end
1891
+ ERB.new(File.read(table_thead_path).strip).result(binding)
1892
+ end
1893
+
1894
+ def to_html_tbody(threshold=30)
1895
+ table_tbody_path =
1896
+ if index.is_a?(MultiIndex)
1897
+ File.expand_path('../iruby/templates/dataframe_mi_tbody.html.erb', __FILE__)
1898
+ else
1899
+ File.expand_path('../iruby/templates/dataframe_tbody.html.erb', __FILE__)
1900
+ end
1901
+ ERB.new(File.read(table_tbody_path).strip).result(binding)
1902
+ end
1903
+
1795
1904
  def to_s
1796
- to_html
1905
+ "#<#{self.class}#{': ' + @name.to_s if @name}(#{nrows}x#{ncols})>"
1797
1906
  end
1798
1907
 
1799
1908
  # Method for updating the metadata (i.e. missing value positions) of the
@@ -1900,14 +2009,13 @@ module Daru
1900
2009
 
1901
2010
  # Pretty print in a nice table format for the command line (irb/pry/iruby)
1902
2011
  def inspect spacing=10, threshold=15
1903
- row_headers = index.is_a?(MultiIndex) ? index.sparse_tuples : index.to_a
1904
2012
  name_part = @name ? ": #{@name} " : ''
1905
2013
 
1906
2014
  "#<#{self.class}#{name_part}(#{nrows}x#{ncols})>\n" +
1907
2015
  Formatters::Table.format(
1908
2016
  each_row.lazy,
1909
2017
  row_headers: row_headers,
1910
- headers: vectors,
2018
+ headers: headers,
1911
2019
  threshold: threshold,
1912
2020
  spacing: spacing
1913
2021
  )
@@ -2002,8 +2110,32 @@ module Daru
2002
2110
  end
2003
2111
  end
2004
2112
 
2113
+ # returns array of row tuples at given index(s)
2114
+ def access_row_tuples_by_indexs *indexes
2115
+ positions = @index.pos(*indexes)
2116
+
2117
+ return populate_row_for(positions) if positions.is_a? Numeric
2118
+
2119
+ res = []
2120
+ new_rows = @data.map { |vec| vec[*indexes] }
2121
+ indexes.each do |index|
2122
+ tuples = []
2123
+ new_rows.map { |row| tuples += [row[index]] }
2124
+ res << tuples
2125
+ end
2126
+ res
2127
+ end
2128
+
2005
2129
  private
2006
2130
 
2131
+ def headers
2132
+ Daru::Index.new(Array(index.name) + @vectors.to_a)
2133
+ end
2134
+
2135
+ def row_headers
2136
+ index.is_a?(MultiIndex) ? index.sparse_tuples : index.to_a
2137
+ end
2138
+
2007
2139
  def convert_categorical_vectors names
2008
2140
  names.map do |n|
2009
2141
  next unless self[n].category?
@@ -2034,7 +2166,7 @@ module Daru
2034
2166
  end
2035
2167
 
2036
2168
  def dispatch_to_axis(axis, method, *args, &block)
2037
- if axis == :vector || axis == :column
2169
+ if %i[vector column].include?(axis)
2038
2170
  send("#{method}_vector", *args, &block)
2039
2171
  elsif axis == :row
2040
2172
  send("#{method}_row", *args, &block)
@@ -2044,7 +2176,7 @@ module Daru
2044
2176
  end
2045
2177
 
2046
2178
  def dispatch_to_axis_pl(axis, method, *args, &block)
2047
- if axis == :vector || axis == :column
2179
+ if %i[vector column].include?(axis)
2048
2180
  send("#{method}_vectors", *args, &block)
2049
2181
  elsif axis == :row
2050
2182
  send("#{method}_rows", *args, &block)
@@ -2053,7 +2185,7 @@ module Daru
2053
2185
  end
2054
2186
  end
2055
2187
 
2056
- AXES = [:row, :vector].freeze
2188
+ AXES = %i[row vector].freeze
2057
2189
 
2058
2190
  def extract_axis names, default=:vector
2059
2191
  if AXES.include?(names.last)
@@ -2065,7 +2197,7 @@ module Daru
2065
2197
 
2066
2198
  def access_vector *names
2067
2199
  if names.first.is_a?(Range)
2068
- dup(@vectors[names.first])
2200
+ dup(@vectors.subset(names.first))
2069
2201
  elsif @vectors.is_a?(MultiIndex)
2070
2202
  access_vector_multi_index(*names)
2071
2203
  else
@@ -2087,14 +2219,18 @@ module Daru
2087
2219
 
2088
2220
  def access_vector_single_index *names
2089
2221
  if names.count < 2
2090
- pos = @vectors[names.first]
2222
+ begin
2223
+ pos = @vectors.is_a?(Daru::DateTimeIndex) ? @vectors[names.first] : @vectors.pos(names.first)
2224
+ rescue IndexError
2225
+ raise IndexError, "Specified vector #{names.first} does not exist"
2226
+ end
2091
2227
 
2092
2228
  return @data[pos] if pos.is_a?(Numeric)
2093
2229
 
2094
2230
  names = pos
2095
2231
  end
2096
2232
 
2097
- new_vectors = names.map { |name| [name, @data[@vectors[name]]] }.to_h
2233
+ new_vectors = names.map { |name| [name, @data[@vectors.pos(name)]] }.to_h
2098
2234
 
2099
2235
  order = names.is_a?(Array) ? Daru::Index.new(names) : names
2100
2236
  Daru::DataFrame.new(new_vectors, order: order,
@@ -2126,7 +2262,7 @@ module Daru
2126
2262
  if @index.empty?
2127
2263
  insert_vector_in_empty name, vector
2128
2264
  else
2129
- vec = prepare_vector_for_insert name, vector
2265
+ vec = prepare_for_insert name, vector
2130
2266
 
2131
2267
  assign_or_add_vector name, vec
2132
2268
  end
@@ -2173,25 +2309,35 @@ module Daru
2173
2309
  @data.map! { |v| v.empty? ? v.reindex(@index) : v }
2174
2310
  end
2175
2311
 
2176
- def prepare_vector_for_insert name, vector
2177
- if vector.is_a?(Daru::Vector)
2178
- # so that index-by-index assignment is avoided when possible.
2179
- return vector.dup if vector.index == @index
2180
-
2181
- Daru::Vector.new([], name: coerce_name(name), index: @index).tap { |v|
2182
- @index.each do |idx|
2183
- v[idx] = vector.index.include?(idx) ? vector[idx] : nil
2184
- end
2185
- }
2312
+ def prepare_for_insert name, arg
2313
+ if arg.is_a? Daru::Vector
2314
+ prepare_vector_for_insert name, arg
2315
+ elsif arg.respond_to?(:to_a)
2316
+ prepare_enum_for_insert name, arg
2186
2317
  else
2187
- # FIXME: No spec checks this case... And SizeError is not a thing - zverok, 2016-05-08
2188
- if @size != vector.size
2189
- raise SizeError,
2190
- "Specified vector of length #{vector.size} cannot be inserted in DataFrame of size #{@size}"
2318
+ prepare_value_for_insert name, arg
2319
+ end
2320
+ end
2321
+
2322
+ def prepare_vector_for_insert name, vector
2323
+ # so that index-by-index assignment is avoided when possible.
2324
+ return vector.dup if vector.index == @index
2325
+ Daru::Vector.new([], name: coerce_name(name), index: @index).tap { |v|
2326
+ @index.each do |idx|
2327
+ v[idx] = vector.index.include?(idx) ? vector[idx] : nil
2191
2328
  end
2329
+ }
2330
+ end
2192
2331
 
2193
- Daru::Vector.new(vector, name: coerce_name(name), index: @index)
2332
+ def prepare_enum_for_insert name, enum
2333
+ if @size != enum.size
2334
+ raise "Specified vector of length #{enum.size} cannot be inserted in DataFrame of size #{@size}"
2194
2335
  end
2336
+ Daru::Vector.new(enum, name: coerce_name(name), index: @index)
2337
+ end
2338
+
2339
+ def prepare_value_for_insert name, value
2340
+ Daru::Vector.new(Array(value) * @size, name: coerce_name(name), index: @index)
2195
2341
  end
2196
2342
 
2197
2343
  def insert_or_modify_row indexes, vector
@@ -2276,8 +2422,10 @@ module Daru
2276
2422
 
2277
2423
  case source.first
2278
2424
  when Array
2425
+ vectors ||= (0..source.size-1).to_a
2279
2426
  initialize_from_array_of_arrays source, vectors, index, opts
2280
2427
  when Vector
2428
+ vectors ||= (0..source.size-1).to_a
2281
2429
  initialize_from_array_of_vectors source, vectors, index, opts
2282
2430
  when Hash
2283
2431
  initialize_from_array_of_hashes source, vectors, index, opts
@@ -226,7 +226,7 @@ module Daru
226
226
  to_a.each(&block)
227
227
  end
228
228
 
229
- attr_reader :frequency, :offset, :periods
229
+ attr_reader :frequency, :offset, :periods, :keys
230
230
 
231
231
  # Create a DateTimeIndex with or without a frequency in data. The constructor
232
232
  # should be used for creating DateTimeIndex by directly passing in DateTime
@@ -253,6 +253,7 @@ module Daru
253
253
  # DateTime.new(2012,4,11), DateTime.new(2012,4,12)], freq: :infer)
254
254
  # #=>#<DateTimeIndex:84198340 offset=D periods=8 data=[2012-04-05T00:00:00+00:00...2012-04-12T00:00:00+00:00]>
255
255
  def initialize data, opts={freq: nil}
256
+ super data
256
257
  Helper.possibly_convert_to_date_time data
257
258
 
258
259
  @offset =
@@ -405,7 +406,7 @@ module Daru
405
406
  @data
406
407
  else
407
408
  @data.sort_by(&:last)
408
- end.transpose.first
409
+ end.transpose.first || []
409
410
  end
410
411
 
411
412
  # Size of index.
@@ -419,6 +420,7 @@ module Daru
419
420
 
420
421
  def inspect
421
422
  meta = [@periods, @frequency ? "frequency=#{@frequency}" : nil].compact.join(', ')
423
+ return "#<#{self.class}(#{meta})>" if @data.empty?
422
424
  "#<#{self.class}(#{meta}) " \
423
425
  "#{@data.first[0]}...#{@data.last[0]}>"
424
426
  end
@@ -490,7 +492,7 @@ module Daru
490
492
  # @return [Array<Integer>] Array containing minutes of each index.
491
493
  # @!method sec
492
494
  # @return [Array<Integer>] Array containing seconds of each index.
493
- [:year, :month, :day, :hour, :min, :sec].each do |meth|
495
+ %i[year month day hour min sec].each do |meth|
494
496
  define_method(meth) do
495
497
  each_with_object([]) do |d, arr|
496
498
  arr << d.send(meth)
@@ -528,7 +530,7 @@ module Daru
528
530
  slice first, last
529
531
  end
530
532
 
531
- def slice_between_dates first, last # rubocop:disable Metrics/AbcSize
533
+ def slice_between_dates first, last # rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity
532
534
  # about that ^ disable: I'm waiting for cleaner understanding
533
535
  # of offsets logic. Reference: https://github.com/v0dro/daru/commit/7e1c34aec9516a9ba33037b4a1daaaaf1de0726a#diff-a95ef410a8e1f4ea3cc48d231bb880faR250
534
536
  start = @data.bsearch { |d| d[0] >= first }
@@ -542,7 +544,7 @@ module Daru
542
544
  st = @data.index(start)
543
545
  en = after_en ? @data.index(after_en) - 1 : Helper.last_date(@data)[1]
544
546
  return start[1] if st == en
545
- DateTimeIndex.new(@data[st..en].transpose[0])
547
+ DateTimeIndex.new(@data[st..en].transpose[0] || []) # empty slice guard
546
548
  end
547
549
  end
548
550