Showing posts with label SEM. Show all posts
Showing posts with label SEM. Show all posts

Saturday, March 18, 2017

Bifactor always fits best

Recently, I reviewed a paper where the authors wanted to test whether a second-order factor or bifactor model fitted their data best. They had about 580 observations for 6 items, measuring two factors. As this amounts to three item indicators per factor, it is like two just-identified latent variable models in one. But with two factors, the model is clearly overidentied. However, I wondered whether their tests would be able to find the true model. In general, I expect bifactor models to often fit better, as they are less restricted versions of second-order factor models. I wondered whether bifactor models even fit better when the true model is the second-order factor model. I performed a small simulation to see.

I generated 100 datasets with 6 items, measuring two second-order factors, and one first-order factor:

library(lavaan)
set.seed(642)
rdata <- list()
for (i in 1:100) {
  # generate first-order factor:
  FO_factor <- rnorm(580)
  # generate second-order factors:
  SO_factor1 <- FO_factor + rnorm(580, sd = 1)
  SO_factor2 <- FO_factor + rnorm(580, sd = 1)
  # generate the observed data:
  rdata[[i]] <- data.frame(X1 = SO_factor1 + rnorm(580, sd = .75), X2 = SO_factor1 + rnorm(580, sd = .75), 
                           X3 = SO_factor1 + rnorm(580, sd = .75), X4 = SO_factor2 + rnorm(580, sd = .75),
                           X5 = SO_factor2 + rnorm(580, sd = .75), X6 = SO_factor2 + rnorm(580, sd = .75))
}

Then I created a unidimensional model, a model with two correlated factors, a second-order factor model, and two bifactor models to fit on the datasets:

library(semPlot)
F1.mod <- '
  F =~ X1 + X2 + X3 + X4 + X5 + X6
'
semPaths(F1.mod)

F2.mod <- '
  F1 =~ X1 + X2 + X3
  F2 =~ X4 + X5 + X6
'
semPaths(F2.mod)

SO.mod <- '
  F1 =~ X1 + X2 + X3 
  F2 =~ X4 + X5 + X6
  F =~ a*F1 + a*F2
'
semPaths(SO.mod)
 
BF.mod <- '
  G =~ X1 + X2 + X3 + X4 + X5 + X6
  F1 =~ X1 + X2 + X3
  F2 =~ X4 + X5 + X6
'
semPaths(BF.mod)
 
BF2.mod <- '
  G =~ X1 + X2 + X3 + X4 + X5 + X6
  F1 =~ X1 + X2 + X3
'
semPaths(BF2.mod)

Then I fitted the models to each of the datasets and calculated p-values (of the chi-square statistic), CFIs and RMSEAs:

F1.fit <- list()
F2.fit <- list()
SO.fit <- list()
BF.fit <- list()
BF2.fit <- list()
cfis <- list()
rmseas <- list()
pvals <- list()
results <- data.frame(dataset = rep(1:100, each = 5), pval = NA, cfi = NA, 
                      rmsea = NA, mod = rep(1:5, times = 100))
fit.ind <- c("pvalue", "cfi", "rmsea")
for (i in 1:100) {
  F1.fit[[i]] <- cfa(F1.mod, data = rdata[[i]], std.lv = TRUE)
  F2.fit[[i]] <- cfa(F2.mod, data = rdata[[i]], std.lv = TRUE)
  SO.fit[[i]] <- cfa(SO.mod, data = rdata[[i]], std.lv = TRUE)
  BF.fit[[i]] <- cfa(BF.mod, data = rdata[[i]], orthogonal = TRUE, std.lv = TRUE)
  BF2.fit[[i]] <- cfa(BF2.mod, data = rdata[[i]], orthogonal = TRUE, std.lv = TRUE)
  results[(i-1)*5+1, 2:4] <- fitmeasures(F1.fit[[i]], fit.ind)
  results[(i-1)*5+2, 2:4] <- fitmeasures(F2.fit[[i]], fit.ind)
  results[(i-1)*5+3, 2:4] <- fitmeasures(SO.fit[[i]], fit.ind)
  results[(i-1)*5+4, 2:4] <- fitmeasures(BF.fit[[i]], fit.ind)
  results[(i-1)*5+5, 2:4] <- fitmeasures(BF2.fit[[i]], fit.ind)
}
results$mod = rep(c("one-factor", "two-factor", "second-order", "bifactor", "bifactor2"), times = 100)
head(results)
aggregate(results[2:4], by = list(results$mod), FUN = mean, na.rm = TRUE)

Not surprisingly, there are a lot of warnings for the first bifactor model, because it may not be identified. We should take the fit indices for that model with a grain of salt.

On average, p-values, RMSEA and CFI indicate bad fit for the one-factor model, as they should. The second-order and two correlated-factor models fit the data well, on average, according to the p-value, CFI and RMSEA. Note that these models are equivalent models, so should fit the data identical.

The most striking findings is that the second bifactor model always seems to fit the data better than the second-order factor model, which was the model that generated the data!

How about the variances of the fit indices, do they differ much between models?

aggregate(results[2:4], by = list(results$mod), FUN = sd, na.rm = TRUE)

They don't seem to differ much. If anything, the variance of the p-values seems comparable between bifactor and second-order factor models. The variance of the CFI is lower for bifactor models, and the variance of RMSEA is lower for the second-order factor model.


Conclusion 

There is not much sense in comparing the fit between second-order and bifactor models if we want to know which model generated the data. A bifactor model will often fit the data better, even when the data were generated using a second-order factor model. I am curious whether this is also the case with more indicators per factor.

Thursday, August 6, 2015

Creating nice SEM diagrams in Powerpoint - the easy way

With five powerpoint shapes, you can create almost any SEM diagram, or at least the diagram below. Just follow the step-by-step guides below, or use this powerpoint template, in which I've included all shapes described below (it's only one slide, see picture). Or, use one of the alternatives at the bottom of the post.



Single headed straight arrow
1) click 'Insert' - 'Shapes'
2) select 'Arrow' under 'Lines'
3) draw
4) right-click on the arrow
5) select 'Format shape'
6) select 'Line style'
7) under 'Arrow settings', select the type and size you would like for the begin and end arrows
8) click 'Close'
9) very good, Daniel-san!

Double headed straight arrow
1) click 'Insert' - 'Shapes',
2) select 'Double headed arrow' under 'Lines',
3) draw
4) right-click on the arrow
5) select 'Format shape'
6) select 'Line style'
7) under 'Arrow settings', select the type and size you would like for the arrow
8) click 'Close'
9) very good, Daniel-san!

Manifest variable
1) click 'Insert' - 'Shapes'
2) select 'Rectangle' under 'Rectangles'
3) draw
4) select the square and just start typing to name the variable 
5) very good, Daniel-san!

Latent variable
1) click 'Insert' - 'Shapes'
2) select 'Oval' under 'Basic Shapes'
3) draw
4) select the circle and just start typing to name the variable
5) very good, Daniel-san!

Double headed curved arrows
Ah, the tricky one! Never use the default 'Curved arrow', it will never look right. Instead:
1) click 'Ínsert' - 'Shapes'
2) select 'Arc' under 'Basic shapes'
3) draw an arc
4) select the rightmost yellow diamond of the arc and drag it to the bottom white square (this should give you the right curve already)
5) right click on the arc
6) select 'Format shape'
7) select 'Line style'
7) under 'Arrow settings', select the type and size you would like for the begin and end arrows
8) click 'Close'
9) very good, Daniel-san!

Alternatives
- Use LaTeX with tikz
- Watch this short video tutorial on creating double head curved arrows in powerpoint: https://www.youtube.com/watch?v=8dAmJxBSLy4

Friday, September 27, 2013

Adjusting size of nodes and text labels in tikz (LaTeX)

The following picture is created with tikz, using the same node sizes and text label sizes for every node:


\documentclass[border=3mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows,positioning}
\begin{document}

\begin{tikzpicture}[auto,node distance=.5cm,
    latent/.style={circle,draw,very thick,inner sep=0pt,minimum size=30mm,align=center},
    manifest/.style={rectangle,draw,very thick,inner sep=0pt,minimum width=45mm,minimum height=10mm},
    paths/.style={->, ultra thick, >=stealth'},
]

% Define observed variables
\node [manifest] (things) at (0,0) {things};

% Define latent variables
\node [latent] (all) [left=3.5cm of things] {All};
\node [latent] (random) [above right=3.5cm of things] {random};


% Draw paths from latent to observed variables
\draw [paths] (all) to node { } (things);
\draw [paths] (random) to node { } (things);

\end{tikzpicture}
\end{document}




However, I didn't like the node sizes,  so I changed them using the 'scale' argument within the 'node' command:



\documentclass[border=3mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows,positioning}
\begin{document}

\begin{tikzpicture}[auto,node distance=.5cm,
    latent/.style={circle,draw,very thick,inner sep=0pt,minimum size=30mm,align=center},
    manifest/.style={rectangle,draw,very thick,inner sep=0pt,minimum width=45mm,minimum height=10mm},
    paths/.style={->, ultra thick, >=stealth'},
]

% Define observed variables
\node [manifest, scale=.75] (things) at (0,0) {things};

% Define latent variables
\node [latent] (all) [left=3.5cm of things] {All};
\node [latent, scale=.5] (random) [above right=3.5cm of things] {random};


% Draw paths from latent to observed variables
\draw [paths] (all) to node { } (things);
\draw [paths] (random) to node { } (things);

\end{tikzpicture}
\end{document}




The scale command changes the size of the node, as well as the size of the text label. So, you may want to change the size of the text labels only. You can do this by using one of the following LaTeX text size commands:




\documentclass[border=3mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows,positioning}
\begin{document}

\begin{tikzpicture}[auto,node distance=.5cm,
    latent/.style={circle,draw,very thick,inner sep=0pt,minimum size=30mm,align=center},
    manifest/.style={rectangle,draw,very thick,inner sep=0pt,minimum width=45mm,minimum height=10mm},
    paths/.style={->, ultra thick, >=stealth'},
]

% Define observed variables
\node [manifest, scale=.75] (things) at (0,0) {\Large things};

% Define latent variables
\node [latent] (all) [left=3.5cm of things] {\large All};
\node [latent, scale=.5] (random) [above right=3.5cm of things] {\huge random};


% Draw paths from latent to observed variables
\draw [paths] (all) to node { } (things);
\draw [paths] (random) to node { } (things);

\end{tikzpicture}
\end{document}




Note that you can always change font size locally in LaTeX documents by using one of the following commands:

\tiny
\scriptsize
\footnotesize
\small
\normalsize
\large
\Large
\LARGE
\huge
\Huge 

Friday, September 20, 2013

I think tikz iz fantaztic! (software for drawing SEM models)

I have been trying to produce my own diagrams for structural equation models and path diagrams. Today, I produced the following diagram using the tikz package in LaTeX:


Here is the code for creating the diagram (please note: it works using 'pdf texify', not using 'texify', not sure about the rest):


\documentclass[border=3mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows,positioning}
\newcommand{\at}{\makeatletter @\makeatother}
\begin{document}
\begin{tikzpicture}[auto,node distance=.5cm,
    latent/.style={circle,draw,very thick,inner sep=0pt,minimum size=30mm,align=center},
    manifest/.style={rectangle,draw,very thick,inner sep=0pt,minimum width=45mm,minimum height=10mm},
    paths/.style={->, ultra thick, >=stealth'},
    twopaths/.style={<->, ultra thick, >=stealth'}
]

% Define observed variables
\node [manifest] (BSS01T1) at (0,0) {BSS01 \at T1};
\node [manifest] (BSS02T1) [below=of BSS01T1]  {BSS02 \at T1};
\node [manifest] (BSS03T1) [below=of BSS02T1]  {BSS03 \at T1};

\node [manifest] (BSS17T1) [below=2cm of BSS03T1]  {BSS16 \at T1};
\node [manifest] (BSS18T1) [below=of BSS17T1]  {BSS17 \at T1};
\node [manifest] (BSS19T1) [below=of BSS18T1]  {BSS19 \at T1};

\node [manifest] (BSS01T2) [below=2cm of BSS19T1]  {BSS01 \at T2};
\node [manifest] (BSS02T2) [below=of BSS01T2]  {BSS02 \at T2};
\node [manifest] (BSS03T2) [below=of BSS02T2]  {BSS03 \at T2};

\node [manifest] (BSS17T2) [below=2cm of BSS03T2]  {BSS17 \at  T2};
\node [manifest] (BSS18T2) [below=of BSS17T2]  {BSS18 \at  T2};
\node [manifest] (BSS19T2) [below=of BSS18T2]  {BSS19 \at  T2};


% Draw dashed vertical lines to show that items in middle of questionnaire are not shown
\draw[dashed, ultra thick] (BSS03T1.south) -- (BSS17T1.north);
\draw[dashed, ultra thick] (BSS03T2.south) -- (BSS17T2.north); 


% Define latent variables
\node [latent] (SIT1) [left=3.5cm of BSS17T1] {Suicidal \\ Ideation \at T1};
\node [latent] (SIT2) [left=3.5cm of BSS03T2] {Suicidal \\ Ideation \at T2};


% Draw paths form latent to observed variables
\foreach \all in {BSS01T1, BSS02T1, BSS03T1, BSS17T1, BSS18T1, BSS19T1}{
    \draw [paths] (SIT1.east) to node { } (\all.west);
}

\foreach \all in {BSS01T2, BSS02T2, BSS03T2, BSS17T2, BSS18T2, BSS19T2}{
    \draw [paths] (SIT2.east) to node { } (\all.west);
}


% Draw lines to indicate (residual) covariances
\draw [twopaths] (BSS01T1.east) to [bend left=90] (BSS01T2.east);
\draw [twopaths] (BSS02T1.east) to [bend left=90] (BSS02T2.east);
\draw [twopaths] (BSS03T1.east) to [bend left=90] (BSS03T2.east);
\draw [twopaths] (BSS17T1.east) to [bend left=90] (BSS17T2.east);
\draw [twopaths] (BSS18T1.east) to [bend left=90] (BSS18T2.east);
\draw [twopaths] (BSS19T1.east) to [bend left=90] (BSS19T2.east);
\draw [twopaths] (SIT1.west) to [bend right=90] (SIT2);


\end{tikzpicture}
\end{document}

Thursday, September 5, 2013

Some notes on R-package 'lavaan'


The cfa function is a (convenience) wrapper for the lavaan function. For beginners, it's best to use the cfa function.

FIML estimation is not available for binary / ordered / categorical data. However, version 0.5-14 allows for pairwise deletion (used to be only listwise, prior to 0.5-14) when using WLS estimation.

The model is specified by assigning a character string:
model <- ' model specification '

The model specification consists of statements like:

Latent variable 'Factor 1' is measured by observed variables 'x1', 'x2', and 'x3':
factor1 =~ x1 + x2 + x3

Observed variables 'x1' and 'x2' have a residual covariance:
x1 ~~ x2

Observed variable 'x1' has a residual variance:
x1 ~~

Variable 1 (dep var; may be observed or latent) 'v1' is regressed on variable 2 (indep var; may be observed or latent) and variable 3 (indep var; may be observed or latent):
v1 ~ v2 + v3

Variable 1 (may be observed or latent) has an intercept ('1'), that should be fixed to zero:
v1 ~ 1*0

The first threshold of variable 1 should be fixed to zero:
v1 | 0 * t1








Monday, January 30, 2012

Factor mixture analysis in Mplus

I'm using factor mixture analysis (FMA) for the estimation of latent classes (latent categories) and latent traits (latent dimensions) in the same model. I think it's great that this model provides an opportunity for combining factors and classes. Muthen even goes so far as to say that performing a Latent Class Analysis (LCA) or Factor Analysis (FA) is actually performing a restricted Factor Mixture Analysis (FMA), because in these models, the dimensional, or categorical, nature of the latent variables are not taken into account.

I was using the paper "MODELS AND STRATEGIES FOR FMA" on the statmodel website, to see how one would go about fitting such a model. It provides much more practical details about how to do a factor mixture analysis than most of the Muthen papers on FMA, which is great. At the same time, they leave some issues unresolved, and some issues just made me wonder. What follows are the questions / problems I came across, and my opinion on these issues.




Latent (co)variances

While their fmm-2 to fmm-5 models allow for the estimation of factor covariance matrices, only in fmm-3 to fmm-5, covariances between latent traits are modelled. I have been wondering for some time, why only class specific factor variances are modelled in fmm-2, while factor covariances are fixed to zero. The answer is simple and straightforward: by definition, latent classes do not permit covariances between the variables they explain, within classes. Covariances between the latent factors are supposed to be explained by the classes, so no covariations is allowed. However, variation on the latent traits within classes is allowed, by estimating variances for the factors, within class.


Prepare to wait and wait and wait


Estimating (c0)variances for the latent traits requires numerical integration.
This is invoked by adding the line "ALGORITHM = INTEGRATION" in the ANALYSIS command. Be prepared to wait a long time: it may take very long, depending on you sample size, number of observed variables, and number of latent variables. If you want a faster, but less precise solution, add the line "INTEGRATION = STANDARD(7)" (the default is 15). This should speed up things.

Obviously, more factors and more classes take more time. My model, consisting of two factors and 28 binary indicators, running on an HP probook 6550b in Mplus 6, took 24 hours to complete the estimation of a four class model (with the default precision, using 100 random starts and 10 final stage iterations). And then some authors advice to obtain likelihood ratio tests for the k vs. k-1 model comparison. I simply gave up, this would take me a week.


Comparing FMA results to FA or LCA results


I you want to compare the outputs of an exploratory (EFA) or confirmatory factor analysis (consisting of only latent traits, not latent classes) to an FMA model, you may want to obtain values for AIC, BIC and SSABIC to be able to compare an exclusively dimensional model to a factor mixture model. In order to obtain these, use ML estimation (or a robust variation of it: MLM, MLMV or MLR), by typing the line "ESTIMATOR = ML;" in the ANALYSIS command.

How many factors, and how many classes should we fit to the data? The authors don't seem to have an answer, either. In the introduction, they seem to argue that the number of factors and classes of the best fitting models, when only LCA of only FA is applied to the data should be taken as an upper limit for the number of factors and classes in an FMA. Later on however, they note "Because a large number of factors computationally intensive to fit with the already complicated FMM's, the fitting of models stopped with two factors." Yes, and then we didn't even try to obtain the Lo-Mendell-Rubin Likelihood ratio test (TECH 11), or the bootstrapped Likelihood ratio test (TECH 14). I'd suggest you just inspect AIC, BIC and SSABIC values, and especially: check if the model makes sense! A class solution which includes near zero proportions is not a useful solution, so try a solution with less classes.


Different loadings and tresholds (or intercepts) for each class?

Why would one want to estimate different loadings and treshold (or intercepts) in every class? It may result in better model fit, but how are we to interpret the resulting factorial structure? It seems in such a case, we are measuring a different latent variable in every class. Personally, I feel comparing models with non-invariant loadings and tresholds (or intercepts) across classes, turns the factor mixture model into an analysis of measurement invariance across latent classes, which seems to be an altogether different subject.

Tuesday, August 9, 2011

Estimates in LISREL output

Parameter estimates

"In LISREL 7 there are two kinds of standardized solutions: SS (Standardized Solution) and SC (Completely Standardized Solution). In the SS solution the latent variables are scaled to have standard derivations equal to unity; the observed variables are left in their original metric. In the SC solution, the observed as well as the latent variables are standardized."*

For tau (intercepts), a standardized solution is not provided. However, tau does depends on the scale of the observed variable (and on other model parameters). So some kind of standardized solution would be informative.

Obviously, for lambda (factor loadings), standardized and completely standardized solutions are printed, as it depends on the scale of observed and latent variables. For theta-epsilon, only completely standardized estimates are printed, as it only depends on the scale of the observed variables (unstandardized theta epsilon is the (co)variances of the observed variables, unexplained by the factor).



Indicators for model modifications

"When a model does not fit well, the modification indices will often be the most useful way of deciding how to change the model to improve the fit. They give an estimate of how much the chi-square will decrease if a fixed parameter is freed."*

A fitted residual is the observed mean or (co)variance (provided in LISREL input), minus the model implied mean and (co)variance.

"A standardized residual is a fitted residual divided-by the large-sample standard error of the residual."*

Expected change is the predicted estimated change in the parameter when set free, for fixed parameters. I'm not sure by what values expected change is divided to obtain the (completely) standardized estimated change.








* Taken from: Jöreskog, K., & Sörbom, D. (1996). LISREL 8: User's reference guide. Chicago, IL: Scientifi c Software International, Inc.

Monday, August 1, 2011

On calculation of factor means and item intercepts in LISREL, using ML estimation

Options for identification

Among the options for identifying factor means are:
- Fixing the first items intercept to a constant (in most cases: zero)
- Fixing the latent mean to a constant (in most cases: zero)
- Forcing the intercepts to sum to a constant (in most cases: zero)

The second one is not suitable if you expect latent means to differ, and are interested in latent mean or intercept differences. The first and third one are more suitable in such a case, but offer some challenges as well. The third offers a challenge, because I don't know how to do this in LISREL. The first offers a challenge, because item intercepts have to be interpreted as some kind of deviation from the item with intercept fixed to a constant.



Identification by fixing the first item's intercept to zero

In this case, factor means and item intercepts are very dependent on the item chosen for identification. This is an important consideration if one wants to test an hypothesis concerning factor means, for example in multiple group comparisons. It almost amounts to a test concerning observed means for the items used for identification.

Formulae

Let i denote an item used for identification
Let j denote any other item
Let k denote a factor

Let y_ denote an observed item mean
Let alpha denote a factor mean
Let lambda denote a factor loading
Let tau denote an item intercept

alpha(k) = lambda(i) * y_(i)
tau(j) = y_(j) - lambda(j) * alpha(k)

When the model is identified by constraining the first items intercept to 0, and the first items loading to 1 is used, this simplifies to:

alpha(k) = y_(i)
tau(j) = y_(j) - lambda(j) * y_(i)

In words

The factor mean equals the observed mean of the identification item. Other items intercepts are determined by the items factor loading, times the identification items observed mean. An illustration is provided below, for a model of 3 factors fitted to 2 groups.


Examples

Values are taken from LISREL in- and output provided below. Small discrepancies arise from rounding.

1)
The first item is used as an identification item for the first factor.
In the first group, the item intercept for the second item (item 2) of the first factor is calculated as follows:
y_(item1) = 0.425 = alpha(factor1)
tau(item2) = 0.10 = y_(item2) - lambda(item2)*y_(item1) = 0.511 - 0.98*0.425

2)
The fourth item is used as an identification item for the second factor. In the second group, the item intercept for the second item of factor 2 is calculated as follows:
y_(item1) = 0.673 = alpha(factor2)
tau(item11) = -0.01 = y_(item11) - lambda(item11)*y_(item4) = 0.511 - 0.71*0.673


LISREL input

Observed means (y_; item 1-21):

G1: 0.425 0.511 0.488 0.618 0.380 0.320 0.611 0.582 0.182 0.222 0.406 0.389 0.387 0.602 0.530 0.570 0.588 0.092 0.042 0.206 0.375

G2: 0.566 0.459 0.475 0.673 0.289 0.275 0.590 0.559 0.247 0.288 0.474 0.463 0.343 0.553 0.422 0.603 0.494 0.202 0.023 0.217 0.642


Factor pattern (item 1-21):

item factor
1 1
2 1
3 1
4 2
5 1
6 1
7 1
8 1
9 1
10 1
11 2
12 2
13 2
14 1
15 2
16 3
17 2
18 3
19 3
20 2
21 3


LISREL output

Estimated factor means (alpha, factor 1-3):
G1: 0.425 0.618 0.570
G2: 0.566 0.673 0.603


Estimated item intercepts (tau):

item G1 G2

factor 1
1 0.00 0.00
2 0.10 -0.14
3 0.01 -0.23
5 0.03 -0.10
6 0.01 -0.34
7 0.11 -0.26
8 0.19 -0.40
9 0.05 -0.20
10 0.01 -0.13
14 0.16 -0.14

factor 2
4 0.00 0.00
11 0.05 -0.01
12 0.06 0.04
13 0.11 -0.21
15 0.09 -0.09
17 0.00 0.10
20 0.11 0.14

factor 3
16 0.00 0.00
18 0.23 -0.21
19 0.21 -0.04
21 0.16 -0.15


estimated factor loadings (lambda):

item G1 G2

factor 1
1 1.00 1.00
2 0.98 1.07
3 1.12 1.24
5 0.83 0.68
6 0.78 1.09
7 1.18 1.50
8 0.92 1.70
9 0.54 0.79
10 0.51 0.74
14 1.03 1.23

factor 2
4 1.00 1.00
11 0.57 0.71
12 0.72 0.63
13 0.81 0.82
15 1.00 0.75
17 0.96 0.58
20 0.15 0.12

factor 3
16 1.00 1.00
18 0.56 0.69
19 0.45 0.11
21 0.94 1.31