选择第一个积极事件
Posted
技术标签:
【中文标题】选择第一个积极事件【英文标题】:Selecting the first positive event 【发布时间】:2021-01-25 09:43:21 【问题描述】:我正在苦苦思考如何仅使用基于日期的第一个正面测试来创建数据框的子样本。我将展示一个玩具示例。假设我有以下内容;
df = data.frame(guy = c("A", "B", "A", 'B', "C", "C"),
test1 = c(1, 1, 0, 0, 1, 0),
test2 = c(0, 1, 0, 1, 0, 0),
test3 = c(0, 0, 1, 0, 0, 1),
date = as.Date(c('1999-10-20', '1999-10-21', '1999-10-22', '1999-10-23', '1999-10-24', '1999-10-25')));df
#guy test1 test2 test3 date
#1 A 1 0 0 1999-10-20
#2 B 1 1 0 1999-10-21
#3 A 0 0 1 1999-10-22
#4 B 0 1 0 1999-10-23
#5 C 1 0 0 1999-10-24
#6 C 0 0 1 1999-10-25
现在,我想过滤,根据最旧的 date
仅选择第一个阳性测试(即 test1|test2|test3 = 1
)。在我的示例中,我会得到以下信息:
#guy test1 test2 test3 date
#1 A 1 0 0 1999-10-20
#2 B 1 1 0 1999-10-21
#3 C 1 0 0 1999-10-24
数据框:
df = data.frame(guy = c("A", "B", "A", 'B', "C", "C"),
test1 = c(1, 1, 0, 0, 1, 0),
test2 = c(0, 1, 0, 1, 0, 0),
test3 = c(0, 0, 1, 0, 0, 1),
date = as.Date(c('1999-10-20', '1999-10-21', '1999-10-22', '1999-10-23', '1999-10-24', '1999-10-25')));df
任何提示我该怎么做?
【问题讨论】:
为什么sqlite
被标记在这里?
test1 列有字符串 A、B 和 C,您需要如何将其与 1 进行比较?
【参考方案1】:
使用dplyr::top_n
另一个选项是:
df = data.frame(guy = c("A", "B", "A", 'B', "C", "C"),
test1 = c(1, 1, 0, 0, 1, 0),
test2 = c(0, 1, 0, 1, 0, 0),
test3 = c(0, 0, 1, 0, 0, 1),
date = as.Date(c('1999-10-20', '1999-10-21', '1999-10-22', '1999-10-23', '1999-10-24', '1999-10-25')))
library(dplyr)
df %>%
filter(test1 | test2 | test3) %>%
group_by(guy) %>%
top_n(-1, date)
#> # A tibble: 3 x 5
#> # Groups: guy [3]
#> guy test1 test2 test3 date
#> <chr> <dbl> <dbl> <dbl> <date>
#> 1 A 1 0 0 1999-10-20
#> 2 B 1 1 0 1999-10-21
#> 3 C 1 0 0 1999-10-24
【讨论】:
【参考方案2】:使用subset
+ ave
+ max.col
的基本 R 选项
subset(
df,
as.logical(
ave(
max.col(df[grepl("test\\d+", names(df))], "first"),
guy,
FUN = function(x) x == min(x)
)
) & (test1|test2|test3)
)
给了
guy test1 test2 test3 date
1 A 1 0 0 1999-10-20
2 B 1 1 0 1999-10-21
5 C 1 0 0 1999-10-24
【讨论】:
@akrun 是的,你的理解是对的。 OP 想找出test1
、test2
和test3
(按guy
分组)中的第一个正值并获取该行
@akrun 奥基,我明白了。谢谢你纠正我。我会努力解决这个问题
@akrun 我想现在它会是一个安全的版本【参考方案3】:
将dplyr
1.0.0 用于任何个您可以执行的test
列:
library(dplyr)
df %>%
group_by(guy) %>%
slice(which.max(rowSums(select(cur_data(), starts_with('test'))) > 0))
# guy test1 test2 test3 date
# <chr> <dbl> <dbl> <dbl> <date>
#1 A 1 0 0 1999-10-20
#2 B 1 1 0 1999-10-21
#3 C 1 0 0 1999-10-24
以上假设您在每个 guy
中至少有一行,其中包含 1。如果不是这种情况,则意味着您可以拥有一个没有任何 1 的 guy
,您可以使用 match
。
df %>%
group_by(guy) %>%
slice(match(TRUE, rowSums(select(cur_data(), starts_with('test'))) > 0))
【讨论】:
【参考方案4】:另一种方法可以使用inner_join()
完成,并将数据重新整形为 long 以识别旧日期和值。代码如下:
library(tidyverse)
#Code
dfout <- df %>% inner_join(df %>% pivot_longer(-c(guy,date)) %>% group_by(guy,name) %>%
filter(date==min(date) & value==1) %>% ungroup() %>%
group_by(guy) %>%
filter(!duplicated(value)) %>% select(-c(name,value)))
输出:
guy test1 test2 test3 date
1 A 1 0 0 1999-10-20
2 B 1 1 0 1999-10-21
3 C 1 0 0 1999-10-24
【讨论】:
【参考方案5】:base R
的选项
subset(df, seq_len(nrow(df)) == ave(seq_len(nrow(df)) *
(test1|test2|test3), guy, FUN = min))
# guy test1 test2 test3 date
#1 A 1 0 0 1999-10-20
#2 B 1 1 0 1999-10-21
#5 C 1 0 0 1999-10-24
【讨论】:
这是一个非常简单的基础 R 解决方案,喜欢它!【参考方案6】:试试:
library(dplyr)
df %>% filter(test1 | test2 | test3 ) %>%
arrange(date) %>% group_by(guy) %>%
summarize(first(date),first(test1),first(test2),first(test3)) %>%
ungroup
# A tibble: 3 x 5
guy `first(date)` `first(test1)` `first(test2)` `first(test3)`
<chr> <date> <dbl> <dbl> <dbl>
1 A 1999-10-20 1 0 0
2 B 1999-10-21 1 1 0
3 C 1999-10-24 1 0 0
【讨论】:
以上是关于选择第一个积极事件的主要内容,如果未能解决你的问题,请参考以下文章