我正在寻找一种方法来省略不在两个特定值之间的行,而不使用for
循环。年份列中的所有行都在1999年到2002年之间,但是其中一些行不包括这两个日期之间的所有年份。您可以看到如下初始数据:
a <- data.frame(year = c(2000:2002,1999:2002,1999:2002,1999:2001),
id=c(4,6,2,1,3,5,7,4,2,0,-1,-3,4,3))
year id
1 2000 4
2 2001 6
3 2002 2
4 1999 1
5 2000 3
6 2001 5
7 2002 7
8 1999 4
9 2000 2
10 2001 0
11 2002 -1
12 1999 -3
13 2000 4
14 2001 3
已处理的数据集应仅包含1999:2002之间的连续行。以下data.frame
正是我需要的:
year id
1 1999 1
2 2000 3
3 2001 5
4 2002 7
5 1999 4
6 2000 2
7 2001 0
8 2002 -1
当我执行以下for
循环时,我得到以前的data.frame
没有任何问题:
for(i in 1:which(a$year == 2002)[length(which(a$year == 2002))]){
if(a[i,1] == 1999 & a[i+3,1] == 2002){
b <- a[i:(i+3),]
}else{next}
if(!exists("d")){
d <- b
}else{
d <- rbind(d,b)
}
}
但是,我有超过100万行,我需要在不使用for
循环的情况下完成此过程。那有更快的方法吗?
你可以试试这个。首先我们创建连续数字组,然后我们加入完整的日期范围,然后我们过滤任何组是否已满。如果您已经有一个分组变量,这可以减少很多。
library(tidyverse)
df <- data_frame(year = c(2000:2002,1999:2002,1999:2002,1999:2001),
id=c(4,6,2,1,3,5,7,4,2,0,-1,-3,4,3))
df %>%
mutate(groups = cumsum(c(0,diff(year)!=1))) %>%
nest(-groups) %>%
mutate(data = map(data, .f = ~full_join(.x, data_frame(year = 1999:2002), by = "year")),
drop = map_lgl(data, ~any(is.na(.x$id)))) %>%
filter(drop == FALSE) %>%
unnest() %>%
select(-c(groups, drop))
#> # A tibble: 8 x 2
#> year id
#> <int> <dbl>
#> 1 1999 1
#> 2 2000 3
#> 3 2001 5
#> 4 2002 7
#> 5 1999 4
#> 6 2000 2
#> 7 2001 0
#> 8 2002 -1
由reprex package创建于2018-08-31(v0.2.0)。
有一个功能可以自动执行此操作。
首先,使用命令dplyr
或tidyverse
安装名为install.packages("dplyr")
或install.packages("tidyverse")
的软件包。
然后,使用library(dplyr)
加载包。
然后,使用filter
函数:a_filtered = filter(a, year >=1999 & year < 2002)
。
即使有很多行,这应该很快。
我们也可以通过基于检查'年'1999的逻辑表达式创建分组列,然后通过将filter
'年'检查为'1999',将first
检查为'2002'并将last
if
检查为'年'来创建分组列。出现在特定的'grp'
all