Feal Feal - 3 months ago 14
R Question

How to apply a function within a for loop for a set of existing variables of a predifined structure in R?

I have a function for which i need a matrix and a vector as arguments. I will extract the matrices and vectors from a

data.matrix()
and
data.frame()
respectively.

for (i in 1:3) {
assign(paste("vavc", i, sep = ""),as.numeric(inputvar[i,-1]));
assign(paste("cor", i, sep = ""),matrix(input[which(ArtID ==i),-1],nrow = 2 ))
}


What I want now is to apply the resulting variables to the function
cor2cov()
(the function is pasted below the divider in the code section at the end of this post, where you can also find the input for creating a minimum reproducible example).

For example:
cor2cov(cor1,vavc1)


I tried to incorporate the following code into the for-loop

cor2cov(noquote(paste("cor", i, sep = "")),noquote(paste("vavc", i, sep = "")))


Wich gives me an error:

#Error in cor2cov(noquote(paste("cor", 1, sep = "")), noquote(paste("vavc", :
'corMat must be a matrix


Basically the function doesn't get the right arguments.

Any help is appreciated.




Function and minimum code follows now:

ArtID = c(1,2,3)
AC_AC = c(1,1,1)
MKT_AC = c(0.5,0.6,0.2)
AC_MKT = c(0.5,0.6,0.2)
MKT_MKT = c(1,1,1)
input = data.frame(ArtID, AC_AC, MKT_AC, AC_MKT, MKT_MKT)
input <- data.matrix(input)
#Now we need to create the variance vectors
#Create data.frame for testing the varvector-creation loop

ArtIDv = c(1,2,3)
Varvec1 = c(0.3, 0.6)
Varvec1 = c(0.3, 0.6, 0.35)
Varvec2 = c(0.15, 0.19, 0.21)
inputvar = data.frame(ArtIDv,Varvec1,Varvec2)

for (i in 1:3) {
assign(paste("vavc", i, sep = ""),as.numeric(inputvar[i,-1]));
assign(paste("cor", i, sep = ""),matrix(input[which(ArtID ==i),-1],nrow = 2 ))
}

-------------------------

2) Incorporate the cor2cov()-Function into R by copy-pasting the following code:

# Goal: convert a correlation matrix and variance vector
# into the corresponding covariance matrix
#
# Input:
# 'corMat' is a square matrix with 1's on the diagonal
# and valid correlations on the off-diagonal
# 'varVec' is a valid variance vector, with length
# matching the dimension of 'covMat'. A single
# row or single column matrix is also allowed.
# Output:
# the covariance matrix
#
# A warning is given if the covariance matrix is not
# positive definite.
#
cor2cov = function(corMat, varVec) {
# test the input
if (!is.matrix(corMat)) stop("'corMat must be a matrix")
n = nrow(corMat)
if (ncol(corMat) != n) stop("'corMat' must be square")
if (mode(corMat) != "numeric") stop("'corMat must be numeric")
if (mode(varVec) != "numeric") stop("'varVec must be numeric")
if (!is.null(dim(varVec))) {
if (length(dim(varVec)) != 2) stop("'varVec' should be a vector")
if (any(dim(varVec)==1)) stop("'varVec' cannot be a matrix")
varVec = as.numeric(varVec) # convert row or col matrix to a vector
}
if (!all(diag(corMat) == 1)) stop("correlation matrices have 1 on the diagonal")
if (any(corMat < -1 | corMat > +1))
stop("correlations must be between -1 and 1")
if (any(varVec <= 0)) stop("variances must be non-negative")
if (length(varVec) != n) stop("length of 'varMat' does not match 'corMat' size")

# Compute the covariance
sdMat = diag(sqrt(varVec))
rtn = sdMat %*% corMat %*% t(sdMat)
if (det(rtn)<=0) warning("covariance matrix is not positive definite")
return(rtn)
}

#The cor2cov-Function will now be available in your global environment.

Answer

I think you want to use get(...) instead of noquote(...) to refer to the variables dynamically:

> cor2cov(get(paste("cor", i, sep = "")), get(paste("vavc", i, sep = "")))
           [,1]       [,2]
[1,] 0.35000000 0.05422177
[2,] 0.05422177 0.21000000

The get() function takes a string and returns an R variable/function with that name if it exists. It defaults to searching the global namespace.

> x = 'ls'
> class(ls)
[1] "function"
> class(get('ls'))
[1] "function"

While the noquote() function on the other hand returns a string:

> noquote('ls')
[1] ls
> class(noquote('ls'))
[1] "noquote"
> noquote('ls') == 'ls'