Class: Statsample::Factor::PrincipalAxis

Inherits:
Object
  • Object
show all
Includes:
GetText
Defined in:
lib/statsample/factor/principalaxis.rb

Overview

Principal Axis Analysis for a covariance or correlation matrix.

For PCA, use Statsample::Factor::PCA

Usage:

require 'statsample'
a=[2.5, 0.5, 2.2, 1.9, 3.1, 2.3, 2.0, 1.0, 1.5, 1.1].to_scale
b=[2.4,0.7,2.9,2.2,3.0,2.7,1.6,1.1,1.6,0.9].to_scale
ds={'a'=>a,'b'=>b}.to_dataset
cor_matrix=Statsample::Bivariate.correlation_matrix(ds)
pa=Statsample::Factor::PrincipalAxis.new(cor_matrix)
pa.iterate(1)
pa.m
=> 1
pca.component_matrix
=> GSL::Matrix
[  9.622e-01 
   9.622e-01 ]
pca.communalities
=> [0.962964636346122, 0.962964636346122]

References:

Constant Summary collapse

DELTA =

Minimum difference between succesive iterations on sum of communalities

1e-3
MAX_ITERATIONS =

Maximum number of iterations

50

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(matrix, opts = Hash.new) ⇒ PrincipalAxis



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/statsample/factor/principalaxis.rb', line 56

def initialize(matrix, opts=Hash.new)
  @matrix=matrix
  @name=""
  @m=nil
  @initial_eigenvalues=nil
  @initial_communalities=nil
  @component_matrix=nil
  @delta=DELTA
  @smc=true
  @max_iterations=MAX_ITERATIONS
  opts.each{|k,v|
    self.send("#{k}=",v) if self.respond_to? k
  }
  
  if @m.nil?
    pca=PCA.new(::Matrix.rows(@matrix.to_a))
    @m=pca.m
  end
  
  @clean=true
end

Instance Attribute Details

#eigenvaluesObject

Eigenvalues of factor analysis



54
55
56
# File 'lib/statsample/factor/principalaxis.rb', line 54

def eigenvalues
  @eigenvalues
end

#epsilonObject

Tolerance for iteratios.



48
49
50
# File 'lib/statsample/factor/principalaxis.rb', line 48

def epsilon
  @epsilon
end

#initial_eigenvaluesObject (readonly)

Initial eigenvalues



46
47
48
# File 'lib/statsample/factor/principalaxis.rb', line 46

def initial_eigenvalues
  @initial_eigenvalues
end

#iterationsObject (readonly)

Number of iterations required to converge



44
45
46
# File 'lib/statsample/factor/principalaxis.rb', line 44

def iterations
  @iterations
end

#mObject

Number of factors. Set by default to the number of factors with eigen values > 1 on PCA over data



38
39
40
# File 'lib/statsample/factor/principalaxis.rb', line 38

def m
  @m
end

#max_iterationsObject

Maximum number of iterations



52
53
54
# File 'lib/statsample/factor/principalaxis.rb', line 52

def max_iterations
  @max_iterations
end

#nameObject

Name of analysis



41
42
43
# File 'lib/statsample/factor/principalaxis.rb', line 41

def name
  @name
end

#smcObject

Use SMC(squared multiple correlations) as diagonal. If false, use 1



50
51
52
# File 'lib/statsample/factor/principalaxis.rb', line 50

def smc
  @smc
end

Class Method Details

.separate_matrices(matrix, y) ⇒ Object

Returns two matrixes from a correlation matrix with regressors correlation matrix and criteria xy matrix.



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/statsample/factor/principalaxis.rb', line 148

def self.separate_matrices(matrix, y)
  ac=[]
  matrix.column_size.times do |i|
    ac.push(matrix[y,i]) if i!=y
  end
  rxy=Matrix.columns([ac])
  rows=[]
  matrix.row_size.times do |i|
    if i!=y
      row=[]
      matrix.row_size.times do |j|
        row.push(matrix[i,j]) if j!=y
      end
      rows.push(row)
    end
  end
  rxx=Matrix.rows(rows)
  [rxx,rxy]
end

Instance Method Details

#communalities(m = nil) ⇒ Object

Communality for all variables given m factors



78
79
80
81
82
83
84
# File 'lib/statsample/factor/principalaxis.rb', line 78

def communalities(m=nil)
  if m!=@m or @clean
    iterate(m)
    raise "Can't calculate comunality" if @communalities.nil?
  end
  @communalities
end

#component_matrix(m = nil) ⇒ Object

Component matrix for m factors



86
87
88
89
90
91
# File 'lib/statsample/factor/principalaxis.rb', line 86

def component_matrix(m=nil)
  if m!=@m  or @clean
    iterate(m)
  end
  @component_matrix
end

#initial_communalitiesObject



129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/statsample/factor/principalaxis.rb', line 129

def initial_communalities
  if @initial_communalities.nil?
    if @smc
    @initial_communalities=@matrix.column_size.times.collect {|i|
      rxx , rxy = PrincipalAxis.separate_matrices(@matrix,i)
      matrix=(rxy.t*rxx.inverse*rxy)
      matrix[0,0]
    }
    else
      @initial_communalities=[1.0]*@matrix.column_size
    end
  end      
  @initial_communalities
end

#iterate(m = nil) ⇒ Object

Iterate to find the factors



93
94
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
# File 'lib/statsample/factor/principalaxis.rb', line 93

def iterate(m=nil)
  @clean=false
  m||=@m
  @m=m
  t = @max_iterations
  work_matrix=@matrix.to_a
  
  prev_com=initial_communalities
  
  pca=PCA.new(::Matrix.rows(work_matrix))
  @initial_eigenvalues=pca.eigenvalues
  prev_sum=prev_com.inject(0) {|ac,v| ac+v}
  @iterations=0
  t.times do |i|
    @iterations+=1
    prev_com.each_with_index{|v,it|
      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}
    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
    end
    prev_sum=com_sum
    prev_com=@communalities
    
  end
  @component_matrix=pca.component_matrix(m)
end

#report_building(generator) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/statsample/factor/principalaxis.rb', line 172

def report_building(generator)
  iterate if @clean
  anchor=generator.toc_entry(_("Factor Analysis: ")+name)
  generator.html "<div class='pca'>"+_("Factor Analysis")+" #{@name}<a name='#{anchor}'></a>"
 
  generator.text "Number of factors: #{m}"
  generator.text "Iterations: #{@iterations}"
  
  t=ReportBuilder::Table.new(:name=>_("Communalities"), :header=>["Variable","Initial","Extraction"])
  communalities(m).each_with_index {|com,i|
    t.row([i, sprintf("%0.4f", initial_communalities[i]), sprintf("%0.3f", com)])
  }
  generator.parse_element(t)
  
  t=ReportBuilder::Table.new(:name=>_("Eigenvalues"), :header=>["Variable","Value"])
  @initial_eigenvalues.each_with_index {|eigenvalue,i|
    t.row([i, sprintf("%0.3f",eigenvalue)])
  }
  generator.parse_element(t)
  
  t=ReportBuilder::Table.new(:name=>_("Component Matrix"), :header=>["Variable"]+m.times.collect {|c| c+1})
  
  i=0
  component_matrix(m).to_a.each do |row|
    t.row([i]+row.collect {|c| sprintf("%0.3f",c)})
    i+=1
  end
  generator.parse_element(t)
  generator.html("</div>")
end

#summaryObject



167
168
169
170
171
# File 'lib/statsample/factor/principalaxis.rb', line 167

def summary
  rp=ReportBuilder.new()
  rp.add(self)
  rp.to_text
end