statsample-ekatena 2.0.2
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.
- 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
|