lib/statsample/factor/principalaxis.rb in statsample-0.13.1 vs lib/statsample/factor/principalaxis.rb in statsample-0.14.0
- old
+ new
@@ -27,44 +27,52 @@
# * Smith, L. (2002). A tutorial on Principal Component Analysis. Available on http://courses.eas.ualberta.ca/eas570/pca_tutorial.pdf
#
class PrincipalAxis
include DirtyMemoize
include Summarizable
- # Minimum difference between succesive iterations on sum of communalities
- DELTA=1e-3
- # Maximum number of iterations
- MAX_ITERATIONS=50
+ # Name of analysis
+ attr_accessor :name
+
# Number of factors. Set by default to the number of factors
- # with eigen values > 1 on PCA over data
+ # with eigenvalues > 1 (Kaiser criterion).
+ #
+ # _Warning:_ Kaiser criterion overfactors! Give yourself some time
+ # and use Horn's Parallel Analysis.
+ #
attr_accessor :m
- # Name of analysis
- attr_accessor :name
-
# Number of iterations required to converge
attr_reader :iterations
+
# Initial eigenvalues
attr_reader :initial_eigenvalues
- # Tolerance for iteratios.
+
+ # Tolerance for iterations
attr_accessor :epsilon
+
# Use SMC(squared multiple correlations) as diagonal. If false, use 1
attr_accessor :smc
+
# Maximum number of iterations
attr_accessor :max_iterations
+
# Eigenvalues of factor analysis
attr_reader :eigenvalues
+ # Minimum difference between succesive iterations on sum of communalities
+ DELTA=1e-3
+ # Maximum number of iterations
+ MAX_ITERATIONS=25
-
def initialize(matrix, opts=Hash.new)
@matrix=matrix
if @matrix.respond_to? :fields
@fields=@matrix.fields
else
@fields=@matrix.row_size.times.map {|i| _("Variable %d") % (i+1)}
end
-
+ @n_variables=@matrix.row_size
@name=""
@m=nil
@initial_eigenvalues=nil
@initial_communalities=nil
@component_matrix=nil
@@ -72,11 +80,15 @@
@smc=true
@max_iterations=MAX_ITERATIONS
opts.each{|k,v|
self.send("#{k}=",v) if self.respond_to? k
}
-
+ if @matrix.respond_to? :fields
+ @variables_names=@matrix.fields
+ else
+ @variables_names=@n_variables.times.map {|i| "V#{i+1}"}
+ end
if @m.nil?
pca=PCA.new(::Matrix.rows(@matrix.to_a))
@m=pca.m
end
@@ -117,11 +129,11 @@
work_matrix[it][it]=v
}
pca=PCA.new(::Matrix.rows(work_matrix))
@communalities=pca.communalities(m)
@eigenvalues=pca.eigenvalues
- com_sum=@communalities.inject(0) {|ac,v| ac+v}
+ com_sum = @communalities.inject(0) {|ac,v| ac+v}
jump=true
break if (com_sum-prev_sum).abs<@delta
@communalities.each_with_index do |v2,i2|
raise "Variable #{i2} with communality > 1" if v2>1.0
@@ -129,10 +141,15 @@
prev_sum=com_sum
prev_com=@communalities
end
@component_matrix=pca.component_matrix(m)
+ @component_matrix.extend CovariateMatrix
+ @component_matrix.name=_("Factor Matrix")
+ @component_matrix.fields_x = @variables_names
+ @component_matrix.fields_y = m.times.map {|i| "factor_#{i+1}"}
+
end
alias :compute :iterate
def initial_communalities
if @initial_communalities.nil?
@@ -180,21 +197,36 @@
s.table(:name=>_("Communalities"), :header=>[_("Variable"),_("Initial"),_("Extraction")]) do |t|
communalities(m).each_with_index {|com,i|
t.row([@fields[i], sprintf("%0.4f", initial_communalities[i]), sprintf("%0.3f", com)])
}
end
- s.table(:name=>_("Eigenvalues"), :header=>[_("Variable"),_("Value")]) do |t|
+ s.table(:name=>_("Total Variance"), :header=>[_("Factor"), _("I.E.Total"), _("I.E. %"), _("I.E.Cum. %"),
+ _("S.L.Total"), _("S.L. %"), _("S.L.Cum. %")
+ ]) do |t|
+ ac_eigen,ac_i_eigen=0,0
@initial_eigenvalues.each_with_index {|eigenvalue,i|
- t.row([@fields[i], sprintf("%0.3f",eigenvalue)])
+ ac_i_eigen+=eigenvalue
+ ac_eigen+=@eigenvalues[i]
+ new_row=[
+ _("Factor %d") % (i+1),
+ sprintf("%0.3f",eigenvalue),
+ sprintf("%0.3f%%", eigenvalue*100.quo(@n_variables)),
+ sprintf("%0.3f",ac_i_eigen*100.quo(@n_variables))
+ ]
+ if i<@m
+ new_row.concat [
+ sprintf("%0.3f", @eigenvalues[i]),
+ sprintf("%0.3f%%", @eigenvalues[i]*100.quo(@n_variables)),
+ sprintf("%0.3f",ac_eigen*100.quo(@n_variables))
+ ]
+ else
+ new_row.concat ["","",""]
+ end
+
+ t.row new_row
}
end
- s.table(:name=>_("Component Matrix"), :header=>["Variable"]+m.times.collect {|c| c+1}) do |t|
- i=0
- component_matrix(m).to_a.each do |row|
- t.row([@fields[i]]+row.collect {|c| sprintf("%0.3f",c)})
- i+=1
- end
- end
+ s.parse_element(component_matrix)
end
end
dirty_writer :max_iterations, :epsilon, :smc
dirty_memoize :eigenvalues, :iterations, :initial_eigenvalues