Skip to content

Commit

Permalink
Support means in Cor2DataFrame()
Browse files Browse the repository at this point in the history
  • Loading branch information
mikewlcheung committed Jul 13, 2024
1 parent 75f2135 commit a13731f
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 57 deletions.
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Package: metaSEM
Type: Package
Title: Meta-Analysis using Structural Equation Modeling
Version: 1.4.2
Date: 2024-07-10
Version: 1.4.3
Date: 2024-07-13
Depends: R (>= 3.4.0), OpenMx
Imports: Matrix, MASS, ellipse, graphics, stats, utils, mvtnorm, numDeriv, lavaan
Suggests: metafor, semPlot, R.rsp, testthat, matrixcalc
Expand Down
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Release 1.4.3 (Jul 13, 2024)
====================================
* Support means in Cor2DataFrame().

Release 1.4.2 (Jul 10, 2024)
====================================
* Fix the means of the latent variables at 0 in lavaan2RAM().
Expand Down
130 changes: 85 additions & 45 deletions R/Cor2DataFrame.R
Original file line number Diff line number Diff line change
@@ -1,51 +1,91 @@
Cor2DataFrame <- function(x, n, v.na.replace=TRUE, row.names.unique=FALSE,
cor.analysis=TRUE, acov="weighted",
append.vars=TRUE, asyCovOld=FALSE, ...) {

## x is a list of "data", "n", ...
if (all(c("data", "n") %in% names(x))) {
my.cor <- x$data
n <- x$n
obslabels <- colnames(x$data[[1]])
} else {
## x is just a list of correlation matrices. "n" is provided as an argument.
my.cor <- x
obslabels <- colnames(x[[1]])
}
Cor2DataFrame <- function(x, n, v.na.replace=TRUE, cor.analysis=TRUE,
acov=c("weighted", "individual", "unweighted"),
Means, row.names.unique=FALSE, append.vars=TRUE,
asyCovOld=FALSE, ...) {

if (length(my.cor) != length(n)) stop("Lengths of 'x' and 'n' are different.\n")

if (cor.analysis) {
## Standardize and then vechs()
my.df <- list2matrix(x=suppressWarnings(lapply(my.cor, cov2cor)), diag=FALSE)
} else {
## vech()
my.df <- list2matrix(x=my.cor, diag=TRUE)
}
## x is a list of "data", "n", ...
if (all(c("data", "n") %in% names(x))) {
my.cov <- x$data
n <- x$n
obslabels <- colnames(x$data[[1]])
} else {
## x is just a list of correlation matrices. "n" is provided as an argument.
my.cov <- x
obslabels <- colnames(x[[1]])
}

if (asyCovOld) {
acovR <- asyCovOld(x=my.cor, n=n, cor.analysis=cor.analysis, acov=acov, ...)
} else {
acovR <- asyCov(x=my.cor, n=n, cor.analysis=cor.analysis, acov=acov, ...)
}
if (length(my.cov) != length(n)) stop("Lengths of 'x' and 'n' are different.\n")

if (cor.analysis) {
## Standardize and then vechs()
my.df <- list2matrix(x=suppressWarnings(lapply(my.cov, cov2cor)), diag=FALSE)
} else {
## vech()
my.df <- list2matrix(x=my.cov, diag=TRUE)
}

if (asyCovOld) {
acovR <- asyCovOld(x=my.cov, n=n, cor.analysis=cor.analysis, acov=acov, ...)
} else {
acovR <- asyCov(x=my.cov, n=n, cor.analysis=cor.analysis, acov=acov, ...)
}

## NA is not allowed in definition variables
## They are replaced by 1e10
if (v.na.replace) acovR[is.na(acovR)] <- 1e10

## x is a list of "data", "n", and moderators, and append
## Append the moderators x[-c(1,2)] into data
if (all(c(c("data", "n") %in% names(x), length(names(x))>2, append.vars))) {
data <- suppressWarnings(data.frame(my.df, acovR, x[-c(1,2)], check.names=FALSE))
} else {
data <- suppressWarnings(data.frame(my.df, acovR, check.names=FALSE))
}

## Use unique row names if the row names are duplicated.
if (row.names.unique) rownames(data) <- make.names(names(x), unique=TRUE)

## NA is not allowed in definition variables
## They are replaced by 1e10
if (v.na.replace) acovR[is.na(acovR)] <- 1e10

## x is a list of "data", "n", and moderators, and append
## Append the moderators x[-c(1,2)] into data
if ( all(c(c("data", "n") %in% names(x),
length(names(x))>2,
append.vars)) ) {
data <- suppressWarnings(data.frame(my.df, acovR, x[-c(1,2)], check.names=FALSE))
} else {
data <- suppressWarnings(data.frame(my.df, acovR, check.names=FALSE))
#### Additional means
if (!missing(Means)) {

## Some basic checks
if (nrow(Means) != length(n)) {
stop("Number of rows of 'Means' and length of 'n' are different.\n")
}
if (ncol(Means) != length(obslabels)) {
stop("Number of columns of 'Means' and covariance matrices are different.\n")
}

## Use unique row names if the row names are duplicated.
if (row.names.unique) rownames(data) <- make.names(names(x), unique=TRUE)
if (!identical(colnames(my.cov[[1]]), colnames(Means))) {
stop("The variable names are not in the same order in 'x' and 'Means'. The results are likely incorrect unless this is what you want.\n")
}

## Sampling covariance matrices of the means: covariance matrices/n
## NA are replaced with 10^5
acov_mean <- mapply(function(x, y) {
out <- x/y
out[is.na(out)] <- 1e10
out},
my.cov, n, SIMPLIFY=FALSE)
acov_mean <- t(sapply(acov_mean, function(x) vech(x)))

list(data=data, n=n, obslabels=obslabels, ylabels=dimnames(my.df)[[2]],
vlabels=dimnames(acovR)[[2]])
## Variable names of p (sampling covariance matrix of the means
pCovNames <- matrix(paste("M(",
outer(obslabels, obslabels, paste, sep = " "),
")", sep=""),
nrow=length(obslabels), ncol=length(obslabels))
pCovNames <- vech(pCovNames)
colnames(acov_mean) <- pCovNames

if (row.names.unique) {
rownames(acov_mean) <- make.names(rownames(acov_mean), unique=TRUE)
}

list(data=cbind(data, Means, acov_mean), n=n, obslabels=obslabels,
ylabels=colnames(my.df), vlabels=colnames(acovR),
Meanvlabels=pCovNames)
} else {
## Without the means
list(data=data, n=n, obslabels=obslabels, ylabels=colnames(my.df),
vlabels=colnames(acovR))
}
}
14 changes: 8 additions & 6 deletions man/Cor2DataFrame.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
sampling covariance matrices. It uses the \code{asyCov} at the backend.
}
\usage{
Cor2DataFrame(x, n, v.na.replace = TRUE, row.names.unique = FALSE,
cor.analysis = TRUE, acov="weighted", append.vars=TRUE,
asyCovOld=FALSE, ...)
Cor2DataFrame(x, n, v.na.replace=TRUE, cor.analysis=TRUE,
acov=c("weighted", "individual", "unweighted"),
Means, row.names.unique=FALSE, append.vars=TRUE,
asyCovOld=FALSE, ...)
}
%- maybe also 'usage' for other objects documented here.
\arguments{
Expand All @@ -22,15 +23,16 @@ Cor2DataFrame(x, n, v.na.replace = TRUE, row.names.unique = FALSE,
be provided.}
\item{v.na.replace}{Logical. Missing value is not allowed in definition
variables. If it is \code{TRUE} (the default), missing value is
replaced by a large value (1e10). These values are not used in the analysis.}
\item{row.names.unique}{Logical, If it is \code{FALSE} (the default), unique
row names are not created.}
replaced by a large value (1e10). These values are not used in the analysis.}
\item{cor.analysis}{Logical. The output is either a correlation or
covariance matrix.}
\item{acov}{If it is \code{weighted}, the average correlation/covariance
matrix is calculated based on the weighted mean with the sample
sizes. The average correlation/covariance matrix is used to calculate the sampling
variance-covariance matrices.}
\item{Means}{An optional matrix of means. The number of rows must be the same as the length of \code{n}. The sampling covariance matrices of the means are calculated by the covariance matrices divided by the sample sizes. Therefore, it is important to make sure that covariance matrices (not correlation matrices) are used in \code{x} when \code{Means} are included; otherwise, the calculated sampling covariance matrices of the means are incorrect.}
\item{row.names.unique}{Logical, If it is \code{FALSE} (the default), unique
row names are not created.}
\item{append.vars}{Whether to append the additional variables to
the output dataframe.}
\item{asyCovOld}{Whether to use the old version of \code{asyCov}. See \code{\link[metaSEM]{asyCov}}.}
Expand Down
4 changes: 2 additions & 2 deletions man/metaSEM-package.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
\tabular{ll}{
Package: \tab metaSEM\cr
Type: \tab Package\cr
Version: \tab 1.4.2\cr
Date: \tab 2024-07-10\cr
Version: \tab 1.4.3\cr
Date: \tab 2024-07-13\cr
License: \tab GPL (>=2)\cr
LazyLoad: \tab yes\cr
}
Expand Down
34 changes: 32 additions & 2 deletions man/readData.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,20 @@ readLowTriMat(file, no.var, ...)
## 1.0 NA 0.4\nNA NA NA\n0.4 NA 1.0",
## file="fullmat.dat", sep="")

## Read the correlation matrices
## Read the correlation matrices from a file
## my.full <- readFullMat("fullmat.dat")

## Read the correlation matrices from a string
x <-
"1.0 0.3 0.4
0.3 1.0 0.5
0.4 0.5 1.0
1.0 NA 0.4
NA NA NA
0.4 NA 1.0"

my.full <- readFullMat(textConnection(x))

## my.full
# $`1`
# x1 x2 x3
Expand All @@ -71,9 +82,20 @@ readLowTriMat(file, no.var, ...)
## cat("1.0\n0.3 1.0\n0.4 0.5 1.0\n1.0\nNA NA\n0.4 NA 1.0",
## file="lowertriangle.dat", sep="")

## Read the lower triangle correlation matrices
## Read the lower triangle correlation matrices from a file
## my.lowertri <- readLowTriMat(file = "lowertriangle.dat", no.var = 3)

## Read the correlation matrices from a string
x <-
"1.0
0.3 1.0
0.4 0.5 1.0
1.0
NA NA
0.4 NA 1.0"

my.lowertri <- readLowTriMat(textConnection(x), no.var = 3)

## my.lowertri
# $`1`
# x1 x2 x3
Expand All @@ -96,8 +118,16 @@ readLowTriMat(file, no.var, ...)
## cat("1.0 0.3 0.4 1.0 0.5 1.0\n1.0 NA 0.4 NA NA 1.0\n",
## file="stackvec.dat", sep="")

## Read the stack vectors from a file
## my.vec <- readStackVec("stackvec.dat")

## Read the stack vectors from a string
x <- "
1.0 0.3 0.4 1.0 0.5 1.0
1.0 NA 0.4 NA NA 1.0"

my.vec <- readStackVec(textConnection(x))

## my.vec
# $`1`
# x1 x2 x3
Expand Down

0 comments on commit a13731f

Please sign in to comment.