R 根据日期和时间有条件地删除行

R 根据日期和时间有条件地删除行,r,datetime,R,Datetime,我正在尝试实现一种过滤这个数据帧的方法 我希望对其进行过滤,以便如果名称列中存在重复响应(如Jim出现两次),我希望仅当进度列值大于70时,根据EndDate列保留具有最早日期和时间的行。否则,我希望在EndDate列中选择日期和时间较晚的行 根据条件,我们将“EndDate”转换为DateTime类,然后按“Name”、“EndDate”排列,如果“Progres”的第一个元素大于70,则按“Name”分组,返回索引1,否则返回切片中的最后一行索引以子集行 library(tidyverse)

我正在尝试实现一种过滤这个数据帧的方法


我希望对其进行过滤,以便如果名称列中存在重复响应(如Jim出现两次),我希望仅当进度列值大于70时,根据EndDate列保留具有最早日期和时间的行。否则,我希望在EndDate列中选择日期和时间较晚的行

根据条件,我们将“EndDate”转换为DateTime类,然后按“Name”、“EndDate”排列,如果“Progres”的第一个元素大于70,则按“Name”分组,返回索引1,否则返回切片中的最后一行索引以子集行

library(tidyverse)
library(lubridate)
df %>%  
   mutate(EndDate = mdy_hm(EndDate)) %>%
   # if there are multiple formats
   # mutate(EndDate = anytime::anytime(EndDate)) %>%
   arrange(Name, EndDate) %>% 
   group_by(Name) %>%
   slice(if(first(Progress) > 70) 1 else n())
# A tibble: 7 x 3
# Groups:   Name [7]
#  Name   Progress EndDate            
#  <chr>  <chr>    <dttm>             
#1 Jane   70       2018-11-30 11:18:00
#2 Jim    25       2018-11-29 18:04:00
#3 Jose   80       2018-11-25 14:20:00
#4 Matt   20       2018-12-01 22:52:00
#5 Mickey 65       2018-11-29 18:15:00
#6 Peter  20       2018-11-26 12:07:00
#7 Tom    45       2018-12-02 15:27:00
注意:如果有多个“DateTime”格式,一个选项是anytime::anytime,而不是使用dplyr的mdy_hm,我们首先使用lubridate中的parse_date_time将EndDate对象转换为date time对象,然后根据名称对_进行分组,如果进度>70且每个名称的行数大于1,则选择具有最小EndDate的行,否则选择最大EndDate。如果名称只有一行,则默认情况下仅选择该行

library(dplyr)
library(lubridate)

df %>%
  mutate(EndDate = parse_date_time(EndDate,c("%m-%d-%y %H:%M","%Y-%m-%d %H:%M:%S"))) %>%
  group_by(Name) %>%
  slice(ifelse(n() > 1, 
        ifelse(any(Progress > 70), which.min(EndDate), which.max(EndDate)), 1))


#  Name   Progress EndDate            
#  <chr>  <chr>    <dttm>             
#1 Jane   70       2018-11-30 11:18:00
#2 Jim    25       2018-11-29 18:04:00
#3 Jose   80       2018-11-25 14:20:00
#4 Matt   20       2018-12-01 22:52:00
#5 Mickey 65       2018-11-29 18:15:00
#6 Peter  20       2018-11-26 12:07:00
#7 Tom    45       2018-12-02 15:27:00

当然,这也可以使用data.table来完成

样本数据


当我在“711未能解析”的实际非常大的数据集上运行此操作时,我收到了一条提示。这指的是什么?@M76很可能意味着某些EndDate值无法使用lubridate的mdy_hm转换为datetime。也许它们的格式和显示的不同?是的,就是这样。出于某种原因,有些格式是11/25/18 16:10,我不知道为什么,但如果我将它们转换为其他格式,函数会工作吗?此外,根据目前的代码,您认为它是否适用于此格式11/25/18 16:10或此格式2018-12-02 15:27:00@M76目前,该准则适用于2018年11月25日16:10和2018年11月25日16:10。mdy_hm应该工作18年以及2018年。除了这两种格式之外,还有其他日期类型吗?然后使用parse_date_time并指定这两种格式。我已经更新了答案。没关系,我的意思是编辑你的问题会让每个人都明白。很少有人检查别人回答的评论,所以我明白你的意思。是的,我想我不能包括这一点,因为之前的数据帧没有这些日期格式,也不想让一些人的答案无效。即使完整的问题和示例数据框架会使以前的答案无效,但通常最好还是更改完整的问题和示例数据框架吗?尽管事先有一个包含所有模式的结构良好的问题是很好的,但我知道大数据可能会有一些问题,如您提到的问题。在这种情况下,如果问题没有太大变化,我会编辑它;如果问题变得完全不同,我会创建一个新问题。只通知一个人的答案的问题是,其他人不知道这个问题,可能无法更改答案。在这种情况下,您通知了用户,用户进行了更改并确认,而其他人甚至不知道他们的解决方案是否有效
library(dplyr)
library(lubridate)

df %>%
  mutate(EndDate = parse_date_time(EndDate,c("%m-%d-%y %H:%M","%Y-%m-%d %H:%M:%S"))) %>%
  group_by(Name) %>%
  slice(ifelse(n() > 1, 
        ifelse(any(Progress > 70), which.min(EndDate), which.max(EndDate)), 1))


#  Name   Progress EndDate            
#  <chr>  <chr>    <dttm>             
#1 Jane   70       2018-11-30 11:18:00
#2 Jim    25       2018-11-29 18:04:00
#3 Jose   80       2018-11-25 14:20:00
#4 Matt   20       2018-12-01 22:52:00
#5 Mickey 65       2018-11-29 18:15:00
#6 Peter  20       2018-11-26 12:07:00
#7 Tom    45       2018-12-02 15:27:00
df <- structure(list(Name = c("Jim", "Jane", "Jose", "Matt", "Mickey", 
                        "Tom", "Peter", "Jane", "Jim", "Jose"), Progress = c("65", "20", 
                                                                             "80", "20", "65", "45", "20", "70", "25", "80"), EndDate = c("11/25/2018 16:45", 
                                                                                                                                          "11/25/2018 18:05", "11/25/2018 14:20", "12/1/2018 22:52", "11/29/2018 18:15", 
                                                                                                                                          "12/2/2018 15:27", "11/26/2018 12:07", "11/30/2018 11:18", "11/29/2018 18:04", 
                                                                                                                                          "11/29/2018 21:12")), row.names = c(NA, -10L), class = "data.frame")
#create the data.table (can also be done using setDT(df) )
dt <- as.data.table( df )
#set the dates to a proper POSIXct-format
dt[, EndDate := as.POSIXct( EndDate, format = "%m/%d/%Y %H:%M") ]
#order omn EndDate (by reference!)
setorder( dt, EndDate )
#summarise by Name, if first Progress >70 then keep it, else keep last Progress
dt[ , list( Progress = ifelse( Progress[1] > 70, Progress[1], Progress[.N] ) ), by = .(Name)][]
microbenchmark::microbenchmark(
  data.table = {
    dt[, EndDate := as.POSIXct( EndDate, format = "%m/%d/%Y %H:%M") ]
    setorder( dt, EndDate )
    dt[ , list( Progress = ifelse( Progress[1] > 70, Progress[1], Progress[.N] ) ), by = .(Name)][]
  },
  tidyverse1 = {
    df %>%  
      mutate(EndDate = mdy_hm(EndDate)) %>%
      arrange(Name, EndDate) %>% 
      group_by(Name) %>%
      slice(if(first(Progress) > 70) 1 else n())
  },
  tidyverse2 = {
    df %>%
      mutate(EndDate = mdy_hm(EndDate)) %>%
      group_by(Name) %>%
      slice(ifelse(n() > 1, 
                   ifelse(any(Progress > 70), which.min(EndDate), which.max(EndDate)), 1))
  }
)


# Unit: milliseconds
#       expr      min       lq     mean   median       uq      max neval
# data.table 1.654241 2.030820 2.709023 2.556978 2.782023 30.36590   100
# tidyverse1 6.847731 7.218286 8.742247 7.516838 8.034861 72.00902   100
# tidyverse2 6.173201 6.506398 7.286639 6.764582 7.088591 52.10180   100