statsample 0.5.1 → 0.6.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.
Files changed (51) hide show
  1. data/History.txt +12 -0
  2. data/Manifest.txt +13 -0
  3. data/README.txt +2 -1
  4. data/demo/pca.rb +29 -0
  5. data/demo/umann.rb +8 -0
  6. data/lib/distribution.rb +0 -1
  7. data/lib/matrix_extension.rb +35 -21
  8. data/lib/statsample.rb +31 -28
  9. data/lib/statsample/anova.rb +7 -2
  10. data/lib/statsample/bivariate.rb +17 -11
  11. data/lib/statsample/codification.rb +136 -87
  12. data/lib/statsample/combination.rb +0 -2
  13. data/lib/statsample/converter/csv18.rb +1 -1
  14. data/lib/statsample/converter/csv19.rb +1 -1
  15. data/lib/statsample/converters.rb +176 -171
  16. data/lib/statsample/crosstab.rb +227 -154
  17. data/lib/statsample/dataset.rb +94 -12
  18. data/lib/statsample/dominanceanalysis.rb +69 -62
  19. data/lib/statsample/dominanceanalysis/bootstrap.rb +25 -21
  20. data/lib/statsample/factor.rb +18 -0
  21. data/lib/statsample/factor/pca.rb +128 -0
  22. data/lib/statsample/factor/principalaxis.rb +133 -0
  23. data/lib/statsample/factor/rotation.rb +125 -0
  24. data/lib/statsample/histogram.rb +99 -0
  25. data/lib/statsample/mle.rb +125 -126
  26. data/lib/statsample/mle/logit.rb +91 -91
  27. data/lib/statsample/mle/probit.rb +84 -85
  28. data/lib/statsample/multiset.rb +1 -1
  29. data/lib/statsample/permutation.rb +96 -0
  30. data/lib/statsample/regression.rb +1 -1
  31. data/lib/statsample/regression/binomial.rb +89 -89
  32. data/lib/statsample/regression/binomial/logit.rb +9 -9
  33. data/lib/statsample/regression/binomial/probit.rb +9 -9
  34. data/lib/statsample/regression/multiple.rb +8 -14
  35. data/lib/statsample/regression/multiple/gslengine.rb +1 -1
  36. data/lib/statsample/regression/multiple/rubyengine.rb +55 -55
  37. data/lib/statsample/resample.rb +12 -17
  38. data/lib/statsample/srs.rb +4 -1
  39. data/lib/statsample/test.rb +23 -22
  40. data/lib/statsample/test/umannwhitney.rb +182 -0
  41. data/lib/statsample/vector.rb +854 -815
  42. data/test/test_bivariate.rb +132 -132
  43. data/test/test_codification.rb +71 -50
  44. data/test/test_dataset.rb +19 -1
  45. data/test/test_factor.rb +44 -0
  46. data/test/test_histogram.rb +26 -0
  47. data/test/test_permutation.rb +37 -0
  48. data/test/test_statistics.rb +74 -63
  49. data/test/test_umannwhitney.rb +17 -0
  50. data/test/test_vector.rb +46 -30
  51. metadata +31 -4
@@ -40,8 +40,6 @@ module Statsample
40
40
  def next_value
41
41
  @d.next_value
42
42
  end
43
-
44
- # Ruby engine for Combinations
45
43
  class CombinationRuby
46
44
  attr_reader :data
47
45
  def initialize(k,n)
@@ -31,7 +31,7 @@ module Statsample
31
31
  ds.add_case(rowa,false)
32
32
  end
33
33
  end
34
- convert_to_scale(ds,fields)
34
+ convert_to_scale_and_date(ds,fields)
35
35
  ds.update_valid_data
36
36
  ds
37
37
  end
@@ -32,7 +32,7 @@ module Statsample
32
32
  ds.add_case(rowa,false)
33
33
  end
34
34
  end
35
- convert_to_scale(ds,fields)
35
+ convert_to_scale_and_date(ds,fields)
36
36
  ds.update_valid_data
37
37
  ds
38
38
  end
@@ -40,6 +40,7 @@ module Statsample
40
40
  query="INSERT INTO #{table} ("+ds.fields.join(",")+") VALUES ("+((["?"]*ds.fields.size).join(","))+")"
41
41
  sth=dbh.prepare(query)
42
42
  ds.each_array{|c| sth.execute(*c) }
43
+ return true
43
44
  end
44
45
  # Create a sql, basen on a given Dataset
45
46
  #
@@ -72,182 +73,186 @@ module Statsample
72
73
  end
73
74
  end
74
75
  end
75
- class SpreadsheetBase
76
- class << self
77
- def extract_fields(row)
78
- fields=row.to_a.collect{|c| c.downcase}
79
- fields.recode_repeated
80
- end
81
-
82
- def process_row(row,empty)
83
- row.to_a.collect do |c|
84
- if empty.include?(c)
85
- nil
86
- else
87
- if c.is_a? String and c.is_number?
88
- if c=~/^\d+$/
89
- c.to_i
90
- else
91
- c.gsub(",",".").to_f
92
- end
93
- else
94
- c
95
- end
96
- end
97
- end
98
- end
99
- def convert_to_scale(ds,fields)
100
- fields.each do |f|
101
- if ds[f].can_be_scale?
102
- ds[f].type=:scale
103
- end
104
- end
76
+ class SpreadsheetBase
77
+ class << self
78
+ def extract_fields(row)
79
+ fields=row.to_a.collect{|c| c.downcase}
80
+ fields.recode_repeated
81
+ end
82
+
83
+ def process_row(row,empty)
84
+ row.to_a.collect do |c|
85
+ if empty.include?(c)
86
+ nil
87
+ else
88
+ if c.is_a? String and c.is_number?
89
+ if c=~/^\d+$/
90
+ c.to_i
91
+ else
92
+ c.gsub(",",".").to_f
93
+ end
94
+ else
95
+ c
105
96
  end
106
-
97
+ end
107
98
  end
99
+ end
100
+ def convert_to_scale_and_date(ds,fields)
101
+ fields.each do |f|
102
+ if ds[f].can_be_scale?
103
+ ds[f].type=:scale
104
+ elsif ds[f].can_be_date?
105
+ ds[f].type=:date
106
+ end
107
+ end
108
+ end
109
+
108
110
  end
111
+ end
109
112
  class PlainText < SpreadsheetBase
110
- class << self
111
- def read(filename, fields)
112
- ds=Statsample::Dataset.new(fields)
113
- fp=File.open(filename,"r")
114
- fp.each_line do |line|
115
- row=process_row(line.strip.split(/\s+/),[""])
116
- next if row==["\x1A"]
117
- ds.add_case_array(row)
118
- end
119
- convert_to_scale(ds,fields)
120
- ds.update_valid_data
121
- ds
122
- end
113
+ class << self
114
+ def read(filename, fields)
115
+ ds=Statsample::Dataset.new(fields)
116
+ fp=File.open(filename,"r")
117
+ fp.each_line do |line|
118
+ row=process_row(line.strip.split(/\s+/),[""])
119
+ next if row==["\x1A"]
120
+ ds.add_case_array(row)
121
+ end
122
+ convert_to_scale_and_date(ds,fields)
123
+ ds.update_valid_data
124
+ ds
123
125
  end
126
+ end
124
127
  end
125
- class Excel < SpreadsheetBase
126
- class << self
127
- def write(dataset,filename)
128
- require 'spreadsheet'
129
- book = Spreadsheet::Workbook.new
130
- sheet = book.create_worksheet
131
- format = Spreadsheet::Format.new :color => :blue,
132
- :weight => :bold
133
- sheet.row(0).concat(dataset.fields)
134
- sheet.row(0).default_format = format
135
- i=1
136
- dataset.each_array{|row|
137
- sheet.row(i).concat(row)
138
- i+=1
139
- }
140
- book.write(filename)
128
+ class Excel < SpreadsheetBase
129
+ class << self
130
+ # Write a Excel spreadsheet based on a dataset
131
+ # * TODO: Format nicely date values
132
+ def write(dataset,filename)
133
+ require 'spreadsheet'
134
+ book = Spreadsheet::Workbook.new
135
+ sheet = book.create_worksheet
136
+ format = Spreadsheet::Format.new :color => :blue,
137
+ :weight => :bold
138
+ sheet.row(0).concat(dataset.fields)
139
+ sheet.row(0).default_format = format
140
+ i=1
141
+ dataset.each_array{|row|
142
+ sheet.row(i).concat(row)
143
+ i+=1
144
+ }
145
+ book.write(filename)
146
+ end
147
+ # Returns a dataset based on a xls file
148
+ # USE:
149
+ # ds = Statsample::Excel.read("test.xls")
150
+ #
151
+ def read(filename, worksheet_id=0, ignore_lines=0, empty=[''])
152
+ require 'spreadsheet'
153
+ first_row=true
154
+ fields=[]
155
+ fields_data={}
156
+ ds=nil
157
+ line_number=0
158
+ book = Spreadsheet.open filename
159
+ sheet= book.worksheet worksheet_id
160
+ sheet.each do |row|
161
+ begin
162
+ dates=[]
163
+ row.formats.each_index{|i|
164
+ if !row.formats[i].nil? and row.formats[i].number_format=="DD/MM/YYYY"
165
+ dates.push(i)
166
+ end
167
+ }
168
+ line_number+=1
169
+ if(line_number<=ignore_lines)
170
+ #puts "Skip line #{line_number}:#{row.to_s}"
171
+ next
141
172
  end
142
- # Returns a dataset based on a xls file
143
- # USE:
144
- # ds = Statsample::Excel.read("test.xls")
145
- #
146
- def read(filename, worksheet_id=0, ignore_lines=0, empty=[''])
147
- require 'spreadsheet'
148
- first_row=true
149
- fields=[]
150
- fields_data={}
151
- ds=nil
152
- line_number=0
153
- book = Spreadsheet.open filename
154
- sheet= book.worksheet worksheet_id
155
- sheet.each do |row|
156
- begin
157
- dates=[]
158
- row.formats.each_index{|i|
159
- if !row.formats[i].nil? and row.formats[i].number_format=="DD/MM/YYYY"
160
- dates.push(i)
161
- end
162
- }
163
- line_number+=1
164
- if(line_number<=ignore_lines)
165
- #puts "Skip line #{line_number}:#{row.to_s}"
166
- next
167
- end
168
- # This should be fixed.
169
- # If we have a Formula, should be resolver first
170
- i=-1
171
- row.collect!{|c|
172
- i+=1
173
- if c.is_a? Spreadsheet::Formula
174
- if(c.value.is_a? Spreadsheet::Excel::Error)
175
- nil
176
- else
177
- c.value
178
- end
179
- elsif dates.include? i and !c.nil? and c.is_a? Numeric
180
- row.date(i)
181
- else
182
- c
183
- end
184
- }
185
- if first_row
186
- fields=extract_fields(row)
187
- ds=Statsample::Dataset.new(fields)
188
- first_row=false
189
- else
190
- rowa=process_row(row,empty)
191
- (fields.size - rowa.size).times {
192
- rowa << nil
193
- }
194
- ds.add_case(rowa,false)
195
- end
196
- rescue => e
197
- error="#{e.to_s}\nError on Line # #{line_number}:#{row.join(",")}"
198
- raise
199
- end
173
+ # This should be fixed.
174
+ # If we have a Formula, should be resolver first
175
+ i=-1
176
+ row.collect!{|c|
177
+ i+=1
178
+ if c.is_a? Spreadsheet::Formula
179
+ if(c.value.is_a? Spreadsheet::Excel::Error)
180
+ nil
181
+ else
182
+ c.value
183
+ end
184
+ elsif dates.include? i and !c.nil? and c.is_a? Numeric
185
+ row.date(i)
186
+ else
187
+ c
200
188
  end
201
- convert_to_scale(ds,fields)
202
- ds.update_valid_data
203
- ds
189
+ }
190
+ if first_row
191
+ fields=extract_fields(row)
192
+ ds=Statsample::Dataset.new(fields)
193
+ first_row=false
194
+ else
195
+ rowa=process_row(row,empty)
196
+ (fields.size - rowa.size).times {
197
+ rowa << nil
198
+ }
199
+ ds.add_case(rowa,false)
204
200
  end
201
+ rescue => e
202
+ error="#{e.to_s}\nError on Line # #{line_number}:#{row.join(",")}"
203
+ raise
204
+ end
205
205
  end
206
+ convert_to_scale_and_date(ds, fields)
207
+ ds.update_valid_data
208
+ ds
209
+ end
206
210
  end
207
- module Mx
208
- class << self
209
- def write(dataset,filename,type=:covariance)
210
- puts "Writing MX File"
211
- File.open(filename,"w") {|fp|
212
- fp.puts "! #{filename}"
213
- fp.puts "! Output generated by Statsample"
214
- fp.puts "Data Ninput=#{dataset.fields.size} Nobservations=#{dataset.cases}"
215
- fp.puts "Labels "+dataset.fields.join(" ")
216
- case type
217
- when :raw
218
- fp.puts "Rectangular"
219
- dataset.each {|row|
220
- out=dataset.fields.collect {|f|
221
- if dataset[f].is_valid? row[f]
222
- row[f]
223
- else
224
- "."
225
- end
226
- }
227
- fp.puts out.join("\t")
228
- }
229
- fp.puts "End Rectangular"
230
- when :covariance
231
- fp.puts " CMatrix Full"
232
- cm=Statsample::Bivariate.covariance_matrix(dataset)
233
- d=(0...(cm.row_size)).collect {|row|
234
- (0...(cm.column_size)).collect{|col|
235
- cm[row,col].nil? ? "." : sprintf("%0.3f", cm[row,col])
236
- }.join(" ")
237
- }.join("\n")
238
- fp.puts d
211
+ end
212
+ module Mx
213
+ class << self
214
+ def write(dataset,filename,type=:covariance)
215
+ puts "Writing MX File"
216
+ File.open(filename,"w") do |fp|
217
+ fp.puts "! #{filename}"
218
+ fp.puts "! Output generated by Statsample"
219
+ fp.puts "Data Ninput=#{dataset.fields.size} Nobservations=#{dataset.cases}"
220
+ fp.puts "Labels "+dataset.fields.join(" ")
221
+ case type
222
+ when :raw
223
+ fp.puts "Rectangular"
224
+ dataset.each do |row|
225
+ out=dataset.fields.collect do |f|
226
+ if dataset[f].is_valid? row[f]
227
+ row[f]
228
+ else
229
+ "."
239
230
  end
240
- }
231
+ end
232
+ fp.puts out.join("\t")
233
+ end
234
+ fp.puts "End Rectangular"
235
+ when :covariance
236
+ fp.puts " CMatrix Full"
237
+ cm=Statsample::Bivariate.covariance_matrix(dataset)
238
+ d=(0...(cm.row_size)).collect {|row|
239
+ (0...(cm.column_size)).collect{|col|
240
+ cm[row,col].nil? ? "." : sprintf("%0.3f", cm[row,col])
241
+ }.join(" ")
242
+ }.join("\n")
243
+ fp.puts d
244
+ end
241
245
  end
246
+ end
242
247
  end
243
- end
248
+ end
244
249
  module GGobi
245
250
  class << self
246
- def write(dataset,filename,opt={})
247
- File.open(filename,"w") {|fp|
248
- fp.write(self.out(dataset,opt))
249
- }
250
- end
251
+ def write(dataset,filename,opt={})
252
+ File.open(filename,"w") {|fp|
253
+ fp.write(self.out(dataset,opt))
254
+ }
255
+ end
251
256
  def out(dataset,opt={})
252
257
  require 'ostruct'
253
258
  default_opt = {:dataname => "Default", :description=>"", :missing=>"NA"}
@@ -291,17 +296,17 @@ EOC
291
296
  out
292
297
 
293
298
  end
294
- def values_definition(c,missing)
295
- c.collect{|v|
296
- if v.nil?
297
- "#{missing}"
298
- elsif v.is_a? Numeric
299
- "#{v}"
300
- else
301
- "#{v.gsub(/\s+/,"_")}"
302
- end
303
- }.join(" ")
304
- end
299
+ def values_definition(c,missing)
300
+ c.collect{|v|
301
+ if v.nil?
302
+ "#{missing}"
303
+ elsif v.is_a? Numeric
304
+ "#{v}"
305
+ else
306
+ "#{v.gsub(/\s+/,"_")}"
307
+ end
308
+ }.join(" ")
309
+ end
305
310
  # Outputs a string for a variable definition
306
311
  # v = vector
307
312
  # name = name of the variable
@@ -3,163 +3,236 @@ module Statsample
3
3
  # With this, you can create reports and do chi square test
4
4
  # The first vector will be at rows and the second will the the columns
5
5
  #
6
- class Crosstab
7
- include GetText
8
- bindtextdomain("statsample")
9
- attr_reader :v_rows, :v_cols
10
- attr_accessor :row_label, :column_label
11
- def initialize(v1,v2)
12
- raise ArgumentError, "Both arguments should be Vectors" unless v1.instance_of? Vector and v2.instance_of? Vector
13
- raise ArgumentError, "Vectors should be the same size" unless v1.size==v2.size
14
- @v_rows,@v_cols=v1,v2
15
- end
16
- def rows_names
17
- @v_rows.factors.sort
18
- end
19
- def cols_names
20
- @v_cols.factors.sort
21
- end
22
- def rows_total
23
- @v_rows.frequencies
24
- end
25
- def cols_total
26
- @v_cols.frequencies
27
- end
28
- def frequencies
29
- base=rows_names.inject([]){|s,row|
30
- s+=cols_names.collect{|col| [row,col]}
31
- }.inject({}) {|s,par|
32
- s[par]=0
33
- s
34
- }
35
- base.update(Statsample::vector_cols_matrix(@v_rows,@v_cols).to_a.to_vector.frequencies)
36
- end
6
+ class Crosstab
7
+ include GetText
8
+ bindtextdomain("statsample")
9
+ attr_reader :v_rows, :v_cols
10
+ attr_accessor :row_label, :column_label, :name, :percentage_row, :percentage_column, :percentage_total
11
+ def initialize(v1,v2,opts=Hash.new)
12
+ raise ArgumentError, "Both arguments should be Vectors" unless v1.is_a? Statsample::Vector and v2.is_a? Statsample::Vector
13
+ raise ArgumentError, "Vectors should be the same size" unless v1.size==v2.size
14
+ @v_rows, @v_cols=Statsample.only_valid(v1,v2)
15
+ @cases=@v_rows.size
16
+ @row_label=nil
17
+ @column_label=nil
18
+ @name=nil
19
+ @percentage_row=@percentage_column=@percentage_total=false
20
+ opts.each{|k,v|
21
+ self.send("#{k}=",v) if self.respond_to? k
22
+ }
23
+ if(@name.nil?)
24
+ if (!@row_label.nil? and !@column_label.nil?)
25
+ @name=_("Crosstab %s - %s") % [@row_label, @column_label]
26
+ else
27
+ @name=_("Crosstab")
28
+ end
29
+ end
30
+ end
31
+ def rows_names
32
+ @v_rows.factors.sort
33
+ end
34
+ def cols_names
35
+ @v_cols.factors.sort
36
+ end
37
+ def rows_total
38
+ @v_rows.frequencies
39
+ end
40
+ def cols_total
41
+ @v_cols.frequencies
42
+ end
43
+ def frequencies
44
+ base=rows_names.inject([]){|s,row|
45
+ s+=cols_names.collect{|col| [row,col]}
46
+ }.inject({}) {|s,par|
47
+ s[par]=0
48
+ s
49
+ }
50
+ base.update(Statsample::vector_cols_matrix(@v_rows,@v_cols).to_a.to_vector.frequencies)
51
+ end
37
52
  def to_matrix
38
- f=frequencies
39
- rn=rows_names
40
- cn=cols_names
41
- Matrix.rows(rn.collect{|row|
42
- cn.collect{|col| f[[row,col]]}
43
- })
53
+ f=frequencies
54
+ rn=rows_names
55
+ cn=cols_names
56
+ Matrix.rows(rn.collect{|row|
57
+ cn.collect{|col| f[[row,col]]}
58
+ })
44
59
  end
45
- def frequencies_by_row
46
- f=frequencies
47
- rows_names.inject({}){|sr,row|
48
- sr[row]=cols_names.inject({}) {|sc,col|
49
- sc[col]=f[[row,col]]
50
- sc
51
- }
52
- sr
53
- }
54
- end
55
- def frequencies_by_col
56
- f=frequencies
57
- cols_names.inject({}){|sc,col|
58
- sc[col]=rows_names.inject({}) {|sr,row|
59
- sr[row]=f[[row,col]]
60
- sr
61
- }
62
- sc
63
- }
64
- end
65
- # Chi square, based on expected and real matrix
66
- def chi_square
67
- require 'statsample/test'
68
- Statsample::Test.chi_square(self.to_matrix, matrix_expected)
69
- end
70
- # Useful to obtain chi square
71
- def matrix_expected
72
- rn=rows_names
73
- cn=cols_names
74
- rt=rows_total
75
- ct=cols_total
76
- t=@v_rows.size.to_f
77
- m=rn.collect{|row|
78
- cn.collect{|col|
79
- (rt[row]*ct[col]) / t
80
- }
81
- }
82
- Matrix.rows(m)
60
+ def frequencies_by_row
61
+ f=frequencies
62
+ rows_names.inject({}){|sr,row|
63
+ sr[row]=cols_names.inject({}) {|sc,col| sc[col]=f[[row,col]]; sc}
64
+ sr
65
+ }
66
+ end
67
+ def frequencies_by_col
68
+ f=frequencies
69
+ cols_names.inject({}){|sc,col|
70
+ sc[col]=rows_names.inject({}) {|sr,row| sr[row]=f[[row,col]]; sr}
71
+ sc
72
+ }
73
+ end
74
+ # Chi square, based on expected and real matrix
75
+ def chi_square
76
+ require 'statsample/test'
77
+ Statsample::Test.chi_square(self.to_matrix, matrix_expected)
78
+ end
79
+ # Useful to obtain chi square
80
+ def matrix_expected
81
+ rn=rows_names
82
+ cn=cols_names
83
+ rt=rows_total
84
+ ct=cols_total
85
+ t=@v_rows.size
86
+ m=rn.collect{|row|
87
+ cn.collect{|col|
88
+ (rt[row]*ct[col]).quo(t)
89
+ }
90
+ }
91
+ Matrix.rows(m)
92
+ end
93
+ def cols_empty_hash
94
+ cols_names.inject({}) {|a,x| a[x]=0;a}
95
+ end
96
+ def to_reportbuilder(generator)
97
+ anchor=generator.add_toc_entry(_("Crosstab: ")+name)
98
+ generator.add_html "<div class='crosstab'>"+_("Crosstab")+" #{@name}<a name='#{anchor}'></a>"
99
+ fq=frequencies
100
+ rn=rows_names
101
+ cn=cols_names
102
+ total=0
103
+ total_cols=cols_empty_hash
104
+ generator.add_text "Chi Square: #{chi_square}"
105
+ generator.add_text(_("Rows: %s") % @row_label) unless @row_label.nil?
106
+ generator.add_text(_("Columns: %s") % @column_label) unless @column_label.nil?
107
+
108
+ t=ReportBuilder::Table.new(:name=>@name+" - "+_("Raw"), :header=>[""]+cols_names.collect {|c| @v_cols.labeling(c)}+[_("Total")])
109
+ rn.each do |row|
110
+ total_row=0
111
+ t_row=[@v_rows.labeling(row)]
112
+ cn.each do |col|
113
+ data=fq[[row,col]]
114
+ total_row+=fq[[row,col]]
115
+ total+=fq[[row,col]]
116
+ total_cols[col]+=fq[[row,col]]
117
+ t_row.push(data)
83
118
  end
84
- def cols_empty_hash
85
- cols_names.inject({}) {|a,x| a[x]=0;a}
119
+ t_row.push(total_row)
120
+ t.add_row(t_row)
121
+ end
122
+ t.add_horizontal_line
123
+ t_row=[_("Total")]
124
+ cn.each do |v|
125
+ t_row.push(total_cols[v])
126
+ end
127
+ t_row.push(total)
128
+ t.add_row(t_row)
129
+ generator.parse_element(t)
130
+
131
+ if(@percentage_row)
132
+ table_percentage(generator,:row)
133
+ end
134
+ if(@percentage_column)
135
+ table_percentage(generator,:column)
136
+ end
137
+ if(@percentage_total)
138
+ table_percentage(generator,:total)
139
+ end
140
+
141
+ generator.add_html("</div>")
142
+ end
143
+
144
+
145
+
146
+ def table_percentage(generator,type)
147
+ fq=frequencies
148
+ cn=cols_names
149
+ rn=rows_names
150
+ rt=rows_total
151
+ ct=cols_total
152
+
153
+ type_name=case type
154
+ when :row then _("% Row")
155
+ when :column then _("% Column")
156
+ when :total then _("% Total")
157
+ end
158
+
159
+ t=ReportBuilder::Table.new(:name=>@name+" - "+_(type_name), :header=>[""]+cols_names.collect {|c| @v_cols.labeling(c) } + [_("Total")])
160
+ rn.each do |row|
161
+ t_row=[@v_rows.labeling(row)]
162
+ cn.each do |col|
163
+ total=case type
164
+ when :row then rt[row]
165
+ when :column then ct[col]
166
+ when :total then @cases
167
+ end
168
+ data = sprintf("%0.2f%%", fq[[row,col]]*100.0/ total )
169
+ t_row.push(data)
170
+ end
171
+ total=case type
172
+ when :row then rt[row]
173
+ when :column then @cases
174
+ when :total then @cases
175
+ end
176
+ t_row.push(sprintf("%0.2f%%", rt[row]*100.0/total))
177
+ t.add_row(t_row)
86
178
  end
87
179
 
88
- def summary(report_type = ConsoleSummary)
89
- out=""
90
- out.extend report_type
91
- fq=frequencies
92
- rn=rows_names
93
- cn=cols_names
94
- total=0
95
- total_cols=cols_empty_hash
96
- out.add "Chi Square: #{chi_square}\n"
97
- out.add(_("Rows: %s\n") % @row_label) unless @row_label.nil?
98
- out.add(_("Columns: %s\n") % @column_label) unless @column_label.nil?
99
-
100
- t=Statsample::ReportTable.new([""]+cols_names+[_("Total")])
101
- rn.each{|row|
102
- total_row=0
103
- t_row=[@v_rows.labeling(row)]
104
- cn.each{|col|
105
- data=fq[[row,col]]
106
- total_row+=fq[[row,col]]
107
- total+=fq[[row,col]]
108
- total_cols[col]+=fq[[row,col]]
109
- t_row.push(data)
110
- }
111
- t_row.push(total_row)
112
- t.add_row(t_row)
113
- }
114
- t.add_horizontal_line
115
- t_row=[_("Total")]
116
- cn.each{|v|
117
- t_row.push(total_cols[v])
118
- }
119
- t_row.push(total)
120
- t.add_row(t_row)
121
- out.parse_table(t)
122
- out
123
- end
124
- def to_s
125
- fq=frequencies
126
- rn=rows_names
127
- cn=cols_names
128
- total=0
129
- total_cols=cols_empty_hash
130
- max_row_size = rn.inject(0) {|s,x| sl=@v_rows.labeling(x).size; sl>s ? sl : s}
131
-
132
- max_row_size=max_row_size<6 ? 6 : max_row_size
133
-
134
- max_col_size = cn.inject(0) {|s,x| sl=@v_cols.labeling(x).size; sl>s ? sl : s}
135
- max_col_size = frequencies.inject(max_col_size) {|s,x| x[1].to_s.size>s ? x[1].to_s.size : s}
136
-
137
- out=""
138
- out << " " * (max_row_size+2) << "|" << cn.collect{|c| name=@v_cols.labeling(c); " "+name+(" "*(max_col_size-name.size))+" "}.join("|") << "| Total\n"
139
- linea="-" * (max_row_size+2) << "|" << ("-"*(max_col_size+2) +"|")*cn.size << "-"*7 << "\n"
140
- out << linea
141
- rn.each{|row|
142
- total_row=0;
143
- name=@v_rows.labeling(row)
144
- out << " " +name << " "*(max_row_size-name.size) << " | "
145
- cn.each{|col|
146
- data=fq[[row,col]].to_s
147
- total_row+=fq[[row,col]]
148
- total+=fq[[row,col]]
149
- total_cols[col]+=fq[[row,col]]
150
- out << " " << data << " "*(max_col_size-data.size) << "| "
151
- }
152
- out << " " << total_row.to_s
153
- out << "\n"
154
- }
155
- out << linea
156
- out << " Total " << " "*(max_row_size-5) << "| "
157
- cn.each{|v|
158
- data=total_cols[v].to_s
159
- out << " " << data << " "*(max_col_size-data.size) << "| "
160
- }
161
- out << " " << total.to_s
162
- out
163
- end
164
- end
180
+ t.add_horizontal_line
181
+ t_row=[_("Total")]
182
+ cn.each{|col|
183
+ total=case type
184
+ when :row then @cases
185
+ when :column then ct[col]
186
+ when :total then @cases
187
+ end
188
+ t_row.push(sprintf("%0.2f%%", ct[col]*100.0/total))
189
+ }
190
+ t_row.push("100%")
191
+ t.add_row(t_row)
192
+ generator.parse_element(t)
193
+ end
194
+
195
+
196
+
197
+ def to_s
198
+ fq=frequencies
199
+ rn=rows_names
200
+ cn=cols_names
201
+ total=0
202
+ total_cols=cols_empty_hash
203
+ max_row_size = rn.inject(0) {|s,x| sl=@v_rows.labeling(x).size; sl>s ? sl : s}
204
+
205
+ max_row_size=max_row_size<6 ? 6 : max_row_size
206
+
207
+ max_col_size = cn.inject(0) {|s,x| sl=@v_cols.labeling(x).size; sl>s ? sl : s}
208
+ max_col_size = frequencies.inject(max_col_size) {|s,x| x[1].to_s.size>s ? x[1].to_s.size : s}
209
+
210
+ out=""
211
+ out << " " * (max_row_size+2) << "|" << cn.collect{|c| name=@v_cols.labeling(c); " "+name+(" "*(max_col_size-name.size))+" "}.join("|") << "| Total\n"
212
+ linea="-" * (max_row_size+2) << "|" << ("-"*(max_col_size+2) +"|")*cn.size << "-"*7 << "\n"
213
+ out << linea
214
+ rn.each{|row|
215
+ total_row=0;
216
+ name=@v_rows.labeling(row)
217
+ out << " " +name << " "*(max_row_size-name.size) << " | "
218
+ cn.each{|col|
219
+ data=fq[[row,col]].to_s
220
+ total_row+=fq[[row,col]]
221
+ total+=fq[[row,col]]
222
+ total_cols[col]+=fq[[row,col]]
223
+ out << " " << data << " "*(max_col_size-data.size) << "| "
224
+ }
225
+ out << " " << total_row.to_s
226
+ out << "\n"
227
+ }
228
+ out << linea
229
+ out << " Total " << " "*(max_row_size-5) << "| "
230
+ cn.each{|v|
231
+ data=total_cols[v].to_s
232
+ out << " " << data << " "*(max_col_size-data.size) << "| "
233
+ }
234
+ out << " " << total.to_s
235
+ out
236
+ end
237
+ end
165
238
  end