statsample-ekatena 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.travis.yml +23 -0
- data/CONTRIBUTING.md +17 -0
- data/Gemfile +2 -0
- data/History.txt +457 -0
- data/LICENSE.txt +12 -0
- data/README.md +175 -0
- data/Rakefile +44 -0
- data/benchmarks/correlation_matrix_15_variables.rb +32 -0
- data/benchmarks/correlation_matrix_5_variables.rb +33 -0
- data/benchmarks/correlation_matrix_methods/correlation_matrix.ds +0 -0
- data/benchmarks/correlation_matrix_methods/correlation_matrix.html +93 -0
- data/benchmarks/correlation_matrix_methods/correlation_matrix.rb +71 -0
- data/benchmarks/correlation_matrix_methods/correlation_matrix.xls +0 -0
- data/benchmarks/correlation_matrix_methods/correlation_matrix_gsl_ruby.ods +0 -0
- data/benchmarks/correlation_matrix_methods/correlation_matrix_with_graphics.ods +0 -0
- data/benchmarks/correlation_matrix_methods/results.ds +0 -0
- data/benchmarks/factor_map.rb +37 -0
- data/benchmarks/helpers_benchmark.rb +5 -0
- data/data/locale/es/LC_MESSAGES/statsample.mo +0 -0
- data/doc_latex/manual/equations.tex +78 -0
- data/examples/boxplot.rb +28 -0
- data/examples/chisquare_test.rb +23 -0
- data/examples/correlation_matrix.rb +32 -0
- data/examples/dataset.rb +30 -0
- data/examples/dominance_analysis.rb +33 -0
- data/examples/dominance_analysis_bootstrap.rb +32 -0
- data/examples/histogram.rb +26 -0
- data/examples/icc.rb +24 -0
- data/examples/levene.rb +29 -0
- data/examples/multiple_regression.rb +20 -0
- data/examples/multivariate_correlation.rb +33 -0
- data/examples/parallel_analysis.rb +40 -0
- data/examples/polychoric.rb +40 -0
- data/examples/principal_axis.rb +26 -0
- data/examples/reliability.rb +31 -0
- data/examples/scatterplot.rb +25 -0
- data/examples/t_test.rb +27 -0
- data/examples/tetrachoric.rb +17 -0
- data/examples/u_test.rb +24 -0
- data/examples/vector.rb +20 -0
- data/examples/velicer_map_test.rb +46 -0
- data/grab_references.rb +29 -0
- data/lib/spss.rb +134 -0
- data/lib/statsample-ekatena/analysis.rb +100 -0
- data/lib/statsample-ekatena/analysis/suite.rb +89 -0
- data/lib/statsample-ekatena/analysis/suitereportbuilder.rb +44 -0
- data/lib/statsample-ekatena/anova.rb +24 -0
- data/lib/statsample-ekatena/anova/contrast.rb +79 -0
- data/lib/statsample-ekatena/anova/oneway.rb +187 -0
- data/lib/statsample-ekatena/anova/twoway.rb +207 -0
- data/lib/statsample-ekatena/bivariate.rb +406 -0
- data/lib/statsample-ekatena/bivariate/pearson.rb +54 -0
- data/lib/statsample-ekatena/codification.rb +182 -0
- data/lib/statsample-ekatena/converter/csv.rb +28 -0
- data/lib/statsample-ekatena/converter/spss.rb +48 -0
- data/lib/statsample-ekatena/converters.rb +211 -0
- data/lib/statsample-ekatena/crosstab.rb +188 -0
- data/lib/statsample-ekatena/daru.rb +115 -0
- data/lib/statsample-ekatena/dataset.rb +10 -0
- data/lib/statsample-ekatena/dominanceanalysis.rb +425 -0
- data/lib/statsample-ekatena/dominanceanalysis/bootstrap.rb +232 -0
- data/lib/statsample-ekatena/factor.rb +104 -0
- data/lib/statsample-ekatena/factor/map.rb +124 -0
- data/lib/statsample-ekatena/factor/parallelanalysis.rb +166 -0
- data/lib/statsample-ekatena/factor/pca.rb +242 -0
- data/lib/statsample-ekatena/factor/principalaxis.rb +243 -0
- data/lib/statsample-ekatena/factor/rotation.rb +198 -0
- data/lib/statsample-ekatena/formula/fit_model.rb +46 -0
- data/lib/statsample-ekatena/formula/formula.rb +306 -0
- data/lib/statsample-ekatena/graph.rb +11 -0
- data/lib/statsample-ekatena/graph/boxplot.rb +236 -0
- data/lib/statsample-ekatena/graph/histogram.rb +198 -0
- data/lib/statsample-ekatena/graph/scatterplot.rb +213 -0
- data/lib/statsample-ekatena/histogram.rb +180 -0
- data/lib/statsample-ekatena/matrix.rb +329 -0
- data/lib/statsample-ekatena/multiset.rb +310 -0
- data/lib/statsample-ekatena/regression.rb +65 -0
- data/lib/statsample-ekatena/regression/multiple.rb +89 -0
- data/lib/statsample-ekatena/regression/multiple/alglibengine.rb +128 -0
- data/lib/statsample-ekatena/regression/multiple/baseengine.rb +251 -0
- data/lib/statsample-ekatena/regression/multiple/gslengine.rb +129 -0
- data/lib/statsample-ekatena/regression/multiple/matrixengine.rb +205 -0
- data/lib/statsample-ekatena/regression/multiple/rubyengine.rb +86 -0
- data/lib/statsample-ekatena/regression/simple.rb +121 -0
- data/lib/statsample-ekatena/reliability.rb +150 -0
- data/lib/statsample-ekatena/reliability/icc.rb +415 -0
- data/lib/statsample-ekatena/reliability/multiscaleanalysis.rb +181 -0
- data/lib/statsample-ekatena/reliability/scaleanalysis.rb +233 -0
- data/lib/statsample-ekatena/reliability/skillscaleanalysis.rb +114 -0
- data/lib/statsample-ekatena/resample.rb +15 -0
- data/lib/statsample-ekatena/shorthand.rb +125 -0
- data/lib/statsample-ekatena/srs.rb +169 -0
- data/lib/statsample-ekatena/test.rb +82 -0
- data/lib/statsample-ekatena/test/bartlettsphericity.rb +45 -0
- data/lib/statsample-ekatena/test/chisquare.rb +73 -0
- data/lib/statsample-ekatena/test/f.rb +52 -0
- data/lib/statsample-ekatena/test/kolmogorovsmirnov.rb +63 -0
- data/lib/statsample-ekatena/test/levene.rb +88 -0
- data/lib/statsample-ekatena/test/t.rb +309 -0
- data/lib/statsample-ekatena/test/umannwhitney.rb +208 -0
- data/lib/statsample-ekatena/test/wilcoxonsignedrank.rb +90 -0
- data/lib/statsample-ekatena/vector.rb +19 -0
- data/lib/statsample-ekatena/version.rb +3 -0
- data/lib/statsample.rb +282 -0
- data/po/es/statsample.mo +0 -0
- data/po/es/statsample.po +959 -0
- data/po/statsample.pot +947 -0
- data/references.txt +24 -0
- data/statsample-ekatena.gemspec +49 -0
- data/test/fixtures/bank2.dat +200 -0
- data/test/fixtures/correlation_matrix.rb +17 -0
- data/test/fixtures/df.csv +15 -0
- data/test/fixtures/hartman_23.matrix +9 -0
- data/test/fixtures/stock_data.csv +500 -0
- data/test/fixtures/tetmat_matrix.txt +5 -0
- data/test/fixtures/tetmat_test.txt +1001 -0
- data/test/helpers_tests.rb +83 -0
- data/test/test_analysis.rb +176 -0
- data/test/test_anova_contrast.rb +36 -0
- data/test/test_anovaoneway.rb +26 -0
- data/test/test_anovatwoway.rb +37 -0
- data/test/test_anovatwowaywithdataset.rb +47 -0
- data/test/test_anovawithvectors.rb +102 -0
- data/test/test_awesome_print_bug.rb +16 -0
- data/test/test_bartlettsphericity.rb +25 -0
- data/test/test_bivariate.rb +164 -0
- data/test/test_codification.rb +78 -0
- data/test/test_crosstab.rb +67 -0
- data/test/test_dominance_analysis.rb +39 -0
- data/test/test_factor.rb +228 -0
- data/test/test_factor_map.rb +38 -0
- data/test/test_factor_pa.rb +56 -0
- data/test/test_fit_model.rb +88 -0
- data/test/test_ggobi.rb +35 -0
- data/test/test_gsl.rb +15 -0
- data/test/test_histogram.rb +109 -0
- data/test/test_matrix.rb +48 -0
- data/test/test_multiset.rb +176 -0
- data/test/test_regression.rb +231 -0
- data/test/test_reliability.rb +223 -0
- data/test/test_reliability_icc.rb +198 -0
- data/test/test_reliability_skillscale.rb +57 -0
- data/test/test_resample.rb +24 -0
- data/test/test_srs.rb +9 -0
- data/test/test_statistics.rb +69 -0
- data/test/test_stest.rb +69 -0
- data/test/test_stratified.rb +17 -0
- data/test/test_test_f.rb +33 -0
- data/test/test_test_kolmogorovsmirnov.rb +34 -0
- data/test/test_test_t.rb +62 -0
- data/test/test_umannwhitney.rb +27 -0
- data/test/test_vector.rb +12 -0
- data/test/test_wilcoxonsignedrank.rb +64 -0
- metadata +570 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'statsample/analysis/suite'
|
2
|
+
require 'statsample/analysis/suitereportbuilder'
|
3
|
+
|
4
|
+
module Statsample
|
5
|
+
# DSL to create analysis without hazzle.
|
6
|
+
# * Shortcuts methods to avoid use complete namescapes, many based on R
|
7
|
+
# * Attach/detach vectors to workspace, like R
|
8
|
+
# == Example
|
9
|
+
# an1=Statsample::Analysis.store(:first) do
|
10
|
+
# # Load excel file with x,y,z vectors
|
11
|
+
# ds=excel('data.xls')
|
12
|
+
# # See variables on ds dataset
|
13
|
+
# names(ds)
|
14
|
+
# # Attach the vectors to workspace, like R
|
15
|
+
# attach(ds)
|
16
|
+
# # vector 'x' is attached to workspace like a method,
|
17
|
+
# # so you can use like any variable
|
18
|
+
# mean,sd=x.mean, x.sd
|
19
|
+
# # Shameless R robbery
|
20
|
+
# a=c( 1:10)
|
21
|
+
# b=c(21:30)
|
22
|
+
# summary(cor(ds)) # Call summary method on correlation matrix
|
23
|
+
# end
|
24
|
+
# # You can run the analysis by its name
|
25
|
+
# Statsample::Analysis.run(:first)
|
26
|
+
# # or using the returned variables
|
27
|
+
# an1.run
|
28
|
+
# # You can also generate a report using ReportBuilder.
|
29
|
+
# # .summary() method call 'report_building' on the object,
|
30
|
+
# # instead of calling text summary
|
31
|
+
# an1.generate("report.html")
|
32
|
+
module Analysis
|
33
|
+
@@stored_analysis={}
|
34
|
+
@@last_analysis=nil
|
35
|
+
def self.clear_analysis
|
36
|
+
@@stored_analysis.clear
|
37
|
+
end
|
38
|
+
def self.stored_analysis
|
39
|
+
@@stored_analysis
|
40
|
+
end
|
41
|
+
def self.last
|
42
|
+
@@stored_analysis[@@last_analysis]
|
43
|
+
end
|
44
|
+
def self.store(name, opts=Hash.new,&block)
|
45
|
+
raise "You should provide a block" if !block
|
46
|
+
@@last_analysis=name
|
47
|
+
opts={:name=>name}.merge(opts)
|
48
|
+
@@stored_analysis[name]=Suite.new(opts,&block)
|
49
|
+
end
|
50
|
+
# Run analysis +*args+
|
51
|
+
# Without arguments, run all stored analysis
|
52
|
+
# Only 'echo' will be returned to screen
|
53
|
+
def self.run(*args)
|
54
|
+
args=stored_analysis.keys if args.size==0
|
55
|
+
raise "Analysis #{args} doesn't exists" if (args - stored_analysis.keys).size>0
|
56
|
+
args.each do |name|
|
57
|
+
stored_analysis[name].run
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Add analysis +*args+ to an reportbuilder object.
|
62
|
+
# Without arguments, add all stored analysis
|
63
|
+
# Each analysis is wrapped inside a ReportBuilder::Section object
|
64
|
+
# This is the method is used by save() and to_text()
|
65
|
+
|
66
|
+
def self.add_to_reportbuilder(rb, *args)
|
67
|
+
args=stored_analysis.keys if args.size==0
|
68
|
+
raise "Analysis #{name} doesn't exists" if (args - stored_analysis.keys).size>0
|
69
|
+
args.each do |name|
|
70
|
+
section=ReportBuilder::Section.new(:name=>stored_analysis[name].name)
|
71
|
+
rb_an=stored_analysis[name].add_to_reportbuilder(section)
|
72
|
+
rb.add(section)
|
73
|
+
rb_an.run
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Save the analysis on a file
|
78
|
+
# Without arguments, add all stored analysis
|
79
|
+
def self.save(filename, *args)
|
80
|
+
rb=ReportBuilder.new(:name=>filename)
|
81
|
+
add_to_reportbuilder(rb, *args)
|
82
|
+
rb.save(filename)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Run analysis and return as string
|
86
|
+
# output of echo callings
|
87
|
+
# Without arguments, add all stored analysis
|
88
|
+
|
89
|
+
def self.to_text(*args)
|
90
|
+
rb=ReportBuilder.new(:name=>"Analysis #{Time.now}")
|
91
|
+
add_to_reportbuilder(rb, *args)
|
92
|
+
rb.to_text
|
93
|
+
end
|
94
|
+
# Run analysis and return to screen all
|
95
|
+
# echo and summary callings
|
96
|
+
def self.run_batch(*args)
|
97
|
+
puts to_text(*args)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Statsample
|
2
|
+
module Analysis
|
3
|
+
class Suite
|
4
|
+
include Statsample::Shorthand
|
5
|
+
attr_accessor :output
|
6
|
+
attr_accessor :name
|
7
|
+
attr_reader :block
|
8
|
+
def initialize(opts=Hash.new(), &block)
|
9
|
+
if !opts.is_a? Hash
|
10
|
+
opts={:name=>opts}
|
11
|
+
end
|
12
|
+
|
13
|
+
@block=block
|
14
|
+
@name=opts[:name] || "Analysis #{Time.now}"
|
15
|
+
@attached=[]
|
16
|
+
@output=opts[:output] || ::STDOUT
|
17
|
+
end
|
18
|
+
# Run the analysis, putting output on
|
19
|
+
def run
|
20
|
+
@block.arity<1 ? instance_eval(&@block) : @block.call(self)
|
21
|
+
end
|
22
|
+
# Provides a description of the procedure. Only appears as a commentary on
|
23
|
+
# SuiteReportBuilder outputs
|
24
|
+
def desc(d)
|
25
|
+
@output.puts("Description:")
|
26
|
+
@output.puts(" #{d}")
|
27
|
+
end
|
28
|
+
def echo(*args)
|
29
|
+
@output.puts(*args)
|
30
|
+
end
|
31
|
+
def summary(obj)
|
32
|
+
obj.summary
|
33
|
+
end
|
34
|
+
def add_to_reportbuilder(rb)
|
35
|
+
SuiteReportBuilder.new({:name=>name, :rb=>rb}, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def generate(filename)
|
39
|
+
ar=SuiteReportBuilder.new({:name=>name}, &block)
|
40
|
+
ar.generate(filename)
|
41
|
+
end
|
42
|
+
def to_text
|
43
|
+
ar=SuiteReportBuilder.new({:name=>name}, &block)
|
44
|
+
ar.to_text
|
45
|
+
end
|
46
|
+
|
47
|
+
def attach(ds)
|
48
|
+
@attached.push(ds)
|
49
|
+
end
|
50
|
+
def detach(ds=nil)
|
51
|
+
if ds.nil?
|
52
|
+
@attached.pop
|
53
|
+
else
|
54
|
+
@attached.delete(ds)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
alias :old_boxplot :boxplot
|
58
|
+
alias :old_histogram :histogram
|
59
|
+
alias :old_scatterplot :scatterplot
|
60
|
+
|
61
|
+
def show_svg(svg)
|
62
|
+
require 'tmpdir'
|
63
|
+
fn=Dir.tmpdir+"/image_#{Time.now.to_f}.svg"
|
64
|
+
File.open(fn,"w") {|fp| fp.write svg}
|
65
|
+
if RUBY_PLATFORM =~/darwin/
|
66
|
+
%x(open -a safari #{fn})
|
67
|
+
else
|
68
|
+
%x(xdg-open #{fn})
|
69
|
+
end
|
70
|
+
end
|
71
|
+
def boxplot(*args)
|
72
|
+
show_svg(old_boxplot(*args).to_svg)
|
73
|
+
end
|
74
|
+
def histogram(*args)
|
75
|
+
show_svg(old_histogram(*args).to_svg)
|
76
|
+
end
|
77
|
+
def scatterplot(*args)
|
78
|
+
show_svg(old_scatterplot(*args).to_svg)
|
79
|
+
end
|
80
|
+
|
81
|
+
def method_missing(name, *args,&block)
|
82
|
+
@attached.reverse.each do |ds|
|
83
|
+
return ds[name] if ds.vectors.to_a.include? (name)
|
84
|
+
end
|
85
|
+
raise "Method #{name} doesn't exists"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Statsample
|
2
|
+
module Analysis
|
3
|
+
class SuiteReportBuilder < Suite
|
4
|
+
attr_accessor :rb
|
5
|
+
def initialize(opts=Hash.new,&block)
|
6
|
+
if !opts.is_a? Hash
|
7
|
+
opts={:name=>opts}
|
8
|
+
end
|
9
|
+
super(opts,&block)
|
10
|
+
@rb=opts[:rb] || ReportBuilder.new(:name=>name)
|
11
|
+
end
|
12
|
+
def generate(filename)
|
13
|
+
run if @block
|
14
|
+
@rb.save(filename)
|
15
|
+
end
|
16
|
+
def to_text
|
17
|
+
run if @block
|
18
|
+
@rb.to_text
|
19
|
+
end
|
20
|
+
def summary(o)
|
21
|
+
@rb.add(o)
|
22
|
+
end
|
23
|
+
def desc(d)
|
24
|
+
@rb.add(d)
|
25
|
+
end
|
26
|
+
def echo(*args)
|
27
|
+
args.each do |a|
|
28
|
+
@rb.add(a)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def boxplot(*args)
|
33
|
+
@rb.add(old_boxplot(*args))
|
34
|
+
end
|
35
|
+
def histogram(*args)
|
36
|
+
@rb.add(old_histogram(*args))
|
37
|
+
end
|
38
|
+
def boxplot(*args)
|
39
|
+
@rb.add(old_boxplot(*args))
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Statsample
|
2
|
+
module Anova
|
3
|
+
class << self
|
4
|
+
def oneway(*args)
|
5
|
+
OneWay.new(*args)
|
6
|
+
end
|
7
|
+
def twoway(*args)
|
8
|
+
TwoWay.new(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def oneway_with_vectors(*args)
|
12
|
+
OneWayWithVectors.new(*args)
|
13
|
+
end
|
14
|
+
def twoway_with_vectors(*args)
|
15
|
+
TwoWayWithVectors.new(*args)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'statsample/anova/oneway'
|
23
|
+
require 'statsample/anova/contrast'
|
24
|
+
require 'statsample/anova/twoway'
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Statsample
|
2
|
+
module Anova
|
3
|
+
class Contrast
|
4
|
+
attr_reader :psi
|
5
|
+
|
6
|
+
attr_reader :msw
|
7
|
+
include Summarizable
|
8
|
+
def initialize(opts=Hash.new)
|
9
|
+
raise "Should set at least vectors options" if opts[:vectors].nil?
|
10
|
+
@vectors=opts[:vectors]
|
11
|
+
@c=opts[:c]
|
12
|
+
@c1,@c2=opts[:c1], opts[:c2]
|
13
|
+
@t_options=opts[:t_options] || {:estimate_name=>_("Psi estimate")}
|
14
|
+
@name=opts[:name] || _("Contrast")
|
15
|
+
@psi=nil
|
16
|
+
@anova=Statsample::Anova::OneWayWithVectors.new(@vectors)
|
17
|
+
@msw=@anova.msw
|
18
|
+
end
|
19
|
+
# Hypothesis contrast, selecting index for each constrast
|
20
|
+
# For example, if you want to contrast x_0 against x_1 and x_2
|
21
|
+
# you should use
|
22
|
+
# c.contrast([0],[1,2])
|
23
|
+
def c_by_index(c1,c2)
|
24
|
+
contrast=[0]*@vectors.size
|
25
|
+
c1.each {|i| contrast[i]=1.quo(c1.size)}
|
26
|
+
c2.each {|i| contrast[i]=-1.quo(c2.size)}
|
27
|
+
@c=contrast
|
28
|
+
c(contrast)
|
29
|
+
end
|
30
|
+
def psi
|
31
|
+
if @psi.nil?
|
32
|
+
c(@c) if @c
|
33
|
+
c_by_index(@c1,@c2) if (@c1 and @c2)
|
34
|
+
end
|
35
|
+
@psi
|
36
|
+
end
|
37
|
+
def confidence_interval(cl=nil)
|
38
|
+
t_object.confidence_interval(cl)
|
39
|
+
end
|
40
|
+
# Hypothesis contrast, using custom values
|
41
|
+
# Every parameter is a contrast value. You should use
|
42
|
+
# the same number of contrast as vectors on class and the sum
|
43
|
+
# of constrast should be 0.
|
44
|
+
def c(args=nil)
|
45
|
+
|
46
|
+
return @c if args.nil?
|
47
|
+
@c=args
|
48
|
+
raise "contrast number!=vector number" if args.size!=@vectors.size
|
49
|
+
#raise "Sum should be 0" if args.inject(0) {|ac,v| ac+v}!=0
|
50
|
+
@psi=args.size.times.inject(0) {|ac,i| ac+(args[i]*@vectors[i].mean)}
|
51
|
+
end
|
52
|
+
def standard_error
|
53
|
+
sum=@vectors.size.times.inject(0) {|ac,i|
|
54
|
+
ac+((@c[i].rationalize**2).quo(@vectors[i].size))
|
55
|
+
}
|
56
|
+
Math.sqrt(@msw*sum)
|
57
|
+
end
|
58
|
+
alias :se :standard_error
|
59
|
+
def df
|
60
|
+
@vectors.inject(0) {|ac,v| ac+v.size}-@vectors.size
|
61
|
+
end
|
62
|
+
def t_object
|
63
|
+
Statsample::Test::T.new(psi, se, df, @t_options)
|
64
|
+
end
|
65
|
+
def t
|
66
|
+
t_object.t
|
67
|
+
end
|
68
|
+
def probability
|
69
|
+
t_object.probability
|
70
|
+
end
|
71
|
+
def report_building(builder)
|
72
|
+
builder.section(:name=>@name) do |s|
|
73
|
+
s.text _("Contrast:%s") % c.join(",")
|
74
|
+
s.parse_element(t_object)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
module Statsample
|
2
|
+
module Anova
|
3
|
+
# = Generic Anova one-way.
|
4
|
+
# You could enter the sum of squares or the mean squares. You
|
5
|
+
# should enter the degrees of freedom for numerator and denominator.
|
6
|
+
# == Usage
|
7
|
+
# anova=Statsample::Anova::OneWay(:ss_num=>10,:ss_den=>20, :df_num=>2, :df_den=>10, @name=>"ANOVA for....")
|
8
|
+
class OneWay
|
9
|
+
include Summarizable
|
10
|
+
attr_reader :df_num, :df_den, :ss_num, :ss_den, :ms_num, :ms_den, :ms_total, :df_total, :ss_total
|
11
|
+
# Name of ANOVA Analisys
|
12
|
+
attr_accessor :name
|
13
|
+
attr_accessor :name_denominator
|
14
|
+
attr_accessor :name_numerator
|
15
|
+
def initialize(opts=Hash.new)
|
16
|
+
@name=@name_numerator=@name_denominator=nil
|
17
|
+
|
18
|
+
# First see if sum of squares or mean squares are entered
|
19
|
+
raise ArgumentError, "You should set d.f." unless (opts.has_key? :df_num and opts.has_key? :df_den)
|
20
|
+
@df_num=opts.delete :df_num
|
21
|
+
@df_den=opts.delete :df_den
|
22
|
+
@df_total=@df_num+@df_den
|
23
|
+
if(opts.has_key? :ss_num and opts.has_key? :ss_den)
|
24
|
+
@ss_num = opts.delete :ss_num
|
25
|
+
@ss_den =opts.delete :ss_den
|
26
|
+
@ms_num =@ss_num.quo(@df_num)
|
27
|
+
@ms_den =@ss_den.quo(@df_den)
|
28
|
+
elsif (opts.has_key? :ms_num and opts.has_key? :ms_den)
|
29
|
+
@ms_num =opts.delete :ms_num
|
30
|
+
@ms_den =opts.delete :ms_den
|
31
|
+
@ss_num =@ms_num * @df_num
|
32
|
+
@ss_den =@ss_den * @df_den
|
33
|
+
end
|
34
|
+
@ss_total=@ss_num+@ss_den
|
35
|
+
@ms_total=@ms_num+@ms_den
|
36
|
+
opts_default={:name=>"ANOVA",
|
37
|
+
:name_denominator=>_("Explained variance"),
|
38
|
+
:name_numerator=>_("Unexplained variance")}
|
39
|
+
@opts=opts_default.merge(opts)
|
40
|
+
opts.keys.each {|k|
|
41
|
+
send("#{k}=", @opts[k]) if self.respond_to? "#{k}="
|
42
|
+
}
|
43
|
+
@f_object=Statsample::Test::F.new(@ms_num, @ms_den, @df_num,@df_den)
|
44
|
+
end
|
45
|
+
# F value
|
46
|
+
def f
|
47
|
+
@f_object.f
|
48
|
+
end
|
49
|
+
# P-value of F test
|
50
|
+
def probability
|
51
|
+
@f_object.probability
|
52
|
+
end
|
53
|
+
def report_building(builder) #:nodoc:
|
54
|
+
builder.section(:name=>@name) do |b|
|
55
|
+
report_building_table(b)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
def report_building_table(builder) #:nodoc:
|
59
|
+
builder.table(:name=>_("%s Table") % @name, :header=>%w{source ss df ms f p}.map {|v| _(v)}) do |t|
|
60
|
+
t.row([@name_numerator, sprintf("%0.3f",@ss_num), @df_num, sprintf("%0.3f",@ms_num), sprintf("%0.3f",f), sprintf("%0.3f", probability)])
|
61
|
+
t.row([@name_denominator, sprintf("%0.3f",@ss_den), @df_den, sprintf("%0.3f",@ms_den), "", ""])
|
62
|
+
t.row([_("Total"), sprintf("%0.3f",@ss_total), @df_total, sprintf("%0.3f",@ms_total),"",""])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
# One Way Anova with vectors
|
69
|
+
# Example:
|
70
|
+
# v1 = Daru::Vector.new([2,3,4,5,6])
|
71
|
+
# v2 = Daru::Vector.new([3,3,4,5,6])
|
72
|
+
# v3 = Daru::Vector.new([5,3,1,5,6])
|
73
|
+
# anova=Statsample::Anova::OneWayWithVectors.new([v1,v2,v3])
|
74
|
+
# anova.f
|
75
|
+
# => 0.0243902439024391
|
76
|
+
# anova.probability
|
77
|
+
# => 0.975953044203438
|
78
|
+
# anova.sst
|
79
|
+
# => 32.9333333333333
|
80
|
+
#
|
81
|
+
class OneWayWithVectors < OneWay
|
82
|
+
# Show on summary Levene test
|
83
|
+
attr_accessor :summary_levene
|
84
|
+
# Show on summary descriptives for vectors
|
85
|
+
attr_accessor :summary_descriptives
|
86
|
+
# Show on summary of contrasts
|
87
|
+
attr_accessor :summary_contrasts
|
88
|
+
# Array with stored contrasts
|
89
|
+
attr_reader :contrasts
|
90
|
+
|
91
|
+
def initialize(*args)
|
92
|
+
if args[0].is_a? Array
|
93
|
+
@vectors = args.shift
|
94
|
+
else
|
95
|
+
@vectors = args.find_all {|v| v.is_a? Daru::Vector}
|
96
|
+
opts = args.find {|v| v.is_a? Hash}
|
97
|
+
end
|
98
|
+
opts||=Hash.new
|
99
|
+
opts_default={:name=>_("Anova One-Way"),
|
100
|
+
:name_numerator=>_("Between Groups"),
|
101
|
+
:name_denominator=>_("Within Groups"),
|
102
|
+
:summary_descriptives=>false,
|
103
|
+
:summary_levene=>true,
|
104
|
+
:summary_contrasts=>true
|
105
|
+
}
|
106
|
+
@opts=opts_default.merge(opts).merge(:ss_num=>ssbg, :ss_den=>sswg, :df_num=>df_bg, :df_den=>df_wg)
|
107
|
+
@contrasts=[]
|
108
|
+
super(@opts)
|
109
|
+
end
|
110
|
+
alias :sst :ss_total
|
111
|
+
alias :msb :ms_num
|
112
|
+
alias :msw :ms_den
|
113
|
+
|
114
|
+
# Generates and store a contrast.
|
115
|
+
# Options should be provided as a hash
|
116
|
+
# [:c]=>contrast vector
|
117
|
+
# [:c1 - :c2]=>index for automatic construction of contrast
|
118
|
+
# [:name]=>contrast name
|
119
|
+
|
120
|
+
def contrast(opts=Hash.new)
|
121
|
+
name=opts[:name] || _("Contrast for %s") % @name
|
122
|
+
opts=opts.merge({:vectors=>@vectors, :name=>name})
|
123
|
+
c=Statsample::Anova::Contrast.new(opts)
|
124
|
+
@contrasts.push(c)
|
125
|
+
c
|
126
|
+
end
|
127
|
+
|
128
|
+
def levene
|
129
|
+
Statsample::Test.levene(@vectors, :name=>_("Test of Homogeneity of variances (Levene)"))
|
130
|
+
end
|
131
|
+
# Total mean
|
132
|
+
def total_mean
|
133
|
+
sum=@vectors.inject(0){|a,v| a+v.sum}
|
134
|
+
sum.quo(n)
|
135
|
+
end
|
136
|
+
# Sum of squares within groups
|
137
|
+
def sswg
|
138
|
+
@sswg||=@vectors.inject(0) {|total,vector| total+vector.ss }
|
139
|
+
end
|
140
|
+
# Sum of squares between groups
|
141
|
+
def ssbg
|
142
|
+
m=total_mean
|
143
|
+
@vectors.inject(0) do |total,vector|
|
144
|
+
total + (vector.mean-m).square * vector.size
|
145
|
+
end
|
146
|
+
end
|
147
|
+
# Degrees of freedom within groups
|
148
|
+
def df_wg
|
149
|
+
@dk_wg||=n-k
|
150
|
+
end
|
151
|
+
def k
|
152
|
+
@k||=@vectors.size
|
153
|
+
end
|
154
|
+
# Degrees of freedom between groups
|
155
|
+
def df_bg
|
156
|
+
k-1
|
157
|
+
end
|
158
|
+
# Total number of cases
|
159
|
+
def n
|
160
|
+
@vectors.inject(0){|a,v| a+v.size}
|
161
|
+
end
|
162
|
+
def report_building(builder) # :nodoc:
|
163
|
+
builder.section(:name=>@name) do |s|
|
164
|
+
if summary_descriptives
|
165
|
+
s.table(:name=>_("Descriptives"),:header=>%w{Name N Mean SD Min Max}.map {|v| _(v)}) do |t|
|
166
|
+
@vectors.each do |v|
|
167
|
+
t.row [v.name, v.reject_values(*Daru::MISSING_VALUES).size, "%0.4f" % v.mean, "%0.4f" % v.sd, "%0.4f" % v.min, "%0.4f" % v.max]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
if summary_levene
|
173
|
+
s.parse_element(levene)
|
174
|
+
end
|
175
|
+
report_building_table(s)
|
176
|
+
if summary_contrasts and @contrasts.size>0
|
177
|
+
|
178
|
+
@contrasts.each do |c|
|
179
|
+
s.parse_element(c)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|