statsample-sem 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ --color
2
+ -f s
3
+ -b
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ puts "Statsample-SEM specs: Running on Ruby Version: #{RUBY_VERSION}"
4
+
5
+ require "rubygems"
6
+ require 'spec'
7
+ require 'spec/autorun'
8
+ require 'statsample'
9
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
10
+ require 'statsample/sem'
@@ -0,0 +1,158 @@
1
+ $:.unshift(File.dirname(__FILE__)+"/.")
2
+ require 'spec_helper'
3
+
4
+ describe Statsample::SEM::Model do
5
+ before(:all) do
6
+ begin
7
+ @data_path=File.dirname(__FILE__)+"/fixtures/demo_open_mx.ds"
8
+ @ds=Statsample.load(@data_path)
9
+ rescue
10
+ @data_path=File.dirname(__FILE__)+"/fixtures/demo_open_mx.csv"
11
+ @ds=Statsample::CSV.read(@data_path)
12
+ end
13
+ end
14
+
15
+ before(:each) do
16
+ @model=Statsample::SEM::Model.new
17
+ end
18
+ it "method manifests= should set manifests" do
19
+ @model.manifests=@ds.fields
20
+ @model.manifests.should==@ds.fields
21
+ end
22
+ it "method manifests with argument should set manifests" do
23
+ @model.manifests @ds.fields
24
+ @model.manifests.should==@ds.fields
25
+ end
26
+ it "method latents= should set latents" do
27
+ @model.latents=["G"]
28
+ @model.latents.should==["G"]
29
+ end
30
+ it "method latents with argument should set latents" do
31
+ @model.latents ["G"]
32
+ @model.latents.should==["G"]
33
+ end
34
+ it "should automaticly set manifest and latents with data and path" do
35
+ @model.data_from_matrix(Statsample::Bivariate.covariance_matrix(@ds), :cases=>@ds.dup_only_valid.cases)
36
+ @model.path :from=>"G1", :to=>['x1','x2']
37
+ @model.path :from=>"G2", :to=>['x3','x4']
38
+ @model.latents.should==['G1','G2']
39
+ @model.manifests.should==['x1','x2','x3','x4']
40
+ end
41
+
42
+
43
+
44
+ it "method path with :from should create a variance path" do
45
+ @model.path :from=>"x1"
46
+ @model.paths.should=={
47
+ ['x1','x1']=>{:from=>'x1',:to=>'x1',:arrow=>2,:label=>'var x1', :free=>true, :value=>nil}
48
+ }
49
+ end
50
+ it "method path with :from and :two should create a regression path" do
51
+ @model.path :from=>"G", :to=>'x1'
52
+ @model.paths.should=={
53
+ ['G','x1']=>{:from=>'G',:to=>'x1',:arrow=>1,:label=>'G to x1', :free=>true, :value=>nil}
54
+ }
55
+ end
56
+ it "method path with :from, :two and arrows should set label automaticly" do
57
+ @model.path :from=>"G", :to=>'x1', :arrows=>1
58
+ @model.path :from=>"G", :to=>'x2', :arrows=>2
59
+
60
+ @model.paths.should=={
61
+ ['G','x1']=>{:from=>'G',:to=>'x1',:arrow=>1,:label=>'G to x1', :free=>true, :value=>nil},
62
+ ['G','x2']=>{:from=>'G',:to=>'x2',:arrow=>2,:label=>'G cov x2', :free=>true, :value=>nil}
63
+ }
64
+ end
65
+ it "method path should label correctly" do
66
+ @model.path :from=>"G", :to=>['x1','x2','x3'], :labels=>['to x1','to x2']
67
+ @model.paths.should=={
68
+ ['G','x1']=>{:from=>'G',:to=>'x1',:arrow=>1,:label=>'to x1', :free=>true, :value=>nil},
69
+ ['G','x2']=>{:from=>'G',:to=>'x2',:arrow=>1,:label=>'to x2', :free=>true, :value=>nil},
70
+ ['G','x3']=>{:from=>'G',:to=>'x3',:arrow=>1,:label=>'G to x3', :free=>true, :value=>nil}
71
+ }
72
+ end
73
+
74
+
75
+
76
+ it "method path with free array set values in proper order" do
77
+ @model.path :from=>"G", :to=>['x1','x2','x3'], :free=>[false,true,false], :values=>[1,2,3]
78
+ @model.paths.should=={
79
+ ['G','x1']=>{:from=>'G',:to=>'x1',:arrow=>1,:label=>'G to x1', :free=>false, :value=>1},
80
+ ['G','x2']=>{:from=>'G',:to=>'x2',:arrow=>1,:label=>'G to x2', :free=>true, :value=>nil},
81
+ ['G','x3']=>{:from=>'G',:to=>'x3',:arrow=>1,:label=>'G to x3', :free=>false, :value=>3}
82
+ }
83
+ end
84
+ it "method path with free array set scalar value in proper order" do
85
+ @model.path :from=>"G", :to=>['x1','x2','x3'], :free=>[false,true,false], :values=>1.0
86
+ @model.paths.should=={
87
+ ['G','x1']=>{:from=>'G',:to=>'x1',:arrow=>1,:label=>'G to x1', :free=>false, :value=>1.0},
88
+ ['G','x2']=>{:from=>'G',:to=>'x2',:arrow=>1,:label=>'G to x2', :free=>true, :value=>nil},
89
+ ['G','x3']=>{:from=>'G',:to=>'x3',:arrow=>1,:label=>'G to x3', :free=>false, :value=>1.0}
90
+ }
91
+ end
92
+
93
+
94
+ describe "with multiple in and outs" do
95
+ it "should set correctly 1 in, multiple outs" do
96
+ @model.path :from=>"G", :to=>['x1','x2']
97
+ @model.paths.should=={
98
+ ['G','x1']=>{:from=>'G',:to=>'x1',:arrow=>1,:label=>'G to x1', :free=>true, :value=>nil},
99
+ ['G','x2']=>{:from=>'G',:to=>'x2',:arrow=>1,:label=>'G to x2', :free=>true, :value=>nil}
100
+ }
101
+ end
102
+ it "should set correctly multiple ins, 1 out" do
103
+ @model.path :from=>["x1","x2"], :to=>['x3']
104
+ @model.paths.should=={
105
+ ['x1','x3']=>{:from=>'x1',:to=>'x3',:arrow=>1,:label=>'x1 to x3', :free=>true, :value=>nil},
106
+ ['x2','x3']=>{:from=>'x2',:to=>'x3',:arrow=>1,:label=>'x2 to x3', :free=>true, :value=>nil}
107
+ }
108
+ end
109
+ it "should set correctly multiple ins, multiples outs, with :all=>false" do
110
+ @model.path :from=>["x1","x2"], :to=>['x3','x4']
111
+ @model.paths.should=={
112
+ ['x1','x3']=>{:from=>'x1',:to=>'x3',:arrow=>1,:label=>'x1 to x3', :free=>true, :value=>nil},
113
+ ['x2','x4']=>{:from=>'x2',:to=>'x4',:arrow=>1,:label=>'x2 to x4', :free=>true, :value=>nil}
114
+ }
115
+ end
116
+ it "should set correctly multiple ins, multiples outs, with :all=>true" do
117
+ @model.path :from=>["x1","x2"], :to=>['x3','x4'], :all=>true
118
+ @model.paths.should=={
119
+ ['x1','x3']=>{:from=>'x1',:to=>'x3',:arrow=>1,:label=>'x1 to x3', :free=>true, :value=>nil},
120
+ ['x1','x4']=>{:from=>'x1',:to=>'x4',:arrow=>1,:label=>'x1 to x4', :free=>true, :value=>nil},
121
+ ['x2','x3']=>{:from=>'x2',:to=>'x3',:arrow=>1,:label=>'x2 to x3', :free=>true, :value=>nil},
122
+
123
+ ['x2','x4']=>{:from=>'x2',:to=>'x4',:arrow=>1,:label=>'x2 to x4', :free=>true, :value=>nil}
124
+ }
125
+ end
126
+ end
127
+
128
+ it "should accept a dataset" do
129
+ @model.data_from_dataset(@ds)
130
+ @model.data_type.should==:raw
131
+ @model.ds.should==@ds
132
+ @model.variables.should==@ds.fields
133
+ end
134
+ it "should accept a covariance matrix" do
135
+ @model.data_from_matrix(Statsample::Bivariate.covariance_matrix(@ds), :cases=>@ds.dup_only_valid.cases)
136
+ @model.data_type.should==:covariance
137
+ @model.cases.should==@ds.cases
138
+ @model.variables.should==@ds.fields
139
+ end
140
+ it "should accept a correlation matrix" do
141
+ @model.data_from_matrix(Statsample::Bivariate.correlation_matrix(@ds), :cases=>@ds.dup_only_valid.cases)
142
+ @model.data_type.should==:correlation
143
+ @model.cases.should==@ds.cases
144
+ @model.variables.should==@ds.fields
145
+ end
146
+ it "should duplicate correctly using 'dup'" do
147
+ @model.data_from_dataset(@ds)
148
+ @model.path :from=>"G", :to=>['x1','x2']
149
+ model2=@model.dup
150
+ model2.paths.should==@model.paths
151
+ model2.manifests.should==@model.manifests
152
+ model2.latents.should==@model.latents
153
+ model2.cases.should==@model.cases
154
+
155
+
156
+ end
157
+
158
+ end
@@ -0,0 +1,142 @@
1
+ $:.unshift(File.dirname(__FILE__)+"/.")
2
+ require 'spec_helper'
3
+
4
+ describe Statsample::SEM::OpenMxEngine do
5
+ before(:all) do
6
+ begin
7
+ @data_path=File.dirname(__FILE__)+"/fixtures/demo_open_mx.ds"
8
+ @ds=Statsample.load(@data_path)
9
+ rescue
10
+ @data_path=File.dirname(__FILE__)+"/fixtures/demo_open_mx.csv"
11
+ @ds=Statsample::CSV.read(@data_path)
12
+ end
13
+ @cov_matrix=Statsample::Bivariate.covariance_matrix(@ds)
14
+ @cases=@ds.cases
15
+ end
16
+ describe "using matrix based data" do
17
+ before(:all) do
18
+ @model=Statsample::SEM::Model.new do |m|
19
+ m.manifests @ds.fields
20
+ m.latents %w{G}
21
+ m.path :from=>m.latents, :to=>m.manifests
22
+ m.path :from=>m.manifests
23
+ m.path :from=>m.latents, :free=>false, :values=>1.0
24
+ m.data_from_matrix(@cov_matrix,:cases=>@cases)
25
+ end
26
+ @engine=Statsample::SEM::OpenMxEngine.new(@model)
27
+ end
28
+ it "should generate a valid r query" do
29
+ @engine.r_query.size.should>=0
30
+ end
31
+ it "should compute and return well formed response" do
32
+ lambda{@engine.compute}.should_not raise_error
33
+ pp @engine.r_summary
34
+ @engine.r_summary.should be_instance_of (Array)
35
+ end
36
+ it "should return a valid graphviz definition for model" do
37
+ @engine.graphviz.size.should>=0
38
+ end
39
+ it "method chi_square return X^2 of model" do
40
+ @engine.chi_square.should be_close(7.384,0.001)
41
+ end
42
+ it "method df return degrees of freedom of model" do
43
+ @engine.df.should==5
44
+ end
45
+ it "method chi_square_null return X^2 of null model" do
46
+ @engine.chi_square_null.should be_close(3725.0596,0.001)
47
+ end
48
+ it "method df_null return degrees of freedom for null model" do
49
+ @engine.df_null.should==10
50
+ end
51
+ it "method goodness_of_fit return GFI" do
52
+ pending('Not Implemented')
53
+ @engine.goodness_of_fit.should be_close(0.99426, 0.0001)
54
+ end
55
+ it "method adjusted_goodness_of_fit return AGFI" do
56
+ pending('Not Implemented')
57
+ @engine.adjusted_goodness_of_fit.should be_close(0.98277, 0.0001)
58
+ end
59
+ it "method rmsea and derivatives returns... RMSEA!" do
60
+ @engine.rmsea.should be_close(0.030911, 0.0001)
61
+ end
62
+ it "method rmsea_alpha and rmsea_confidence_interval returns alpa and ci for RMSEA" do
63
+ pending('Not Implemented other methods')
64
+ @engine.rmsea_alpha.should==0.90
65
+ @engine.rmsea_confidence_interval[0].should be_nil
66
+ @engine.rmsea_confidence_interval[1].should be_close(0.074569, 0.0001)
67
+ end
68
+ it "method nfi returns NFI" do
69
+ @engine.nfi.should be_close(0.99802, 0.0001)
70
+ end
71
+ it "method nnfi returns NNFI" do
72
+
73
+ @engine.nnfi.should be_close(0.99872, 0.0001)
74
+ end
75
+ it "method cfi returns CFI" do
76
+ @engine.cfi.should be_close(0.99936, 0.0001)
77
+ end
78
+ it "method srmr returns SRMR" do
79
+ pending('Not Implemented')
80
+ @engine.srmr.should be_close(0.0032191, 0.0001)
81
+ end
82
+ it "method bic returns BIC" do
83
+ pending("Not well implemented")
84
+ @engine.bic.should be_close(-23.689, 0.001)
85
+ end
86
+ it "method iterations returns the number of iterations" do
87
+ pending('Not Implemented')
88
+ @engine.iterations.should==30
89
+ end
90
+
91
+ # G to x1 0.397152 0.0155826 25.4869 0 x1 <--- G
92
+ # G to x2 0.503662 0.0182767 27.5576 0 x2 <--- G
93
+ # G to x3 0.577242 0.0204998 28.1584 0 x3 <--- G
94
+ # G to x4 0.702774 0.0240755 29.1905 0 x4 <--- G
95
+ # G to x5 0.796251 0.0267431 29.7741 0 x5 <--- G
96
+ # var x1 0.040814 0.0028254 14.4455 0 x1 <--> x1
97
+ # var x2 0.038020 0.0028185 13.4893 0 x2 <--> x2
98
+ # var x3 0.040827 0.0031653 12.8986 0 x3 <--> x3
99
+ # var x4 0.039387 0.0034217 11.5110 0 x4 <--> x4
100
+ # var x5 0.036287 0.0036916 9.8296 0 x5 <--> x5
101
+ it "coefficients returns a hash of Parameter estimates" do
102
+ coeffs=@engine.coefficients
103
+ coeffs[['G','x1']][:estimate].should be_close(0.397152, 0.00001)
104
+ coeffs[['G','x1']][:se].should be_close(0.0155826, 0.0001)
105
+ coeffs[['G','x1']][:label].should=='G to x1'
106
+ # pending('Not Implemented z')
107
+ # coeffs[['G','x1']][:z].should be_close(25.4869, 0.0001)
108
+ end
109
+
110
+
111
+ end
112
+ if(false)
113
+ describe "using raw data" do
114
+ before(:each) do
115
+ @model=Statsample::SEM::Model.new do |m|
116
+ m.manifests @ds.fields
117
+ m.latents %w{G}
118
+ m.path :from=>m.latents, :to=>m.manifests
119
+ m.path :from=>m.manifests
120
+ m.path :from=>m.latents, :free=>false, :values=>1.0
121
+ m.path :from=>"one", :to=>m.manifests
122
+ m.data_from_dataset(@ds)
123
+ end
124
+ @engine=Statsample::SEM::OpenMxEngine.new(@model)
125
+ end
126
+ it "should generate a valid r query" do
127
+ @engine.r_query.size.should>=0
128
+ end
129
+ it "should compute and return well formed response" do
130
+ lambda{@engine.compute}.should_not raise_error
131
+ @engine.r_summary.should be_instance_of (Array)
132
+ end
133
+ it "should return a valid graphviz definition for model" do
134
+ @engine.graphviz.should match "digraph"
135
+ end
136
+
137
+
138
+ end
139
+ end
140
+
141
+ end
142
+
@@ -0,0 +1,116 @@
1
+ $:.unshift(File.dirname(__FILE__)+"/.")
2
+ require 'spec_helper'
3
+
4
+ describe Statsample::SEM::SemJFoxEngine do
5
+ before(:all) do
6
+ begin
7
+ @data_path=File.dirname(__FILE__)+"/fixtures/demo_open_mx.ds"
8
+ @ds=Statsample.load(@data_path)
9
+ rescue
10
+ @data_path=File.dirname(__FILE__)+"/fixtures/demo_open_mx.csv"
11
+ @ds=Statsample::CSV.read(@data_path)
12
+ end
13
+ @cov_matrix=Statsample::Bivariate.covariance_matrix(@ds)
14
+ @cases=@ds.cases
15
+ end
16
+ describe "using matrix based data" do
17
+ before(:all) do
18
+ @model=Statsample::SEM::Model.new do |m|
19
+ m.manifests @ds.fields
20
+ m.latents %w{G}
21
+ m.path :from=>m.latents, :to=>m.manifests
22
+ m.path :from=>m.manifests
23
+ m.path :from=>m.latents, :free=>false, :values=>1.0
24
+ m.data_from_matrix(@cov_matrix,:cases=>@cases)
25
+ end
26
+ @engine=Statsample::SEM::SemJFoxEngine.new(@model)
27
+ end
28
+ it "should generate a valid r query" do
29
+ @engine.r_query.size.should>=0
30
+ end
31
+ it "should compute and return well formed response" do
32
+ lambda{@engine.compute}.should_not raise_error
33
+ @engine.r_summary.should be_instance_of (Array)
34
+ end
35
+ it "should return a valid graphviz definition for model" do
36
+ @engine.graphviz.should match "digraph"
37
+ end
38
+
39
+ # Model Chisquare = 7.384 Df = 5 Pr(>Chisq) = 0.19361
40
+ # Chisquare (null model) = 3725.1 Df = 10
41
+ # Goodness-of-fit index = 0.99426
42
+ # Adjusted goodness-of-fit index = 0.98277
43
+ # RMSEA index = 0.030911 90% CI: (NA, 0.074569)
44
+ # Bentler-Bonnett NFI = 0.99802
45
+ # Tucker-Lewis NNFI = 0.99872
46
+ # Bentler CFI = 0.99936
47
+ # SRMR = 0.0032191
48
+ # BIC = -23.689
49
+
50
+ it "method chi_square return X^2 of model" do
51
+ @engine.chi_square.should be_close(7.384,0.001)
52
+ end
53
+ it "method df return degrees of freedom of model" do
54
+ @engine.df.should==5
55
+ end
56
+ it "method chi_square_null return X^2 of null model" do
57
+ @engine.chi_square_null.should be_close(3725.0596,0.001)
58
+ end
59
+ it "method df_null return degrees of freedom for null model" do
60
+ @engine.df_null.should==10
61
+ end
62
+ it "method goodness_of_fit return GFI" do
63
+ @engine.goodness_of_fit.should be_close(0.99426, 0.0001)
64
+ end
65
+ it "method adjusted_goodness_of_fit return AGFI" do
66
+ @engine.adjusted_goodness_of_fit.should be_close(0.98277, 0.0001)
67
+ end
68
+ it "method rmsa and derivatives returns... RMSEA!" do
69
+ @engine.rmsea.should be_close(0.030911, 0.0001)
70
+ @engine.rmsea_alpha.should==0.90
71
+ @engine.rmsea_confidence_interval[0].should be_nil
72
+ @engine.rmsea_confidence_interval[1].should be_close(0.074569, 0.0001)
73
+ end
74
+ it "method nfi returns NFI" do
75
+ @engine.nfi.should be_close(0.99802, 0.0001)
76
+ end
77
+ it "method nnfi returns NNFI" do
78
+ @engine.nnfi.should be_close(0.99872, 0.0001)
79
+ end
80
+ it "method cfi returns CFI" do
81
+ @engine.cfi.should be_close(0.99936, 0.0001)
82
+ end
83
+ it "method srmr returns SRMR" do
84
+ @engine.srmr.should be_close(0.0032191, 0.0001)
85
+ end
86
+ it "method bic returns BIC" do
87
+ @engine.bic.should be_close(-23.689, 0.001)
88
+ end
89
+ it "method iterations returns the number of iterations" do
90
+ @engine.iterations.should==30
91
+ end
92
+
93
+ # G to x1 0.397152 0.0155826 25.4869 0 x1 <--- G
94
+ # G to x2 0.503662 0.0182767 27.5576 0 x2 <--- G
95
+ # G to x3 0.577242 0.0204998 28.1584 0 x3 <--- G
96
+ # G to x4 0.702774 0.0240755 29.1905 0 x4 <--- G
97
+ # G to x5 0.796251 0.0267431 29.7741 0 x5 <--- G
98
+ # var x1 0.040814 0.0028254 14.4455 0 x1 <--> x1
99
+ # var x2 0.038020 0.0028185 13.4893 0 x2 <--> x2
100
+ # var x3 0.040827 0.0031653 12.8986 0 x3 <--> x3
101
+ # var x4 0.039387 0.0034217 11.5110 0 x4 <--> x4
102
+ # var x5 0.036287 0.0036916 9.8296 0 x5 <--> x5
103
+ it "coefficients returns a hash of Parameter estimates" do
104
+ coeffs=@engine.coefficients
105
+ coeffs[['G','x1']][:estimate].should be_close(0.397152, 0.00001)
106
+ coeffs[['G','x1']][:se].should be_close(0.0155826, 0.00001)
107
+ coeffs[['G','x1']][:z].should be_close(25.4869, 0.0001)
108
+ coeffs[['G','x1']][:label].should=='G to x1'
109
+ end
110
+
111
+
112
+ end
113
+
114
+
115
+ end
116
+
@@ -0,0 +1,36 @@
1
+ $:.unshift(File.dirname(__FILE__)+"/.")
2
+ require 'spec_helper'
3
+
4
+ describe Statsample::SEM do
5
+ before(:all) do
6
+ begin
7
+ @data_path=File.dirname(__FILE__)+"/fixtures/demo_open_mx.ds"
8
+ @ds=Statsample.load(@data_path)
9
+ rescue
10
+ @data_path=File.dirname(__FILE__)+"/fixtures/demo_open_mx.csv"
11
+ @ds=Statsample::CSV.read(@data_path)
12
+ end
13
+ @cov_matrix=Statsample::Bivariate.covariance_matrix(@ds)
14
+ @cases=@ds.cases
15
+ @sem=Statsample::SEM.new do |m|
16
+ m.manifests @ds.fields
17
+ m.latents %w{G}
18
+ m.path :from=>m.latents, :to=>m.manifests
19
+ m.path :from=>m.manifests
20
+ m.path :from=>m.latents, :free=>false, :values=>1.0
21
+ m.data_from_matrix(@cov_matrix,:cases=>@cases)
22
+ end
23
+ end
24
+ it "should calculate SEM using openmx" do
25
+ @sem.engine=:openmx
26
+ @sem.name="Using OpenMx"
27
+ @sem.compute.should be_true
28
+ end
29
+ it "should calculate SEM using sem" do
30
+ @sem.engine=:sem
31
+ @sem.name="Using SEM"
32
+ @sem.compute.should be_true
33
+ end
34
+
35
+ end
36
+