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