statsample 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +12 -0
- data/Manifest.txt +13 -0
- data/README.txt +2 -1
- data/demo/pca.rb +29 -0
- data/demo/umann.rb +8 -0
- data/lib/distribution.rb +0 -1
- data/lib/matrix_extension.rb +35 -21
- data/lib/statsample.rb +31 -28
- data/lib/statsample/anova.rb +7 -2
- data/lib/statsample/bivariate.rb +17 -11
- data/lib/statsample/codification.rb +136 -87
- data/lib/statsample/combination.rb +0 -2
- data/lib/statsample/converter/csv18.rb +1 -1
- data/lib/statsample/converter/csv19.rb +1 -1
- data/lib/statsample/converters.rb +176 -171
- data/lib/statsample/crosstab.rb +227 -154
- data/lib/statsample/dataset.rb +94 -12
- data/lib/statsample/dominanceanalysis.rb +69 -62
- data/lib/statsample/dominanceanalysis/bootstrap.rb +25 -21
- data/lib/statsample/factor.rb +18 -0
- data/lib/statsample/factor/pca.rb +128 -0
- data/lib/statsample/factor/principalaxis.rb +133 -0
- data/lib/statsample/factor/rotation.rb +125 -0
- data/lib/statsample/histogram.rb +99 -0
- data/lib/statsample/mle.rb +125 -126
- data/lib/statsample/mle/logit.rb +91 -91
- data/lib/statsample/mle/probit.rb +84 -85
- data/lib/statsample/multiset.rb +1 -1
- data/lib/statsample/permutation.rb +96 -0
- data/lib/statsample/regression.rb +1 -1
- data/lib/statsample/regression/binomial.rb +89 -89
- data/lib/statsample/regression/binomial/logit.rb +9 -9
- data/lib/statsample/regression/binomial/probit.rb +9 -9
- data/lib/statsample/regression/multiple.rb +8 -14
- data/lib/statsample/regression/multiple/gslengine.rb +1 -1
- data/lib/statsample/regression/multiple/rubyengine.rb +55 -55
- data/lib/statsample/resample.rb +12 -17
- data/lib/statsample/srs.rb +4 -1
- data/lib/statsample/test.rb +23 -22
- data/lib/statsample/test/umannwhitney.rb +182 -0
- data/lib/statsample/vector.rb +854 -815
- data/test/test_bivariate.rb +132 -132
- data/test/test_codification.rb +71 -50
- data/test/test_dataset.rb +19 -1
- data/test/test_factor.rb +44 -0
- data/test/test_histogram.rb +26 -0
- data/test/test_permutation.rb +37 -0
- data/test/test_statistics.rb +74 -63
- data/test/test_umannwhitney.rb +17 -0
- data/test/test_vector.rb +46 -30
- metadata +31 -4
@@ -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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
-
#
|
143
|
-
#
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
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
|
-
|
202
|
-
|
203
|
-
|
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
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
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
|
-
|
248
|
+
end
|
244
249
|
module GGobi
|
245
250
|
class << self
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
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
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
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
|
data/lib/statsample/crosstab.rb
CHANGED
@@ -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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
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
|
-
|
85
|
-
|
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
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
total
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
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
|