如何使用dplyr包筛选所有站点共有的datetime数据行?
问题:保留所有站点共有的datetime对应的行
我有一个包含station、datetime和miles三列的数据框,想要保留那些**所有站点(ALL STATIONS)**都存在的共同datetime对应的行。以下是可复现的示例代码:
library(tidyverse) library(lubridate) df <- data.frame(station = c("A","A","A","B","B","B", "C","C","C"), date = c("1998-05-03","1999-06-01","2000-03-02", "1998-05-03","1999-06-01","2000-03-02", "1998-05-03","1999-06-01","2000-04-15"), time = c("00:00:10","00:00:20","00:00:50", "00:00:10","00:00:20","00:00:40", "00:00:34","00:00:20","00:00:40"), miles = rnorm(9)) df <- df %>% mutate(datetime = paste(date,time,sep = " "), datetime = as_datetime(datetime)) %>% select(station,datetime,miles)
当前数据框内容:
| station | datetime | miles |
|---|---|---|
| A | 1998-05-03 00:00:10 | 1.8587913 |
| A | 1999-06-01 00:00:20 | 0.1271054 |
| A | 2000-03-02 00:00:50 | 1.4531250 |
| B | 1998-05-03 00:00:10 | 0.3544122 |
| B | 1999-06-01 00:00:20 | 0.1033785 |
| B | 2000-03-02 00:00:40 | 0.9861990 |
| C | 1998-05-03 00:00:34 | 1.5029350 |
| C | 1999-06-01 00:00:20 | 1.1215914 |
| C | 2000-04-15 00:00:40 | 0.5222949 |
期望输出:
| station | datetime | miles |
|---|---|---|
| A | 1999-06-01 00:00:20 | 0.1271054 |
| B | 1999-06-01 00:00:20 | 0.1033785 |
| C | 1999-06-01 00:00:20 | 1.1215914 |
可以看到,只有1999-06-01 00:00:20是所有站点都存在的datetime。我尝试了以下代码但未能成功:
df %>% filter(station %in% (split(df$station, df$datetime) %>% reduce(intersect)))
解决方案(dplyr)
你之前的代码逻辑搞反了:它是在找所有datetime都出现的站点,而我们需要的是找所有站点都出现的datetime。正确的思路是统计每个datetime对应的唯一站点数量,筛选出数量等于总站点数的datetime,再过滤原数据:
方法1:先计算总站点数,再筛选
# 获取数据中所有唯一站点的数量 total_stations <- df %>% distinct(station) %>% nrow() # 筛选出所有站点都覆盖的datetime,并保留对应行 df %>% group_by(datetime) %>% filter(n_distinct(station) == total_stations) %>% ungroup()
方法2:更简洁的写法
无需单独计算总站点数,直接在分组内对比:
df %>% group_by(datetime) %>% filter(n_distinct(station) == n_distinct(df$station)) %>% ungroup()
代码解释
group_by(datetime):按datetime分组n_distinct(station):统计当前分组内的唯一站点数量- 对比该数量与整个数据的总站点数,相等则说明该datetime在所有站点都存在,保留这些行
内容的提问来源于stack exchange,提问作者Kon Ath
相关产品推荐
相关产品推荐

