问题描述
我主动帮助遇到问题的朋友,并很快意识到这超出了我的能力。我有兴趣进行过滤以删除属于另一个组的第一条记录或在其后的某个组的记录。
我正在按“物种”,“年”和“性别”分组,并希望删除在“ m”的第一个“ observation_doy”之后出现的“ sex”为“ f”的记录。在此示例中,我要删除的记录以粗体显示。
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)
我也曾尝试创建一个“双面”滤镜,这似乎与dplyr哲学不符。我认为这种方法的问题是使dplyr识别主要的过滤条件,在这种情况下为'
clean_df <- raw_df %>%
group_by(species,sex) %>%
dplyr::filter(sex == 'f' & sampling_doy <= print(filter(sex == 'm',(slice_min(sampling_doy,n = 1)))))
请注意,我在右边的表达式上进行了“打印”,以尝试返回用于
最后,我尝试使用case_when,但是在允许该函数确定LHS和RHS归因于许多运算符的地方也存在问题。
clean_df <- raw_df %>%
group_by(species,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',n = 1)) ~ NA,))))))
我也在此尝试了一个变体:
clean_df <- raw_df %>%
dplyr::filter(generations == 'partially bivoltine') %>%
group_by(species,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,))
我还考虑过在分组依据中使用“排列”,并尝试在第一个男性记录之前对所有女性记录进行切片。但是,这似乎不是一个好方法。
所以我的第一个问题是:谁能解决这个问题?在我看来,使用case_when并将左手表达式转换为在case_when内调用的函数是最好的方法。但是,与此同时,我觉得从根本上说,这并不是基于我发现的其他示例设置使用case_when的方式。有时我会把一些非常简单的数学运算混入其中,但是通常情况下,相当简单的数学运算在感兴趣的列之间作用相同。
第二个问题是:对于这个主题,是否有一种普遍建议的方法,还是我必须依靠编写函数来完成类似的事情?
对这篇文章的长度深表歉意,但是对您的帮助非常感谢。我还标记了数据表,因为它似乎有一个不错的简单解决方案。
解决方法
这可以通过联接来完成。
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)