Reputation: 1979
I have a 5x5 covariance matrix as below:
unique.items <- c(1,2,3,4)
diag <- rep("Free",length(unique.items)+1)
offdiag <- rep("0.0", (length(unique.items)+1)*length(unique.items)/2 )
m <- matrix(NA, ncol = length(diag), nrow = length(diag))
m[lower.tri(m)] <- offdiag
m[upper.tri(m)] <- t(m)[upper.tri(t(m))]
diag(m) <- diag
> m
[,1] [,2] [,3] [,4] [,5]
[1,] "Free" "0.0" "0.0" "0.0" "0.0"
[2,] "0.0" "Free" "0.0" "0.0" "0.0"
[3,] "0.0" "0.0" "Free" "0.0" "0.0"
[4,] "0.0" "0.0" "0.0" "Free" "0.0"
[5,] "0.0" "0.0" "0.0" "0.0" "Free"
Then, I get the lower triangle by:
lower.triangle <- paste(tapply(m[lower.tri(m, diag = TRUE)],
row(m)[lower.tri(m, diag = TRUE)], FUN = toString),
collapse=",")
> lower.triangle
"Free,
0.0, Free,
0.0, 0.0, Free,
0.0, 0.0, 0.0, Free,
0.0, 0.0, 0.0, 0.0, Free"
I need to generate a character variable including a grouping variable as below.
group <- c(1,2,3,4)
desired output
"Equal = (G4, Covariance[2]), (G1, Covariance[2]), (G2, Covariance[2]), (G3, Covariance[2]);
Equal = (G4, Covariance[5]), (G1, Covariance[5]), (G2, Covariance[5]), (G3, Covariance[5]);
Equal = (G4, Covariance[9]), (G1, Covariance[9]), (G2, Covariance[9]), (G3, Covariance[9]);
Equal = (G4, Covariance[14]), (G1, Covariance[14]), (G2, Covariance[14]), (G3, Covariance[14]);"
G1, G2, G3, and G4 are for grouping. The numbers in Covariance[#]
are for the order of the diagonal elements in the lower triangle of the matrix.
Free
) element's order is 0
in the lower.triangle
object. I do not need that in the desired output.Free
) order number should be then 2 because the order starts with 0
.Covariance[#]
.Any help is appreciated. Thanks!
Upvotes: 0
Views: 166
Reputation: 389185
Set the upper triangular matrix to NA
and get the index of 'Free'
values in m
omitting NA
values. Use that index to produce the text that you want using paste0
and sprintf
.
group <- c(4,1:3)
m[upper.tri(m)] <- NA
inds <- which(na.omit(c(t(m))) == 'Free')[-1] - 1
#first -1 because you want to ignore first 'Free' and
#second -1 because indexing start from 0 in your case.
inds
#[1] 2 5 9 14
sapply(inds, function(x)paste0('Equal = ',
paste0(sprintf('(G%d, Covariance[%d])', group, x), collapse = " , ")))
#[1] "Equal = (G4, Covariance[2]) , (G1, Covariance[2]) , (G2, Covariance[2]) , (G3, Covariance[2])"
#[2] "Equal = (G4, Covariance[5]) , (G1, Covariance[5]) , (G2, Covariance[5]) , (G3, Covariance[5])"
#[3] "Equal = (G4, Covariance[9]) , (G1, Covariance[9]) , (G2, Covariance[9]) , (G3, Covariance[9])"
#[4] "Equal = (G4, Covariance[14]) , (G1, Covariance[14]) , (G2, Covariance[14]) , (G3, Covariance[14])"
Upvotes: 1
Reputation: 22024
The data statement above makes a 6x6 matrix, so I edited it to make a 5x5 instead, to replicate what you've got above. Then, by using the upper triangle, it's actually easier to find the order number of the free elements.
unique.items <- c(1,2,3,4,5)
diag <- rep("Free",length(unique.items))
offdiag <- rep("0.0", (length(unique.items)-1)*length(unique.items)/2 )
m <- matrix(NA, ncol = length(diag), nrow = length(diag))
m[lower.tri(m)] <- offdiag
m[upper.tri(m)] <- t(m)[upper.tri(t(m))]
diag(m) <- diag
Since you don't want the first element, we could do the following:
ut <- m[,-1][upper.tri(m, diag=TRUE)[,-1]]
ut
# [1] "0.0" "Free" "0.0" "0.0" "Free" "0.0" "0.0" "0.0" "Free" "0.0" "0.0" "0.0"
# [13] "0.0" "Free"
This removes the first column from m
and then finds the upper triangle of m
, but cuts the first column of the output off. Next, just find which observations are "Free"
and those are the order numbers we're calling inds
.
inds <- which(ut == "Free")
We then can define the group
variable. We can also define the two pieces of each of the string - the group and the covariance statement.
group <- c(1,2,3,4)
eg <- expand.grid(group = paste0("G", group), cov=paste0(" Covariance[", inds, "]"))
head(eg)
# group cov
# 1 G1 Covariance[2]
# 2 G2 Covariance[2]
# 3 G3 Covariance[2]
# 4 G4 Covariance[2]
# 5 G1 Covariance[5]
# 6 G2 Covariance[5]
Next, we split the data frame based on the cov
variable, so that all of the same covariance groups are together.
eg <- split(eg, eg$cov)
eg
is now a list with four groups, one for each covariance group.
Now, with a bunch of paste statements, we could put all of the pieces together.
## collapses all of the pasted statements together by a new-line character \n
out <- paste(
## does the paste functions to each element of the list
sapply(eg, function(x)
## puts Equal = and ; around the result below
paste0("Equal = ",
## pastes the (G#, covariance[#]) together and collapses by a ,
paste(
## makes (G#, covariance[#])
paste0("(", x$group, ",", x$cov, ")"),
collapse=", "),
";")
),
collapse="\n")
cat(out)
# Equal = (G1, Covariance[2]), (G2, Covariance[2]), (G3, Covariance[2]), (G4, Covariance[2]);
# Equal = (G1, Covariance[5]), (G2, Covariance[5]), (G3, Covariance[5]), (G4, Covariance[5]);
# Equal = (G1, Covariance[9]), (G2, Covariance[9]), (G3, Covariance[9]), (G4, Covariance[9]);
# Equal = (G1, Covariance[14]), (G2, Covariance[14]), (G3, Covariance[14]), (G4, Covariance[14]);
Upvotes: 1