intermediate/advanced 在 dplyr 中跨组过滤
intermediate/advanced filtering in dplyr across groups
我提出要帮助一位朋友解决问题,但我很快意识到这超出了我的能力范围。我对过滤以删除落在另一组的第一条记录上或之后的一组记录感兴趣。
我按 'species'、'year' 和 'sex' 进行分组,并希望删除第一个之后 'sex' 为“f”的任何记录'observation_doy' 的“米”。在这个例子中,我要删除的记录以粗体表示。
library(tidyverse)
library(janitor)
原创
species generations year observation_doy sex
1 Linnaea borealis partially bimodal 2009 165 f
2 Linnaea borealis partially bimodal 2010 150 f
3 Linnaea borealis partially bimodal 2010 155 f
4 Linnaea borealis partially bimodal 2010 160 m
**5 Linnaea borealis partially bimodal 2010 160 f**
6 helianthus deserticola partially bimodal 2009 174 f
7 helianthus deserticola partially bimodal 2009 174 f
8 helianthus deserticola partially bimodal 2009 180 m
**9 helianthus deserticola partially bimodal 2009 180 f**
10 helianthus deserticola partially bimodal 2009 184 m
11 helianthus deserticola partially bimodal 2010 174 f
12 helianthus deserticola partially bimodal 2010 174 f
**13 helianthus deserticola partially bimodal 2010 180 f**
14 helianthus deserticola partially bimodal 2010 180 m
15 helianthus deserticola partially bimodal 2010 184 m
16 helianthus deserticola partially bimodal 2011 174 f
17 helianthus deserticola partially bimodal 2011 174 f
18 helianthus deserticola partially bimodal 2011 180 f
19 helianthus deserticola partially bimodal 2011 180 m
**20 helianthus deserticola partially bimodal 2011 184 f
21 helianthus deserticola partially bimodal 2011 184 f**
22 helianthus bolanderi partially bimodal 2009 174 f
23 helianthus bolanderi partially bimodal 2009 174 f
24 helianthus bolanderi partially bimodal 2009 180 m
**25 helianthus bolanderi partially bimodal 2009 180 f**
26 helianthus bolanderi partially bimodal 2009 184 m
期望的结果:
species generations year observation_doy sex
1 Linneae borealis partially bimodal 2009 165 f
2 Linneae borealis partially bimodal 2010 150 f
3 Linneae borealis partially bimodal 2010 155 f
4 Linneae borealis partially bimodal 2010 160 m
5 helianthus deserticola partially bimodal 2009 174 f
6 helianthus deserticola partially bimodal 2009 174 f
7 helianthus deserticola partially bimodal 2009 180 m
8 helianthus deserticola partially bimodal 2009 180 f
9 helianthus deserticola partially bimodal 2009 184 m
10 helianthus deserticola partially bimodal 2010 174 f
11 helianthus deserticola partially bimodal 2010 174 f
12 helianthus deserticola partially bimodal 2010 180 m
13 helianthus deserticola partially bimodal 2010 184 m
14 helianthus deserticola partially bimodal 2011 174 f
15 helianthus deserticola partially bimodal 2011 174 f
16 helianthus deserticola partially bimodal 2011 180 m
17 helianthus bolanderi partially bimodal 2009 174 f
18 helianthus bolanderi partially bimodal 2009 174 f
19 helianthus bolanderi partially bimodal 2009 180 m
20 helianthus bolanderi partially bimodal 2009 184 m
原始数据集大约有 10 列的 10k 条记录,因此非常易于管理。但是我似乎没有解决这个问题的好方法。以下是我尝试过的一些方法——以及我怀疑它们失败的原因;我再次怀疑这些是无效的方法。
按组、过滤器和切片查找第一个男性出现日期非常容易。我怀疑我可以在此之后创建一串数字,并使用 %notin%(否定 %in%)删除日期之后的女性记录。但我不知道如何将 %notin% 限制到该子集,除非过滤掉数据集。然而,这种方法似乎很糟糕,会产生多个中间体。
first_male_emergence <- df %>% dplyr::filter(generations == 'partially bimodal') %>%
dplyr::group_by(species, year, sex) %>%
dplyr::filter(sex == 'm') %>%
dplyr::slice_min(sampling_doy, n=1)
我也曾尝试创建一个 'two sided' 过滤器,这似乎与 dplyr 理念不符。我认为这种方法的问题是让 dplyr 识别主要的过滤标准,在本例中是“<=”符号。
clean_df <- raw_df %>%
group_by(species, year, sex) %>%
dplyr::filter(sex == 'f' & sampling_doy <= print(filter(sex == 'm',(slice_min(sampling_doy, n = 1)))))
请注意,我在右侧的表达式上有 'print',试图 return 数值以供 <= 运算符计算,但这是行不通的。我尝试了多种方法来打印此值,以便操作员不会对动词过滤器做出反应,即 {.} 的变体,但无济于事(我怀疑我做错了)。我试过将 () 中语句的每一侧嵌套来嵌套,但无济于事。
最后我尝试使用 case_when,但是由于许多运算符,允许函数确定 LHS 和 RHS 的位置也存在问题。
clean_df <- raw_df %>%
group_by(species, year, sex) %>%
mutate(sampling_doy_1 = case_when(
(sex == 'f' & sampling_doy <=
filter(sex == 'm',(slice_max(sampling_doy, n = 1)) ~ sampling_doy,
(sex == 'f' & sampling_doy >=
filter(sex == 'm',(slice_max(sampling_doy, n = 1)) ~ NA,
))))))
我也尝试了一个变体:
clean_df <- raw_df %>%
dplyr::filter(generations == 'partially bivoltine') %>%
group_by(species, year, sex) %>%
mutate(sampling_doy_1 = case_when(
sex == 'f' & sampling_doy < sex == 'm', sampling_doy ~ sampling_doy,
sex == 'f' & sampling_doy > sex == 'm', sampling_doy ~ NA,
))
我也考虑过在group by内使用arrangeing,并尝试在第一条男性记录之前对所有女性记录进行切片。但是,这似乎不是一个好方法。
所以我的第一个问题是:任何人都可以解决这个问题吗?在我看来,使用 case_when 并将左侧表达式转换为在 case_when 内调用的函数是最好的做法。但是,与此同时,根据我发现的其他示例,我觉得这根本不是 case_when 的设置方式。有时我会在其中加入一些非常简单的数学运算,但通常是非常简单的数学运算,它们在感兴趣的列中的作用相同。
第二个问题是:这个主题是否有一般建议的方法,或者我是否必须依靠编写函数来完成这样的事情?
对于本文的篇幅,我们深表歉意post,但非常感谢任何帮助。我还标记了数据表,因为它似乎有一个不错的简单解决方案。
这可以通过连接来完成。
male_first_obs <- my_data %>%
group_by(species, year) %>%
filter(sex == "m") %>%
summarize(male_first_obs_doy = min(observation_doy))
my_data %>%
left_join(male_first_obs, by = c(species, year)) %>%
group_by(species, year) %>%
filter(!(sex == "f" & observation_day > male_first_obs_doy)) %>%
select(-male_first_obs_doy)
如果您不关心 dbplyr
兼容性等,您可能会更简洁,例如:
my_data %>%
group_by(species, year) %>%
mutate(male_first_obs_day = min(observation_doy[which(sex == "m")])) %>%
filter(!(sex == "f" & observation_day > male_first_obs_doy)) %>%
select(-male_first_obs_doy)
我提出要帮助一位朋友解决问题,但我很快意识到这超出了我的能力范围。我对过滤以删除落在另一组的第一条记录上或之后的一组记录感兴趣。
我按 'species'、'year' 和 'sex' 进行分组,并希望删除第一个之后 'sex' 为“f”的任何记录'observation_doy' 的“米”。在这个例子中,我要删除的记录以粗体表示。
library(tidyverse)
library(janitor)
原创
species generations year observation_doy sex
1 Linnaea borealis partially bimodal 2009 165 f
2 Linnaea borealis partially bimodal 2010 150 f
3 Linnaea borealis partially bimodal 2010 155 f
4 Linnaea borealis partially bimodal 2010 160 m
**5 Linnaea borealis partially bimodal 2010 160 f**
6 helianthus deserticola partially bimodal 2009 174 f
7 helianthus deserticola partially bimodal 2009 174 f
8 helianthus deserticola partially bimodal 2009 180 m
**9 helianthus deserticola partially bimodal 2009 180 f**
10 helianthus deserticola partially bimodal 2009 184 m
11 helianthus deserticola partially bimodal 2010 174 f
12 helianthus deserticola partially bimodal 2010 174 f
**13 helianthus deserticola partially bimodal 2010 180 f**
14 helianthus deserticola partially bimodal 2010 180 m
15 helianthus deserticola partially bimodal 2010 184 m
16 helianthus deserticola partially bimodal 2011 174 f
17 helianthus deserticola partially bimodal 2011 174 f
18 helianthus deserticola partially bimodal 2011 180 f
19 helianthus deserticola partially bimodal 2011 180 m
**20 helianthus deserticola partially bimodal 2011 184 f
21 helianthus deserticola partially bimodal 2011 184 f**
22 helianthus bolanderi partially bimodal 2009 174 f
23 helianthus bolanderi partially bimodal 2009 174 f
24 helianthus bolanderi partially bimodal 2009 180 m
**25 helianthus bolanderi partially bimodal 2009 180 f**
26 helianthus bolanderi partially bimodal 2009 184 m
期望的结果:
species generations year observation_doy sex
1 Linneae borealis partially bimodal 2009 165 f
2 Linneae borealis partially bimodal 2010 150 f
3 Linneae borealis partially bimodal 2010 155 f
4 Linneae borealis partially bimodal 2010 160 m
5 helianthus deserticola partially bimodal 2009 174 f
6 helianthus deserticola partially bimodal 2009 174 f
7 helianthus deserticola partially bimodal 2009 180 m
8 helianthus deserticola partially bimodal 2009 180 f
9 helianthus deserticola partially bimodal 2009 184 m
10 helianthus deserticola partially bimodal 2010 174 f
11 helianthus deserticola partially bimodal 2010 174 f
12 helianthus deserticola partially bimodal 2010 180 m
13 helianthus deserticola partially bimodal 2010 184 m
14 helianthus deserticola partially bimodal 2011 174 f
15 helianthus deserticola partially bimodal 2011 174 f
16 helianthus deserticola partially bimodal 2011 180 m
17 helianthus bolanderi partially bimodal 2009 174 f
18 helianthus bolanderi partially bimodal 2009 174 f
19 helianthus bolanderi partially bimodal 2009 180 m
20 helianthus bolanderi partially bimodal 2009 184 m
原始数据集大约有 10 列的 10k 条记录,因此非常易于管理。但是我似乎没有解决这个问题的好方法。以下是我尝试过的一些方法——以及我怀疑它们失败的原因;我再次怀疑这些是无效的方法。
按组、过滤器和切片查找第一个男性出现日期非常容易。我怀疑我可以在此之后创建一串数字,并使用 %notin%(否定 %in%)删除日期之后的女性记录。但我不知道如何将 %notin% 限制到该子集,除非过滤掉数据集。然而,这种方法似乎很糟糕,会产生多个中间体。
first_male_emergence <- df %>% dplyr::filter(generations == 'partially bimodal') %>%
dplyr::group_by(species, year, sex) %>%
dplyr::filter(sex == 'm') %>%
dplyr::slice_min(sampling_doy, n=1)
我也曾尝试创建一个 'two sided' 过滤器,这似乎与 dplyr 理念不符。我认为这种方法的问题是让 dplyr 识别主要的过滤标准,在本例中是“<=”符号。
clean_df <- raw_df %>%
group_by(species, year, sex) %>%
dplyr::filter(sex == 'f' & sampling_doy <= print(filter(sex == 'm',(slice_min(sampling_doy, n = 1)))))
请注意,我在右侧的表达式上有 'print',试图 return 数值以供 <= 运算符计算,但这是行不通的。我尝试了多种方法来打印此值,以便操作员不会对动词过滤器做出反应,即 {.} 的变体,但无济于事(我怀疑我做错了)。我试过将 () 中语句的每一侧嵌套来嵌套,但无济于事。
最后我尝试使用 case_when,但是由于许多运算符,允许函数确定 LHS 和 RHS 的位置也存在问题。
clean_df <- raw_df %>%
group_by(species, year, sex) %>%
mutate(sampling_doy_1 = case_when(
(sex == 'f' & sampling_doy <=
filter(sex == 'm',(slice_max(sampling_doy, n = 1)) ~ sampling_doy,
(sex == 'f' & sampling_doy >=
filter(sex == 'm',(slice_max(sampling_doy, n = 1)) ~ NA,
))))))
我也尝试了一个变体:
clean_df <- raw_df %>%
dplyr::filter(generations == 'partially bivoltine') %>%
group_by(species, year, sex) %>%
mutate(sampling_doy_1 = case_when(
sex == 'f' & sampling_doy < sex == 'm', sampling_doy ~ sampling_doy,
sex == 'f' & sampling_doy > sex == 'm', sampling_doy ~ NA,
))
我也考虑过在group by内使用arrangeing,并尝试在第一条男性记录之前对所有女性记录进行切片。但是,这似乎不是一个好方法。
所以我的第一个问题是:任何人都可以解决这个问题吗?在我看来,使用 case_when 并将左侧表达式转换为在 case_when 内调用的函数是最好的做法。但是,与此同时,根据我发现的其他示例,我觉得这根本不是 case_when 的设置方式。有时我会在其中加入一些非常简单的数学运算,但通常是非常简单的数学运算,它们在感兴趣的列中的作用相同。
第二个问题是:这个主题是否有一般建议的方法,或者我是否必须依靠编写函数来完成这样的事情?
对于本文的篇幅,我们深表歉意post,但非常感谢任何帮助。我还标记了数据表,因为它似乎有一个不错的简单解决方案。
这可以通过连接来完成。
male_first_obs <- my_data %>%
group_by(species, year) %>%
filter(sex == "m") %>%
summarize(male_first_obs_doy = min(observation_doy))
my_data %>%
left_join(male_first_obs, by = c(species, year)) %>%
group_by(species, year) %>%
filter(!(sex == "f" & observation_day > male_first_obs_doy)) %>%
select(-male_first_obs_doy)
如果您不关心 dbplyr
兼容性等,您可能会更简洁,例如:
my_data %>%
group_by(species, year) %>%
mutate(male_first_obs_day = min(observation_doy[which(sex == "m")])) %>%
filter(!(sex == "f" & observation_day > male_first_obs_doy)) %>%
select(-male_first_obs_doy)