Using this simple R code, I have performed a factor analysis on my dataset:

factanal(df, factors = 6, scores = "regression", rotation = "varimax")

I have now found significant factors that I want to keep. I also have chosen to generate scores using the "regression" argument. I'm still not clear on all the steps factanal uses to provide the scores, but after some digging, I found that the "regression" argument does use what is known as Thomson's regression to generate some score. That score then seems to be turned into a z-score given all the scores.

So here is the question: Let's say that some new data comes in and I want to be able to give it a score as well. This new data happens to be one individual sample (the equivalent of one row of a new dataset).

Is there a proper way to give an individual sample a score or must the scores be generated on a population basis?


I wrote the following function that takes the fit object returned by factanal and new data that you provide (e.g., a data frame or matrix with identical variable names), along with the original data.

score_new_data <- function(fit, new_data, original_data) {
    means <- sapply(original_data[,row.names(fit$correlation)], mean)
    sds <- sapply(original_data[,row.names(fit$correlation)], sd)
    z <- as.matrix(scale(new_data[,row.names(fit$correlation)], 
                         center = means,
                        scale = sds))
    z %*% solve(fit$correlation, fit$loadings)

So for example,

bfi <- na.omit(bfi)
variables <- c("A1", "A2", "A3", "A4", "C1", "C2", "C3", "C4")
data <- bfi[,variables]
fit <- factanal(data, factors = 2, scores = "regression", rotation = "varimax")

This is a typical factor analysis.

And now supply some new data along with the fit of the factor analysis and the original data:

 score_new_data(fit, data[1:5, ], data)

And it generates the following:

> score_new_data(fit, data[1:5, ], data)
         Factor1    Factor2
61623  1.4937101  0.1714941
61629 -0.8927227 -1.7240081
61634 -0.4091523 -0.1982590
61640  0.4855813 -1.1968676
61661 -1.2631737  0.6817574

The answer here provides additional details: https://stackoverflow.com/a/4146131/180892

If you look at the code for factanal you can also learn more about what the regression method of scoring involves:

  Lambda <- fit$loadings # lambda are the loadings
  zz <- scale(z, TRUE, TRUE) # matrix of data is z standardized
  # cv is correlation matrix
  sc <- zz %*% solve(cv, Lambda)
  • $\begingroup$ Beautiful! I get it now. Thanks again Jeromy! $\endgroup$ – thevengefulco Aug 7 '18 at 5:50
  • $\begingroup$ I just adjusted the function so that it uses the means and sds of the original data for standardizing the new data. $\endgroup$ – Jeromy Anglim Aug 8 '18 at 0:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.