spec/vector_spec.rb in daru_lite-0.1.1 vs spec/vector_spec.rb in daru_lite-0.1.2

- old
+ new

@@ -1,138 +1,124 @@ require 'spec_helper.rb' +require 'vector/aggregatable_example' +require 'vector/calculatable_example' +require 'vector/convertible_example' +require 'vector/duplicatable_example' +require 'vector/fetchable_example' +require 'vector/filterable_example' +require 'vector/indexable_example' +require 'vector/iterable_example' +require 'vector/joinable_example' +require 'vector/missable_example' +require 'vector/queryable_example' +require 'vector/setable_example' +require 'vector/sortable_example' describe DaruLite::Vector do ALL_DTYPES.each do |dtype| describe dtype.to_s do - before do - @common_all_dtypes = DaruLite::Vector.new( - [5, 5, 5, 5, 5, 6, 6, 7, 8, 9, 10, 1, 2, 3, 4, 11, -99, -99], - dtype: dtype, name: :common_all_dtypes) - end - - context "#initialize" do - before do - @tuples = [ + describe "#initialize" do + let(:multi_index) do + tuples = [ [:a, :one, :foo], [:a, :two, :bar], [:b, :one, :bar], [:b, :two, :baz] ] - - @multi_index = DaruLite::MultiIndex.from_tuples(@tuples) + DaruLite::MultiIndex.from_tuples(tuples) end it "initializes from an Array" do - dv = DaruLite::Vector.new [1,2,3,4,5], name: :ravan, - index: [:ek, :don, :teen, :char, :pach], dtype: dtype + dv = DaruLite::Vector.new( + [1, 2, 3, 4, 5], + name: :ravan, + index: [:ek, :don, :teen, :char, :pach], + dtype: + ) expect(dv.name) .to eq(:ravan) - expect(dv.index).to eq(DaruLite::Index.new [:ek, :don, :teen, :char, :pach]) + expect(dv.index).to eq(DaruLite::Index.new([:ek, :don, :teen, :char, :pach])) end it "accepts Index object" do idx = DaruLite::Index.new [:yoda, :anakin, :obi, :padme, :r2d2] - dv = DaruLite::Vector.new [1,2,3,4,5], name: :yoga, index: idx, dtype: dtype + dv = DaruLite::Vector.new([1,2,3,4,5], name: :yoga, index: idx, dtype:) expect(dv.name) .to eq(:yoga) expect(dv.index).to eq(idx) end it "accepts a MultiIndex object" do - dv = DaruLite::Vector.new [1,2,3,4], name: :mi, index: @multi_index, dtype: dtype + dv = DaruLite::Vector.new([1,2,3,4], name: :mi, index: multi_index, dtype:) expect(dv.name).to eq(:mi) - expect(dv.index).to eq(@multi_index) + expect(dv.index).to eq(multi_index) end it "raises error for improper Index" do expect { - dv = DaruLite::Vector.new [1,2,3,4,5], name: :yoga, index: [:i, :j, :k] + dv = DaruLite::Vector.new [1, 2, 3, 4, 5], name: :yoga, index: [:i, :j, :k] }.to raise_error expect { - idx = DaruLite::Index.new [:i, :j, :k] - dv = DaruLite::Vector.new [1,2,3,4,5], name: :yoda, index: idx, dtype: dtype + idx = DaruLite::Index.new([:i, :j, :k]) + dv = DaruLite::Vector.new([1, 2, 3, 4, 5], name: :yoda, index: idx, dtype:) }.to raise_error end it "raises error for improper MultiIndex" do expect { - dv = DaruLite::Vector.new [1,2,3,4,5], name: :mi, index: @multi_index + dv = DaruLite::Vector.new([1, 2, 3, 4, 5], name: :mi, index: multi_index) }.to raise_error end it "initializes without specifying an index" do - dv = DaruLite::Vector.new [1,2,3,4,5], name: :vishnu, dtype: dtype + dv = DaruLite::Vector.new([1, 2, 3, 4, 5], name: :vishnu, dtype:) - expect(dv.index).to eq(DaruLite::Index.new [0,1,2,3,4]) + expect(dv.index).to eq(DaruLite::Index.new([0, 1, 2, 3, 4])) end it "inserts nils for extra indices" do - dv = DaruLite::Vector.new [1,2,3], name: :yoga, index: [0,1,2,3,4], dtype: dtype + dv = DaruLite::Vector.new([1, 2, 3], name: :yoga, index: [0, 1, 2, 3, 4], dtype:) - expect(dv).to eq([1,2,3,nil,nil].dv(:yoga,nil, :array)) + expect(dv).to eq([1, 2, 3, nil, nil].dv(:yoga,nil, :array)) end it "inserts nils for extra indices (MultiIndex)" do - dv = DaruLite::Vector.new [1,2], name: :mi, index: @multi_index, dtype: :array - expect(dv).to eq(DaruLite::Vector.new([1,2,nil,nil], name: :mi, index: @multi_index, dtype: :array)) + dv = DaruLite::Vector.new [1, 2], name: :mi, index: multi_index, dtype: :array + expect(dv).to eq(DaruLite::Vector.new([1, 2, nil, nil], name: :mi, index: multi_index, dtype: :array)) end it "accepts all sorts of objects for indexing" do - dv = DaruLite::Vector.new [1,2,3,4], index: ['a', 'b', :r, 0] - expect(dv.to_a).to eq([1,2,3,4]) + dv = DaruLite::Vector.new([1, 2, 3, 4], index: ['a', 'b', :r, 0]) + expect(dv.to_a).to eq([1, 2, 3, 4]) expect(dv.index.to_a).to eq(['a', 'b', :r, 0]) end end - context "#reorder!" do - let(:vector_with_dtype) do - DaruLite::Vector.new( - [1, 2, 3, 4], - index: [:a, :b, :c, :d], - dtype: dtype) - end - let(:arranged_vector) do - DaruLite::Vector.new([4,3,2,1], index: [:d, :c, :b, :a], dtype: dtype) - end - - before do - vector_with_dtype.reorder! [3, 2, 1, 0] - end - - it "rearranges with passed order" do - expect(vector_with_dtype).to eq arranged_vector - end - - it "doesn't change dtype" do - expect(vector_with_dtype.data.class).to eq arranged_vector.data.class - end - end - - context ".new_with_size" do + describe ".new_with_size" do it "creates new vector from only size" do - v1 = DaruLite::Vector.new 10.times.map { nil }, dtype: dtype - v2 = DaruLite::Vector.new_with_size 10, dtype: dtype + v1 = DaruLite::Vector.new(10.times.map { nil }, dtype:) + v2 = DaruLite::Vector.new_with_size(10, dtype:) expect(v2).to eq(v1) end if dtype == :array it "creates new vector from only size and value" do a = rand - v1 = DaruLite::Vector.new 10.times.map { a }, dtype: dtype - v2 = DaruLite::Vector.new_with_size(10, value: a, dtype: dtype) + v1 = DaruLite::Vector.new(10.times.map { a }, dtype:) + v2 = DaruLite::Vector.new_with_size(10, value: a, dtype:) expect(v2).to eq(v1) end it "accepts block" do v1 = DaruLite::Vector.new 10.times.map {|i| i * 2 } - v2 = DaruLite::Vector.new_with_size(10, dtype: dtype) { |i| i * 2 } + v2 = DaruLite::Vector.new_with_size(10, dtype:) { |i| i * 2 } expect(v2).to eq(v1) end end - context ".[]" do + describe ".[]" do it "returns same results as R-c()" do reference = DaruLite::Vector.new([0, 4, 5, 6, 10]) expect(DaruLite::Vector[0, 4, 5, 6, 10]) .to eq(reference) expect(DaruLite::Vector[0, 4..6, 10]) .to eq(reference) expect(DaruLite::Vector[[0], [4, 5, 6], [10]]) .to eq(reference) @@ -141,585 +127,10 @@ expect(DaruLite::Vector[[0], DaruLite::Vector.new([4, 5, 6]), [10]]) .to eq(reference) end end - context "#[]" do - context DaruLite::Index do - before :each do - @dv = DaruLite::Vector.new [1,2,3,4,5], name: :yoga, - index: [:yoda, :anakin, :obi, :padme, :r2d2], dtype: dtype - end - - it "returns an element after passing an index" do - expect(@dv[:yoda]).to eq(1) - end - - it "returns an element after passing a numeric index" do - expect(@dv[0]).to eq(1) - end - - it "returns a vector with given indices for multiple indices" do - expect(@dv[:yoda, :anakin]).to eq(DaruLite::Vector.new([1,2], name: :yoda, - index: [:yoda, :anakin], dtype: dtype)) - end - - it "returns a vector with given indices for multiple numeric indices" do - expect(@dv[0,1]).to eq(DaruLite::Vector.new([1,2], name: :yoda, - index: [:yoda, :anakin], dtype: dtype)) - end - - it "returns a vector when specified symbol Range" do - expect(@dv[:yoda..:anakin]).to eq(DaruLite::Vector.new([1,2], - index: [:yoda, :anakin], name: :yoga, dtype: dtype)) - end - - it "returns a vector when specified numeric Range" do - expect(@dv[3..4]).to eq(DaruLite::Vector.new([4,5], name: :yoga, - index: [:padme, :r2d2], dtype: dtype)) - end - - it "returns correct results for index of multiple index" do - v = DaruLite::Vector.new([1,2,3,4], index: ['a','c',1,:a]) - expect(v['a']).to eq(1) - expect(v[:a]).to eq(4) - expect(v[1]).to eq(3) - expect(v[0]).to eq(1) - end - - it "raises exception for invalid index" do - expect { @dv[:foo] }.to raise_error(IndexError) - expect { @dv[:obi, :foo] }.to raise_error(IndexError) - end - end - - context DaruLite::MultiIndex do - before do - @tuples = [ - [:a,:one,:bar], - [:a,:one,:baz], - [:a,:two,:bar], - [:a,:two,:baz], - [:b,:one,:bar], - [:b,:two,:bar], - [:b,:two,:baz], - [:b,:one,:foo], - [:c,:one,:bar], - [:c,:one,:baz], - [:c,:two,:foo], - [:c,:two,:bar], - [:d,:one,:foo] - ] - @multi_index = DaruLite::MultiIndex.from_tuples(@tuples) - @vector = DaruLite::Vector.new( - Array.new(13) { |i| i }, index: @multi_index, - dtype: dtype, name: :mi_vector) - end - - it "returns a single element when passed a row number" do - expect(@vector[1]).to eq(1) - end - - it "returns a single element when passed the full tuple" do - expect(@vector[:a, :one, :baz]).to eq(1) - end - - it "returns sub vector when passed first layer of tuple" do - mi = DaruLite::MultiIndex.from_tuples([ - [:one,:bar], - [:one,:baz], - [:two,:bar], - [:two,:baz]]) - expect(@vector[:a]).to eq(DaruLite::Vector.new([0,1,2,3], index: mi, - dtype: dtype, name: :sub_vector)) - end - - it "returns sub vector when passed first and second layer of tuple" do - mi = DaruLite::MultiIndex.from_tuples([ - [:foo], - [:bar]]) - expect(@vector[:c,:two]).to eq(DaruLite::Vector.new([10,11], index: mi, - dtype: dtype, name: :sub_sub_vector)) - end - - it "returns sub vector not a single element when passed the partial tuple" do - mi = DaruLite::MultiIndex.from_tuples([[:foo]]) - expect(@vector[:d, :one]).to eq(DaruLite::Vector.new([12], index: mi, - dtype: dtype, name: :sub_sub_vector)) - end - - it "returns a vector with corresponding MultiIndex when specified numeric Range" do - mi = DaruLite::MultiIndex.from_tuples([ - [:a,:two,:baz], - [:b,:one,:bar], - [:b,:two,:bar], - [:b,:two,:baz], - [:b,:one,:foo], - [:c,:one,:bar], - [:c,:one,:baz] - ]) - expect(@vector[3..9]).to eq(DaruLite::Vector.new([3,4,5,6,7,8,9], index: mi, - dtype: dtype, name: :slice)) - end - - it "raises exception for invalid index" do - expect { @vector[:foo] }.to raise_error(IndexError) - expect { @vector[:a, :two, :foo] }.to raise_error(IndexError) - expect { @vector[:x, :one] }.to raise_error(IndexError) - end - end - - context DaruLite::CategoricalIndex do - # before { skip } - context "non-numerical index" do - let (:idx) { DaruLite::CategoricalIndex.new [:a, :b, :a, :a, :c] } - let (:dv) { DaruLite::Vector.new 'a'..'e', index: idx } - - context "single category" do - context "multiple instances" do - subject { dv[:a] } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 3 } - its(:to_a) { is_expected.to eq ['a', 'c', 'd'] } - its(:index) { is_expected.to eq( - DaruLite::CategoricalIndex.new([:a, :a, :a])) } - end - - context "single instance" do - subject { dv[:c] } - - it { is_expected.to eq 'e' } - end - end - - context "multiple categories" do - subject { dv[:a, :c] } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 4 } - its(:to_a) { is_expected.to eq ['a', 'c', 'd', 'e'] } - its(:index) { is_expected.to eq( - DaruLite::CategoricalIndex.new([:a, :a, :a, :c])) } - end - - context "multiple positional indexes" do - subject { dv[0, 1, 2] } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 3 } - its(:to_a) { is_expected.to eq ['a', 'b', 'c'] } - its(:index) { is_expected.to eq( - DaruLite::CategoricalIndex.new([:a, :b, :a])) } - end - - context "single positional index" do - subject { dv[1] } - - it { is_expected.to eq 'b' } - end - - context "invalid category" do - it { expect { dv[:x] }.to raise_error IndexError } - end - - context "invalid positional index" do - it { expect { dv[30] }.to raise_error IndexError } - end - end - - context "numerical index" do - let (:idx) { DaruLite::CategoricalIndex.new [1, 1, 2, 2, 3] } - let (:dv) { DaruLite::Vector.new 'a'..'e', index: idx } - - context "single category" do - context "multiple instances" do - subject { dv[1] } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 2 } - its(:to_a) { is_expected.to eq ['a', 'b'] } - its(:index) { is_expected.to eq( - DaruLite::CategoricalIndex.new([1, 1])) } - end - - context "single instance" do - subject { dv[3] } - - it { is_expected.to eq 'e' } - end - end - end - end - end - - context "#at" do - context DaruLite::Index do - let (:idx) { DaruLite::Index.new [1, 0, :c] } - let (:dv) { DaruLite::Vector.new ['a', 'b', 'c'], index: idx } - - let (:idx_dt) { DaruLite::DateTimeIndex.new(['2017-01-01', '2017-02-01', '2017-03-01']) } - let (:dv_dt) { DaruLite::Vector.new(['a', 'b', 'c'], index: idx_dt) } - - context "single position" do - it { expect(dv.at 1).to eq 'b' } - end - - context "multiple positions" do - subject { dv.at 0, 2 } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 2 } - its(:to_a) { is_expected.to eq ['a', 'c'] } - its(:'index.to_a') { is_expected.to eq [1, :c] } - end - - context "invalid position" do - it { expect { dv.at 3 }.to raise_error IndexError } - end - - context "invalid positions" do - it { expect { dv.at 2, 3 }.to raise_error IndexError } - end - - context "range" do - subject { dv.at 0..1 } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 2 } - its(:to_a) { is_expected.to eq ['a', 'b'] } - its(:'index.to_a') { is_expected.to eq [1, 0] } - end - - context "range with negative end" do - subject { dv.at 0..-2 } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 2 } - its(:to_a) { is_expected.to eq ['a', 'b'] } - its(:'index.to_a') { is_expected.to eq [1, 0] } - end - - context "range with single element" do - subject { dv.at 0..0 } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 1 } - its(:to_a) { is_expected.to eq ['a'] } - its(:'index.to_a') { is_expected.to eq [1] } - end - - context "Splat .at on DateTime index" do - subject { dv_dt.at(*[1,2]) } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 2 } - its(:to_a) { is_expected.to eq ['b', 'c'] } - its(:'index.to_a') { is_expected.to eq ['2017-02-01', '2017-03-01'] } - end - end - - context DaruLite::MultiIndex do - let (:idx) do - DaruLite::MultiIndex.from_tuples [ - [:a,:one,:bar], - [:a,:one,:baz], - [:b,:two,:bar], - [:a,:two,:baz], - ] - end - let (:dv) { DaruLite::Vector.new 1..4, index: idx } - - context "single position" do - it { expect(dv.at 1).to eq 2 } - end - - context "multiple positions" do - subject { dv.at 2, 3 } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 2 } - its(:to_a) { is_expected.to eq [3, 4] } - its(:'index.to_a') { is_expected.to eq [[:b, :two, :bar], - [:a, :two, :baz]] } - end - - context "invalid position" do - it { expect { dv.at 4 }.to raise_error IndexError } - end - - context "invalid positions" do - it { expect { dv.at 2, 4 }.to raise_error IndexError } - end - - context "range" do - subject { dv.at 2..3 } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 2 } - its(:to_a) { is_expected.to eq [3, 4] } - its(:'index.to_a') { is_expected.to eq [[:b, :two, :bar], - [:a, :two, :baz]] } - end - - context "range with negative end" do - subject { dv.at 2..-1 } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 2 } - its(:to_a) { is_expected.to eq [3, 4] } - its(:'index.to_a') { is_expected.to eq [[:b, :two, :bar], - [:a, :two, :baz]] } - end - - context "range with single element" do - subject { dv.at 2..2 } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 1 } - its(:to_a) { is_expected.to eq [3] } - its(:'index.to_a') { is_expected.to eq [[:b, :two, :bar]] } - end - end - - context DaruLite::CategoricalIndex do - let (:idx) { DaruLite::CategoricalIndex.new [:a, 1, 1, :a, :c] } - let (:dv) { DaruLite::Vector.new 'a'..'e', index: idx } - - context "multiple positional indexes" do - subject { dv.at 0, 1, 2 } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 3 } - its(:to_a) { is_expected.to eq ['a', 'b', 'c'] } - its(:index) { is_expected.to eq( - DaruLite::CategoricalIndex.new([:a, 1, 1])) } - end - - context "single positional index" do - subject { dv.at 1 } - - it { is_expected.to eq 'b' } - end - - context "invalid position" do - it { expect { dv.at 5 }.to raise_error IndexError } - end - - context "invalid positions" do - it { expect { dv.at 2, 5 }.to raise_error IndexError } - end - - context "range" do - subject { dv.at 0..2 } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 3 } - its(:to_a) { is_expected.to eq ['a', 'b', 'c'] } - its(:index) { is_expected.to eq( - DaruLite::CategoricalIndex.new([:a, 1, 1])) } - end - - context "range with negative end" do - subject { dv.at 0..-3 } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 3 } - its(:to_a) { is_expected.to eq ['a', 'b', 'c'] } - its(:index) { is_expected.to eq( - DaruLite::CategoricalIndex.new([:a, 1, 1])) } - end - - context "range with single element" do - subject { dv.at 0..0 } - - it { is_expected.to be_a DaruLite::Vector } - its(:size) { is_expected.to eq 1 } - its(:to_a) { is_expected.to eq ['a'] } - its(:index) { is_expected.to eq( - DaruLite::CategoricalIndex.new([:a])) } - end - end - end - - context "#[]=" do - context DaruLite::Index do - before :each do - @dv = DaruLite::Vector.new [1,2,3,4,5], name: :yoga, - index: [:yoda, :anakin, :obi, :padme, :r2d2], dtype: dtype - end - - it "assigns at the specified index" do - @dv[:yoda] = 666 - expect(@dv[:yoda]).to eq(666) - end - - it "assigns at the specified Integer index" do - @dv[0] = 666 - expect(@dv[:yoda]).to eq(666) - end - - it "sets dtype to Array if a nil is assigned" do - @dv[0] = nil - expect(@dv.dtype).to eq(:array) - end - - it "assigns correctly for a mixed index Vector" do - v = DaruLite::Vector.new [1,2,3,4], index: ['a',:a,0,66] - v['a'] = 666 - expect(v['a']).to eq(666) - - v[0] = 666 - expect(v[0]).to eq(666) - - v[3] = 666 - expect(v[3]).to eq(666) - - expect(v).to eq(DaruLite::Vector.new([666,2,666,666], - index: ['a',:a,0,66])) - end - end - - context DaruLite::MultiIndex do - before :each do - @tuples = [ - [:a,:one,:bar], - [:a,:one,:baz], - [:a,:two,:bar], - [:a,:two,:baz], - [:b,:one,:bar], - [:b,:two,:bar], - [:b,:two,:baz], - [:b,:one,:foo], - [:c,:one,:bar], - [:c,:one,:baz], - [:c,:two,:foo], - [:c,:two,:bar] - ] - @multi_index = DaruLite::MultiIndex.from_tuples(@tuples) - @vector = DaruLite::Vector.new Array.new(12) { |i| i }, index: @multi_index, - dtype: dtype, name: :mi_vector - end - - it "assigns all lower layer indices when specified a first layer index" do - @vector[:b] = 69 - expect(@vector).to eq(DaruLite::Vector.new([0,1,2,3,69,69,69,69,8,9,10,11], - index: @multi_index, name: :top_layer_assignment, dtype: dtype - )) - end - - it "assigns all lower indices when specified first and second layer index" do - @vector[:b, :one] = 69 - expect(@vector).to eq(DaruLite::Vector.new([0,1,2,3,69,5,6,69,8,9,10,11], - index: @multi_index, name: :second_layer_assignment, dtype: dtype)) - end - - it "assigns just the precise value when specified complete tuple" do - @vector[:b, :one, :foo] = 69 - expect(@vector).to eq(DaruLite::Vector.new([0,1,2,3,4,5,6,69,8,9,10,11], - index: @multi_index, name: :precise_assignment, dtype: dtype)) - end - - it "assigns correctly when numeric index" do - @vector[7] = 69 - expect(@vector).to eq(DaruLite::Vector.new([0,1,2,3,4,5,6,69,8,9,10,11], - index: @multi_index, name: :precise_assignment, dtype: dtype)) - end - - it "fails predictably on unknown index" do - expect { @vector[:d] = 69 }.to raise_error(IndexError) - expect { @vector[:b, :three] = 69 }.to raise_error(IndexError) - expect { @vector[:b, :two, :test] = 69 }.to raise_error(IndexError) - end - end - - context DaruLite::CategoricalIndex do - context "non-numerical index" do - let (:idx) { DaruLite::CategoricalIndex.new [:a, :b, :a, :a, :c] } - let (:dv) { DaruLite::Vector.new 'a'..'e', index: idx } - - context "single category" do - context "multiple instances" do - subject { dv } - before { dv[:a] = 'x' } - - its(:size) { is_expected.to eq 5 } - its(:to_a) { is_expected.to eq ['x', 'b', 'x', 'x', 'e'] } - its(:index) { is_expected.to eq idx } - end - - context "single instance" do - subject { dv } - before { dv[:b] = 'x' } - - its(:size) { is_expected.to eq 5 } - its(:to_a) { is_expected.to eq ['a', 'x', 'c', 'd', 'e'] } - its(:index) { is_expected.to eq idx } - end - end - - context "multiple categories" do - subject { dv } - before { dv[:a, :c] = 'x' } - - its(:size) { is_expected.to eq 5 } - its(:to_a) { is_expected.to eq ['x', 'b', 'x', 'x', 'x'] } - its(:index) { is_expected.to eq idx } - end - - context "multiple positional indexes" do - subject { dv } - before { dv[0, 1, 2] = 'x' } - - its(:size) { is_expected.to eq 5 } - its(:to_a) { is_expected.to eq ['x', 'x', 'x', 'd', 'e'] } - its(:index) { is_expected.to eq idx } - end - - context "single positional index" do - subject { dv } - before { dv[1] = 'x' } - - its(:size) { is_expected.to eq 5 } - its(:to_a) { is_expected.to eq ['a', 'x', 'c', 'd', 'e'] } - its(:index) { is_expected.to eq idx } - end - - context "invalid category" do - it { expect { dv[:x] = 'x' }.to raise_error IndexError } - end - - context "invalid positional index" do - it { expect { dv[30] = 'x'}.to raise_error IndexError } - end - end - - context "numerical index" do - let (:idx) { DaruLite::CategoricalIndex.new [1, 1, 2, 2, 3] } - let (:dv) { DaruLite::Vector.new 'a'..'e', index: idx } - - context "single category" do - subject { dv } - before { dv[1] = 'x' } - - its(:size) { is_expected.to eq 5 } - its(:to_a) { is_expected.to eq ['x', 'x', 'c', 'd', 'e'] } - its(:index) { is_expected.to eq idx } - end - - context "multiple categories" do - subject { dv } - before { dv[1, 2] = 'x' } - - its(:size) { is_expected.to eq 5 } - its(:to_a) { is_expected.to eq ['x', 'x', 'x', 'x', 'e'] } - its(:index) { is_expected.to eq idx } - end - end - end - end - context "#==" do subject { vector == other_vector } let(:vector) { DaruLite::Vector.new(data, name:, index:, dtype:) } let(:data) { [1, 2, 3, 4, 5] } @@ -859,176 +270,10 @@ it { is_expected.to eq(false) } end end end - context "#set_at" do - context DaruLite::Index do - let (:idx) { DaruLite::Index.new [1, 0, :c] } - let (:dv) { DaruLite::Vector.new ['a', 'b', 'c'], index: idx } - - context "single position" do - subject { dv } - before { dv.set_at [1], 'x' } - - its(:to_a) { is_expected.to eq ['a', 'x', 'c'] } - end - - context "multiple positions" do - subject { dv } - before { dv.set_at [0, 2], 'x' } - - its(:to_a) { is_expected.to eq ['x', 'b', 'x'] } - end - - context "invalid position" do - it { expect { dv.set_at [3], 'x' }.to raise_error IndexError } - end - - context "invalid positions" do - it { expect { dv.set_at [2, 3], 'x' }.to raise_error IndexError } - end - end - - context DaruLite::MultiIndex do - let(:idx) do - DaruLite::MultiIndex.from_tuples [ - [:a,:one,:bar], - [:a,:one,:baz], - [:b,:two,:bar], - [:a,:two,:baz], - ] - end - let(:dv) { DaruLite::Vector.new 1..4, index: idx } - - context "single position" do - subject { dv } - before { dv.set_at [1], 'x' } - - its(:to_a) { is_expected.to eq [1, 'x', 3, 4] } - end - - context "multiple positions" do - subject { dv } - before { dv.set_at [2, 3], 'x' } - - its(:to_a) { is_expected.to eq [1, 2, 'x', 'x'] } - end - - context "invalid position" do - it { expect { dv.set_at [4], 'x' }.to raise_error IndexError } - end - - context "invalid positions" do - it { expect { dv.set_at [2, 4], 'x' }.to raise_error IndexError } - end - end - - context DaruLite::CategoricalIndex do - let (:idx) { DaruLite::CategoricalIndex.new [:a, 1, 1, :a, :c] } - let (:dv) { DaruLite::Vector.new 'a'..'e', index: idx } - - context "multiple positional indexes" do - subject { dv } - before { dv.set_at [0, 1, 2], 'x' } - - its(:to_a) { is_expected.to eq ['x', 'x', 'x', 'd', 'e'] } - end - - context "single positional index" do - subject { dv } - before { dv.set_at [1], 'x' } - - its(:to_a) { is_expected.to eq ['a', 'x', 'c', 'd', 'e'] } - end - - context "invalid position" do - it { expect { dv.set_at [5], 'x' }.to raise_error IndexError } - end - - context "invalid positions" do - it { expect { dv.set_at [2, 5], 'x' }.to raise_error IndexError } - end - end - end - - context '#head' do - subject(:vector) do - DaruLite::Vector.new (1..20).to_a, dtype: dtype - end - - it 'takes 10 by default' do - expect(vector.head).to eq DaruLite::Vector.new (1..10).to_a - end - - it 'takes num if provided' do - expect(vector.head(3)).to eq DaruLite::Vector.new (1..3).to_a - end - - it 'does not fail on too large num' do - expect(vector.head(3000)).to eq vector - end - end - - context '#tail' do - subject(:vector) do - DaruLite::Vector.new (1..20).to_a, dtype: dtype - end - - it 'takes 10 by default' do - expect(vector.tail).to eq DaruLite::Vector.new (11..20).to_a, index: (10..19).to_a - end - - it 'takes num if provided' do - expect(vector.tail(3)).to eq DaruLite::Vector.new (18..20).to_a, index: (17..19).to_a - end - - it 'does not fail on too large num' do - expect(vector.tail(3000)).to eq vector - end - end - - context '#last' do - subject(:vector) do - DaruLite::Vector.new (1..20).to_a, dtype: dtype - end - - it 'takes 1 by default' do - expect(vector.last).to eq 20 - end - - it 'takes num if provided' do - expect(vector.last(3)).to eq DaruLite::Vector.new (18..20).to_a, index: (17..19).to_a - end - - it 'does not fail on too large num' do - expect(vector.last(3000)).to eq vector - end - end - - context "#concat" do - before :each do - @dv = DaruLite::Vector.new [1,2,3,4,5], name: :yoga, - index: [:warwick, :thompson, :jackson, :fender, :esp], dtype: dtype - end - - it "concatenates a new element at the end of vector with index" do - @dv.concat 6, :ibanez - - expect(@dv.index) .to eq( - DaruLite::Index.new([:warwick, :thompson, :jackson, :fender, :esp, :ibanez])) - expect(@dv[:ibanez]).to eq(6) - expect(@dv[5]) .to eq(6) - end - - it "raises error if index not specified" do - expect { - @dv.concat 6 - }.to raise_error - end - end - context "#delete" do context DaruLite::Index do it "deletes specified value in the vector" do dv = DaruLite::Vector.new [1,2,3,4,5], name: :a, dtype: dtype @@ -1061,558 +306,52 @@ index: [:one, :two, :four, :five], dtype: dtype) end end end - context "#delete_if" do - it "deletes elements if block evaluates to true" do - v = DaruLite::Vector.new [1,22,33,45,65,32,524,656,123,99,77], dtype: dtype - ret = v.delete_if { |d| d % 11 == 0 } - expect(ret).to eq( - DaruLite::Vector.new([1,45,65,32,524,656,123], - index: [0,3,4,5,6,7,8], dtype: dtype)) - expect(ret.dtype).to eq(dtype) - end - end - - context "#keep_if" do - it "keeps elements if block returns true" do - v = DaruLite::Vector.new([1,22,33,45,65,32,524,656,123,99,77], dtype: dtype) - ret = v.keep_if { |d| d < 35 } - - expect(ret).to eq( - DaruLite::Vector.new([1,22,33,32], index: [0,1,2,5], dtype: dtype)) - expect(v.dtype).to eq(ret.dtype) - end - end - - context "#index_of" do - context DaruLite::Index do - it "returns index of specified value" do - dv = DaruLite::Vector.new [1,2,3,4,5], name: :a, - index: [:one, :two, :three, :four, :five], dtype: dtype - - expect(dv.index_of(1)).to eq(:one) - end - end - - context DaruLite::MultiIndex do - it "returns tuple of specified value" do - mi = DaruLite::MultiIndex.from_tuples([ - [:a,:two,:bar], - [:a,:two,:baz], - [:b,:one,:bar], - [:b,:two,:bar] - ]) - vector = DaruLite::Vector.new([1,2,3,4], index: mi, dtype: dtype) - expect(vector.index_of(3)).to eq([:b,:one,:bar]) - end - end - end - - context "#to_df" do - let(:dv) { DaruLite::Vector.new(['a','b','c'], name: :my_dv, index: ['alpha', 'beta', 'gamma']) } - let(:df) { dv.to_df } - - it 'is a dataframe' do - expect(df).to be_a DaruLite::DataFrame - end - - it 'converts the vector to a single-vector dataframe' do - expect(df[:my_dv]).to eq dv - end - - it 'has the same index as the original vector' do - expect(df.index).to eq dv.index - end - - it 'has the same name as the vector' do - expect(df.name).to eq :my_dv - end - end - - context "#to_h" do - context DaruLite::Index do - it "returns the vector as a hash" do - dv = DaruLite::Vector.new [1,2,3,4,5], name: :a, - index: [:one, :two, :three, :four, :five], dtype: dtype - - expect(dv.to_h).to eq({one: 1, two: 2, three: 3, four: 4, five: 5}) - end - end - - context DaruLite::MultiIndex do - pending - # it "returns vector as a Hash" do - # pending - # mi = DaruLite::MultiIndex.from_tuples([ - # [:a,:two,:bar], - # [:a,:two,:baz], - # [:b,:one,:bar], - # [:b,:two,:bar] - # ]) - # vector = DaruLite::Vector.new([1,2,3,4], index: mi, dtype: dtype) - # expect(vector.to_h).to eq({ - # [:a,:two,:bar] => 1, - # [:a,:two,:baz] => 2, - # [:b,:one,:bar] => 3, - # [:b,:two,:bar] => 4 - # }) - # end - end - end - - context "#to_json" do - subject(:vector) do - DaruLite::Vector.new [1,2,3,4,5], name: :a, - index: [:one, :two, :three, :four, :five], dtype: dtype - end - - its(:to_json) { is_expected.to eq(vector.to_h.to_json) } - end - - context "#to_s" do - before do - @v = DaruLite::Vector.new ["a", "b"], index: [1, 2] - end - - it 'produces a class, size description' do - expect(@v.to_s).to eq("#<DaruLite::Vector(2)>") - end - - it 'produces a class, name, size description' do - @v.name = "Test" - expect(@v.to_s).to eq("#<DaruLite::Vector: Test(2)>") - end - - it 'produces a class, name, size description when the name is a symbol' do - @v.name = :Test - expect(@v.to_s).to eq("#<DaruLite::Vector: Test(2)>") - end - end - - context "#uniq" do - before do - @v = DaruLite::Vector.new [1, 2, 2, 2.0, 3, 3.0], index:[:a, :b, :c, :d, :e, :f] - end - it "keeps only unique values" do - expect(@v.uniq).to eq(DaruLite::Vector.new [1, 2, 2.0, 3, 3.0], index: [:a, :b, :d, :e, :f]) - end - end - context "#cast" do ALL_DTYPES.each do |new_dtype| it "casts from #{dtype} to #{new_dtype}" do v = DaruLite::Vector.new [1,2,3,4], dtype: dtype v.cast(dtype: new_dtype) expect(v.dtype).to eq(new_dtype) end end end - context "#sort" do - context DaruLite::Index do - before do - @dv = DaruLite::Vector.new [33,2,15,332,1], name: :dv, index: [:a, :b, :c, :d, :e] - end - - it "sorts the vector with defaults and returns a new vector, preserving indexing" do - expect(@dv.sort).to eq(DaruLite::Vector.new([1,2,15,33,332], name: :dv, index: [:e, :b, :c, :a, :d])) - end - - it "sorts the vector in descending order" do - expect(@dv.sort(ascending: false)).to eq(DaruLite::Vector.new([332,33,15,2,1], name: :dv, index: [:d, :a, :c, :b, :e])) - end - - it "accepts a block" do - str_dv = DaruLite::Vector.new ["My Jazz Guitar", "Jazz", "My", "Guitar"] - - sorted = str_dv.sort { |a,b| a.length <=> b.length } - expect(sorted).to eq(DaruLite::Vector.new(["My", "Jazz", "Guitar", "My Jazz Guitar"], index: [2,1,3,0])) - end - - it "places nils near the beginning of the vector when sorting ascendingly" do - with_nils = DaruLite::Vector.new [22,4,nil,111,nil,2] - - expect(with_nils.sort).to eq(DaruLite::Vector.new([nil,nil,2,4,22,111], index: [2,4,5,1,0,3])) - end if dtype == :array - - it "places nils near the beginning of the vector when sorting descendingly" do - with_nils = DaruLite::Vector.new [22,4,nil,111,nil,2] - - expect(with_nils.sort(ascending: false)).to eq( - DaruLite::Vector.new [111,22,4,2,nil,nil], index: [3,0,1,5,4,2]) - end - - it "correctly sorts vector in ascending order with non-numeric data and nils" do - non_numeric = DaruLite::Vector.new ['a','b', nil, 'aa', '1234', nil] - - expect(non_numeric.sort(ascending: true)).to eq( - DaruLite::Vector.new [nil,nil,'1234','a','aa','b'], index: [2,5,4,0,3,1]) - end - - it "correctly sorts vector in descending order with non-numeric data and nils" do - non_numeric = DaruLite::Vector.new ['a','b', nil, 'aa', '1234', nil] - - expect(non_numeric.sort(ascending: false)).to eq( - DaruLite::Vector.new ['b','aa','a','1234',nil,nil], index: [1,3,0,4,5,2]) - end - end - - context DaruLite::MultiIndex do - before do - mi = DaruLite::MultiIndex.from_tuples([ - [:a, :one, :foo], - [:a, :two, :bar], - [:b, :one, :bar], - [:b, :two, :baz], - [:b, :three, :bar] - ]) - @vector = DaruLite::Vector.new([44,22,111,0,-56], index: mi, name: :unsorted, - dtype: dtype) - end - - it "sorts vector" do - mi_asc = DaruLite::MultiIndex.from_tuples([ - [:b, :three, :bar], - [:b, :two, :baz], - [:a, :two, :bar], - [:a, :one, :foo], - [:b, :one, :bar] - ]) - expect(@vector.sort).to eq(DaruLite::Vector.new([-56,0,22,44,111], index: mi_asc, - name: :ascending, dtype: dtype)) - end - - it "sorts in descending" do - mi_dsc = DaruLite::MultiIndex.from_tuples([ - [:b, :one, :bar], - [:a, :one, :foo], - [:a, :two, :bar], - [:b, :two, :baz], - [:b, :three, :bar] - ]) - expect(@vector.sort(ascending: false)).to eq(DaruLite::Vector.new( - [111,44,22,0,-56], index: mi_dsc, name: :descending, dtype: dtype)) - end - - it "sorts using the supplied block" do - mi_abs = DaruLite::MultiIndex.from_tuples([ - [:b, :two, :baz], - [:a, :two, :bar], - [:a, :one, :foo], - [:b, :three, :bar], - [:b, :one, :bar] - ]) - expect(@vector.sort { |a,b| a.abs <=> b.abs }).to eq(DaruLite::Vector.new( - [0,22,44,-56,111], index: mi_abs, name: :sort_abs, dtype: dtype)) - end - end - - context DaruLite::CategoricalIndex do - let(:idx) { DaruLite::CategoricalIndex.new [:a, 1, :a, 1, :c] } - let(:dv_numeric) { DaruLite::Vector.new [4, 5, 3, 2, 1], index: idx } - let(:dv_string) { DaruLite::Vector.new ['xxxx', 'zzzzz', 'ccc', 'bb', 'a'], index: idx } - let(:dv_nil) { DaruLite::Vector.new [3, nil, 2, 1, -1], index: idx } - - context "increasing order" do - context "numeric" do - subject { dv_numeric.sort } - - its(:size) { is_expected.to eq 5 } - its(:to_a) { is_expected.to eq [1, 2, 3, 4, 5] } - its(:'index.to_a') { is_expected.to eq [:c, 1, :a, :a, 1] } - end - - context "non-numeric" do - subject { dv_string.sort } - - its(:size) { is_expected.to eq 5 } - its(:to_a) { is_expected.to eq ['a', 'bb', 'ccc', 'xxxx', 'zzzzz'] } - its(:'index.to_a') { is_expected.to eq [:c, 1, :a, :a, 1] } - end - - context "block" do - subject { dv_string.sort { |a, b| a.length <=> b.length } } - - its(:to_a) { is_expected.to eq ['a', 'bb', 'ccc', 'xxxx', 'zzzzz'] } - its(:'index.to_a') { is_expected.to eq [:c, 1, :a, :a, 1] } - end - - context "nils" do - subject { dv_nil.sort } - - its(:to_a) { is_expected.to eq [nil, -1, 1, 2, 3] } - its(:'index.to_a') { is_expected.to eq [1, :c, 1, :a, :a] } - end - end - - context "decreasing order" do - context "numeric" do - subject { dv_numeric.sort(ascending: false) } - - its(:size) { is_expected.to eq 5 } - its(:to_a) { is_expected.to eq [5, 4, 3, 2, 1] } - its(:'index.to_a') { is_expected.to eq [1, :a, :a, 1, :c] } - end - - context "non-numeric" do - subject { dv_string.sort(ascending: false) } - - its(:size) { is_expected.to eq 5 } - its(:to_a) { is_expected.to eq ['zzzzz', 'xxxx', 'ccc', 'bb', 'a'] } - its(:'index.to_a') { is_expected.to eq [1, :a, :a, 1, :c] } - end - - context "block" do - subject do - dv_string.sort(ascending: false) { |a, b| a.length <=> b.length } - end - - its(:to_a) { is_expected.to eq ['zzzzz', 'xxxx', 'ccc', 'bb', 'a'] } - its(:'index.to_a') { is_expected.to eq [1, :a, :a, 1, :c] } - end - - context "nils" do - subject { dv_nil.sort(ascending: false) } - - its(:to_a) { is_expected.to eq [3, 2, 1, -1, nil] } - its(:'index.to_a') { is_expected.to eq [:a, :a, 1, :c, 1] } - end - end - end - end - - context "#index=" do - before do - @vector = DaruLite::Vector.new([1,2,3,4,5]) - end - - it "simply reassigns index" do - index = DaruLite::DateTimeIndex.date_range(:start => '2012', :periods => 5) - @vector.index = index - - expect(@vector.index.class).to eq(DaruLite::DateTimeIndex) - expect(@vector['2012-1-1']).to eq(1) - end - - it "accepts an array as index" do - @vector.index = [5,4,3,2,1] - - expect(@vector.index.class).to eq(DaruLite::Index) - expect(@vector[5]).to eq(1) - end - - it "accepts an range as index" do - @vector.index = 'a'..'e' - - expect(@vector.index.class).to eq(DaruLite::Index) - expect(@vector['a']).to eq(1) - end - - it "raises error for index size != vector size" do - expect { - @vector.index = DaruLite::Index.new([4,2,6]) - }.to raise_error(ArgumentError, 'Size of supplied index 3 '\ - 'does not match size of Vector') - end - end - - context "#reindex!" do - before do - @vector = DaruLite::Vector.new([1,2,3,4,5]) - @index = DaruLite::Index.new([3,4,1,0,6]) - end - it "intelligently reindexes" do - @vector.reindex!(@index) - expect(@vector).to eq( - DaruLite::Vector.new([4,5,2,1,nil], index: @index)) - end - end - - context "#reindex" do - before do - @vector = DaruLite::Vector.new([1,2,3,4,5]) - @index = DaruLite::Index.new([3,4,1,0,6]) - end - it "intelligently reindexes" do - expect(@vector.reindex(@index)).to eq( - DaruLite::Vector.new([4,5,2,1,nil], index: @index)) - end - end - - context "#dup" do - before do - @dv = DaruLite::Vector.new [1,2], name: :yoda, index: [:happy, :lightsaber] - end - - it "copies the original data" do - expect(@dv.dup.send(:data)).to eq([1,2]) - end - - it "creates a new data object" do - expect(@dv.dup.send(:data).object_id).not_to eq(@dv.send(:data).object_id) - end - - it "copies the name" do - expect(@dv.dup.name).to eq(:yoda) - end - - it "copies the original index" do - expect(@dv.dup.index).to eq(DaruLite::Index.new([:happy, :lightsaber])) - end - - it "creates a new index object" do - expect(@dv.dup.index.object_id).not_to eq(@dv.index.object_id) - end - end - - context "#collect" do - it "returns an Array" do - a = @common_all_dtypes.collect { |v| v } - expect(a).to eq([5, 5, 5, 5, 5, 6, 6, 7, 8, 9, 10, 1, 2, 3, 4, 11, -99, -99]) - end - end - - context "#map" do - it "maps" do - a = @common_all_dtypes.map { |v| v } - expect(a).to eq([5, 5, 5, 5, 5, 6, 6, 7, 8, 9, 10, 1, 2, 3, 4, 11, -99, -99]) - end - end - - context "#map!" do - it "destructively maps" do - @common_all_dtypes.map! { |v| v + 1 } - expect(@common_all_dtypes).to eq(DaruLite::Vector.new( - [6, 6, 6, 6, 6, 7, 7, 8, 9, 10, 11, 2, 3, 4, 5, 12, -98, -98], - dtype: dtype)) - end - end - - context "#recode" do - it "maps and returns a vector of dtype of self by default" do - a = @common_all_dtypes.recode { |v| v == -99 ? 1 : 0 } - exp = DaruLite::Vector.new [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1] - expect(a).to eq(exp) - expect(a.dtype).to eq(:array) - end - end - - context "#recode!" do - before :each do - @vector = DaruLite::Vector.new( - [5, 5, 5, 5, 5, 6, 6, 7, 8, 9, 10, 1, 2, 3, 4, 11, -99, -99], - dtype: dtype, name: :common_all_dtypes) - end - - it "destructively maps and returns a vector of dtype of self by default" do - @vector.recode! { |v| v == -99 ? 1 : 0 } - exp = DaruLite::Vector.new [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1] - expect(@vector).to eq(exp) - expect(@vector.dtype).to eq(dtype) - end - end - - context "#verify" do - it "returns a hash of invalid data and index of data" do - v = DaruLite::Vector.new [1,2,3,4,5,6,-99,35,-100], dtype: dtype - h = v.verify { |d| d > 0 } - e = { 6 => -99, 8 => -100 } - expect(h).to eq(e) - end - end - - context "#summary" do - subject { dv.summary } - - context 'all types' do - let(:dv) { DaruLite::Vector.new([1,2,3,4,5], name: 'vector') } - - it { is_expected.to include dv.name } - - it { is_expected.to include "n :#{dv.size}" } - - it { is_expected.to include "non-missing:#{dv.size - dv.count_values(*DaruLite::MISSING_VALUES)}" } - end - - - context "numeric type" do - let(:dv) { DaruLite::Vector.new([1,2,5], name: 'numeric') } - - it { is_expected. to eq %Q{ - |= numeric - | n :3 - | non-missing:3 - | median: 2 - | mean: 2.6667 - | std.dev.: 2.0817 - | std.err.: 1.2019 - | skew: 0.2874 - | kurtosis: -2.3333 - }.unindent } - end - - context "numeric type with missing values" do - let(:dv) { DaruLite::Vector.new([1,2,5,nil,Float::NAN], name: 'numeric') } - - it { is_expected.not_to include 'skew' } - it { is_expected.not_to include 'kurtosis' } - end - - if dtype == :array - context "object type" do - let(:dv) { DaruLite::Vector.new([1,1,2,2,"string",nil,Float::NAN], name: 'object') } - - if RUBY_VERSION >= '2.2' - it { is_expected.to eq %Q{ - |= object - | n :7 - | non-missing:5 - | factors: 1,2,string - | mode: 1,2 - | Distribution - | string 1 50.00% - | NaN 1 50.00% - | 1 2 100.00% - | 2 2 100.00% - }.unindent } - else - it { is_expected.to eq %Q{ - |= object - | n :7 - | non-missing:5 - | factors: 1,2,string - | mode: 1,2 - | Distribution - | NaN 1 50.00% - | string 1 50.00% - | 2 2 100.00% - | 1 2 100.00% - }.unindent } - end - end - end - end - context "#bootstrap" do it "returns a vector with mean=mu and sd=se" do rng = Distribution::Normal.rng(0, 1) - vector =DaruLite::Vector.new_with_size(100, dtype: dtype) { rng.call} + vector =DaruLite::Vector.new_with_size(100, dtype:) { rng.call} df = vector.bootstrap([:mean, :sd], 200) se = 1 / Math.sqrt(vector.size) expect(df[:mean].mean).to be_within(0.3).of(0) expect(df[:mean].sd).to be_within(0.02).of(se) end end + + it_behaves_like 'a calculatable Vector', dtype + it_behaves_like 'a convertible Vector', dtype + it_behaves_like 'a fetchable Vector', dtype + it_behaves_like 'a filterable Vector', dtype + it_behaves_like 'an indexable Vector', dtype + it_behaves_like 'an iterable Vector', dtype + it_behaves_like 'a joinable Vector', dtype + it_behaves_like 'a setable Vector', dtype + it_behaves_like 'a sortable Vector', dtype end end # describe ALL_DTYPES.each # ----------------------------------------------------------------------- # works with arrays only + it_behaves_like 'an aggregatable Vector' + it_behaves_like 'a duplicatable Vector' + it_behaves_like 'a missable Vector' + it_behaves_like 'a queryable Vector' + context "#splitted" do it "splits correctly" do a = DaruLite::Vector.new ['a', 'a,b', 'c,d', 'a,d', 'd', 10, nil] expect(a.splitted).to eq([%w(a), %w(a b), %w(c d), %w(a d), %w(d), [10], nil]) end @@ -1632,316 +371,11 @@ it { is_expected.to be_a DaruLite::Vector } its(:to_a) { is_expected.to eq [true, false, true, true, true] } end end - context "#clone_structure" do - context DaruLite::Index do - before do - @vec = DaruLite::Vector.new([1,2,3,4,5], index: [:a,:b,:c,:d,:e]) - end - - it "clones a vector with its index and fills it with nils" do - expect(@vec.clone_structure).to eq(DaruLite::Vector.new([nil,nil,nil,nil,nil], index: [:a,:b,:c,:d,:e])) - end - end - - context DaruLite::MultiIndex do - pending - end - end - - context '#reject_values'do - let(:dv) { DaruLite::Vector.new [1, nil, 3, :a, Float::NAN, nil, Float::NAN, 1], - index: 11..18 } - context 'reject only nils' do - subject { dv.reject_values nil } - - it { is_expected.to be_a DaruLite::Vector } - its(:to_a) { is_expected.to eq [1, 3, :a, Float::NAN, Float::NAN, 1] } - its(:'index.to_a') { is_expected.to eq [11, 13, 14, 15, 17, 18] } - end - - context 'reject only float::NAN' do - subject { dv.reject_values Float::NAN } - - it { is_expected.to be_a DaruLite::Vector } - its(:to_a) { is_expected.to eq [1, nil, 3, :a, nil, 1] } - its(:'index.to_a') { is_expected.to eq [11, 12, 13, 14, 16, 18] } - end - - context 'reject both nil and float::NAN' do - subject { dv.reject_values nil, Float::NAN } - - it { is_expected.to be_a DaruLite::Vector } - its(:to_a) { is_expected.to eq [1, 3, :a, 1] } - its(:'index.to_a') { is_expected.to eq [11, 13, 14, 18] } - end - - context 'reject any other value' do - subject { dv.reject_values 1, 3 } - - it { is_expected.to be_a DaruLite::Vector } - its(:to_a) { is_expected.to eq [nil, :a, Float::NAN, nil, Float::NAN] } - its(:'index.to_a') { is_expected.to eq [12, 14, 15, 16, 17] } - end - - context 'when resultant vector has only one value' do - subject { dv.reject_values 1, :a, nil, Float::NAN } - - it { is_expected.to be_a DaruLite::Vector } - its(:to_a) { is_expected.to eq [3] } - its(:'index.to_a') { is_expected.to eq [13] } - end - - context 'when resultant vector has no value' do - subject { dv.reject_values 1, 3, :a, nil, Float::NAN, 5 } - - it { is_expected.to be_a DaruLite::Vector } - its(:to_a) { is_expected.to eq [] } - its(:'index.to_a') { is_expected.to eq [] } - end - - context 'test caching' do - let(:dv) { DaruLite::Vector.new [nil]*8, index: 11..18} - before do - dv.reject_values nil - [1, nil, 3, :a, Float::NAN, nil, Float::NAN, 1].each_with_index do |v, pos| - dv.set_at [pos], v - end - end - - context 'reject only nils' do - subject { dv.reject_values nil } - - it { is_expected.to be_a DaruLite::Vector } - its(:to_a) { is_expected.to eq [1, 3, :a, Float::NAN, Float::NAN, 1] } - its(:'index.to_a') { is_expected.to eq [11, 13, 14, 15, 17, 18] } - end - - context 'reject only float::NAN' do - subject { dv.reject_values Float::NAN } - - it { is_expected.to be_a DaruLite::Vector } - its(:to_a) { is_expected.to eq [1, nil, 3, :a, nil, 1] } - its(:'index.to_a') { is_expected.to eq [11, 12, 13, 14, 16, 18] } - end - - context 'reject both nil and float::NAN' do - subject { dv.reject_values nil, Float::NAN } - - it { is_expected.to be_a DaruLite::Vector } - its(:to_a) { is_expected.to eq [1, 3, :a, 1] } - its(:'index.to_a') { is_expected.to eq [11, 13, 14, 18] } - end - - context 'reject any other value' do - subject { dv.reject_values 1, 3 } - - it { is_expected.to be_a DaruLite::Vector } - its(:to_a) { is_expected.to eq [nil, :a, Float::NAN, nil, Float::NAN] } - its(:'index.to_a') { is_expected.to eq [12, 14, 15, 16, 17] } - end - end - end - - context '#include_values?' do - context 'only nils' do - context 'true' do - let(:dv) { DaruLite::Vector.new [1, 2, 3, :a, 'Unknown', nil] } - it { expect(dv.include_values? nil).to eq true } - end - - context 'false' do - let(:dv) { DaruLite::Vector.new [1, 2, 3, :a, 'Unknown'] } - it { expect(dv.include_values? nil).to eq false } - end - end - - context 'only Float::NAN' do - context 'true' do - let(:dv) { DaruLite::Vector.new [1, nil, 2, 3, Float::NAN] } - it { expect(dv.include_values? Float::NAN).to eq true } - end - - context 'false' do - let(:dv) { DaruLite::Vector.new [1, nil, 2, 3] } - it { expect(dv.include_values? Float::NAN).to eq false } - end - end - - context 'both nil and Float::NAN' do - context 'true with only nil' do - let(:dv) { DaruLite::Vector.new [1, Float::NAN, 2, 3] } - it { expect(dv.include_values? nil, Float::NAN).to eq true } - end - - context 'true with only Float::NAN' do - let(:dv) { DaruLite::Vector.new [1, nil, 2, 3] } - it { expect(dv.include_values? nil, Float::NAN).to eq true } - end - - context 'false' do - let(:dv) { DaruLite::Vector.new [1, 2, 3] } - it { expect(dv.include_values? nil, Float::NAN).to eq false } - end - end - - context 'any other value' do - context 'true' do - let(:dv) { DaruLite::Vector.new [1, 2, 3, 4, nil] } - it { expect(dv.include_values? 1, 2, 3, 5).to eq true } - end - - context 'false' do - let(:dv) { DaruLite::Vector.new [1, 2, 3, 4, nil] } - it { expect(dv.include_values? 5, 6).to eq false } - end - end - end - - context '#count_values' do - let(:dv) { DaruLite::Vector.new [1, 2, 3, 1, 2, nil, nil] } - it { expect(dv.count_values 1, 2).to eq 4 } - it { expect(dv.count_values nil).to eq 2 } - it { expect(dv.count_values 3, Float::NAN).to eq 1 } - it { expect(dv.count_values 4).to eq 0 } - end - - context '#indexes' do - context DaruLite::Index do - let(:dv) { DaruLite::Vector.new [1, 2, 1, 2, 3, nil, nil, Float::NAN], - index: 11..18 } - - subject { dv.indexes 1, 2, nil, Float::NAN } - it { is_expected.to be_a Array } - it { is_expected.to eq [11, 12, 13, 14, 16, 17, 18] } - end - - context DaruLite::MultiIndex do - let(:mi) do - DaruLite::MultiIndex.from_tuples([ - ['M', 2000], - ['M', 2001], - ['M', 2002], - ['M', 2003], - ['F', 2000], - ['F', 2001], - ['F', 2002], - ['F', 2003] - ]) - end - let(:dv) { DaruLite::Vector.new [1, 2, 1, 2, 3, nil, nil, Float::NAN], - index: mi } - - subject { dv.indexes 1, 2, Float::NAN } - it { is_expected.to be_a Array } - it { is_expected.to eq( - [ - ['M', 2000], - ['M', 2001], - ['M', 2002], - ['M', 2003], - ['F', 2003] - ]) } - end - end - - context '#replace_values' do - subject do - DaruLite::Vector.new( - [1, 2, 1, 4, nil, Float::NAN, nil, Float::NAN], - index: 11..18 - ) - end - - context 'replace nils and NaNs' do - before { subject.replace_values [nil, Float::NAN], 10 } - its(:to_a) { is_expected.to eq [1, 2, 1, 4, 10, 10, 10, 10] } - end - - context 'replace arbitrary values' do - before { subject.replace_values [1, 2], 10 } - its(:to_a) { is_expected.to eq( - [10, 10, 10, 4, nil, Float::NAN, nil, Float::NAN]) } - end - - context 'works for single value' do - before { subject.replace_values nil, 10 } - its(:to_a) { is_expected.to eq( - [1, 2, 1, 4, 10, Float::NAN, 10, Float::NAN]) } - end - end - - context "#replace_nils" do - it "replaces all nils with the specified value" do - vec = DaruLite::Vector.new([1,2,3,nil,nil,4]) - expect(vec.replace_nils(2)).to eq(DaruLite::Vector.new([1,2,3,2,2,4])) - end - - it "replaces all nils with the specified value (bang)" do - vec = DaruLite::Vector.new([1,2,3,nil,nil,4]).replace_nils!(2) - expect(vec).to eq(DaruLite::Vector.new([1,2,3,2,2,4])) - end - end - - context '#rolling_fillna!' do - subject do - DaruLite::Vector.new( - [Float::NAN, 2, 1, 4, nil, Float::NAN, 3, nil, Float::NAN] - ) - end - - context 'rolling_fillna! forwards' do - before { subject.rolling_fillna!(:forward) } - its(:to_a) { is_expected.to eq [0, 2, 1, 4, 4, 4, 3, 3, 3] } - end - - context 'rolling_fillna! backwards' do - before { subject.rolling_fillna!(direction: :backward) } - its(:to_a) { is_expected.to eq [2, 2, 1, 4, 3, 3, 3, 0, 0] } - end - - context 'all invalid vector' do - subject do - DaruLite::Vector.new( - [Float::NAN, Float::NAN, Float::NAN, Float::NAN, Float::NAN] - ) - end - before { subject.rolling_fillna!(:forward) } - its(:to_a) { is_expected.to eq [0, 0, 0, 0, 0] } - end - - context 'with non-default index' do - subject do - DaruLite::Vector.new( - [Float::NAN, 2, 1, 4, nil, Float::NAN, 3, nil, Float::NAN], - index: %w[a b c d e f g h i] - ) - end - before { subject.rolling_fillna!(direction: :backward) } - it { is_expected.to eq DaruLite::Vector.new([2, 2, 1, 4, 3, 3, 3, 0, 0], index: %w[a b c d e f g h i]) } - end - end - - context '#rolling_fillna' do - subject do - DaruLite::Vector.new( - [Float::NAN, 2, 1, 4, nil, Float::NAN, 3, nil, Float::NAN] - ) - end - - context 'rolling_fillna forwards' do - it { expect(subject.rolling_fillna(:forward).to_a).to eq [0, 2, 1, 4, 4, 4, 3, 3, 3] } - end - - context 'rolling_fillna backwards' do - it { expect(subject.rolling_fillna(direction: :backward).to_a).to eq [2, 2, 1, 4, 3, 3, 3, 0, 0] } - end - end - - context "#type" do + describe "#type" do before(:each) do @numeric = DaruLite::Vector.new([1,2,3,4,5]) @multi = DaruLite::Vector.new([1,2,3,'sameer','d']) @with_nils = DaruLite::Vector.new([1,2,3,4,nil]) end @@ -1980,154 +414,82 @@ @with_nils[4] = 'string' expect(@with_nils.type).to eq(:object) end end - context "#to_matrix" do - before do - @vector = DaruLite::Vector.new [1,2,3,4,5,6] - end + describe "#split_by_separator" do + subject { vector.split_by_separator(separator) } - it "converts DaruLite::Vector to a horizontal Ruby Matrix" do - expect(@vector.to_matrix).to eq(Matrix[[1,2,3,4,5,6]]) - end + let(:vector) { DaruLite::Vector.new ['a', 'a,b', 'c,d', 'a,d', 10, nil] } + let(:separator) { ',' } - it "converts DaruLite::Vector to a vertical Ruby Matrix" do - expect(@vector.to_matrix(:vertical)).to eq(Matrix.columns([[1,2,3,4,5,6]])) - end - - it 'raises on wrong axis' do - expect { @vector.to_matrix(:strange) }.to raise_error(ArgumentError) - end - end - - context "#only_numerics" do - it "returns only numerical or missing data" do - v = DaruLite::Vector.new([1,2,nil,3,4,'s','a',nil]) - expect(v.only_numerics).to eq(DaruLite::Vector.new([1,2,nil,3,4,nil], - index: [0,1,2,3,4,7])) - end - end - - context "#split_by_separator" do - def expect_correct_tokens hash + def expect_correct_tokens(hash) expect(hash['a'].to_a).to eq([1, 1, 0, 1, 0, nil]) expect(hash['b'].to_a).to eq([0, 1, 0, 0, 0, nil]) expect(hash['c'].to_a).to eq([0, 0, 1, 0, 0, nil]) expect(hash['d'].to_a).to eq([0, 0, 1, 1, 0, nil]) expect(hash[10].to_a).to eq([0, 0, 0, 0, 1, nil]) end - before do - @a = DaruLite::Vector.new ['a', 'a,b', 'c,d', 'a,d', 10, nil] - @b = @a.split_by_separator(',') - end - it "returns a Hash" do - expect(@b.class).to eq(Hash) + expect(subject.class).to eq(Hash) end - it "returned Hash has keys with with different values of @a" do - expect(@b.keys).to eq(['a', 'b', 'c', 'd', 10]) + it "returned Hash has keys with with different values of a" do + expect(subject.keys).to eq(['a', 'b', 'c', 'd', 10]) end it "returns a Hash, whose values are DaruLite::Vector" do - @b.each_key do |key| - expect(@b[key].class).to eq(DaruLite::Vector) + subject.each_key do |key| + expect(subject[key].class).to eq(DaruLite::Vector) end end it "ensures that hash values are n times the tokens appears" do - expect_correct_tokens @b + expect_correct_tokens subject end - it "gives the same values using a different separator" do - a = DaruLite::Vector.new ['a', 'a*b', 'c*d', 'a*d', 10, nil] - b = a.split_by_separator '*' - expect_correct_tokens b - end - end + context 'when using a different separator' do + let(:vector) { DaruLite::Vector.new ['a', 'a*b', 'c*d', 'a*d', 10, nil] } + let(:separator) { '*' } - context "#split_by_separator_freq" do - it "returns the number of ocurrences of tokens" do - a = DaruLite::Vector.new ['a', 'a,b', 'c,d', 'a,d', 10, nil] - expect(a.split_by_separator_freq).to eq( - { 'a' => 3, 'b' => 1, 'c' => 1, 'd' => 2, 10 => 1 }) + it "gives the same values using a different separator" do + expect_correct_tokens subject + end end end - context "#reset_index!" do - it "resets any index to a numerical serialized index" do - v = DaruLite::Vector.new([1,2,3,4,5,nil,nil,4,nil]) - r = v.reject_values(*DaruLite::MISSING_VALUES).reset_index! - expect(r).to eq(DaruLite::Vector.new([1,2,3,4,5,4])) - expect(r.index).to eq(DaruLite::Index.new([0,1,2,3,4,5])) + describe "#split_by_separator_freq" do + subject { vector.split_by_separator_freq } - indexed = DaruLite::Vector.new([1,2,3,4,5], index: [:a, :b, :c, :d, :e]) - expect(indexed.reset_index!.index).to eq(DaruLite::Index.new([0,1,2,3,4])) + let(:vector) { DaruLite::Vector.new ['a', 'a,b', 'c,d', 'a,d', 10, nil] } + + it "returns the number of ocurrences of tokens" do + expect(subject).to eq( + { 'a' => 3, 'b' => 1, 'c' => 1, 'd' => 2, 10 => 1 } + ) end end - context "#rename" do - before :each do - @v = DaruLite::Vector.new [1,2,3,4,5,5], name: :this_vector - end + describe "#rename" do + let(:vector) { DaruLite::Vector.new [1, 2, 3, 4, 5, 5], name: :this_vector } it "assings name" do - @v.rename :that_vector - expect(@v.name).to eq(:that_vector) + vector.rename :that_vector + expect(vector.name).to eq(:that_vector) end it "stores name as a symbol" do - @v.rename "This is a vector" - expect(@v.name).to eq("This is a vector") + vector.rename "This is a vector" + expect(vector.name).to eq("This is a vector") end it "returns vector" do - expect(@v.rename 'hello').to be_a DaruLite::Vector + expect(vector.rename 'hello').to be_a DaruLite::Vector end end - context "#any?" do - before do - @v = DaruLite::Vector.new([1,2,3,4,5]) - end - - it "returns true if block returns true for any one of the elements" do - expect(@v.any?{ |e| e == 1 }).to eq(true) - end - - it "returns false if block is false for all elements" do - expect(@v.any?{ |e| e > 10 }).to eq(false) - end - end - - context "#all?" do - before do - @v = DaruLite::Vector.new([1,2,3,4,5]) - end - - it "returns true if block is true for all elements" do - expect(@v.all? { |e| e < 6 }).to eq(true) - end - - it "returns false if block is false for any one element" do - expect(@v.all? { |e| e == 2 }).to eq(false) - end - end - - context "#detach_index" do - it "creates a DataFrame with first Vector as index and second as values of the Vector" do - v = DaruLite::Vector.new([1,2,3,4,5,6], - index: ['a', 'b', 'c', 'd', 'e', 'f'], name: :values) - expect(v.detach_index).to eq(DaruLite::DataFrame.new({ - index: ['a', 'b', 'c', 'd', 'e', 'f'], - values: [1,2,3,4,5,6] - })) - end - end - describe '#lag' do let(:source) { DaruLite::Vector.new(1..5) } context 'by default' do subject { source.lag } @@ -2168,51 +530,13 @@ context 'large negative' do let(:amount) { -(source.size + 100) } it { is_expected.to eq DaruLite::Vector.new([nil]*source.size) } end - end - context "#group_by" do - let(:dv) { DaruLite::Vector.new [:a, :b, :a, :b, :c] } - - context 'vector not specified' do - subject { dv.group_by } - - it { is_expected.to be_a DaruLite::Core::GroupBy } - its(:'groups.size') { is_expected.to eq 3 } - its(:groups) { is_expected.to eq({[:a]=>[0, 2], [:b]=>[1, 3], [:c]=>[4]}) } - end - - context 'vector name specified' do - before { dv.name = :hello } - subject { dv.group_by :hello } - - it { is_expected.to be_a DaruLite::Core::GroupBy } - its(:'groups.size') { is_expected.to eq 3 } - its(:groups) { is_expected.to eq({[:a]=>[0, 2], [:b]=>[1, 3], [:c]=>[4]}) } - end - - context 'vector name invalid' do - before { dv.name = :hello } - it { expect { dv.group_by :abc }.to raise_error } - end - end - - context '#match' do - subject { dv.match(regexp) } - - context 'returns matching array for a given regexp' do - let(:dv) { DaruLite::Vector.new ['3 days', '5 weeks', '2 weeks'] } - let(:regexp) { /weeks/ } - - it { is_expected.to eq([false, true, true]) } - end - end - - context '#method_missing' do + describe '#method_missing' do context 'getting' do subject(:vector) { DaruLite::Vector.new [1,2,3], index: [:a, :b, :c] } it 'returns value for existing index' do expect(vector.a).to eq 1 @@ -2232,28 +556,10 @@ expect { vector.d = 5 }.to raise_error IndexError end end end - context "#sort_by_index" do - let(:asc) { vector.sort_by_index } - let(:desc) { vector.sort_by_index(ascending: false) } - - context 'numeric vector' do - let(:vector) { DaruLite::Vector.new [11, 13, 12], index: [23, 21, 22] } - specify { expect(asc.to_a).to eq [13, 12, 11] } - specify { expect(desc.to_a).to eq [11, 12, 13] } - end - - context 'mix variable type index' do - let(:vector) { DaruLite::Vector.new [11, Float::NAN, nil], - index: [21, 23, 22] } - specify { expect(asc.to_a).to eq [11, nil, Float::NAN] } - specify { expect(desc.to_a).to eq [Float::NAN, nil, 11] } - end - end - - context '#db_type' do + describe '#db_type' do it 'is DATE for vector with any date in it' do # FIXME: is it sane?.. - zverok expect(DaruLite::Vector.new(['2016-03-01', 'foo', 4]).db_type).to eq 'DATE' end