根据数据列表过滤数据框

时间:2019-08-01 16:58:25

标签: r tidyverse

在对数据列表中的数据帧进行多重过滤时,我遇到了麻烦。我的真实数据集非常庞大,因此我如下创建了一个伪造的数据集,以使该问题可复制。

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.grid

 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))

因此,在Cluster == 35函数内分配filter时将应用相同的内容。然后,我还将绑定这两个数据帧。

但是您可以看到,组的长度不相等。例如,第三个Grup_info里面有四个元素,就像第三个Cluster_grup一样。

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

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

1 个答案:

答案 0 :(得分:1)

很高兴见到你,maydin

我编写了可能想要的代码。

数据输入

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)