R:高效的数据帧split-apply(连接)

时间:2018-04-30 00:49:39

标签: r dplyr concatenation

我希望获得一些专家建议,以便有效地删除一列中的数据帧行(columnA),其中存在重复值,同时创建一个连接另一列条目的新变量(columnB) )在columnA有重复的情况下。下面我提供一个玩具数据框:

my_df <- data.frame('DateTime' = c('2017/05/05 08:30:00', '2017/05/05 08:30:00', 
                               '2017/05/05 08:30:00', '2017/12/08 08:30:00',
                              '2018/01/15 18:50:00', '2017/12/20 21:46:00',
                              '2017/11/12 18:50:00', '2017/11/03 08:30:00',
                              '2017/11/03 08:30:00', '2017/12/03 08:30:00'),
                     'Event' = c('A', 'B', 'C', 'A', 'A', 'B', 'C', 'A', 'B', 'A'),
                     'Var1' = rnorm(10),
                     stringsAsFactors = FALSE)

在此数据框中,DateTime列是一个字符列,2017/05/08 08:30:00出现3次,而2017/11/03 08:30:00出现两次。我的目标是折叠存在重复DateTime的行,并创建一个连接Event条目的新列。因此,新列(例如AllEvents)应该在2017/05/05 08:30:00行中输入A-B-C。对于DateTimeAllEvents中的行2017/11/03 08:30:00,其值应为A-B。最后,对于所有其他行,AllEvents应与Event列匹配。

我的尝试似乎非常笨重。

我首先提取DateTime的唯一值,其中有多个entr:

require(dplyr)
duped_datetime <- unique(my_df[duplicated(my_df$DateTime), 'DateTime'])

然后我将my_df子集提取出有重复项的条目

subset_df <- my_df[my_df$DateTime %in% duped_datetime,]

接下来,我创建一个连接向量的函数:

my_concat <- function(x){
concat_str <- subset_df %>% filter(DateTime == x) %>% 
                            select(Event) %>% 
                            unlist() %>% 
                            paste(collapse="+") 
return(concat_str)
}

接下来,我遍历重复日期并应用my_concat函数:

named_vc <- sapply(duped_datetime, FUN = my_concat)

结果合并为一个新的数据框

new_df <- data.frame('DateTime' = duped_datetime,
                     'AllEvents' = unname(named_vc), 
                      stringsAsFactors = FALSE)

合并结果并清理final_df以保留我需要的行和列。

final_df <- left_join(my_df, new_df, by = 'DateTime')  %>% 
            mutate(AllEvents = ifelse(is.na(AllEvents), Event, AllEvents)) 
final_df <- final_df[!duplicated(final_df$DateTime),]
final_df['Event'] <- NULL  

我得到了我需要的结果但是你可以看到代码很可怕。使用groupby,apply和lambda函数可以在Python中用4行完成整个过程,但是对于我来说如何在R中干净地完成相同的任务并不是很明显。

    DateTime            Var1      AllEvents
2017/05/05 08:30:00   -0.8350209    A+B+C
2017/12/08 08:30:00    1.1534819    A
2018/01/15 18:50:00   -0.3501990    A
2017/12/20 21:46:00   -0.6664841    B
2017/11/12 18:50:00    1.7142981    C
2017/11/03 08:30:00   -2.0133559    A+B
2017/12/03 08:30:00   -0.6150040    A

感谢任何有耐心阅读本文的人。

2 个答案:

答案 0 :(得分:5)

这可以在dplyr中直接完成,group_by可以正常使用DateTime值:

my_df %>%
    group_by(DateTime) %>%
    summarise(Var1 = first(Var1),
              Event = paste0(Event, collapse = "+"))

输出:

# A tibble: 7 x 3
  DateTime              Var1 Event
  <chr>                <dbl> <chr>
1 2017/05/05 08:30:00  0.159 A+B+C
2 2017/11/03 08:30:00 -0.610 A+B  
3 2017/11/12 18:50:00  0.465 C    
4 2017/12/03 08:30:00 -1.89  A    
5 2017/12/08 08:30:00  0.793 A    
6 2017/12/20 21:46:00  0.755 B    
7 2018/01/15 18:50:00  0.511 A  

答案 1 :(得分:3)

只是为了变化,data.table

中的情况相同
library(data.table)
setDT(my_df)

my_df[, .(Var1  = first(Var1)
        , Event = paste0(Event, collapse = "+"))
      , by = DateTime]

给出

              DateTime       Var1 Event
1: 2017/05/05 08:30:00  0.2366874 A+B+C
2: 2017/12/08 08:30:00  0.3699069     A
3: 2018/01/15 18:50:00 -0.2420663     A
4: 2017/12/20 21:46:00 -1.4720633     B
5: 2017/11/12 18:50:00 -0.5961595     C
6: 2017/11/03 08:30:00 -1.1467001   A+B
7: 2017/12/03 08:30:00 -0.6135086     A

请注意保留my_df的顺序。