【问题标题】:R Apply functions to lists with lapplyR 使用 lapply 将函数应用于列表
【发布时间】:2018-02-11 10:17:47
【问题描述】:

我有三个列表,List1 包含标识符,List2 包含逗号分隔的字符串,这些字符串可能是 List1 中的项目,List3 包含数字(一些测量分数)。

List1=c("Object1","Object2",......,"Objectn")
List2=c("Object1","Object2,Object3","Object4","Object5","Object6", .... )
List3=c("0.90","0,80",....)

所有列表的长度相同。

我要做什么,对于List1中的每一项,对于List2中的每一项,检查交集是否不为空,并增加一个分数。

我可以反复执行此操作,但由于我的列表太长,我想使用 lapply 执行此操作但失败了。任何帮助将不胜感激。

FinalScoreList="",

for(i in 1:length(List1)){

  score=0

   for(j in 1:length(List2)){


      if(length(intersect(List1[[i]], 
             as.list(unlist(strsplit(as.character(List2[j]),',')))))>0) {

            score=score+as.double(List3[j])

        }

      }

     FinalScoreList=c(FinalScoreList,score)

   }

【问题讨论】:

    标签: r list lapply


    【解决方案1】:

    我认为这与您所追求的一致:

    List1=c("Object1","Object2", "0.70")
    List2=c("Object1","Object2", "Object3")
    List3=c("0.90","0,80", "0.70")
    
    # Make a list of lists
    All_Lists = list(
      "List1" = List1,
      "List2" = List2,
      "List3" = List3
    )
    
    # Create a dataframe listing all pairwise combinations of the lists
    intersect_df <- data.frame(t(combn(names(All_Lists), 2)))
    
    # Add a new column to this dataframe indicating the length of the intersection
    # between each pair of lists
    intersect_df$count <- apply(intersect_df, 1, function(r) length(intersect(All_Lists[[r[1]]], All_Lists[[r[2]]])))
    

    输出:

    > intersect_df
         X1    X2 count
    1 List1 List2     2
    2 List1 List3     1
    3 List2 List3     0
    

    所以输出中的每一行都指定了两个列表(X1X2)的组合,count 列表示这两个列表之间的交集长度。

    【讨论】:

    • 问题是list2中的项目可能是List1的串联项目,例如:List2=c("Object1","Object2,Object3","Object4","Object5","Object6" , .... )。第二项是 Object2,Object3 这就是我应用 strsplit 的原因,这很耗时。谢谢你的建议。
    【解决方案2】:

    首先,我不建议将名称“List”(List1,List2,List3...)给非列表项。 其次,因为您希望“List3”元素是数字的,所以从一开始就这样做。我创建了以下示例:

    library(dplyr)
    List1=c("Object1","Object2","Object3","Object4","Object5","Object6","Object7","Object8")
    List2=c("Object3","Object4","Object5","Object6","Object7","Object8","Object9","Object10")
    List3=c("0.90","0.80","0.70","0.60","0.50","0.40","0.30","0.20")%>%as.numeric
    

    现在只需对您的代码进行少量更改,我们就可以得到 FinalScoreList

    FinalScoreList=c()
    
    for(i in 1:length(List1)){
    
      score=0
    
      for(j in 1:length(List2)){
    
        if(length(intersect(List1[[i]], as.list(unlist(strsplit(as.character(List2[j]),',')))))>0) {
          score=score+List3[j]
        }
      }
      FinalScoreList=c(FinalScoreList,score)
    }
    > FinalScoreList
    [1] 0.0 0.0 0.9 0.8 0.7 0.6 0.5 0.4
    

    我们可以在不循环下面的代码的情况下得到相同的结果:

    df=data.frame(List1,List2,List3)
    df$Matches<-0
    matches0<-grep(List1,pattern=paste(intersect(List2,List1),collapse="|"))
    matches1<-grep(List2,pattern=paste(intersect(List2,List1),collapse="|"))
    df$Matches[matches0]<-List3[matches1]
    > df$Matches
    [1] 0.0 0.0 0.9 0.8 0.7 0.6 0.5 0.4
    

    【讨论】:

      【解决方案3】:

      您可以在循环之前执行List2 的拆分,这已经加快了速度。同样,当您从一个空向量 FinalScoreList 开始时,R 必须在每一步中都增加它,这也会使其变慢。

      这是一个嵌套lapply/sapply-calls的解决方案:

      List2 <- lapply(List2, function(x) unlist(strsplit(x, split = ",")))
      
      FinalScoreList <- lapply(List1, function(x) {
        indicator <- sapply(List2, function(y) x %in% y) 
        sum(List3[indicator])
      })
      
      unlist(FinalScoreList)
      

      正如@Antonis 已经说过的,您应该已经将您的List3 向量存储为数字向量。

      数据

      List1 <- paste0("Object", 1:10)
      List2 <- c("Object1", "Object6,Object5", "Object2,Object1", "Object7", 
                 "Object6,Object8", "Object5,Object9", "Object4,Object2", 
                 "Object3,Object8", "Object2,Object6", "Object10,Object3")
      List3 <- runif(10)
      

      【讨论】:

      • 谢谢凯丝。现在假设 List1 与 List2 具有相同的性质,即项目可以是串联的字符串:
      【解决方案4】:

      谢谢你们。

      现在假设 List1 与 List2 具有相同的性质,即项目可以是串联的字符串。也可以有不同的长度。

      我在 List1 上做了 lapply strsplit,但我仍然在 FinalScoreList 中获得了 NA。

      List1 <- c("Object1", "Object7,Object5", "Object2,Object1")
      
      
      List2 <- c("Object1", "Object6,Object5", "Object0,Object1", "Object7", 
                 "Object6,Object8", "Object5,Object9", "Object4,Object2", 
                 "Object3,Object8", "Object2,Object3", "Object10,Object3")
      
      
      List3 <- runif(10)
      
      List2 <- lapply(List2, function(x) unlist(strsplit(x, split = ",")))
      
      
      List1 <- lapply(List1, function(x) unlist(strsplit(x, split = ",")))
      
      FinalScoreList <- lapply(List1, function(x) {
        indicator <- sapply(List2, function(y) {x %in% y}) 
        sum(List3[indicator])
      })
      
      unlist(FinalScoreList)
      

      [1] 1.595639 NA NA

      【讨论】:

      • 请相应地更新您的原始问题,不要发布修改作为答案。您可能只需要将x %in% y 替换为any(x %in% y)
      猜你喜欢
      • 2019-11-09
      • 1970-01-01
      • 2014-03-17
      • 2020-05-08
      • 2015-10-12
      • 1970-01-01
      • 2021-07-12
      • 1970-01-01
      相关资源
      最近更新 更多