【问题标题】:Nested loop in R: number of items to replace is not a multiple of replacement lengthR中的嵌套循环:要替换的项目数不是替换长度的倍数
【发布时间】:2017-03-11 23:36:31
【问题描述】:

我尝试使用嵌套循环对我的数据集进行子集化。不幸的是,它似乎无法正常工作:我收到了几个警告,并且循环也没有按我希望的那样工作。

这里有一个简短的代码示例。提供的数据只是一个示例 - 实际数据集要大得多:任何涉及手动选取值的解决方案都是不可行的。

# #Generate example data
unique_test <- list()
unique_test[[1]] <- c(178.5, 179.5, 180.5, 181.5)
unique_test[[2]] <- c(269.5, 270.5, 271.5)



tmp_dataframe1 <- data.frame(myID = c(268, 305, 268, 305, 268, 305, 306), 
                            myvalue = c(1.150343, 2.830392, 1.150343, 2.830392, 1.150343, 2.830392, 1.150343), 
                            myInter = c(178.5, 178.5, 179.5, 179.5, 180.5, 180.5, 181.5))

tmp_dataframe2 <- data.frame(myID = c(144, 188, 196, 300, 301, 302, 303, 97), 
                             myvalue = c(1.293493, 3.286649, 1.408049, 0.469219, 11.143147, 0.687355, 0.508603, 0.654335), 
                             myInter = c(269.5, 269.5, 269.5, 270.5, 270.5, 271.5, 185.5, 186.5))



mydata <- list()
mydata[[1]] <- tmp_dataframe1
mydata[[2]] <- tmp_dataframe2
########################

# #Generate nested loop
mysubset <- list() #Define list

for(i in 1:length(unique_test)){
  #Prepare list of lists
  mysubset[[i]] <- NaN
  for(j in 1:length(unique_test[[i]])){
    #Select myvalues whose myInter data equals the one found in unique_test and assign them to a new subset
    mysubset[[i]][j] <- mydata[[i]][which(mydata[[i]]$myInter == unique_test[[i]][j]),][["myvalue"]]
  }
}

# #There are warnings and the nested loop is not really doing, what it is supposed to do!

R 给出以下警告:

Warning messages:
1: In mysubset[[i]][j] <- mydata[[i]][which(mydata[[i]]$myInter ==  :
  number of items to replace is not a multiple of replacement length
2: In mysubset[[i]][j] <- mydata[[i]][which(mydata[[i]]$myInter ==  :
  number of items to replace is not a multiple of replacement length
3: In mysubset[[i]][j] <- mydata[[i]][which(mydata[[i]]$myInter ==  :
  number of items to replace is not a multiple of replacement length
4: In mysubset[[i]][j] <- mydata[[i]][which(mydata[[i]]$myInter ==  :
  number of items to replace is not a multiple of replacement length
5: In mysubset[[i]][j] <- mydata[[i]][which(mydata[[i]]$myInter ==  :
  number of items to replace is not a multiple of replacement length

如果我将自己限制为数据集中的第一个元素,则“正常”(即非嵌套)循环会起作用:

# #If I don't use a nested loop (by just using the first element in both "mydata" and "unique_test"), things seem to work out
# #But obviously, this is not really what I want to achieve (I can't just manually select every element in mydata and unique_test)
mysubset <- list()
for(i in 1:length(unique_test[[1]])){
  #Select myvalues whose myInter data equals the one found in unique_test and assign them to a new subset
  mysubset[[i]] <- mydata[[1]][which(mydata[[1]]$myInter == unique_test[[1]][i]),][["myvalue"]]
}

是不是我首先必须使用适当的维度来启动我的列表?但是,如果我的数据集中所有元素的尺寸都不相同(这就是我必须首先使用 length() 函数的原因),我该怎么做? 如您所见,mydata[[1]] 的维度与 mydata[[2]] 不同。 因此,以下链接中提供的解决方案不适用于此数据集:

Error in R :Number of items to replace is not a multiple of replacement length

Error in `*tmp*`[[k]] : subscript out of bounds in R

我很确定我丢失了一些明显的东西,但我就是找不到它。非常感谢任何帮助!

如果有更好的方法在没有循环的情况下实现相同的效果(我确信有,例如 apply() 或类似子集() 的东西),我也会很感激这样的 cmets。不幸的是,我对能够快速实施它们的替代方案不够熟悉。

【问题讨论】:

    标签: r list loops nested nested-lists


    【解决方案1】:

    由于嵌套的for 循环而不是向量本身,您尝试将数字向量分配给嵌套列表时,只需将您的分配包装在list() 中。

    mysubset[[i]][j] <- list(mydata[[i]][which(mydata[[i]]$myInter == unique_test[[i]][j]),][["myvalue"]])
    

    或者更短的which()不需要也不需要外方括号:

    mysubset[[i]][j] <- list(mydata[[i]][mydata[[i]]$myInter == unique_test[[i]][j], c("myvalue")])
    

    或者,考虑一个应用解决方案,因为您不需要最初分配一个空列表并迭代地扩展它以将值绑定到它。嵌套lapplysapplymapply,甚至rapply 都可以一次调用创建所需的列表和维度。 mapply 假定 unique_testmydata 始终是长度相等的对象。

    # NESTED LAPPLY
    mysubset2 <- lapply(seq(length(unique_test)), function(i) {
      lapply(seq(length(unique_test[[i]])), function(j){
        mydata[[i]][mydata[[i]]$myInter == unique_test[[i]][j], c("myvalue")]
      })
    })
    
    # NESTED SAPPLY
    mysubset3 <- sapply(seq(length(unique_test)), function(i) {
      sapply(seq(length(unique_test[[i]])), function(j){
          mydata[[i]][mydata[[i]]$myInter == unique_test[[i]][j], c("myvalue")]
      })
    }, simplify = FALSE)
    
    # NESTED M/LAPPLY  
    mysubset4 <- mapply(function(u, m){
      lapply(u, function(i) m[m$myInter == i, c("myvalue")])
    }, unique_test, mydata, SIMPLIFY = FALSE)
    
    # NESTED R/LAPPLY 
    mysubset5 <- rapply(unique_test, function(i){
      df <- do.call(rbind, mydata)
      lapply(i, function(u) df[df$myInter == u, c("myvalue")])      
    }, how="list")
    
    # ALL SUBSETS EQUAL EXACTLY
    all.equal(mysubset, mysubset2)
    # [1] TRUE    
    all.equal(mysubset, mysubset3)
    # [1] TRUE    
    all.equal(mysubset, mysubset4)
    # [1] TRUE
    all.equal(mysubset, mysubset5)
    # [1] TRUE
    

    【讨论】:

      【解决方案2】:

      你能发布你期望 mysubset 的样子吗?根据我的理解,这应该使用 unique_test 中的值对 myvalue 进行子集化:

      mysubset <- unique(unlist(lapply(unlist(unique_test),function(x) subset(mydata,myInter==x,select="myvalue"))))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多