【问题标题】:Split dataframe into list of multiple dataframes based on multiple columns and select specific columns for each nested dataframe基于多列将数据框拆分为多个数据框列表,并为每个嵌套数据框选择特定列
【发布时间】:2021-02-11 11:07:25
【问题描述】:

我有一个这样的数据框:

|DOI                           | WoS| Scopus| Dim| WoS_Year| Scopus_Year| Dim_Year|
|:-----------------------------|---:|------:|---:|--------:|-----------:|--------:|
|10.1515/jag-2017-0010         |  NA|      1|   1|       NA|        2017|     2017|
|10.1007/978-3-662-55771-6_9   |  NA|     NA|   1|       NA|          NA|     2020|
|10.1088/1361-6668/30/2/024004 |   1|      1|  NA|     2017|        2017|       NA|
|10.3390/ma12010124            |   1|      1|  NA|     2019|        2019|       NA|
|10.1002/ppsc.201700109        |   1|      1|   1|     2017|        2017|     2017|

我想将其拆分为 3 个数据帧的列表 (list_of_df),其中:

  • WoSlist_of_df$WoS 应该包含所有具有WoS = 1DOI,以及类似于旧WoS_Year 的列Year
  • Scopuslist_of_df$Scopus 应该包含所有具有Scopus= 1DOI,以及类似于旧Scopus_Year 的列Year
  • Dimlist_of_df$Dim 应该包含所有具有Dim= 1DOI,以及类似于旧Dim_Year 的列Year

(实际上有多个以WoS_*Scopus_*Dim_* 开头的列,我希望将每一列都保留在新的相应list_of_df 中,但是通过删除诸如WoS_ 等的起始字符串。

例如,starting_with("Scopus_") 的所有列都应在 list_of_df$Scopus 中,但列名中应不包含 Scopus_。)

实现这一目标的最佳方法是什么?

我对@9​​87654346@ 或dplyr::nest(df, WoS:Dim) 的尝试没有结果...

感谢您的帮助!

> dput(df)

structure(list(DOI = c("10.1515/jag-2017-0010", "10.1007/978-3-662-55771-6_9", 
"10.1088/1361-6668/30/2/024004", "10.3390/ma12010124", "10.1002/ppsc.201700109"
), WoS = c(NA, NA, 1L, 1L, 1L), Scopus = c(1L, NA, 1L, 1L, 1L
), Dim = c(1L, 1L, NA, NA, 1L), WoS_Year = c(NA, NA, 2017L, 2019L, 
2017L), Scopus_Year = c(2017L, NA, 2017L, 2019L, 2017L), Dim_Year = c(2017L, 
2020L, NA, NA, 2017L)), row.names = c(2186L, 9505L, 12281L, 11882L, 
874L), class = "data.frame")

【问题讨论】:

    标签: r dataframe dplyr nested nested-lists


    【解决方案1】:

    在基础 R 中你可以这样做:

    df1 <- subset(reshape(df, matrix(2:ncol(df),2, byrow=TRUE), dir="long", idvar = "DOI", 
                           times = c("WoS","Scopus","Dim")), WoS==1)
    rownames(df1)<-NULL
    split(df1, df1$time)
    
    $Dim
                               DOI time WoS WoS_Year
    8        10.1515/jag-2017-0010  Dim   1     2017
    9  10.1007/978-3-662-55771-6_9  Dim   1     2020
    10      10.1002/ppsc.201700109  Dim   1     2017
    
    $Scopus
                                DOI   time WoS WoS_Year
    4         10.1515/jag-2017-0010 Scopus   1     2017
    5 10.1088/1361-6668/30/2/024004 Scopus   1     2017
    6            10.3390/ma12010124 Scopus   1     2019
    7        10.1002/ppsc.201700109 Scopus   1     2017
    
    $WoS
                                DOI time WoS WoS_Year
    1 10.1088/1361-6668/30/2/024004  WoS   1     2017
    2            10.3390/ma12010124  WoS   1     2019
    3        10.1002/ppsc.201700109  WoS   1     2017
    

    您可以更改列名以匹配您想要的内容

    另一种方式:

    lapply(split.default(df[-1],sub("_.*","",names(df[-1]))),
            function(x)na.omit(cbind(df[1], x)[x[[1]]==1,]))
    $Dim
                                 DOI Dim Dim_Year
    2186       10.1515/jag-2017-0010   1     2017
    9505 10.1007/978-3-662-55771-6_9   1     2020
    874       10.1002/ppsc.201700109   1     2017
    
    $Scopus
                                    DOI Scopus Scopus_Year
    2186          10.1515/jag-2017-0010      1        2017
    12281 10.1088/1361-6668/30/2/024004      1        2017
    11882            10.3390/ma12010124      1        2019
    874          10.1002/ppsc.201700109      1        2017
    
    $WoS
                                    DOI WoS WoS_Year
    12281 10.1088/1361-6668/30/2/024004   1     2017
    11882            10.3390/ma12010124   1     2019
    874          10.1002/ppsc.201700109   1     2017
    

    【讨论】:

    • lapply 的第二个解决方案非常优雅……谢谢! (但是有没有办法摆脱最后列名中的WoS_*Scopus_*?)我想我应该将user2974591的colnames()gsub()整合到lapply函数中,但我不是100% 确定如何做到这一点。
    • lapply(split.default(df[-1],sub("_.*","",names(df[-1]))), function(x)na.omit(cbind(df[1], setNames(x, sub("_.*","", names(x))))[x[[1]]==1,])) 应该可以工作
    【解决方案2】:

    base R 中的另一个,如果这是预期的输出

    res=list()
    for (k in c("WoS","Scopus","Dim")) {
      res[[k]]=df[df[,k]==1 & !is.na(df[,k]),grepl(k,colnames(df)) | c(TRUE,rep(FALSE,ncol(df)-1))]
      colnames(res[[k]])=gsub(paste0(k,"_"),"",colnames(res[[k]]))
    }
    
    $WoS
                                    DOI WoS Year
    12281 10.1088/1361-6668/30/2/024004   1 2017
    11882            10.3390/ma12010124   1 2019
    874          10.1002/ppsc.201700109   1 2017
    
    $Scopus
                                    DOI Scopus Year
    2186          10.1515/jag-2017-0010      1 2017
    12281 10.1088/1361-6668/30/2/024004      1 2017
    11882            10.3390/ma12010124      1 2019
    874          10.1002/ppsc.201700109      1 2017
    
    $Dim
                                 DOI Dim Year
    2186       10.1515/jag-2017-0010   1 2017
    9505 10.1007/978-3-662-55771-6_9   1 2020
    874       10.1002/ppsc.201700109   1 2017
    

    【讨论】:

    • 太好了,非常感谢!出于某种原因,它删除了我的DOI 列。你知道为什么会这样吗?
    • @anpami 很难说,但我确实假设 DOI 列位于原始数据框中的位置 1,这是否改变了?这就是右边的东西|在循环的第一行执行。
    • 啊,你是对的。我的代码添加了一个X 列......所以在df[1] &lt;- NULL 之后它再次工作。谢谢你。虽然我喜欢你的代码(非常感谢!),但我认为我必须接受 @Onyambu 的第二个解决方案 lapply。原因是 Onyambu 的 lapply-solution 非常抽象和通用,它适用于列名称中的任何字符(即,不仅适用于 WoS_Scopus_Dim_,而且适用于发生的任何其他字符到那里)。我觉得这个最优雅。不过,感谢您的解决方案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-13
    • 1970-01-01
    • 1970-01-01
    • 2020-01-08
    • 1970-01-01
    相关资源
    最近更新 更多