ExamplesOfGNNR {lazy.mat} | R Documentation |
Examples of GN and NR
Description
Examples of GN and NR in the context of Logistic Regression. Multidimensional Scaling, Factor Analysis and PCA.
Examples
## Not run:
#
# For comparison reason, the following package is required:
library(nlsr)
#
#####################################################################
#
# ML and Bayes MAP Estimation of Logistic Regression Parameters
# by Newton-Raphson Method
#
#####################################################################
#
# probability (logistic function with matrix X, no 1.7)
# X is the regressor matrix, beta is the regression coefficient vector
# Returns a vector of length nrow(X).
Prob <- function( beta, X ){
if( is.matrix(X) | is.data.frame(X) ) z=X%*%beta
else z=X*beta
P=1/(1+exp(-z))
return( P )
} # end of P
#
#
#
# This is the objective function to be minimized:
# Minus log likelihood
# parameter beta is the first argument and the second argument data
# will be passed to this via ... parameter.
# Returns a scalar.
#
mllh <- function( beta, data ){
# minus log likelihood: multiple regressor matrix X
locx=which(regexpr("x",colnames(data)) > 0)
X=as.matrix(data[,locx]); f=data$f; r=data$r
p=Prob(beta,X)
llh=sum( r*log(p)+(f-r)*log(1-p) )
return( -llh )
} # end of mllh
#
#
# First derivative of mllh wrt beta.
# parameter beta is the first argument and the second argument data
# will be passed to this via ... parameter.
# Returns a vector of size length(beta).
#
dmllh_a <- function( beta, data ){
# analytic first derivative of mllh: multiple regressor matrix X
locx=which(regexpr("x",colnames(data)) > 0)
X=as.matrix(data[,locx]); f=data$f; r=data$r
p=Prob(beta,X)
dab=colSums(c(r-f*p)*X)
# cat(".da.")
return( -dab )
} # end of dmllh_a
#
#
dmllh_n <- function( beta, data, mllh=NULL ){
# numeric first derivative of mllh: multiple regressor matrix X
# Not Used.
res=JacobianMat( beta, mllh, data=data)
return( res )
} # end of dmllh_n
#
#
#
# Second derivative of mllh wrt beta.
# parameter beta is the first argument and the second argument data
# will be passed to this via ... parameter.
# Returns a square matrix of size length(beta).
#
d2mllh_nn <- function( param, data, mllh=NULL ){
# numeric second derivative matrix using numeric first derivative of mllh
# dmllh_n comes from the parent environment
# Not Used.
res=JacobianMat( param, dmllh_n, data=data, mllh=mllh )
# cat(".d2an.")
return( res )
} # end of d2mllh_nn
#
#
d2mllh_an <- function( param, data ){
# numeric second derivative matrix using analytic first derivative of mllh
# dmllh_a comes from the parent environment
# Not Used.
res=JacobianMat( param, dmllh_a, data=data )
# cat(".d2an.")
return( res )
} # end of d2mllh_an
#
#
d2mllh_aa <- function( param, data ){
# analytic second derivative matrix of mllh
# not yet available
locx=which(regexpr("x",colnames(data)) > 0)
X=as.matrix(data[,locx]); f=data$f; r=data$r
p=Prob(param,X)
dPdbetaa=c(p*(1-p))*X
H=t(f*X)%*%dPdbetaa
return(H)
} # end of d2mllh_aa
#
#
#
#
#
#
# generate data
#
#
# seed for random numbers
seed=1701
set.seed(seed)
#
# true value of beta
beta=c(-1,2,3)
# # of parameters = # of regressors = # of columns of X including intercept.
nq=length(beta)
#
# # of trials per obs
ff=c(1,2,3) # will be recycled.
# ff=1
#
# generate regressor matrix X
n=50
#
# regressor matrix as 1 and normal random variable
X=cbind(1, matrix(rnorm(n*(nq-1)),n,nq-1) )
colnames(X)=paste("x",(1:nq)-1,sep="")
#
# true response probability
p=Prob(beta,X)
#
# generate f=# of trials, r=# of successes, y=sample proportion
f=sample( ff, n, rep=1 )
r=mapply( function(size,prob) rbinom(1,size,prob) , f, p )
y=r/f
#
# data frame
data=data.frame( id=1:n, X, f, r, y, p )
print(data)
#
# initial value
# beta0=c(0,1,1)
beta0=rev(beta)
#
#
#
# Estimation Starts Here.
#
#
#
# Arguments to nlminb or NR
#
# First "beta0" argument is the starting value of the parameter.
# Second argument "mllh" is the objective function to be minimized
# which must have "beta0" as its first argument.
# The additional argument to this function can be passed through ... .
# or, the objects in the environment in which the objective function
# "mllh" is defined can be accessed from within the objective function.
# In the example below, data, which contains f and r,
# is passed to "mllh" via ... argument of nlminb or NR.
#
# Note that, unlike nlm or nlfb which require the gradient to be returned
# as an attribute "gradient" of the function value,
# nlminb or NR uses the gradient or hessian functions which return
# the gradient or hessian as their values.
#
#
# mle by native nlminb
# no analytic gradient and hessian
# Ones like dmllh_n or d2mllh_nn must be used in nlminb.
resnlminb=nlminb( beta0, mllh, data=data, control=list(trace=0) )
# with analytic gradient
resnlminb2=nlminb( beta0, mllh, data=data, control=list(trace=0)
, gradient=dmllh_a )
# with analytic gradient and Hessian
resnlminb3=nlminb( beta0, mllh, data=data, control=list(trace=0)
, gradient=dmllh_a, hessian=d2mllh_aa )
#
#
# solution by NR
# no analytic gradient and hessian
# Functions similar to dmllh_n or d2mllh_nn will be created by in NR.
resNR=NR( x=beta0, mllh, data=data, print=2 )
# with analytic gradient
resNR2=NR( x=beta0, mllh, data=data, gradient=dmllh_a, print=2 )
# with analytic gradient and Hessian
resNR3=NR( x=beta0, mllh, data=data, gradient=dmllh_a, hessian=d2mllh_aa
, print=2 )
#
#
# comparison of results
p1=resnlminb$par; p2=resnlminb2$par; p3=resnlminb3$par
pNR1=resNR$par; pNR2=resNR2$par; pNR3=resNR3$par
cat("\n\nComparizon of the Results: Parameters\n")
Print(p1,p2,p3)
Print(pNR1,pNR2,pNR3)
#
# comparison of gradient
g1=dmllh_a( p1, data ); g2=dmllh_a( p2, data ); g3=dmllh_a( p3, data )
gNR1=dmllh_a( pNR1, data ); gNR2=dmllh_a( pNR2, data )
gNR3=dmllh_a( pNR3, data )
cat("\n\nComparison of the Results: Gradients\n")
Print(g1,g2,g3)
Print(gNR1,gNR2,gNR3)
#
#
#
#
#
# Bayes MAP
#
#
# prior
#
# The prior distribution of beta is N(mu, inv(invSigma)), where
# mu is the prior mean vector and invSigma is the prior dispersion matrix.
#
# In addition to data which contains (r,f), mu and invSigma will be
# passed to the objective function "mlogpostpdf" via ... argument
# of NR or nlminb.
#
#
logpriorpdf <- function( beta, mu, invSigma ){
# logarithm of multivariate normal pdf (constant terms omitted)
lpdf=-0.5*c(beta-mu)%*%invSigma%*%c(beta-mu) + 0.5*det(invSigma)
return(lpdf)
} # logpriorpdf
#
# popsterior pdf is proportional to the likelihood x prior pdf
mlogpostpdf <- function( beta, data, mu, invSigma ){
# minus log posterior density
# log post pdf of beta is log likelihood + log prior pdf
lppdf= -mllh( beta, data ) + logpriorpdf( beta, mu, invSigma )
return( -lppdf )
} # end of mlogpostpdf
#
#
#
# prior constant (hyper parameters) vague prior N(0,100 I)
mu=rep(0,length(beta0)); invSigma=0.01*diag(length(beta0))
#
# MAP estimates
resNR4=NR( x=beta0, mlogpostpdf, data=data, mu=mu, invSigma=invSigma )
pNR4=resNR4$par;
resnlminb4=nlminb( beta0, mlogpostpdf, data=data, mu=mu, invSigma=invSigma
, control=list(trace=0) )
p4=resnlminb4$par
#
# evaluate the final gradient numerically
gNR4=JacobianMat( pNR4, mlogpostpdf, data=data, mu=mu, invSigma=invSigma )
g4=JacobianMat( p4, mlogpostpdf, data=data, mu=mu, invSigma=invSigma )
#
#
# prior constant (hyper parameters) sharp prior N(0,I)
mu=rep(0,length(beta0)); invSigma=diag(length(beta0))
#
# MAP estimates
resNR5=NR( x=beta0, mlogpostpdf, data=data, mu=mu, invSigma=invSigma )
pNR5=resNR5$par
resnlminb5=nlminb( beta0, mlogpostpdf, data=data, mu=mu, invSigma=invSigma
, control=list(trace=0) )
p5=resnlminb5$par
#
# evaluate the final gradient numerically
gNR5=JacobianMat( pNR5, mlogpostpdf, data=data, mu=mu, invSigma=invSigma )
g5=JacobianMat( p5, mlogpostpdf, data=data, mu=mu, invSigma=invSigma )
#
cat("\n\nComparison\n")
Print(p1,p4,p5)
Print(pNR1,pNR4,pNR5)
Print(gNR4,g4,gNR5,g5)
#
#
#####################################################################
#
# End of
# ML and Bayes MAP Estimation of Logistic Regression Parameters
# by Newton-Raphson Method
#
#####################################################################
#
#
#
#
#
#
#
#
#
#####################################################################
#
# Multidimensional Scaling
#
#####################################################################
#
#
residmds <- function( vecX ){
# residual of metric mds: vech(O-D)
# Shin-ichi Mayeakawa
# 20210713,20220713,14,22
#
# Note that ns, O, and locLH come from the environment where
# this function was defined.
#
# convert vecX to matrix X
X=matrix(vecX,ns)
#
# Euclidean distance
XX=rowSums(X*X)
XX11=XX%*%matrix(1,1,ns)
D=sqrt( abs( XX11-2*X%*%t(X)+t(XX11) ) )
#
# lower half of O-D
resid=c( (O-D)[locLH] )
#
return( resid )
#
} # end of residmds
#
#
residmds2 <- function( vecX ){
# residual of metric mds: vech(D-O) to be used by nlfb
# Shin-ichi Mayeakawa
# 20210713,20220713,14,22
#
return( -residmds( vecX ) )
} # end of residmds2
#
#
rssmds <- function( vecX ){
# residual of metric mds: ssq(vech(O-D))
# Shin-ichi Mayeakawa
# 20210713,20220713,14,22
#
return( sum( residmds(vecX)^2 ) )
} # end of rssmds
#
#
Jacmds <- function( vecX ){
# Numeric Jacobian of vech(O-D), i.e. -vech(D)
# Shin-ichi Mayeakawa
# 20210713,20220713,14,22
F=JacobianMat( vecX, residmds )
return( F )
} # end of gradmds
#
#
Jacmds_a <- function( vecX ){
# Analytic Jacobian of vech(D)
# Shin-ichi Mayeakawa
# 20220723
# convert vecX to matrix X
X=matrix(vecX,ns)
# Euclidean distance
XX=rowSums(X*X)
XX11=XX%*%matrix(1,1,ns)
D=sqrt( abs( XX11-2*X%*%t(X)+t(XX11) ) )
vecD=D[locLH]
#
# This is the Jacobian of vech(D) wrt vec(X)
F=matrix(0,npair,ns*ndim)
#
if(0){
k=0
for( i in 2:ns ){
for( j in 1:(i-1) ){
k=k+1
for( a in 1:ndim ){
F[k,(a-1)*ns+i]=(X[i,a]-X[j,a])/D[i,j]
F[k,(a-1)*ns+j]=-(X[i,a]-X[j,a])/D[i,j]
}
}
}
} # en of skip
#
GX=G%*%X
for( k in 1:npair ){
for( a in 1:ndim ){
ximxja=GX[k,a]
F[k,(a-1)*ns+locvLH[k,1]]=ximxja/vecD[k]
F[k,(a-1)*ns+locvLH[k,2]]=-ximxja/vecD[k]
}
}
#
return( F )
#
} # end of Jacmds_a
#
#
HessQmds_a <- function( vecX ){
# approximate Hessian calculated from analytic Jacobian of vech(D)
# Shin-ichi Mayeakawa
# 20220722,23
F=Jacmds_a( vecX )
H=t(F)%*%F
H=H + 0.01*min(abs(diag(H)))*diag(nrow(H))
return( 2*H )
} # end of HessQmds_a
#
#
gradmds <- function( vecX ){
# numeric gradient of rssmds
# Shin-ichi Mayeakawa
# 20210713,20220713,14,22,23
res=JacobianMat( vecX, rssmds )
return( res )
} # end of gradmds
#
#
gradmds_a <- function( vecX ){
# analytic gradient of rssmds
# Shin-ichi Mayeakawa
# 20220723
res=c( -2*residmds(vecX)%*%Jacmds_a(vecX) )
return( res )
} # end of gradmds_a
#
#
normalizemds <- function( vecX ){
# normalize X in each of GN/NR iteration
# Shin-ichi Mayekawa
# 20220723
#
# convert vecX to matrix X
X=matrix(vecX,ns)
# column center X
return( c( normalize_config(X,center=1) ))
} # end of normalizemds
#
#
#
#
# generate test data
#
# X=as.matrix( expand.grid(-3:3, -3:3) )
X=as.matrix( expand.grid(-2:2, -2:2) )
# X=as.matrix( expand.grid(-1:1,-1:1) )
ns=nrow(X); ndim=ncol(X)
sname=paste("s",1:ns,sep="")
#
set.seed(1701)
sigmaE=0.5
XX=rowSums(X*X)
XX11=XX%*%matrix(1,1,ns)
D=sqrt( abs( XX11-2*X%*%t(X)+t(XX11) ) )
O=D+sigmaE*rnorm(ns*ns)
O=round( 0.5*(O+t(O))-diag(diag(O)), 2 )
locLH=lower.tri(O, diag=FALSE)
npair=sum(locLH)
# locvLH=vechindex(ns,1,0,type=2)
locvLH=cbind(row(O)[locLH],col(O)[locLH])
# G matrix for paired comparison
G=matrix(0,npair,ns)
for( k in 1:npair ){
G[k,locvLH[k,1]]=1; G[k,locvLH[k,2]]=-1
}
#
#
#
# # of dimensions
ndim=2
#
#
# initial by classic mds
J=diag(ns)-matrix(1,ns,ns)/ns
B=-0.5*J%*%O^2%*%J
ev=eigen(B)
P=ev$vectors[,1:ndim]
L=diag(ev$values[1:ndim])
Xcmds=P%*%sqrt(L)
#
X0=Xcmds
rss0=rssmds( c(X0) )
g0=gradmds( c(X0) )
title=paste("CMDS: rss =", round(rss0,3))
plot(X0, main=title)
text( X0, sname, pos=4 )
#
#
#
# Gauss-Newton
#
# by nlfb
resnlfb=nlfb(c(X0),residmds2, control=list(femax=1000,japprox="jacentral"))
X1=matrix(resnlfb$coefficients,ns)
rss1=rssmds( c(X1) )
g1=gradmds( c(X1) )
title=paste("GN by nlfb: rss =", round(rss1,3))
plot(X1, main=title)
text( X1, sname, pos=4 )
#
#
# by GN
resGN=GN( c(X0), residmds, maxiter=100, normalize=normalizemds )
X2=matrix(resGN$par,ns)
rss2=rssmds( c(X2) )
g2=gradmds( c(X2) )
title=paste("GN by GN: rss =", round(rss2,3))
plot(X2, main=title)
text( X2, sname, pos=4 )
#
#
# by GN with analytic gradient
resGN2=GN( c(X0), residmds, maxiter=100, normalize=normalizemds
, jacobian=Jacmds_a )
X21=matrix(resGN2$par,ns)
rss21=rssmds( c(X21) )
g21=gradmds( c(X21) )
title=paste("GN by GN with analytic gradient: rss =", round(rss2,3))
plot(X21, main=title)
text( X21, sname, pos=4 )
#
Print(rss0,rss1,rss2, rss21)
#
#
#
#
# Newton-Raphson
#
# by nlminb
resnlminb=nlminb( c(X0), rssmds, control=list(trace=0) )
X3=matrix(resnlminb$par,ns)
rss3=rssmds( c(X3) )
g3=gradmds( c(X3) )
title=paste("NR by nlminb: rss =", round(rss3,3))
plot(X3, main=title)
text( X3, sname, pos=4 )
#
#
# by NR
resNR=NR( c(X0), rssmds, maxiter=1000, flipd=1, normalize=normalizemds )
X4=matrix(resNR$par,ns)
rss4=rssmds( c(X4) )
g4=gradmds( c(X4) )
title=paste("NR by NR: rss =", round(rss4,3))
plot(X4, main=title)
text( X4, sname, pos=4 )
#
Print(rss0, rss1, rss2, rss3, rss4)
#
#
# by NR by supplying analytic gradient and quasi Hessian.
resNR2=NR( c(X0), rssmds, maxiter=1000, flipd=1
, normalize=normalizemds, grad=gradmds_a, hessian=HessQmds_a )
#
#
X41=matrix(resNR2$par,ns)
rss41=rssmds( c(X41) )
g41=gradmds( c(X41) )
title=paste("NR by NR with quasi H: rss =", round(rss41,3))
plot(X41, main=title)
text( X41, sname, pos=4 )
#
Print(rss1, rss2, rss3, rss4, rss41)
#
#
#
#
if(0){
#
library(lazy.mds)
#
# wmdsGN
resmds=wmdsGN( O, ndim=2, mlevel=9, maxiter=1000, print=1 )
Xw=resmds$X
rssw=rssmds( c(Xw) )
gw=gradmds( c(Xw) )
title=paste("GV by wmdsGN: rss =", round(rssw,3))
plot(Xw, main=title)
text( Xw, sname, pos=4 )
#
Print(rss0, rss1, rss2, rss3, rss4, rssw)
#
Print(max(abs(g0)), max(abs(g1)),max(abs(g2))
,max(abs(g3)),max(abs(g4)),max(abs(gw)))
#
#
}
#
#
#
#####################################################################
#
# End of Multidimensional Scaling
#
#####################################################################
#
#
#
#
#
#
#
#
#
#####################################################################
#
# Factor Analysis
#
#####################################################################
#
#
#
critfa <- function( param, logpsi=0, method="ML", LH=0 ){
# evaluation of ML or LS criterion function: param=c( c(Lambda), psi )
# Shin-ichi Mayekawa
# 20210705,20220723
# uselogpsiasparam -> logpsi: 20220728
#
# S, logdets, ndim and nvar are from the parent env.
#
#
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
if( logpsi ) psi=exp(psi)
Sigma=Lambda%*%Phi%*%t(Lambda)+diag(psi)
#
if( method == "ML" ){
invSigma=solve(Sigma)
crit=tr(S%*%invSigma)+log(det(Sigma)) - logdetS - nvar
}
else{
if( LH == 1 ) crit=sum((S-Sigma)[locLH]^2)
else crit=sum((S-Sigma)^2)
}
#
return( crit )
#
} # end of critfa
#
#
#
#
critfapsi <- function( psi, logpsi=0, method="ML", LH=0 ){
# evaluation of ML or LS criterion function: param=psi
# Shin-ichi Mayekawa
# 20210707
# uselogpsiasparam -> logpsi: 20220728
#
# S, logdets, ndim and nvar are from the parent env.
#
#
# psi or log(psi)
# If the parameter is log(psi), recover original as exp(log(psi)).
if( logpsi ) psi=exp(psi)
#
psi=c(psi)
#
if( method == "ML" ){
# conditional MLE of Lambda given psi
Psimh=diag(1/sqrt(psi))
ev=eigen( Psimh%*%S%*%Psimh )
P=ev$vectors[,1:ndim]
D=ev$values[1:ndim]
Lambda=sqrt(psi)*P%*%diag(sqrt(D-1), nrow=ndim)%*%invPhimh
# log likelihood ratio stat
Sigma=Lambda%*%t(Lambda)+diag(psi)
invSigma=solve(Sigma)
crit=tr(S%*%invSigma)+log(det(Sigma)) - logdetS - nvar
}
else{
# conditional LSE of Lambda given psi
ev=eigen( S-diag(psi) )
P=ev$vectors[,1:ndim]
Gamma=ev$values[1:ndim]
Lambda=P%*%diag(sqrt(Gamma))
# rss
Sigma=Lambda%*%t(Lambda)+diag(psi)
if( LH == 1 ) crit=sum((S-Sigma)[locLH]^2)
else crit=sum((S-Sigma)^2)
}
#
return( crit )
#
} # end of critfapsi
#
#
#
#
gradfa_a <- function( param, logpsi=0, method="ML", LH=0 ){
# analytic gradient of LS or ML critfa wrt param=c(c(Lambda,psi)
# Shin-ichi Mayekawa
# 20220724,25
# avoid Jacfa_a: 20220726dnc
# correction for rss_LH: 20220726dnc,0728
# uselogpsiasparam -> logpsi: 20220728
#
#
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
if( logpsi ) psi=exp(psi)
Sigma=Lambda%*%Phi%*%t(Lambda)+diag(psi)
#
if( method == "LS" ){
SS=S-Sigma
# dLambda=0.5*(-4*diag(diag(SS))%*%Lambda -4*SS%*%Lambda )
if( LH == 0 ) dLambda=-4*SS%*%Lambda%*%Phi
else dLambda=-2*((diag(diag(SS))+SS)%*%Lambda%*%Phi )
dpsi=-2*diag(SS)
if( logpsi == 1 ) dpsi=dpsi*psi
g=c( c(dLambda), dpsi )
}
else{
invSigma=matSwp(Sigma)
iSSmSiS=invSigma%*%(Sigma-S)%*%invSigma
dLambda=2*iSSmSiS%*%Lambda%*%Phi
dpsi=diag(iSSmSiS)
if( logpsi == 1 ) dpsi=dpsi*psi
g=c(c(dLambda),dpsi)
}
#
return( g )
#
} # gradfa_a
#
#
gradfa <- function( param, logpsi=0, method="ML" ){
# numerical gradient of LS or ML critfa wrt param=c(c(Lambda,psi)
# Shin-ichi Mayekawa
# 20220724,25
# uselogpsiasparam -> logpsi: 20220728
#
return( JacobianMat( param, critfa, method=method
, logpsi=logpsi ) )
} # end of gradfa
#
#
#
HessQfa_a <- function( param, logpsi=0, method="LS", LH=0 ){
# analytic quasi Hessian of LS or ML critfa wrt param=c(c(Lambda,psi)
# Shin-ichi Mayekawa
# 20220725
# LH: 20220728
# uselogpsiasparam -> logpsi: 20220728
#
if( method == "ML" ){
cat("\nerror(HessQfa) This is for method=LS only.\n")
stop()
}
F=Jacfa_a( param, logpsi=logpsi, LH=LH )
H=t(F)%*%F
H=H + 0.01*min(abs(diag(H)))*diag(nrow(H))
return( 2*H )
} # end of HessQfa_a
#
#
#
gradfapsi <- function( psiorlogpsi, logpsi=0, method="ML" ){
# numerical gradient of LS or ML critfa wrt param=c(c(Lambda,psi)
# Shin-ichi Mayekawa
# 20220726
# uselogpsiasparam -> logpsi: 20220728
#
# This works with LH=0 and LH=1
#
return( JacobianMat( psiorlogpsi, critfapsi, method=method
, logpsi=logpsi ) )
} # end of gradfapsi
#
#
gradfapsi_a <- function( psiorlogpsi, logpsi=0, method="ML" ){
# analytic gradient of LS or ML critfapsi wrt param=psi or log(psi)
# Shin-ichi Mayekawa
# 20220726
# uselogpsiasparam -> logpsi: 20220728
#
# This is for LH=0
#
#
# psi or log(psi)
# If the parameter is log(psi), recover original as exp(log(psi)).
if( logpsi ) psi=exp(psiorlogpsi)
else psi=psiorlogpsi
psi=c(psi)
#
if( method == "ML" ){
# conditional MLE of Lambda given psi
Psimh=diag(1/sqrt(psi))
ev=eigen( Psimh%*%S%*%Psimh )
Omega2=ev$vectors[,(ndim+1):nvar]^2
theta=ev$values[(ndim+1):nvar]
o2t=Omega2%*%diag(1-theta)
g=c( rowSums(o2t)/psi )
if( logpsi == 1 ) g=g*psi
}
else{
# conditional LSE of Lambda given psi
ev=eigen( S-diag(psi) )
P2=ev$vectors[,(ndim+1):nvar]^2
gamma=ev$values[(ndim+1):nvar]
g=c(-2*rowSums(P2%*%diag(gamma)) )
# above is correct if rss=ssq(S-Sigma), not if rss=ssq((S-Sigma)[locLH])
if( logpsi == 1 ) g=g*psi
}
#
return(g)
#
} # end of gradfapsi_a
#
#
#
#
#
#
residfa <- function( param, logpsi=0 ){
# residual of LS fa vec(S-Sigma)
# Shin-ichi Mayekawa
# 20220728
# uselogpsiasparam -> logpsi: 20220728
#
#
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
if( logpsi ) psi=exp(psi)
Sigma=Lambda%*%Phi%*%t(Lambda)+diag(psi)
#
return( c(S-Sigma) )
#
} # end of residfa
#
#
residfa2 <- function( param, logpsi=0 ){
# residual of LS fa vec(Sigma-S)
# Shin-ichi Mayekawa
# 20220728
# uselogpsiasparam -> logpsi: 20220728
#
#
return( -residfa( param, logpsi=logpsi ) )
#
} # end of residfa2
#
#
#
Jacfa_a <- function( param, logpsi=0, LH=0 ){
# analytic Jacobian of vech(Sigma) or vec(Sigma) wrt param=c(c(Lambda,psi)
# Shin-ichi Mayekawa
# 20220724,25
# LH=0: 20220728
# uselogpsiasparam -> logpsi: 20220728
#
#
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
if( logpsi ) psi=exp(psi)
Sigma=Lambda%*%Phi%*%t(Lambda)+diag(psi)
#
#
if( LH == 1 ){
npair=nvar*(nvar-1)/2
# First, calculate d vec(Sigma) / d vec(Lambda')
F=matrix(0,npair,nvar*ndim+nvar)
#
for( k in 1:npair ){
i=locvLH[k,1]; j=locvLH[k,2]
if( i == j ){
F[k,ndim*(i-1)+(1:ndim)]=2*Lambda[i,]
if( logpsi == 0 ) F[k,ndim*nvar+i]=1
else F[k,ndim*nvar+i]=psi[i]
}
else{
F[k,ndim*(i-1)+(1:ndim)]=Lambda[j,]
F[k,ndim*(j-1)+(1:ndim)]=Lambda[i,]
}
}
} # end of LH
else{
npair=nvar*nvar
# First, calculate d vec(Sigma) / d vec(Lambda')
F=matrix(0,npair,nvar*ndim+nvar)
#
for( k in 1:npair ){
# col-major rollout
j=trunc((k-1)/nvar)+1; i=((k-1)%%nvar)+1
if( i == j ){
F[k,ndim*(i-1)+(1:ndim)]=2*Lambda[i,]
if( logpsi == 0 ) F[k,ndim*nvar+i]=1
else F[k,ndim*nvar+i]=psi[i]
}
else{
F[k,ndim*(i-1)+(1:ndim)]=Lambda[j,]
F[k,ndim*(j-1)+(1:ndim)]=Lambda[i,]
}
}
} # end of LH!=0
#
# F0=matrix(as.numeric(abs(F)>0),npair)
#
# swap the columns
# d vec(S) / d vec(Lambda') -> d vec(S) / d vec(Lambda)
# od=c(t(matrix(1:(nvar*ndim),ndim,nvar)))]
od=matindex(ndim,nvar, type=1, byrow=1)
F[,1:(nvar*ndim)]=F[,od]
#
# F1=matrix(as.numeric(abs(F)>0),npair)
#
return( F )
#
} # end of Jacfa_a
#
#
#
Jacfa_aa <- function( param, logpsi=0, LH=0 ){
# returns analytic Jacobian of vec(S-Sigma) as gradient attribute
# Shin-ichi Mayekawa
# 20220728
# uselogpsiasparam -> logpsi: 20220728
#
res=Jacfa_a( param, logpsi=logpsi, LH=LH )
res0=0
attributes(res0)$gradient=res
return( res0 )
} # end of Jacfa_aa
#
#
gradfa_Ja <- function( param, logpsi=0, method="ML", LH=0 ){
# analytic gradient of LS or ML critfa wrt param=c(c(Lambda,psi)
# If method="LS" Jacfa_a is used.
# Shin-ichi Mayekawa
# 20220724,25
# LH: 20220728
# uselogpsiasparam -> logpsi: 20220728
# Should be the same as gradfa_a
#
#
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
if( logpsi ) psi=exp(psi)
Sigma=Lambda%*%Phi%*%t(Lambda)+diag(psi)
#
if( method == "LS" ){
# by Jacobian: applicable for vec(S) and vech(S)
F=Jacfa_a( param, logpsi=logpsi, LH=LH )
# gradient
g=c( -2*t(F)%*%(S-Sigma)[locLH] )
}
else{
invSigma=matSwp(Sigma)
iSSmSiS=invSigma%*%(Sigma-S)%*%invSigma
dLambda=2*iSSmSiS%*%Lambda%*%Phi
dpsi=diag(iSSmSiS)
if( logpsi == 1 ) dpsi=dpsi*psi
g=c(c(dLambda),dpsi)
}
#
return( g )
#
} # gradfa_Ja
#
#
#
#
#
#
#
#
# generate data
seed <- 1701
set.seed(seed)
#
nvar <- 20; ndim0 <- 3
ps <- 0.2
df <- 500
#
A <- matrix(runif(nvar*ndim0),nvar)
Sigma <- A%*%t(A)
Sigma <- Sigma+ps*diag(nvar)
dS <- sqrt(diag(Sigma))
Sigma <- diag(1/dS)%*%Sigma%*%diag(1/dS)
#
# correlation matrix from Wishart random matrix
S <- rWishart( 1, df, Sigma )
S <- S[,,1]/df
dS <- sqrt(diag(S))
S <- diag(1/dS)%*%S%*%diag(1/dS)
#
# const to be used later
#
# log determinant of S
logdetS=log(det(S))
#
# lower half of S: NOT used.
locLH=lower.tri(S,diag=TRUE)
# vecS=S[locLH]
npair=sum(locLH)
locvLH=cbind(row(S)[locLH],col(S)[locLH])
#
#
#
# # of dimensions to be used
ndim=2
#
#
#
# initial values by pca
ev=eigen( S )
Lambda0=ev$vectors[,1:ndim]%*%diag(sqrt(ev$values[1:ndim]), nrow=ndim)
psi0=pmax(0.001, diag(S-Lambda0%*%t(Lambda0)) )
#
# factor correlation matrix (constant)
Phi=diag(ndim)
invPhi=diag(ndim)
invPhimh=diag(ndim)
#
#
# initial value
param0=c(c(Lambda0),psi0)
param00=c(c(Lambda0),log(psi0))
#
#
#
#
#
# Maximum Likelihood Solution
#
#
#
#
#
#
# ML fa by nlminb: param=c( c(Lambda),psi )
resnlminb=nlminb( param0, critfa, control=list(trace=0)
, lower=1e-3, upper=1-1e-3 )
critnlminb=resnlminb$objective
param=resnlminb$par
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
Print(critnlminb)
#
# ML fa by nlminb with analytic gradient: param=c( c(Lambda),psi )
resnlminb=nlminb( param0, critfa, control=list(trace=0)
, lower=1e-3, upper=1-1e-3, gradient=gradfa_a )
critnlminb=resnlminb$objective
param=resnlminb$par
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
Print(critnlminb)
#
#
# ML fa by NR: param=c( c(Lambda),psi )
resNR=NR( param0, critfa, logpsi=0, maxiter=50, flipd=1 )
critNR=resNR$objective
param=resNR$par
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
Print(critnlminb,critNR)
#
# ML fa by NR with analytic gradient: param=c( c(Lambda),psi )
resNR=NR( param0, critfa, logpsi=0, maxiter=50, flipd=1
, gradient=gradfa_a)
critNR=resNR$objective
param=resNR$par
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
Print(critnlminb,critNR)
#
#
#
#
# ML fa by nlminb: param=c( c(Lambda),log(psi) )
resnlminb=nlminb( param00, critfa, control=list(trace=0)
, logpsi=1 )
critnlminb=resnlminb$objective
param=resnlminb$par
LambdaML=matrix(param[1:(nvar*ndim)],nvar)
psiML=exp( param[-(1:(nvar*ndim))] )
Print(critnlminb)
#
# ML fa by nlminb with analytic gradient: param=c(c(Lambda),log(psi))
resnlminb=nlminb( param00, critfa, control=list(trace=0)
, logpsi=1, gradient=gradfa_a )
critnlminb=resnlminb$objective
param=resnlminb$par
LambdaML=matrix(param[1:(nvar*ndim)],nvar)
psiML=exp( param[-(1:(nvar*ndim))] )
Print(critnlminb)
#
#
# ML fa by NR: param=c( c(Lambda),log(psi) )
resNR=NR( param00, critfa, logpsi=1, maxiter=50, flipd=1 )
critNR=resNR$objective
param=resNR$par
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=exp( param[-(1:(nvar*ndim))] )
Print(critnlminb,critNR)
#
#
# ML fa by NR with analytic gradient: param=c( c(Lambda),log(psi) )
resNR=NR( param00, critfa, logpsi=1, maxiter=50, flipd=1
, gradient=gradfa_a )
critNR=resNR$objective
param=resNR$par
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=exp( param[-(1:(nvar*ndim))] )
Print(critnlminb,critNR)
#
#
#
#
#
#
#
# ML fa by nlminb: param=psi
# with constraints on psi. (no effect)
resnlminb=nlminb( psi0, critfapsi, control=list(trace=0)
, lower=0.02, upper=0.98 )
critnlminb=resnlminb$objective
psinlminb=resnlminb$par
Print(critnlminb,psinlminb)
#
g1=gradfapsi( resnlminb$par )
g2=gradfapsi_a( resnlminb$par )
Print(g1,g2)
#
#
# ML fa by nlminb: param=log(psi)
resnlminb=nlminb( log(psi0), critfapsi, control=list(trace=0)
, logpsi=1 )
critnlminb=resnlminb$objective
psinlminb=exp( resnlminb$par )
Print(critnlminb,psinlminb)
#
g1=gradfapsi( resnlminb$par, logpsi=1 )
g2=gradfapsi_a( resnlminb$par, logpsi=1 )
Print(g1,g2)
#
#
# ML fa by NR: param=psi
resNR=NR( psi0, critfapsi, maxiter=50, flipd=1 )
critNR=resNR$objective
psiNR=resNR$par
Print(critNR,psiNR)
#
g1=gradfapsi( resNR$par )
g2=gradfapsi_a( resNR$par )
Print(g1,g2)
#
#
# ML fa by NR with analytic gradient: param=psi
resNR=NR( psi0, critfapsi, maxiter=50, flipd=1, gradient=gradfapsi_a )
critNR=resNR$objective
psiNR=resNR$par
Print(critNR,psiNR)
#
g1=gradfapsi( resNR$par )
g2=gradfapsi_a( resNR$par )
Print(g1,g2)
#
#
#
# ML fa by NR: param=log(psi)
resNR=NR( log(psi0), critfapsi, logpsi=1, maxiter=50, flipd=1 )
critNR=resNR$objective
psiNR=exp( resNR$par )
Print(critNR,psiNR)
#
g1=gradfapsi( resNR$par, logpsi=1 )
g2=gradfapsi_a( resNR$par, logpsi=1 )
Print(g1,g2)
#
#
# ML fa by NR with analytic gradient: param=log(psi)
resNR=NR( log(psi0), critfapsi, logpsi=1, maxiter=50, flipd=1
, gradient=gradfapsi_a )
critNR=resNR$objective
psiNR=exp( resNR$par )
Print(critNR,psiNR)
#
g1=gradfapsi( resNR$par, logpsi=1 )
g2=gradfapsi_a( resNR$par, logpsi=1 )
Print(g1,g2)
#
#
Print(critnlminb,critNR)
#
#
#
#
#
#
# Least Squares Solution by Newton-Raphson Method
#
#
#
#
#
#
# LS fa by nlminb: param=c(c(Lambda),psi)
resnlminb=nlminb( param0, critfa, control=list(trace=0)
, logpsi=0, method="LS" )
critnlminb=resnlminb$objective
param=resnlminb$par
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
Print(critnlminb)
#
g1=gradfa( param, method="LS" )
g2=gradfa_a( param, method="LS" )
Print(g1,g2)
#
#
# LS fa by nlminb: param=psi
resnlminb=nlminb( psi0, critfapsi, control=list(trace=0)
, method="LS" )
critnlminb=resnlminb$objective
Print(critnlminb,psinlminb)
g1=gradfapsi( resnlminb$par, method="LS" )
g2=gradfapsi_a( resnlminb$par, method="LS" )
Print(g1,g2)
#
#
#
# LS fa by nlminb with reparametrization: param=log(psi)
resnlminb=nlminb( log(psi0), critfapsi, control=list(trace=0)
, logpsi=1, method="LS" )
critnlminb=resnlminb$objective
psinlminb=exp( resnlminb$par )
Print(critnlminb,psinlminb)
g1=gradfapsi( resnlminb$par, logpsi=1, method="LS" )
g2=gradfapsi_a( resnlminb$par, logpsi=1, method="LS" )
Print(g1,g2)
#
#
#
#
# LS fa by NR with analytic g and H: param=c(c(Lambda),psi)
resNR=NR( param0, critfa, logpsi=0, maxiter=500
, flipd=1, method="LS", gradient=gradfa_a, hessian=HessQfa_a )
critNR=resNR$objective
param=resNR$par
Print(critNR,critnlminb)
#
g1=gradfa( resNR$par, logpsi=0, method="LS" )
g2=gradfa_a( resNR$par, logpsi=0, method="LS" )
Print(g1,g2)
#
#
#
# LS by NR with analytic g and H:
# param=c(c(Lambda),log(psi))
resNR=NR( param00, critfa, logpsi=1, maxiter=500
, flipd=1, method="LS", gradient=gradfa_a, hessian=HessQfa_a )
critNR=resNR$objective
param=resNR$par
Print(critNR,critnlminb)
#
g1=gradfa( resNR$par, logpsi=1, method="LS" )
g2=gradfa_a( resNR$par, logpsi=1, method="LS" )
Print(g1,g2)
#
#
#
#
# LS fa by NR: param=log(psi)
resNR=NR( log(psi0), critfapsi, logpsi=1, maxiter=50
, flipd=1, method="LS" )
critNR=resNR$objective
psiNR=exp( resNR$par )
Print(critNR,critnlminb,psiNR)
#
g1=gradfapsi( resNR$par, logpsi=1, method="LS" )
g2=gradfapsi_a( resNR$par, logpsi=1, method="LS" )
Print(g1,g2)
#
#
#
#
#
#
# Least Squares Solution by Gauss-Newton Method
#
#
#
#
# LS fa by nlfb param=c(c(Lambda),psi)
resnlfb=nlfb( param0,residfa2,control=list(femax=1000,japprox="jacentral"))
param=resnlfb$coefficients
critnlfb=resnlfb$ssquares
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
Print(critnlfb)
#
g1=gradfa( param, logpsi=0, method="LS" )
g2=gradfa_a( param, logpsi=0, method="LS" )
Print(g1,g2)
#
#
# LS fa by nlfb with analytic jacobian: param=c(c(Lambda),psi)
resnlfb=nlfb( param0, residfa2, jacfn=Jacfa_aa, control=list(femax=1000) )
param=resnlfb$coefficients
critnlfb=resnlfb$ssquares
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
Print(critnlfb)
#
g1=gradfa( param, logpsi=0, method="LS" )
g2=gradfa_a( param, logpsi=0, method="LS" )
Print(g1,g2)
#
#
#
# LS fa by nlfb param=c(c(Lambda),log(psi))
resnlfb=nlfb( param00, residfa2
, control=list(femax=1000,japprox="jacentral"), logpsi=1 )
param=resnlfb$coefficients
critnlfb=resnlfb$ssquares
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=exp( param[-(1:(nvar*ndim))] )
Print(critnlfb)
#
g1=gradfa( param, logpsi=1, method="LS" )
g2=gradfa_a( param, logpsi=1, method="LS" )
Print(g1,g2)
#
#
# LS fa by nlfb with analytic jacobian: param=c(c(Lambda),log(psi))
resnlfb=nlfb( param00, residfa2, control=list(femax=1000)
, logpsi=1, jacfn=Jacfa_aa )
param=resnlfb$coefficients
critnlfb=resnlfb$ssquares
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=exp( param[-(1:(nvar*ndim))] )
Print(critnlfb)
#
g1=gradfa( param, logpsi=1, method="LS" )
g2=gradfa_a( param, logpsi=1, method="LS" )
Print(g1,g2)
#
# LS fa by GN: param=c(c(Lambda),psi)
resGN=GN( param0, residfa, logpsi=0, maxiter=50 )
param=resGN$par
critGN=resGN$objective
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
Print(critGN, critnlfb)
#
g1=gradfa( resGN$par, logpsi=0, method="LS" )
g2=gradfa_a( resGN$par, logpsi=0, method="LS" )
Print(g1,g2)
#
#
# LS fa by GN with analytic jacobian: param=c(c(Lambda),psi)
resGN=GN( param0, residfa, logpsi=0, maxiter=50
, jacobian=Jacfa_a )
param=resGN$par
critGN=resGN$objective
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=param[-(1:(nvar*ndim))]
Print(critGN, critnlfb)
#
g1=gradfa( resGN$par, logpsi=0, method="LS" )
g2=gradfa_a( resGN$par, logpsi=0, method="LS" )
Print(g1,g2)
#
#
# LS fa by GN: param=c(c(Lambda),log(psi))
resGN=GN( param00, residfa, logpsi=1, maxiter=50 )
param=resGN$par
critGN=resGN$objective
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=exp( param[-(1:(nvar*ndim))] )
Print(critGN, critnlfb)
#
g1=gradfa( resGN$par, logpsi=1, method="LS" )
g2=gradfa_a( resGN$par, logpsi=1, method="LS" )
Print(g1,g2)
#
#
#
#
# LS fa by GN with analytic jacobian: param=c(c(Lambda),log(psi))
resGN=GN( param00, residfa, logpsi=1, maxiter=50, jacobian=Jacfa_a )
param=resGN$par
critGN=resGN$objective
Lambda=matrix(param[1:(nvar*ndim)],nvar)
psi=exp( param[-(1:(nvar*ndim))] )
Print(critGN, critnlfb)
#
g1=gradfa( resGN$par, logpsi=1, method="LS" )
g2=gradfa_a( resGN$par, logpsi=1, method="LS" )
Print(g1,g2)
#
#
#
#####################################################################
#
# End of Factor Analysis
#
#####################################################################
#
#
#
#
#
#
#
#
#
#
#####################################################################
#
# PCA by Newton-Raphson and Gauss-Newton method
#
#####################################################################
#
#
#
# Given n x nvar Y matrix, find n x ndim F and nvar x ndim A such that
# rss = tr( t(Y - F \
# is minimized where ndim << min(n,nvar).
#
# The solution using svd or eigen decomposition is well known
# but here we try to minimize rss directly w.r.t c( c(F), c(A) )
# by Newton-Raphson or Gauss-Newton method.
#
# It's not efficient at all but works.
#
#
#
# We use nlfb function of nlsr package for comparison.
#
library(nlsr)
#
#
rssPCA <- function( vecPCA, ndim=2, Y=0 ){
# rss of PCA: ssq(Y-Yhat)=ssq(Y-F%*%t(A))
# recover F and A from vecPCA and evaluate rss
n=nrow(Y); nvar=ncol(Y)
F=matrix(vecPCA[1:(n*ndim)],n,ndim)
A=matrix(vecPCA[-(1:(n*ndim))],nvar,ndim)
rss=ssq(Y-F%*%t(A))
return( rss )
} # end of rssPCA
#
#
drssPCA <- function( vecPCA, ndim=2, Y=0 ){
# gradient of rss of PCA
# recover F and A from vecPCA and evaluate rss
n=nrow(Y); nvar=ncol(Y)
F=matrix(vecPCA[1:(n*ndim)],n,ndim)
A=matrix(vecPCA[-(1:(n*ndim))],nvar,ndim)
dF=2*(F%*%t(A)%*%A-Y%*%A)
dA=2*(A%*%t(F)%*%F-t(Y)%*%F)
res=c(c(dF),c(dA))
return( res )
} # end of drssPCA
#
#
ymyhatPCA <- function( vecPCA, ndim=2, Y=0 ){
# residual as c(Y-Yhat)
# recover F and A from vecPCA and evaluate vec(Y-F%*%t(A))
n=nrow(Y); nvar=ncol(Y)
F=matrix(vecPCA[1:(n*ndim)],n,ndim)
A=matrix(vecPCA[-(1:(n*ndim))],nvar,ndim)
resid=c(Y-F%*%t(A))
return( resid )
} # end of ymyhatPCA
#
#
yhatmyPCA <- function( vecPCA, ndim=2, Y=0 ){
# residual as c(Yhat-Y) to be used by nlfb
# recover F and A from vecPCA and evaluate vec(F%*%t(A)-Y)
return( -ymyhatPCA( vecPCA, ndim=ndim, Y=Y ) )
} # end of yhatmyPCA
#
#
JacPCA <- function( vecPCA, ndim=2, Y=0 ){
# Jacobian: c( vec( d c(Yhat) / d F ), vec( d c(Yhat) / d A ) )
# recover F and A from vecPCA and evaluate vec(Y-F%*%t(A))
n=nrow(Y); nvar=ncol(Y)
F=matrix(vecPCA[1:(n*ndim)],n,ndim)
A=matrix(vecPCA[-(1:(n*ndim))],nvar,ndim)
#
# Jac
temp=NULL
for( i in 1: n ) temp=append(temp,list(A))
temp=Reduce( b_diag, temp )
# dF=temp[,c(t(matrix(1:(ndim*n),ndim,n)))]
# dF=dF[c(t(matrix(1:(nvar*n),nvar,n))),]
dF=temp[,matindex(ndim,n, type=1, byrow=1)]
dF=dF[matindex(nvar,n, type=1, byrow=1),]
temp=NULL
for( j in 1: nvar ) temp=append(temp,list(F))
temp=Reduce( b_diag, temp )
# dA=temp[,c(t(matrix(1:(ndim*nvar),ndim,nvar)))]
dA=temp[,matindex(ndim,nvar, type=1, byrow=1)]
#
res=cbind( dF, dA )
#
return( res )
} # end of JacPCA
#
#
#
normalizePCA <- function( vecPCA, ndim=2, Y=0 ){
# normalize X in each of GN/NR iteration
# so that F'F=n I and A'A=diag and A[1,] > 0
# 20220723,30
#
# convert vecX to matrix X
n=nrow(Y); nvar=ncol(Y)
F=matrix(vecPCA[1:(n*ndim)],n,ndim)
A=matrix(vecPCA[-(1:(n*ndim))],nvar,ndim)
#
# normalize
res=normalize_config(F,center=0, rotate=1, A=A)
#
F=res$F; A=res$A
for( a in 1:ndim ){
if( A[1,a] < 0 ){
A[,a]=-A[,a]
F[,a]=-F[,a]
}
}
res=list(F=F,A=A)
#
return( unlist(res) )
} # end of normalizePCA
#
#
#
#
# generate data
seed <- 1701
set.seed(seed)
n <- 50; nvar <- 9
Y <- matrix(rnorm(n*nvar),n)%*%(diag(1/(1:nvar)))
# centering
Y=scale( Y, center=TRUE, scale=FALSE )
#
#
#
# initial value
ndim=2
#
set.seed(1701)
F0=matrix(rnorm(n*ndim),n,ndim)
A0=t( solve(t(F0)%*%F0)%*%t(F0)%*%Y )
vecPCA0=c(c(F0),c(A0))
rss0=ssq(Y-F0%*%t(A0))
#
#
#
#
# Estimation starts here.
#
# Using all of F and A as parameters
# normalizing the solution after each NR iteration.
# with or without analytic gradient or Jacobian.
#
#
#
# Newton-Raphson
#
#
#
# by nlminb
cat("\n\n**** Starting PCA by NR by nlminb with analytic gradient ****\n\n")
resnlm=nlminb( vecPCA0, rssPCA, control=list(trace=0), Y=Y, ndim=ndim
, gradient=drssPCA )
vecPCAnlm=resnlm$par
F=matrix(vecPCAnlm[1:(n*ndim)],n,ndim)
A=matrix(vecPCAnlm[-(1:(n*ndim))],nvar,ndim)
resnorm=normalize_config(F,center=0, rotate=1, A=A)
Fnlm=resnorm$F; Anlm=resnorm$A
rssnlm=ssq(Y-Fnlm%*%t(Anlm))
gradnlm=drssPCA( vecPCAnlm, ndim=ndim, Y=Y )
Print(rss0,rssnlm, min(abs(gradnlm)))
#Print(A1,Anlm)
#
#
# by NR
cat("\n\n**** Starting PCA by NR by NR with analytic gradient **** \n\n")
resNR=NR( vecPCA0, rssPCA, Y=Y, ndim=ndim, normalize=normalizePCA
, gradient=drssPCA, flipd=1, maxiter2=3, eps=-9, print=2 )
vecPCANR=resNR$par
F=matrix(vecPCANR[1:(n*ndim)],n,ndim)
A=matrix(vecPCANR[-(1:(n*ndim))],nvar,ndim)
resnorm=normalize_config(F,center=0, rotate=1, A=A)
FNR=resnorm$F; ANR=resnorm$A
rssNR=ssq(Y-FNR%*%t(ANR))
gradNR=drssPCA( vecPCANR, ndim=ndim, Y=Y )
Print(rss0,rssNR, min(abs(gradNR)))
# Print(A1,ANR)
#
#
#
# Gauss-Newton
#
#
#
# by nlsr
cat("\n\n**** Startin PCA by GN by nlfb ****\n\n")
resnlsr=nlfb( vecPCA0, yhatmyPCA, Y=Y, ndim=ndim
, control=list(femax=500,japprox="jacentral") )
vecPCAnlsr=resnlsr$coefficients
F=matrix(vecPCAnlsr[1:(n*ndim)],n,ndim)
A=matrix(vecPCAnlsr[-(1:(n*ndim))],nvar,ndim)
resnorm=normalize_config(F,center=0, rotate=1, A=A)
Fnlsr=resnorm$F; Anlsr=resnorm$A
rssnlsr=ssq(Y-Fnlsr%*%t(Anlsr))
gradnlsr=drssPCA( vecPCAnlsr, ndim=ndim, Y=Y )
Print(rss0,rssnlsr, min(abs(gradnlsr)))
#
#
#
# by GN
cat("\n\n**** Starting PCA by GN w/o analytic Jacobian ****\n\n")
resGN=GN( vecPCA0, ymyhatPCA, Y=Y, ndim=ndim, normalize=normalizePCA
, print=2 )
vecPCAGN=resGN$par
F=matrix(vecPCAGN[1:(n*ndim)],n,ndim)
A=matrix(vecPCAGN[-(1:(n*ndim))],nvar,ndim)
resnorm=normalize_config(F,center=0, rotate=1, A=A)
FGN=resnorm$F; AGN=resnorm$A
rssGN=ssq(Y-FGN%*%t(AGN))
gradGN=drssPCA( vecPCAGN, ndim=ndim, Y=Y )
Print(rss0,rssGN, min(abs(gradGN)))
#
#
# by GN
cat("\n\n**** Starting PCA by GN with analytic Jacobian ****\n\n")
resGN=GN( vecPCA0, ymyhatPCA, Y=Y, ndim=ndim, normalize=normalizePCA
, jacobian=JacPCA, print=2 )
vecPCAGN=resGN$par
F=matrix(vecPCAGN[1:(n*ndim)],n,ndim)
A=matrix(vecPCAGN[-(1:(n*ndim))],nvar,ndim)
resnorm=normalize_config(F,center=0, rotate=1, A=A)
FGN=resnorm$F; AGN=resnorm$A
rssGN2=ssq(Y-FGN%*%t(AGN))
gradGN2=drssPCA( vecPCAGN, ndim=ndim, Y=Y )
Print(rss0,rssGN2, min(abs(gradGN2)))
#
#
#
# final results
# rss
rss=cbind(rssNR,rssnlm, rssGN,rssGN2, rssnlsr)
cat("\n\n Comparison of final rss\n")
Print(rss)
grad=cbind( min(abs(gradnlm)),min(abs(gradNR)),min(abs(gradGN))
, min(abs(gradGN2)), min(abs(gradnlsr)) )
colnames(grad)=c("NR", "nlm", "GN", "GN2", "nlsr")
cat("\n\n Comparison of final gradient\n")
Print(grad)
#
#
#####################################################################
#
# End of PCA by Newton-Raphson and Gauss-Newton method
#
#####################################################################
#
## End(Not run)
[Package lazy.mat version 0.1.6 ]