spec/vector_spec.rb in daru-0.1.5 vs spec/vector_spec.rb in daru-0.1.6

- old
+ new

@@ -82,10 +82,15 @@ dv = Daru::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 + it "initializes array with nils with dtype NMatrix" do + dv = Daru::Vector.new [2, nil], dtype: :nmatrix + expect(dv.to_a).to eq([2, nil]) + expect(dv.index.to_a).to eq([0, 1]) + end end context "#reorder!" do let(:vector_with_dtype) do Daru::Vector.new( @@ -356,10 +361,13 @@ context "#at" do context Daru::Index do let (:idx) { Daru::Index.new [1, 0, :c] } let (:dv) { Daru::Vector.new ['a', 'b', 'c'], index: idx } + let (:idx_dt) { Daru::DateTimeIndex.new(['2017-01-01', '2017-02-01', '2017-03-01']) } + let (:dv_dt) { Daru::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 @@ -403,10 +411,19 @@ it { is_expected.to be_a Daru::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 Daru::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 Daru::MultiIndex do let (:idx) do Daru::MultiIndex.from_tuples [ @@ -996,10 +1013,30 @@ end its(:to_json) { is_expected.to eq(vector.to_h.to_json) } end + context "#to_s" do + before do + @v = Daru::Vector.new ["a", "b"], index: [1, 2] + end + + it 'produces a class, size description' do + expect(@v.to_s).to eq("#<Daru::Vector(2)>") + end + + it 'produces a class, name, size description' do + @v.name = "Test" + expect(@v.to_s).to eq("#<Daru::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("#<Daru::Vector: Test(2)>") + end + end + context "#uniq" do before do @v = Daru::Vector.new [1, 2, 2, 2.0, 3, 3.0], index:[:a, :b, :c, :d, :e, :f] end it "keeps only unique values" do @@ -1357,13 +1394,80 @@ expect(h).to eq(e) end end context "#summary" do - it "has name in the summary" do - expect(@common_all_dtypes.summary.match("#{@common_all_dtypes.name}")).to_not eq(nil) + subject { dv.summary } + + context 'all types' do + let(:dv) { Daru::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(*Daru::MISSING_VALUES)}" } end + + unless dtype == :nmatrix + context "numeric type" do + let(:dv) { Daru::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) { Daru::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 + end + + if dtype == :array + context "object type" do + let(:dv) { Daru::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) @@ -1386,32 +1490,24 @@ a = Daru::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 end - context "#is_nil?" do - before(:each) do - @with_md = Daru::Vector.new([1,2,nil,3,4,nil]) - @without_md = Daru::Vector.new([1,2,3,4,5,6]) - end + context '#is_values' do + let(:dv) { Daru::Vector.new [10, 11, 10, nil, nil] } - it "verifies missing data presence" do - expect(@with_md.is_nil?) .to eq(Daru::Vector.new([false,false,true,false,false,true])) - expect(@without_md.is_nil?).to eq(Daru::Vector.new([false,false,false,false,false,false])) + context 'single value' do + subject { dv.is_values 10 } + it { is_expected.to be_a Daru::Vector } + its(:to_a) { is_expected.to eq [true, false, true, false, false] } end - end - context "#not_nil?" do - before(:each) do - @with_md = Daru::Vector.new([1,2,nil,3,4,nil]) - @without_md = Daru::Vector.new([1,2,3,4,5,6]) + context 'multiple values' do + subject { dv.is_values 10, nil } + it { is_expected.to be_a Daru::Vector } + its(:to_a) { is_expected.to eq [true, false, true, true, true] } end - - it "verifies missing data presence" do - expect(@with_md.not_nil?) .to eq(Daru::Vector.new([true,true,false,true,true,false])) - expect(@without_md.not_nil?).to eq(Daru::Vector.new([true,true,true,true,true,true])) - end end context "#clone_structure" do context Daru::Index do before do @@ -1431,61 +1527,61 @@ context '#reject_values'do let(:dv) { Daru::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 Daru::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 Daru::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 Daru::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 Daru::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 Daru::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 Daru::Vector } its(:to_a) { is_expected.to eq [] } its(:'index.to_a') { is_expected.to eq [] } end - + context 'works for gsl' do let(:dv) { Daru::Vector.new [1, 2, 3, Float::NAN], dtype: :gsl, index: 11..14 } subject { dv.reject_values Float::NAN } - + it { is_expected.to be_a Daru::Vector } its(:dtype) { is_expected.to eq :gsl } its(:to_a) { is_expected.to eq [1, 2, 3].map(&:to_f) } its(:'index.to_a') { is_expected.to eq [11, 12, 13] } end @@ -1499,35 +1595,35 @@ end end context 'reject only nils' do subject { dv.reject_values nil } - + it { is_expected.to be_a Daru::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 Daru::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 Daru::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 Daru::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 @@ -1561,28 +1657,28 @@ context 'both nil and Float::NAN' do context 'true with only nil' do let(:dv) { Daru::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) { Daru::Vector.new [1, nil, 2, 3] } it { expect(dv.include_values? nil, Float::NAN).to eq true } end - + context 'false' do let(:dv) { Daru::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) { Daru::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) { Daru::Vector.new [1, 2, 3, 4, nil] } it { expect(dv.include_values? 5, 6).to eq false } end end @@ -1598,16 +1694,16 @@ context '#indexes' do context Daru::Index do let(:dv) { Daru::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 Daru::MultiIndex do let(:mi) do Daru::MultiIndex.from_tuples([ ['M', 2000], ['M', 2001], @@ -1619,11 +1715,11 @@ ['F', 2003] ]) end let(:dv) { Daru::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], @@ -1632,11 +1728,11 @@ ['M', 2003], ['F', 2003] ]) } end end - + context '#replace_values' do subject do Daru::Vector.new( [1, 2, 1, 4, nil, Float::NAN, nil, Float::NAN], index: 11..18 @@ -1645,17 +1741,17 @@ 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 @@ -1739,31 +1835,31 @@ end end context '#to_nmatrix' do let(:dv) { Daru::Vector.new [1, 2, 3, 4, 5] } - + context 'horizontal axis' do subject { dv.to_nmatrix } it { is_expected.to be_a NMatrix } its(:shape) { is_expected.to eq [1, 5] } its(:to_a) { is_expected.to eq [1, 2, 3, 4, 5] } end - + context 'vertical axis' do subject { dv.to_nmatrix :vertical } - + it { is_expected.to be_a NMatrix } its(:shape) { is_expected.to eq [5, 1] } its(:to_a) { is_expected.to eq [1, 2, 3, 4, 5].map { |i| [i] } } end - + context 'invalid axis' do it { expect { dv.to_nmatrix :hello }.to raise_error ArgumentError } end - + context 'vector contain non-numeric' do let(:dv) { Daru::Vector.new [1, 2, nil, 4] } it { expect { dv.to_nmatrix }.to raise_error ArgumentError } end end @@ -1902,50 +1998,77 @@ values: [1,2,3,4,5,6] })) end end - context "#lag" do - before do - @xiu = Daru::Vector.new([17.28, 17.45, 17.84, 17.74, 17.82, 17.85, 17.36, 17.3, 17.56, 17.49, 17.46, 17.4, 17.03, 17.01, - 16.86, 16.86, 16.56, 16.36, 16.66, 16.77]) + describe '#lag' do + let(:source) { Daru::Vector.new(1..5) } + + context 'by default' do + subject { source.lag } + it { is_expected.to eq Daru::Vector.new([nil, 1, 2, 3, 4]) } end - it "lags the vector by specified amount" do - lag1 = @xiu.lag + subject { source.lag(amount) } - expect(lag1[lag1.size - 1]).to be_within(0.001).of(16.66) - expect(lag1[lag1.size - 2]).to be_within(0.001).of(16.36) + context '0' do + let(:amount) { 0 } + it { is_expected.to eq Daru::Vector.new([1, 2, 3, 4, 5]) } + end - #test with different lagging unit - lag2 = @xiu.lag(2) + context 'same as vector size' do + let(:amount) { source.size } + it { is_expected.to eq Daru::Vector.new([nil]*source.size) } + end - expect(lag2[lag2.size - 1]).to be_within(0.001).of(16.36) - expect(lag2[lag2.size - 2]).to be_within(0.001).of(16.56) + context 'same as vector -ve size' do + let(:amount) { -source.size } + it { is_expected.to eq Daru::Vector.new([nil]*source.size) } end + + context 'positive' do + let(:amount) { 2 } + it { is_expected.to eq Daru::Vector.new([nil, nil, 1, 2, 3]) } + end + + context 'negative' do + let(:amount) { -1 } + it { is_expected.to eq Daru::Vector.new([2, 3, 4, 5, nil]) } + end + + context 'large positive' do + let(:amount) { source.size + 100 } + it { is_expected.to eq Daru::Vector.new([nil]*source.size) } + end + + context 'large negative' do + let(:amount) { -(source.size + 100) } + it { is_expected.to eq Daru::Vector.new([nil]*source.size) } + end + end - + context "#group_by" do let(:dv) { Daru::Vector.new [:a, :b, :a, :b, :c] } - + context 'vector not specified' do - subject { dv.group_by } - + subject { dv.group_by } + it { is_expected.to be_a Daru::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 Daru::Core::GroupBy } its(:'groups.size') { is_expected.to eq 3 } - its(:groups) { is_expected.to eq({[:a]=>[0, 2], [:b]=>[1, 3], [:c]=>[4]}) } + 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 @@ -1972,10 +2095,28 @@ 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) { Daru::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) { Daru::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 it 'is DATE for vector with any date in it' do # FIXME: is it sane?.. - zverok expect(Daru::Vector.new(['2016-03-01', 'foo', 4]).db_type).to eq 'DATE' end @@ -2001,6 +2142,15 @@ it 'should not accept anything else' do expect { Daru::Vector.new([], dtype: :kittens) }.to raise_error(ArgumentError) end end + context '#where clause when Nan, nil data value is present' do + let(:v) { Daru::Vector.new([1,2,3,Float::NAN, nil]) } + + it 'missing/undefined data in Vector/DataFrame' do + expect(v.where(v.lt(4))).to eq(Daru::Vector.new([1,2,3])) + expect(v.where(v.lt(3))).to eq(Daru::Vector.new([1,2])) + expect(v.where(v.lt(2))).to eq(Daru::Vector.new([1])) + end + end end if mri?