statsample 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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