# Calculating average variance extracted (AVE) in R for checking discriminant validity (Fornell-Larcker criterion)

We are using lavaan in R to calculate CFAs (confirmatory factor analyses) and SEMs (structural equation models). We now want to test whether two latent constructs can be assumed to be unrelated (discriminant validity).

Refering to

Fornell, C. & Larcker, D. F. (1981). Evaluating structural equation models with unobservable variables and measurement error. Journal of Marketing Research, 18, 39–50.

we need to calculate the so called average variance extracted (AVE).

I found the following R-help-mailing list post. However, I don't think the output is the AVE I need for the Fornell-Larcker criterion. Values are calculated for each item and not factors.

Does anybody know how to obtain this value within lavaan or any other package?

If it is not possible to automatically obtain the AVE for each construct, can somebody point out how to calculate it based on the lavaan output?

Help would be much appreciated! Thanks.

As it seems the semTools package now provides a function that calculates the AVE based on a model estimated in lavaan:

reliability()

However, the package description notes that the calculation slightly differs from the one proposed in Fornell & Larcker (1981):

"Note that this formula is modified from Fornell & Larcker (1981)
in the case that factor variances are not 1."


I am not quite sure what this means for interpretation of the AVE.

• To answer the post from phx, in the reliability function in semTools, I have adjusted the formula such that it is not sensitive to scale identification. That is, if you use the marker-variable approach for scale identification, the average variance extracted should remain the same as other identification methods.
– user59716
Oct 31, 2014 at 15:23
• I just checked the code. The calculation was wrong. I have updated the development version. See the details how to install the development version in wiki: github.com/simsem/semTools/wiki
– user59716
Oct 31, 2014 at 16:26
• Sorry, @Sunthud, we (specifically the moderators) have to convert it for you; new users aren't allowed to comment until their reputation is >50. (This is to protect the site from spam.) We would love to have you as a member, & I'm sure you could reach 50 quickly. If you'd like to be more active, you may want take our tour, which has information for new users. Oct 31, 2014 at 16:33
• I just mailed with Sunthud. Since he has not enough reputation to comment yet here his answer concerning the bug: simply change the following line: avevar[j] <- mean(trueitem / (trueitem + erritem)) in the semTools::reliability function to avevar[j] <- sum(trueitem) / sum(trueitem + erritem). The bug has not been fixed till 4 days ago.
– phx
Nov 18, 2014 at 6:59

I developed a function to calculate CR and AVE for the sem package. I am sure you can adapt to lavaan.

Code follows:

crave <- function(model, digits=2) {
# ig111207
# computes composite reliability and average variance extracted
# usage: crave(model)
# where model is a sem fitted model
# such as sem.wh.1
require(sem)
coeff <- x[,2]
paths <- as.character(x[,3])
newl <- strsplit(paths, " <--- ")
newl <- as.data.frame(newl)
newl <- t(newl)
item <- newl[,1]
LV <- newl[,2]

coeff2 <- coeff^2
e2 <- 1-coeff2

y <- data.frame(LV, item, coeff, coeff2, e2)
rownames(y) <- item

cr <- by(y, LV, function(x) sum(x$coeff)^2 / (sum(x$coeff)^2+sum(x$e2)) ) ave <- by(y, LV, function(x) sum(x$coeff2) / (sum(x$coeff2)+sum(x$e2)) )

z <- data.frame(
cr=round(as.numeric(cr), digits),
s1=ifelse(cr<.7,"","*"),
ave=round(as.numeric(ave), digits),
s2=ifelse(ave<.5,"","*")
)

#print(y,digits)
#print(z)