按因子级别对 R 数据帧进行子集化,在第一次超过阈值后删除所有行
Subset R dataframe by factor level, removing ALL rows after threshold crossed the FIRST time
我有一些网络会话数据,我试图在上次访问过去一定时间(比如说 10 天)后排除所有观察结果。我有一个 ID、一个 VisitNum 和一个计算的 DateDiff,代表自上次访问以来已经过去的天数。我的 ID 是因子,所以我需要解决方案来处理多个因子水平。
示例数据:
test_data <- data.frame(ID=c("abc123","abc123","abc123","abc123"),
VisitNum=c(1,2,3,4),
DateDiff=c(0,5,30,5))
由于第 3 次访问发生在第 2 次访问后 30 天,我想从数据框中排除第 3 次和第 4 次访问。我提出的解决方案将排除第 3 次访问,但保留第 4 次访问 - 这不是我需要的。
我想要的结果是这样的:
test_results <- data.frame(ID=c("abc123","abc123"),
VisitNum=c(1,2),
DateDiff=c(0,5))
谢谢!
对于此示例,您可以使用基本 R 函数 cummin
:
test_data[as.logical(cummin(test_data$DateDiff < 10)), ]
ID VisitNum DateDiff
1 abc123 1 0
2 abc123 2 5
将此应用到多个 ID 时,您可以使用基本 R 函数 ave
:
test_data[as.logical(ave(test_data$DateDiff, test_data$ID,
FUN=function(i) cummin(i < 10))), ]
ID VisitNum DateDiff
1 abc123 1 0
2 abc123 2 5
6 abc323 2 5
7 abc323 3 5
这里使用as.logical
是因为我们依赖逻辑subestting和ave
returns初始向量的模式
data.table
中的等效操作是
library(data.table
setDT(data.table)
test_data[as.logical(test_data[,cummin(DateDiff < 10), by=ID]$V1)]
数据
test_data <-
structure(list(ID = structure(c(1L, 1L, 1L, 1L, 2L, 3L, 3L),
.Label = c("abc123", "abc223", "abc323"), class = "factor"),
VisitNum = c(1, 2, 3, 4, 2, 2, 3), DateDiff = c(0, 5, 30, 5, 20, 5, 5)),
Names = c("ID", "VisitNum", "DateDiff"), row.names = c(NA, -7L),
class = "data.frame")
您也可以使用which
。
test_data[1:(which(test_data$DateDiff > 10)[1] - 1),]
对于较大的数据集来说,这似乎要快一些
test_data <- data.frame(ID=sample(c("abc123","abc123","abc123","abc123"),2000,T),
VisitNum=1:2000,
DateDiff=sample(c(0,5,30,5),2000,T))
a <- function(dat) dat[1:(which(dat$DateDiff > 10)[1] - 1),]
b <- function(dat) dat[as.logical(cummin(dat$DateDiff < 10)), ]
microbenchmark(a(test_data), b(test_data), times = 1000)
## Unit: microseconds
## expr min lq mean median uq max neval cld
## a(test_data) 141.198 146.1895 197.6538 151.507 167.880 2326.238 1000 a
## b(test_data) 196.443 201.4810 496.1748 209.448 235.708 137785.448 1000 b
对于具有 2000 行的数据集,函数 b 在超过 1000 次执行的中位执行时间中花费了大约 38%。
我有一些网络会话数据,我试图在上次访问过去一定时间(比如说 10 天)后排除所有观察结果。我有一个 ID、一个 VisitNum 和一个计算的 DateDiff,代表自上次访问以来已经过去的天数。我的 ID 是因子,所以我需要解决方案来处理多个因子水平。
示例数据:
test_data <- data.frame(ID=c("abc123","abc123","abc123","abc123"),
VisitNum=c(1,2,3,4),
DateDiff=c(0,5,30,5))
由于第 3 次访问发生在第 2 次访问后 30 天,我想从数据框中排除第 3 次和第 4 次访问。我提出的解决方案将排除第 3 次访问,但保留第 4 次访问 - 这不是我需要的。
我想要的结果是这样的:
test_results <- data.frame(ID=c("abc123","abc123"),
VisitNum=c(1,2),
DateDiff=c(0,5))
谢谢!
对于此示例,您可以使用基本 R 函数 cummin
:
test_data[as.logical(cummin(test_data$DateDiff < 10)), ]
ID VisitNum DateDiff
1 abc123 1 0
2 abc123 2 5
将此应用到多个 ID 时,您可以使用基本 R 函数 ave
:
test_data[as.logical(ave(test_data$DateDiff, test_data$ID,
FUN=function(i) cummin(i < 10))), ]
ID VisitNum DateDiff
1 abc123 1 0
2 abc123 2 5
6 abc323 2 5
7 abc323 3 5
这里使用as.logical
是因为我们依赖逻辑subestting和ave
returns初始向量的模式
data.table
中的等效操作是
library(data.table
setDT(data.table)
test_data[as.logical(test_data[,cummin(DateDiff < 10), by=ID]$V1)]
数据
test_data <-
structure(list(ID = structure(c(1L, 1L, 1L, 1L, 2L, 3L, 3L),
.Label = c("abc123", "abc223", "abc323"), class = "factor"),
VisitNum = c(1, 2, 3, 4, 2, 2, 3), DateDiff = c(0, 5, 30, 5, 20, 5, 5)),
Names = c("ID", "VisitNum", "DateDiff"), row.names = c(NA, -7L),
class = "data.frame")
您也可以使用which
。
test_data[1:(which(test_data$DateDiff > 10)[1] - 1),]
对于较大的数据集来说,这似乎要快一些
test_data <- data.frame(ID=sample(c("abc123","abc123","abc123","abc123"),2000,T),
VisitNum=1:2000,
DateDiff=sample(c(0,5,30,5),2000,T))
a <- function(dat) dat[1:(which(dat$DateDiff > 10)[1] - 1),]
b <- function(dat) dat[as.logical(cummin(dat$DateDiff < 10)), ]
microbenchmark(a(test_data), b(test_data), times = 1000)
## Unit: microseconds
## expr min lq mean median uq max neval cld
## a(test_data) 141.198 146.1895 197.6538 151.507 167.880 2326.238 1000 a
## b(test_data) 196.443 201.4810 496.1748 209.448 235.708 137785.448 1000 b
对于具有 2000 行的数据集,函数 b 在超过 1000 次执行的中位执行时间中花费了大约 38%。