【问题标题】:Filtering a dataframe with respect to the list of data根据数据列表过滤数据框
【发布时间】:2019-08-01 16:58:25
【问题描述】:

我无法在数据框中对数据列表进行多重过滤。我的真实数据集很大,所以我创建了一个如下所示的假数据集以使问题可复制。

set.seed(1)

df <- data.frame(Cluster=round(runif(2000,1,50)),
        Grup = paste0("Group",round(runif(2000,1,10))),
        ID = paste0("id",1:2000),
        Point1 = round(runif(2000,1,100)),
        Point2 = round(runif(2000,1,100)))

Cluster_grup <- list(List1 = data.frame( V1=c(47,35),V2=c(20,35)),
    List2 = data.frame(V1=c(10,5,6),V2=c(49,2,46),V3=c(11,12,13)),
    List3 = data.frame(V1=c(22,3),V2=c(18,18),V3=c(50,25),V4=c(6,7)))



Grup_info <- list(First = c("Group1","Group7"), 
             Second = c("Group4","Group5","Group3"),
             Third = c("Group10","Group8","Group1","Group6"))

我基本上想对Grup_infoCluster_grup 中的数据进行过滤。例如,如果我们取这两个列表的第一个元素,

Grup_info[[1]]
"Group1" "Group7"

Cluster_grup [[1]]
  V1 V2
1 47 20
2 35 35

然后我需要过滤并应用expand.gridlike,

 df_sorted1 <- df %>% filter(.,Cluster == 47 & Grup=="Group1")  %>% 
              select(.,ID,Point1,Point2)
 df_sorted2 <-df %>% filter(.,Cluster == 20 & Grup=="Group7")  %>% 
              select(.,ID,Point1,Point2)

ep1 <- expand.grid(df_sorted1$ID,df_sorted2$ID)
ep2 <- expand.grid(df_sorted1$Point1,df_sorted2$Point1)
ep3 <- expand.grid(df_sorted1$Point2,df_sorted2$Point2)

data.frame(ep1, SumPoint1 = rowSums(ep2),SumPoint2 = rowSums(ep3))

因此,在 filter 函数内分配 Cluster == 35 时,将应用同样的事情。然后我也会绑定这两个数据框。

但如您所见,组的长度并不相等。例如,第三个Grup_info 内部有四个元素,第三个Cluster_grup 有。

最后,我想得到一个列表,包括三个数据帧,它们是expand.grid输出的绑定数据帧。

我实际上可以通过 for 循环或 sapply 系列函数来实现它,但我想知道是否存在更快的解决方案,如 tidyverse 方法或类似的方法。

【问题讨论】:

    标签: r tidyverse


    【解决方案1】:

    很高兴见到你,梅丁

    我大概做了你想要的代码。

    数据输入

    set.seed(1)
    library(dplyr)
    library(tidyverse)
    library(rlang)
    library(data.table)
    df <- data.frame(Cluster=round(runif(2000,1,50)),
                     Grup = paste0("Group",round(runif(2000,1,10))),
                     ID = paste0("id",1:2000),
                     Point1 = round(runif(2000,1,100)),
                     Point2 = round(runif(2000,1,100)))
    
    Cluster_grup <- list(List1 = data.frame( V1=c(47,35),V2=c(20,35)),
                         List2 = data.frame(V1=c(10,5,6),V2=c(49,2,46),V3=c(11,12,13)),
                         List3 = data.frame(V1=c(22,3),V2=c(18,18),V3=c(50,25),V4=c(6,7)))
    
    
    
    Grup_info <- list(List1 = c("Group1","Group7"), 
                      List2 = c("Group4","Group5","Group3"),
                      List3 = c("Group10","Group8","Group1","Group6"))
    

    数据合并

    我合并了Cluster_grupGrup_info

    mergeGrp <-
      sapply(names(Grup_info), function(x){
        material <- Cluster_grup[[ x ]]
        colnames(material)<- Grup_info[[x]]
      return(material)
      })
    > mergeGrp
    $List1
      Group1 Group7
    1     47     20
    2     35     35
    
    $List2
      Group4 Group5 Group3
    1     10     49     11
    2      5      2     12
    3      6     46     13
    
    $List3
      Group10 Group8 Group1 Group6
    1      22     18     50      6
    2       3     18     25      7
    
    

    数据处理

    我使用RbindList 来合并所有结果。 但如果你不想那样,你应该操纵自己。

    FinalResult = lapply(mergeGrp,function(x){
      tidyTest = x %>% tidyr::gather() %>% dplyr::group_by(key)
      result = NULL
      for (i in 1: NROW(x)){
        mate = tidyTest %>% filter(row_number() == i )
        condList = apply(mate,1,function(x){
                    sprintf("( Cluster == %s & Grup == '%s' )",x[2],x[1])
                    })
        filtered = lapply(condList, function(x){
                       df %>% filter_(x) %>% select(ID,Point1,Point2)}
                       )
        ep1 = filtered  %>% purrr::map(.,~.$ID) %>%
                as.vector() %>% expand.grid()
        ep2 = filtered  %>% purrr::map(.,~.$Point1) %>% as.vector() %>%
                expand.grid() %>% rowSums()
        ep3 = filtered  %>% purrr::map(.,~.$Point2) %>% as.vector() %>% 
                expand.grid() %>% rowSums()
        result = rbind(result,data.frame(ep1, SumPoint1 = ep2,SumPoint2 = ep3))
      }
      return(result)
    }
    )
    #rbindlist(FinalResult)
    

    【讨论】:

    • 感谢@SteveLee 的回答。循环内的test 是什么?
    • 糟糕,很抱歉我修复了错误,最后我删除了rbindlist。如果你想用就改成rbindlist(FinalResult, fill = TRUE)
    猜你喜欢
    • 1970-01-01
    • 2020-07-01
    • 2021-12-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-08
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    相关资源
    最近更新 更多