a=matrix(list(),2,2)
a[1,2]=list(2) ##works
a=matrix(list(),2,2)
a[1,2]=list(2,3) ##doesn't work
Error in a[1, 2] = list(2, 3) : number of items to replace is not a
multiple of replacement length
That's the error message from the fourth line. If I try
x=list()
x=list(2,4)
it works, I don't see the difference as a[1,2] is a NULL list..
Thanks in advance.
When you replace with list(2), look at the output:
a=matrix(list(),2,2)
a[1,2]=list(2) sapply(a, class)
# [1] "NULL" "NULL" "numeric" "NULL"
That is, the [1,2] element is not a list.
list(2,3) can be coerced like that to a single element; as RichardScriven points out, the replacement must be length-1; the following works (a bit silly, I agree):
a = matrix(list( ), 2, 2)
a[1, 2] = list(list(2, 3))
a
# [,1] [,2]
# [1,] NULL List,2
# [2,] NULL NULL
(just for reference, I figured this out by playing with dput, like so:)
#What happens if we declare 'a' as a
# matrix of appropriately-sized lists to start with?
a <- matrix(replicate(4, vector("list", 2), simplify = FALSE), 2, 2)
a
# [,1] [,2]
# [1,] List,2 List,2
# [2,] List,2 List,2
#
# can we replace now?
a[1,2] <- list(2,3)
# (same error; what IS 'a[1,2]' for this matrix?)
dput(a[1, 2])
# list(list(NULL, NULL))
# BINGO! we must replace 'a[1,2]' with a length-one list.
Related
When I have a 3D array, I want to obtain the list of row names and column names when selecting some elements in array.
For example,
mdat <- array(c(1,2,3, 11,12,13,1,2,3,2,3,4,3,4,5,4,5,6), dim= c(2, 3, 2),dimnames = list(c("row1", "row2"), c("C.1", "C.2", "C.3"),c("m1","m2")))
which(mdat[,,2]==2) returns location of the elements but I want to obtain the paired row names and column names which are (row 2,c.1),(row 2,c.2). I haven't found a way to get the dimname in 3D array. Have anyone tried this?? Any suggestion is appreciated.
You can try the following :
tmp <- mdat[,,2]
mat <- which(tmp==2, arr.ind = TRUE)
cbind(rownames(tmp)[mat[, 1]], colnames(tmp)[mat[, 2]])
# [,1] [,2]
#[1,] "row2" "C.1"
#[2,] "row2" "C.2"
Maybe you can try the code below with which + dimnames like below
inds <- which(mdat[,,2]==2,arr.ind = T)
nm <- dimnames(mdat[,,2])
sapply(seq_along(nm),function(k) nm[[k]][inds[,k]])
which gives
[,1] [,2]
[1,] "row2" "C.1"
[2,] "row2" "C.2"
What i want to have is a matrix in which each element is a list itself.
See the following example:
1 2 3
1 1,2,4 1,2 1
2 Null 3,4,5,6 1,3
I saw this post, and tried the following but got an error :
b <- array()
b[j, i, ] <- A[i]
where A is a vector itself.
The error was:
Error in b[j, i, ] <- A[i] : incorrect number of subscripts
How should I define and access each element of the matrix and each element of the contained lists?
Update1 :
b<-matrix(list(),nrow = length(d), ncol =length(c))
Error in b[j, i] <- A[i] : replacement has length zero
I want to specify that each element is a list and then try to fill it with various list with different length from zero to n.
Update2 :
running what #BondedDust commented :
b<-matrix(rep(list(),(c*d)),,nrow = length(d), ncol =length(c))
Erorr in b[[j*nrow(b)+i]] <- A[i] : attempt to select less than one element
A :
A[1]<-c(3) F[[1]]<-numeric(0) E[[1]]<-numeric(0)
A[2]<-c(1) F[2]<-c(1) E[2]<-c(1)
A[3]<-c(1) F[3]<-c(2) E[[3]]<-numeric(0)
A[[4]]<-c(1,3) F[[4]]<-numeric(0) E[[4]]<-numeric(0)
A[5]<-c(4) F[5]<-c(4) E[5]<-c(4)
A :values of row 1 , F:row 2 and E :row 3. ( 5 column )
this data is not in this form and is not stored any where,they are the output of another function (there is function in the place of A[i]).the data just show what dose A look likes reproducibly and therefore shows the position in the matrix and gives back the error in update2.A[4] is the element of column 4 row 2.
This builds that matrix although the print method does not display it in the manner you imagined:
matrix( list(c(1,2,4), c(NULL), c(1,2), c(3,4,5,6), c(1), c(1,3)), 2,3)
#---------
[,1] [,2] [,3]
[1,] Numeric,3 Numeric,2 1
[2,] NULL Numeric,4 Numeric,2
Inspect the first element:
> Mlist <- matrix( list(c(1,2,4), c(NULL), c(1,2), c(3,4,5,6), c(1), c(1,3)), 2,3)
> Mlist[1,1]
[[1]]
[1] 1 2 4
> is.matrix(Mlist)
[1] TRUE
> class( Mlist[1,1] )
[1] "list"
Demonstration of creating "matrix of lists" from a list:
> will.become.a.matrix <- list(c(1,2,4), c(NULL), c(1,2), c(3,4,5,6), c(1), c(1,3))
> is.matrix(will.become.a.matrix)
[1] FALSE
> dim(will.become.a.matrix) <- c(2,3)
> is.matrix(will.become.a.matrix)
[1] TRUE
> dim(will.become.a.matrix)
[1] 2 3
> class(will.become.a.matrix[1,1])
[1] "list"
Further requested demonstration:
A<- list(); F=list() E=list()
A[1]<-c(3) ; F[[1]]<-numeric(0); E[[1]]<-numeric(0)
A[2]<-c(1) ; F[2]<-c(1) ; E[2]<-c(1)
A[3]<-c(1) ; F[3]<-c(2) ; E[[3]]<-numeric(0)
A[[4]]<-list(1,3) ;F[[4]]<-numeric(0) ; E[[4]]<-numeric(0)
A[5]<-c(4) ; F[5]<-c(4) ; E[5]<-c(4)
Mlist= c(A,F,E)
M <- matrix(Mlist, length(A), 3)
#=====================================
> M
[,1] [,2] [,3]
[1,] 3 Numeric,0 Numeric,0
[2,] 1 1 1
[3,] 1 2 Numeric,0
[4,] List,2 Numeric,0 Numeric,0
[5,] 4 4 4
You asked (in comments) "....is there a way to define number of column and rows , but not the element itself because they are unknown?"
Answered (initially in comments)
b<-matrix(rep(list(), 6),nrow = 2, ncol =3)
#.... then replace the NULL items with values.
# Need to use "[[": for assignment (which your 'Update 1' did not
# ....and your Update2 only did for some but not all of the assignments.)
b[[1]] <- c(1,2,3,4)
I have a 4x100 matrix where I would like to multiply column 1 with row 1 in its transpose etc and store these matrices somewhere to be able to take the sum of these new matrices lateron.
I really don't know where to start due to the fact that I get 4x4 matrices after the column-row-multiplication. Due to this fact I cannot store them in a matrix
data:
mm num[1:4,1:100]
mm_t num[1:100,1:4]
I'm thinking of creating a list in some way
list1=list()
for(i in 1:100){
list1[i] <- mm[,i]%*%mm_t[i,]
}
but I need some more indices i think because this just leaves me with a number in each argument..
First, your call for data is not clear. Second, are you tryign to multiply each value by itself, or do matrix multiplication
We create a 4x100 matrix and its transpose:
mm <- matrix(1:400, nrow = 4, ncol = 100)
mm.t <- t(mm)
Then we can do the matrix multiplication (which is what you did, and you get a 4 x 4 matrix from the definition of matrix multiplication https://www.wikiwand.com/en/Matrix_multiplication)
If we want to multiply each index by itself (so mm[1,1] by mm [1,1]) then:
mm * mm
This will result in 4x100 matrix where each value is the square of the original value.
If we want the matrix multiplication of each column with itself, then:
sapply(1:100, function(x) {
mm[, x] %*% mm[, x]
})
This results in 100 values: each one is the matrix product of a 4x1 vector with itself.
Let's start with some sample data. Please get in the habit of including things like this in your question:
nr = 4
nc = 100
set.seed(47)
mm = matrix(runif(nr * nc), nrow = nr)
Here's a working answer, very similar to your attempt:
result = list()
for (i in 1:ncol(mm)) result[[i]] = mm[, i] %*% t(mm[, i])
result[1:2]
# [[1]]
# [,1] [,2] [,3] [,4]
# [1,] 0.9544547 0.3653018 0.7439585 0.8035430
# [2,] 0.3653018 0.1398132 0.2847378 0.3075428
# [3,] 0.7439585 0.2847378 0.5798853 0.6263290
# [4,] 0.8035430 0.3075428 0.6263290 0.6764924
#
# [[2]]
# [,1] [,2] [,3] [,4]
# [1,] 0.3289532 0.3965557 0.2231443 0.2689613
# [2,] 0.3965557 0.4780511 0.2690022 0.3242351
# [3,] 0.2231443 0.2690022 0.1513691 0.1824490
# [4,] 0.2689613 0.3242351 0.1824490 0.2199103
As to why yours didn't work, we can experiment and see that indeed we get a number rather than a matrix. The reason is that when you subset a single row or column of a matrix, the dimensions are "dropped" and it is coerced to a plain vector. And when you matrix multiply two vectors, you get their dot product.
mmt = t(mm)
mm[, 1] %*% mmt[1, ]
# [,1]
# [1,] 2.350646
dim(mm[, 1])
# NULL
dim(mmt[1, ])
# NULL
We can avoid this by specifying drop = FALSE in the subset code
dim(mmt[1, , drop = FALSE])
# [1] 1 4
And thus slightly modify your attempt, just adding drop = FALSE will make it work.
res2 = list()
for (i in 1:ncol(mm)) res2[[i]] = mm[, i] %*% mmt[i, , drop = FALSE]
identical(result, res2)
# [1] TRUE
I'm working with a three-dimensional array in R that has dimensions determined by user arguments, and where the first dimension can be of length 1 or more.
Subsetting the array works fine if the first dimension is of length two or more:
Arr2 <- array(rnorm(2 * 4 * 7), dim = c(2, 4, 7))
Arr2[,,1]
But if the first dimension is of length one, the subset operator will return either a vector (if drop = TRUE) or a three-dimensional array (if drop = FALSE):
Arrrrgh <- array(rnorm(1 * 4 * 7), dim = c(1,4,7))
Arrrrgh[,,1]
Arrrrgh[,,1,drop=FALSE]
How can I subset this array along the third dimension, while preserving the first and second dimensions?
As you note, from ?"[" there are only two options to control the dimension, drop=TRUE (the default, which in this case will drop both the first and third dimensions) and drop=FALSE, which won't drop any dimension. Neither of these options returns the desired dimension of c(1, 4):
dim(Arrrrgh[,,1])
# NULL
dim(Arrrrgh[,,1,drop=FALSE])
# [1] 1 4 1
One way to address this would be to set the dimension yourself after the subsetting operation:
`dim<-`(Arrrrgh[,,1], dim(Arrrrgh)[1:2])
# [,1] [,2] [,3] [,4]
# [1,] 0.1548771 0.6833689 -0.7507798 1.271966
You could generalize this to a function that drops specified indices if they have a single value passed and doesn't drop any other indices:
extract.arr <- function(arr, ...) {
m <- match.call(expand.dots=FALSE)
missing <- sapply(m[["..."]], is.symbol)
dot.len <- sapply(m[["..."]], function(x) if (is.symbol(x)) 0 else length(eval(x)))
cdim <- dim(arr)
eff.dim <- ifelse(missing, cdim, dot.len)
`dim<-`(do.call("[", c(list(arr), m[["..."]])), eff.dim[eff.dim > 1 | missing])
}
extract.arr(Arrrrgh, ,,1)
# [,1] [,2] [,3] [,4]
# [1,] -0.8634659 1.031382 0.4290036 0.8359372
extract.arr(Arrrrgh, ,,1:2)
# , , 1
#
# [,1] [,2] [,3] [,4]
# [1,] -0.8634659 1.031382 0.4290036 0.8359372
#
# , , 2
#
# [,1] [,2] [,3] [,4]
# [1,] 0.6970842 0.1185803 0.3768951 -0.4577554
extract.arr(Arrrrgh, 1,1,)
# [1] -0.8634659 0.6970842 0.1580495 -1.6606119 -0.2749313 0.4810924 -1.1139392
Consider the following matrix,
m <- matrix(letters[c(1,2,NA,3,NA,4,5,6,7,8)], 2, byrow=TRUE)
## [,1] [,2] [,3] [,4] [,5]
## [1,] "a" "b" NA "c" NA
## [2,] "d" "e" "f" "g" "h"
I wish to obtain the column indices corresponding to all non-NA elements, merged with the NA elements immediately following:
result <- c(list(1), list(2:3), list(4,5),
list(1), list(2), list(3), list(4), list(5))
Any ideas?
The column (and row) indicies of non-NA elements can be obtained with
which(!is.na(m), TRUE)
A full answer:
Since you want to work row-wise, but R treats vector column-wise, it is easier to work on the transpose of m.
t_m <- t(m)
n_cols <- ncol(m)
We get the array indicies as mentioned above, which gives the start point of each list.
ind_non_na <- which(!is.na(t_m), TRUE)
Since we are working on the transpose, we want the row indices, and we need to deal with each column separately.
start_points <- split(ind_non_na[, 1], ind_non_na[, 2])
The length of each list is given by the difference between starting points, or the difference between the last point and the end of the row (+1). Then we just call seq to get a sequence.
unlist(
lapply(
start_points,
function(x)
{
len <- c(diff(x), n_cols - x[length(x)] + 1L)
mapply(seq, x, length.out = len, SIMPLIFY = FALSE)
}
),
recursive = FALSE
)
This will get you close:
cols <- col(m)
cbind(cols[which(is.na(m))-1],cols[is.na(m)])
[,1] [,2]
[1,] 2 3
[2,] 4 5