Saving vectors of different lengths in a matrix/da

2020-07-13 08:46发布

I have a numeric called area of length 166860. This consists of 412 different elements, most of length 405 and some of length 809. I have their start and end ids.

My goal is to extract them and put them in a matrix/data frame with 412 columns

Right now, I'm trying this code:

m = matrix(NA,ncol=412, nrow=809)
for (j in 1:412){
temp.start = start.ids[j]
temp.end = end.ids[j]
m[,j] = area[temp.start:temp.end]
}

But I just end up with this error message:

"Error in m[, j] = area[temp.start:temp.end] : number of items to replace is not a multiple of replacement length"

标签: r
5条回答
Evening l夕情丶
2楼-- · 2020-07-13 09:04

You are setting the column length to be 412, and matrices cannot be flexible/variable in their length. This means the value you assign to the columns must either have a length of 412 or something less that can fill into a length of 412. From the manual on ?matrix:

If there are too few elements in data to fill the matrix, then the elements in data are recycled. If data has length zero, NA of an appropriate type is used for atomic vectors (0 for raw vectors) and NULL for lists.

As another commenter said, you may have intended to assign to the rows in which case m[j, ] is the way to do that, but you have to then pad the value you are assigning with NA or allow NA's to be filled so the value being assigned is always of length 809.

m = matrix(NA,ncol=412, nrow=809)
for (j in 1:412){
  temp.start = start.ids[j]
  temp.end = end.ids[j]
  val <- area[temp.start:temp.end]
  m[j, ] = c(val, rep(NA, 809 - length(val)))
}
查看更多
倾城 Initia
3楼-- · 2020-07-13 09:04

Maybe others have better answers. As I see it, you have two options:

  1. Change m[,j] to m[1:length(area[temp.start:temp.end]),j] and then you will not get an error but you would have some NA's left.

  2. Use a list of matrices instead, so you would get different dimensions for each matrix.

查看更多
手持菜刀,她持情操
4楼-- · 2020-07-13 09:08

Here's a quite easy approach:

Example data:

area <- c(1:4, 1:5, 1:6, 1:3)
# [1] 1 2 3 4 1 2 3 4 5 1 2 3 4 5 6 1 2 3

start.ids <- which(area == 1)
# [1]  1  5 10 16

end.ids <- c(which(area == 1)[-1] - 1, length(area))
# [1]  4  9 15 18

Create a list with one-row matrices:

mats <- mapply(function(x, y) t(area[seq(x, y)]), start.ids, end.ids)
# [[1]]
#      [,1] [,2] [,3] [,4]
# [1,]    1    2    3    4
# 
# [[2]]
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    1    2    3    4    5
#
# [[3]]
#      [,1] [,2] [,3] [,4] [,5] [,6]
# [1,]    1    2    3    4    5    6
# 
# [[4]]
#      [,1] [,2] [,3]
# [1,]    1    2    3

Use the function rbind.fill.matrix from the plyr package to create the matrix and transpose it (t):

library(plyr)
m <- t(rbind.fill.matrix(mats))
#    [,1] [,2] [,3] [,4]
# 1    1    1    1    1
# 2    2    2    2    2
# 3    3    3    3    3
# 4    4    4    4   NA
# 5   NA    5    5   NA
# 6   NA   NA    6   NA
查看更多
欢心
5楼-- · 2020-07-13 09:09

What about

m[j,] = area[temp.start:temp.end]

?

Edit:

  a <- area[temp.start:temp.end]
  m[1:length(a),j] <- a
查看更多
戒情不戒烟
6楼-- · 2020-07-13 09:14

How about this? I've manufactured some sample data:

#here are the random sets of numbers - length either 408 or 809
nums<-lapply(1:412,function(x)runif(sample(c(408,809),1)))

#this represents your numeric (one list of all the numbers)
nums.vec<-unlist(nums)

#get data about the series (which you have)
nums.lengths<-sapply(nums,function(x)length(x)) 
nums.starts<-cumsum(c(1,nums.lengths[-1]))
nums.ends<-nums.starts+nums.lengths-1


new.vec<-unlist(lapply(1:412,function(x){
    v<-nums.vec[nums.starts[x]:nums.ends[x]]
    c(v,rep(0,(809-length(v))))
}))

matrix(new.vec,ncol=412)
查看更多
登录 后发表回答