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