describe DaruLite::Vector, "categorical" do context "initialize" do context "default parameters" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } subject { dv } it { is_expected.to be_a DaruLite::Vector } its(:size) { is_expected.to eq 5 } its(:type) { is_expected.to eq :category } its(:ordered?) { is_expected.to eq false } its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] } its(:base_category) { is_expected.to eq :a } its(:coding_scheme) { is_expected.to eq :dummy } its(:index) { is_expected.to be_a DaruLite::Index } its(:'index.to_a') { is_expected.to eq [0, 1, 2, 3, 4] } end context "with index" do context "as array" do let(:dv) do DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, index: ['a', 'b', 'c', 'd', 'e'] end subject { dv } its(:index) { is_expected.to be_a DaruLite::Index } its(:'index.to_a') { is_expected.to eq ['a', 'b', 'c', 'd', 'e'] } end context "as range" do let(:dv) do DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, index: 'a'..'e' end subject { dv } its(:index) { is_expected.to be_a DaruLite::Index } its(:'index.to_a') { is_expected.to eq ['a', 'b', 'c', 'd', 'e'] } end context "as index object" do let(:tuples) do [ [:one, :tin, :bar], [:one, :pin, :bar], [:two, :pin, :bar], [:two, :tin, :bar], [:thr, :pin, :foo] ] end let(:idx) { DaruLite::MultiIndex.from_tuples tuples } let(:dv) do DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, index: idx end subject { dv } its(:index) { is_expected.to be_a DaruLite::MultiIndex } its(:'index.to_a') { is_expected.to eq tuples } end context "invalid index" do it { expect { DaruLite::Vector.new [1, 1, 2], type: :category, index: [1, 2] }.to raise_error ArgumentError } end end context '#category?' do let(:non_cat) { DaruLite::Vector.new [1, 2, 3] } let(:cat) { DaruLite::Vector.new [1, 2, 3], type: :category } it { expect(non_cat.category?).to eq false } it { expect(cat.category?).to eq true } end context "with categories" do context "extra categories" do subject { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, categories: [:a, :b, :c, 1] } it { is_expected.to be_a DaruLite::Vector } its(:type) { is_expected.to eq :category } its(:size) { is_expected.to eq 5 } its(:order) { is_expected.to eq [:a, :b, :c, 1] } its(:categories) { is_expected.to eq [:a, :b, :c, 1] } end context "incomplete" do it do expect { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, categories: [:b, :c, 1] }. to raise_error ArgumentError end end end end context "#rename" do let(:dv) { DaruLite::Vector.new [1, 2, 1], type: :category } subject { dv.rename 'hello' } it { is_expected.to be_a DaruLite::Vector } its(:name) { is_expected.to eq 'hello' } end context '#index=' do context DaruLite::Index do let(:idx) { DaruLite::Index.new [1, 2, 3] } let(:dv) { DaruLite::Vector.new ['a', 'b', 'c'], type: :category } before { dv.index = idx } subject { dv } it { is_expected.to be_a DaruLite::Vector } its(:index) { is_expected.to be_a DaruLite::Index } its(:'index.to_a') { is_expected.to eq [1, 2, 3] } end context Range do let(:dv) { DaruLite::Vector.new ['a', 'b', 'c'], type: :category } before { dv.index = 1..3 } subject { dv } it { is_expected.to be_a DaruLite::Vector } its(:index) { is_expected.to be_a DaruLite::Index } its(:'index.to_a') { is_expected.to eq [1, 2, 3] } end context DaruLite::MultiIndex do let(:idx) { DaruLite::MultiIndex.from_tuples [[:a, :one], [:a, :two], [:b, :one]] } let(:dv) { DaruLite::Vector.new ['a', 'b', 'c'], type: :category } before { dv.index = idx } subject { dv } it { is_expected.to be_a DaruLite::Vector } its(:index) { is_expected.to be_a DaruLite::MultiIndex } its(:'index.to_a') { is_expected.to eq [[:a, :one], [:a, :two], [:b, :one]] } end end context "#cut" do context "close at right end" do let(:dv) { DaruLite::Vector.new [1, 2, 5, 14] } subject { dv.cut (0..20).step(5) } it { is_expected.to be_a DaruLite::Vector } its(:type) { is_expected.to eq :category } its(:size) { is_expected.to eq 4 } its(:categories) { is_expected.to eq ['0-4', '5-9', '10-14', '15-19'] } its(:to_a) { is_expected.to eq ['0-4', '0-4', '5-9', '10-14'] } end context "close at left end" do let(:dv) { DaruLite::Vector.new [1, 2, 5, 14] } subject { dv.cut (0..20).step(5), close_at: :left } it { is_expected.to be_a DaruLite::Vector } its(:type) { is_expected.to eq :category } its(:size) { is_expected.to eq 4 } its(:categories) { is_expected.to eq ['1-5', '6-10', '11-15', '16-20'] } its(:to_a) { is_expected.to eq ['1-5', '1-5', '1-5', '11-15'] } end context "labels" do let(:dv) { DaruLite::Vector.new [1, 2, 5, 14] } subject { dv.cut (0..20).step(5), close_at: :left, labels: [:a, :b, :c, :d] } it { is_expected.to be_a DaruLite::Vector } its(:type) { is_expected.to eq :category } its(:size) { is_expected.to eq 4 } its(:categories) { is_expected.to eq [:a, :b, :c, :d] } its(:to_a) { is_expected.to eq [:a, :a, :a, :c] } end end context "#each" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c] } subject { dv.each } it { is_expected.to be_a Enumerator } its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] } end context "#to_a" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c] } subject { dv.to_a } it { is_expected.to be_a Array } its(:size) { is_expected.to eq 5 } it { is_expected.to eq [:a, 1, :a, 1, :c] } end context "#dup" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } before do dv.categories = [:a, :b, :c, 1] dv.name = 'daru' dv.ordered = true end subject { dv.dup } its(:type) { is_expected.to eq :category } its(:ordered?) { is_expected.to eq true } its(:categories) { is_expected.to eq [:a, :b, :c, 1] } its(:name) { is_expected.to eq 'daru' } end context "#add_category" do context "single category" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } subject { dv } before { dv.add_category :b } its(:categories) { is_expected.to eq [:a, 1, :c, :b] } its(:order) { is_expected.to eq [:a, 1, :c, :b] } end context "multiple categories" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } subject { dv } before { dv.add_category :b, :d } its(:categories) { is_expected.to eq [:a, 1, :c, :b, :d] } its(:order) { is_expected.to eq [:a, 1, :c, :b, :d] } end end context '#remove_unused_categories' do context 'base category not removed' do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } before do dv.categories = [:a, :b, :c, 1] dv.base_category = 1 dv.remove_unused_categories end subject { dv } its(:categories) { is_expected.to eq [:a, :c, 1] } its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] } its(:base_category) { is_expected.to eq 1 } end context 'base category removed' do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } before do dv.categories = [:a, :b, :c, 1] dv.base_category = :b dv.remove_unused_categories end subject { dv } its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] } its(:categories) { is_expected.to eq [:a, :c, 1] } its(:base_category) { is_expected.to eq :a } end end context "count" do context "existant category" do context "more than 0" do subject(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } it { expect(dv.count :a).to eq 2 } end context "equal to 0" do subject(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } before { dv.add_category :b } it { expect(dv.count :b).to eq 0 } end end context "non existant category" do subject(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } it { expect { dv.count :k }.to raise_error ArgumentError } end end context "#frequencies" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :hello, categories: [:a, :b, :c, :d, 1] } context "counts" do subject { dv.frequencies } its(:'index.to_a') { is_expected.to eq [:a, :b, :c, :d, 1] } its(:to_a) { is_expected.to eq [2, 0, 1, 0, 2] } its(:name) { is_expected.to eq :hello } end context "percentage" do subject { dv.frequencies :percentage } its(:'index.to_a') { is_expected.to eq [:a, :b, :c, :d, 1] } its(:to_a) { is_expected.to eq [40, 0, 20, 0, 40] } end context "fraction" do subject { dv.frequencies :fraction } its(:'index.to_a') { is_expected.to eq [:a, :b, :c, :d, 1] } its(:to_a) { is_expected.to eq [0.4, 0, 0.2, 0, 0.4] } end context "invalid argument" do it { expect { dv.frequencies :hash }.to raise_error ArgumentError } end end context "#to_category" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], index: 1..5 } subject { dv.to_category ordered: true, categories: [:a, :b, :c, 1] } it { is_expected.to be_a DaruLite::Vector } its(:size) { is_expected.to eq 5 } its(:type) { is_expected.to eq :category } its(:'index.to_a') { is_expected.to eq [1, 2, 3, 4, 5] } its(:ordered?) { is_expected.to eq true } its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] } its(:categories) { is_expected.to eq [:a, :b, :c, 1] } end context "#categories" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } subject { dv.categories } it { is_expected.to be_a Array } its(:size) { is_expected.to eq 3 } its(:'to_a') { is_expected.to eq [:a, 1, :c] } end context "#categories=" do context "extra categories" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } before { dv.categories = [:c, :b, :a, 1] } subject { dv } it { is_expected.to be_a DaruLite::Vector } its(:type) { is_expected.to eq :category } its(:categories) { is_expected.to eq [:c, :b, :a, 1] } its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] } its(:base_category) { is_expected.to eq :a } end context "incomplete" do subject { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } it do expect { subject.categories = [:b, :c, 1] }. to raise_error ArgumentError end end end context "#base_category" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } subject { dv } before { dv.base_category = 1 } its(:base_category) { is_expected.to eq 1 } end context "#coding_scheme" do context "valid coding scheme" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } subject { dv } before { dv.coding_scheme = :deviation } its(:coding_scheme) { is_expected.to eq :deviation } end context "invalid coding scheme" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } it { expect { dv.coding_scheme = :foo }.to raise_error ArgumentError } end end context "#rename_categories" do context 'rename base category' do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, categories: [:a, :x, :y, :c, :b, 1]} subject { dv.rename_categories :a => 1, 1 => 2 } it { is_expected.to be_a DaruLite::Vector } its(:to_a) { is_expected.to eq [1, 2, 1, 2, :c] } its(:categories) { is_expected.to eq [:x, :y, :c, :b, 1, 2] } its(:base_category) { is_expected.to eq 1 } end context 'rename non-base category' do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, categories: [:a, :b, :c, 1] } subject { dv.rename_categories 1 => 2 } it { is_expected.to be_a DaruLite::Vector } its(:to_a) { is_expected.to eq [:a, 2, :a, 2, :c] } its(:categories) { is_expected.to eq [:a, :b, :c, 2] } its(:base_category) { is_expected.to eq :a } end context 'merge' do let(:dv) { DaruLite::Vector.new [:a, :b, :c, :b, :e], type: :category } before { dv.categories = [:a, :b, :c, :d, :e, :f] } subject { dv.rename_categories :d => :a, :c => 1, :e => 1 } it { is_expected.to be_a DaruLite::Vector } its(:categories) { is_expected.to eq [:a, :b, :f, 1] } its(:to_a) { is_expected.to eq [:a, :b, 1, :b, 1] } end end context '#to_non_category' do let(:dv) { DaruLite::Vector.new [1, 2, 3], type: :category, index: [:a, :b, :c], name: :hello } subject { dv.to_non_category } it { is_expected.to be_a DaruLite::Vector } its(:type) { is_expected.not_to eq :category } its(:to_a) { is_expected.to eq [1, 2, 3] } its(:'index.to_a') { is_expected.to eq [:a, :b, :c] } its(:name) { is_expected.to eq :hello } end context '#to_category' do let(:dv) { DaruLite::Vector.new [1, 2, 3], type: :category } it { expect(dv.to_category).to eq dv } end context '#reindex!' do context DaruLite::Index do let(:dv) { DaruLite::Vector.new [3, 2, 1, 3, 2, 1], index: 'a'..'f', type: :category, categories: [1, 2, 3, 4] } before { dv.reindex! ['e', 'f', 'a', 'b', 'c', 'd'] } subject { dv } it { is_expected.to be_a DaruLite::Vector } its(:categories) { is_expected.to eq [1, 2, 3, 4] } its(:to_a) { is_expected.to eq [2, 1, 3, 2, 1, 3] } end context DaruLite::MultiIndex do let(:tuples) do [ [:a,:one,:baz], [:a,:two,:bar], [:a,:two,:baz], [:b,:one,:bar], [:b,:two,:bar], [:b,:two,:baz] ] end let(:idx) { DaruLite::MultiIndex.from_tuples tuples } let(:dv) { DaruLite::Vector.new [3, 2, 1, 3, 2, 1], index: idx, type: :category, categories: [1, 2, 3, 4] } before { dv.reindex! [4, 5, 0, 1, 2, 3].map { |i| tuples[i] } } subject { dv } it { is_expected.to be_a DaruLite::Vector } its(:categories) { is_expected.to eq [1, 2, 3, 4] } its(:to_a) { is_expected.to eq [2, 1, 3, 2, 1, 3] } its(:'index.to_a') { is_expected.to eq [4, 5, 0, 1, 2, 3] .map { |i| tuples[i] } } end context 'invalid index' do let(:dv) { DaruLite::Vector.new [1, 2, 3], type: :category } it { expect { dv.reindex! [1, 1, 1] }.to raise_error ArgumentError } end end context '#reorder!' do context 'valid order' do let(:dv) { DaruLite::Vector.new [3, 2, 1, 3, 2, 1], index: 'a'..'f', type: :category } before { dv.reorder! [5, 4, 3, 2, 1, 0] } subject { dv } it { is_expected.to be_a DaruLite::Vector } its(:categories) { is_expected.to eq [1, 2, 3] } its(:to_a) { is_expected.to eq [1, 2, 3, 1, 2, 3] } end context 'invalid order' do let(:dv) { DaruLite::Vector.new [1, 2, 3], type: :category } it { expect { dv.reorder! [1, 1, 1] }.to raise_error ArgumentError } end end context "#min" do context "ordered" do context "default ordering" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true } it { expect(dv.min).to eq :a } end context "reorder" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true } before { dv.categories = [1, :a, :c] } it { expect(dv.min).to eq 1 } end end context "unordered" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category } it { expect { dv.min }.to raise_error ArgumentError } end end context "#max" do context "ordered" do context "default ordering" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true } it { expect(dv.max).to eq :c } end context "reorder" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true } before { dv.categories = [1, :c, :a] } it { expect(dv.max).to eq :a } end end context "unordered" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c, :a], type: :category } it { expect { dv.max }.to raise_error ArgumentError } end end context "summary" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c, :a], type: :category } subject { dv.describe } it { is_expected.to be_a DaruLite::Vector } its(:categories) { is_expected.to eq 3 } its(:max_freq) { is_expected.to eq 3 } its(:max_category) { is_expected.to eq :a } its(:min_freq) { is_expected.to eq 1 } its(:min_category) { is_expected.to eq :c } end context "#sort!" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true } subject { dv } before { dv.categories = [:c, :a, 1]; dv.sort! } it { is_expected.to be_a DaruLite::Vector } its(:size) { is_expected.to eq 5 } its(:to_a) { is_expected.to eq [:c, :a, :a, 1, 1] } its(:'index.to_a') { is_expected.to eq [4, 0, 2, 1, 3] } end context "#sort" do context 'return sorted vector' do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true } subject { dv.sort } before { dv.categories = [:c, :a, 1] } it { is_expected.to be_a DaruLite::Vector } its(:size) { is_expected.to eq 5 } its(:to_a) { is_expected.to eq [:c, :a, :a, 1, 1] } its(:'index.to_a') { is_expected.to eq [4, 0, 2, 1, 3] } end context 'original vector unaffected' do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, ordered: true } subject { dv } before { dv.categories = [:c, :a, 1]; dv.sort } it { is_expected.to be_a DaruLite::Vector } its(:size) { is_expected.to eq 5 } its(:to_a) { is_expected.to eq [:a, 1, :a, 1, :c] } its(:'index.to_a') { is_expected.to eq [0, 1, 2, 3, 4] } 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], type: :category 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], type: :category)) 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], type: :category)) 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, type: :category)) 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], type: :category)) end it "returns correct results for index of multiple index" do v = DaruLite::Vector.new([1,2,3,4], index: ['a','c',1,:a], type: :category) 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 context "preserves old categories" do let(:dv) do DaruLite::Vector.new [:a, :a, :b, :c, :b], type: :category, categories: [:c, :b, :a, :e] end subject { dv[0, 1, 4] } it { is_expected.to be_a DaruLite::Vector } its(:categories) { is_expected.to eq [:c, :b, :a, :e] } its(:to_a) { is_expected.to eq [:a, :a, :b] } 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, name: :mi_vector, type: :category) 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, name: :sub_vector, type: :category)) 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, name: :sub_sub_vector, type: :category)) 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, name: :sub_sub_vector, type: :category)) 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, name: :slice, type: :category)) 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 context "non-numerical index" do let (:idx) { DaruLite::CategoricalIndex.new [:a, :b, :a, :a, :c] } let (:dv) { DaruLite::Vector.new 'a'..'e', index: idx, type: :category } context "single category" do context "multiple instances" do subject { dv[:a] } it { is_expected.to be_a DaruLite::Vector } its(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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, type: :category } context "single category" do context "multiple instances" do subject { dv[1] } it { is_expected.to be_a DaruLite::Vector } its(:type) { is_expected.to eq :category } 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 "#[]=" 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], type: :category @dv.add_category 666 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 "assigns correctly for a mixed index Vector" do v = DaruLite::Vector.new [1,2,3,4], index: ['a',:a,0,66], type: :category v.add_category 666 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], type: :category)) 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, type: :category, name: :mi_vector @vector.add_category 69 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, type: :category )) 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, type: :category)) 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, type: :category)) 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, type: :category)) 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, type: :category } before { dv.add_category 'x' } 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, type: :category } before { dv.add_category 'x' } 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 "#at" do context DaruLite::Index do let (:idx) { DaruLite::Index.new [1, 0, :c] } let (:dv) { DaruLite::Vector.new ['a', 'b', 'c'], index: idx, type: :category } 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(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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 "preserves old categories" do let(:dv) do DaruLite::Vector.new [:a, :a, :b, :c, :b], type: :category, categories: [:c, :b, :a, :e] end subject { dv.at 0, 1, 4 } it { is_expected.to be_a DaruLite::Vector } its(:categories) { is_expected.to eq [:c, :b, :a, :e] } its(:to_a) { is_expected.to eq [:a, :a, :b] } 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, type: :category } 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(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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, type: :category } context "multiple positional indexes" do subject { dv.at 0, 1, 2 } it { is_expected.to be_a DaruLite::Vector } its(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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 "#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, type: :category } before { dv.add_category 'x' } 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, type: :category } before { dv.add_category 'x' } 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, type: :category } before { dv.add_category 'x' } 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 "#contrast_code" do context "dummy coding" do context "default base category" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc } subject { dv.contrast_code } it { is_expected.to be_a DaruLite::DataFrame } its(:shape) { is_expected.to eq [5, 2] } its(:'abc_1.to_a') { is_expected.to eq [0, 1, 0, 1, 0] } its(:'abc_c.to_a') { is_expected.to eq [0, 0, 0, 0, 1] } end context "manual base category" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc } before { dv.base_category = :c } subject { dv.contrast_code } it { is_expected.to be_a DaruLite::DataFrame } its(:shape) { is_expected.to eq [5, 2] } its(:'abc_a.to_a') { is_expected.to eq [1, 0, 1, 0, 0] } its(:'abc_1.to_a') { is_expected.to eq [0, 1, 0, 1, 0] } end end context "simple coding" do context "default base category" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc } subject { dv.contrast_code } before { dv.coding_scheme = :simple } it { is_expected.to be_a DaruLite::DataFrame } its(:shape) { is_expected.to eq [5, 2] } its(:'abc_1.to_a') { is_expected.to eq [-1/3.0, 2/3.0, -1/3.0, 2/3.0, -1/3.0] } its(:'abc_c.to_a') { is_expected.to eq [-1/3.0, -1/3.0, -1/3.0, -1/3.0, 2/3.0] } end context "manual base category" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc } subject { dv.contrast_code } before do dv.coding_scheme = :simple dv.base_category = :c end it { is_expected.to be_a DaruLite::DataFrame } its(:shape) { is_expected.to eq [5, 2] } its(:'abc_a.to_a') { is_expected.to eq [2/3.0, -1/3.0, 2/3.0, -1/3.0, -1/3.0] } its(:'abc_1.to_a') { is_expected.to eq [-1/3.0, 2/3.0, -1/3.0, 2/3.0, -1/3.0] } end end context "helmert coding" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc } subject { dv.contrast_code } before { dv.coding_scheme = :helmert } it { is_expected.to be_a DaruLite::DataFrame } its(:shape) { is_expected.to eq [5, 2] } its(:'abc_a.to_a') { is_expected.to eq [2/3.0, -1/3.0, 2/3.0, -1/3.0, -1/3.0] } its(:'abc_1.to_a') { is_expected.to eq [0, 1/2.0, 0, 1/2.0, -1/2.0] } end context "deviation coding" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc } subject { dv.contrast_code } before { dv.coding_scheme = :deviation } it { is_expected.to be_a DaruLite::DataFrame } its(:shape) { is_expected.to eq [5, 2] } its(:'abc_a.to_a') { is_expected.to eq [1, 0, 1, 0, -1] } its(:'abc_1.to_a') { is_expected.to eq [0, 1, 0, 1, -1] } end context "user-defined coding" do let(:df) do DaruLite::DataFrame.new({ rank_level1: [1, -2, -3], rank_level2: [-4, 2, -1], rank_level3: [-3, -1, 5] }, index: ['I', 'II', 'III']) end let(:dv) { DaruLite::Vector.new ['III', 'II', 'I', 'II', 'II'], name: :rank, type: :category } subject { dv.contrast_code user_defined: df } it { is_expected.to be_a DaruLite::DataFrame } its(:shape) { is_expected.to eq [5, 3] } its(:'rank_level1.to_a') { is_expected.to eq [-3, -2, 1, -2, -2] } its(:'rank_level2.to_a') { is_expected.to eq [-1, 2, -4, 2, 2] } its(:'rank_level3.to_a') { is_expected.to eq [5, -1, -3, -1, -1] } end context 'naming' do context "string" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: 'abc' } subject { dv.contrast_code } it { is_expected.to be_a DaruLite::DataFrame } its(:'vectors.to_a') { is_expected.to eq ['abc_1', 'abc_c'] } end context "symbol" do let(:dv) { DaruLite::Vector.new [:a, 1, :a, 1, :c], type: :category, name: :abc } subject { dv.contrast_code } it { is_expected.to be_a DaruLite::DataFrame } its(:'vectors.to_a') { is_expected.to eq [:abc_1, :abc_c] } end end end context '#reject_values'do let(:dv) { DaruLite::Vector.new [1, nil, 3, :a, Float::NAN, nil, Float::NAN, 1], index: 11..18, type: :category } context 'reject only nils' do subject { dv.reject_values nil } it { is_expected.to be_a DaruLite::Vector } its(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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, 20 } it { is_expected.to be_a DaruLite::Vector } its(:type) { is_expected.to eq :category } 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 end context '#include_values?' do context 'only nils' do context 'true' do let(:dv) { DaruLite::Vector.new [1, 2, 3, :a, 'Unknown', nil], type: :category } it { expect(dv.include_values? nil).to eq true } end context 'false' do let(:dv) { DaruLite::Vector.new [1, 2, 3, :a, 'Unknown'], type: :category } 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], type: :category} it { expect(dv.include_values? Float::NAN).to eq true } end context 'false' do let(:dv) { DaruLite::Vector.new [1, nil, 2, 3], type: :category } 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], type: :category} 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], type: :category} it { expect(dv.include_values? nil, Float::NAN).to eq true } end context 'false' do let(:dv) { DaruLite::Vector.new [1, 2, 3], type: :category} 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], type: :category } 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], type: :category } 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], type: :category } 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, type: :category } 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, type: :category } 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, type: :category ) end context 'replace nils and NaNs' do before { subject.replace_values [nil, Float::NAN], 10 } its(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } 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(:type) { is_expected.to eq :category } its(:to_a) { is_expected.to eq( [1, 2, 1, 4, 10, Float::NAN, 10, Float::NAN]) } end end end describe DaruLite::DataFrame, "categorical" do context "#to_category" do let(:df) do DaruLite::DataFrame.new({ a: [1, 2, 3, 4, 5], b: ['first', 'second', 'first', 'second', 'third'], c: ['a', 'b', 'a', 'b', nil] }) end before { df.to_category :b, :c } subject { df } it { is_expected.to be_a DaruLite::DataFrame } its(:'b.type') { is_expected.to eq :category } its(:'c.type') { is_expected.to eq :category } its(:'a.count') { is_expected.to eq 5 } its(:'c.count') { is_expected.to eq 5 } it { expect(df.c.count('a')).to eq 2 } it { expect(df.c.count(nil)).to eq 1 } end context "#interact_code" do context "two vectors" do let(:df) do DaruLite::DataFrame.new({ a: [1, 2, 3, 4, 5], b: ['first', 'second', 'first', 'second', 'third'], c: ['a', 'b', 'a', 'b', 'c'] }) end before do df.to_category :b, :c df[:b].categories = ['first', 'second', 'third'] df[:c].categories = ['a', 'b', 'c'] end context "both full" do subject { df.interact_code [:b, :c], [true, true] } it { is_expected.to be_a DaruLite::DataFrame } its(:shape) { is_expected.to eq [5, 9] } it { expect(subject['b_first:c_a'].to_a).to eq [1, 0, 1, 0, 0] } it { expect(subject['b_first:c_b'].to_a).to eq [0, 0, 0, 0, 0] } it { expect(subject['b_first:c_c'].to_a).to eq [0, 0, 0, 0, 0] } it { expect(subject['b_second:c_a'].to_a).to eq [0, 0, 0, 0, 0] } it { expect(subject['b_second:c_b'].to_a).to eq [0, 1, 0, 1, 0] } it { expect(subject['b_second:c_c'].to_a).to eq [0, 0, 0, 0, 0] } it { expect(subject['b_third:c_a'].to_a).to eq [0, 0, 0, 0, 0] } it { expect(subject['b_third:c_b'].to_a).to eq [0, 0, 0, 0, 0] } it { expect(subject['b_third:c_c'].to_a).to eq [0, 0, 0, 0, 1] } end context "one full" do subject { df.interact_code [:b, :c], [true, false] } it { is_expected.to be_a DaruLite::DataFrame } its(:shape) { is_expected.to eq [5, 6] } it { expect(subject['b_first:c_b'].to_a).to eq [0, 0, 0, 0, 0] } it { expect(subject['b_first:c_c'].to_a).to eq [0, 0, 0, 0, 0] } it { expect(subject['b_second:c_b'].to_a).to eq [0, 1, 0, 1, 0] } it { expect(subject['b_second:c_c'].to_a).to eq [0, 0, 0, 0, 0] } it { expect(subject['b_third:c_b'].to_a).to eq [0, 0, 0, 0, 0] } it { expect(subject['b_third:c_c'].to_a).to eq [0, 0, 0, 0, 1] } end context "none full" do subject { df.interact_code [:b, :c], [false, false] } it { is_expected.to be_a DaruLite::DataFrame } its(:shape) { is_expected.to eq [5, 4] } it { expect(subject['b_second:c_b'].to_a).to eq [0, 1, 0, 1, 0] } it { expect(subject['b_second:c_c'].to_a).to eq [0, 0, 0, 0, 0] } it { expect(subject['b_third:c_b'].to_a).to eq [0, 0, 0, 0, 0] } it { expect(subject['b_third:c_c'].to_a).to eq [0, 0, 0, 0, 1] } end end context "more than two vectors" do let(:df) do DaruLite::DataFrame.new({ a: [1, 1, 2], b: [2, 2, 3], c: [3, 3, 4] }) end before { df.to_category :a, :b, :c } subject { df.interact_code [:a, :b, :c], [false, false, true] } it { is_expected.to be_a DaruLite::DataFrame } its(:shape) { is_expected.to eq [3, 2] } it { expect(subject['a_2:b_3:c_3'].to_a).to eq [0, 0, 0] } it { expect(subject['a_2:b_3:c_4'].to_a).to eq [0, 0, 1] } end end context "#sort!" do let(:df) do DaruLite::DataFrame.new({ a: [1, 2, 1, 4, 5], b: ['II', 'I', 'III', 'II', 'I'], }) end before do df[:b] = df[:b].to_category ordereed: true, categories: ['I', 'II', 'III'] df.sort! [:a, :b] end subject { df } its(:shape) { is_expected.to eq [5, 2] } its(:'a.to_a') { is_expected.to eq [1, 1, 2, 4, 5] } its(:'b.to_a') { is_expected.to eq ['II', 'III', 'I', 'II', 'I'] } end context "#split_by_category" do let(:df) do DaruLite::DataFrame.new({ a: [1, 2, 3, 4, 5, 6, 7], b: [3, 2, 2, 35, 3, 2, 5], cat: [:I, :II, :I, :III, :I, :III, :II] }) end let(:df1) do DaruLite::DataFrame.new({ a: [1, 3, 5], b: [3, 2, 3] }, name: :I, index: [0, 2, 4]) end let(:df2) do DaruLite::DataFrame.new({ a: [2, 7], b: [2, 5] }, name: :II, index: [1, 6]) end let(:df3) do DaruLite::DataFrame.new({ a: [4, 6], b: [35, 2] }, name: :III, index: [3, 5]) end before { df.to_category :cat } subject { df.split_by_category :cat } it { is_expected.to be_a Array } its(:size) { is_expected.to eq 3 } its(:first) { is_expected.to eq df1 } it { expect(subject[1]).to eq df2 } its(:last) { is_expected.to eq df3 } end end