2017-10-09 82 views
1

正如标题所说,我有data.frame像下面,只保留观察连续

df<-data.frame('id'=c('1','1','1','1','1','1','1'),'time'=c('1998','2000','2001','2002','2003','2004','2007')) 
df 
    id time 
1 1 1998 
2 1 2000 
3 1 2001 
4 1 2002 
5 1 2003 
6 1 2004 
7 1 2007 

还有其他一些情况下有比这更短或更长的时间窗口,只是为了说明的缘故。

我想要做的两件事情有关这组数据,首先,找到所有这些id至少五个连续的观测位置,这可以通过以下方法解决here完成。其次,我只想保留中至少连续五行id第一步选择的观察值。理想的结果是:

df 
    id time 
1 1 2000 
2 1 2001 
3 1 2002 
4 1 2003 
5 1 2004 

我可以使用循环和diff功能编写一个复杂的功能,但是这可能是很长的时间都在写函数获得的结果耗时,如果我有一个更大的数据与设置很多,如果id。但是这看起来不像R,我确实认为应该有一个或两个解决方案。

任何人都知道如何做到这一点?您的时间和知识将深受赞赏。提前致谢。

+0

是的,我希望它是数字@bouncyball –

+0

我复制你的代码,并重新运行它,就只是#A tibble:0×3个 #组:身份证,GRP [0] #...有3个变量:id ,时间,grp ,我是否缺少重要的东西?不熟悉'tidyr' –

回答

2

您可以通过id和连续的时间,并filter组,不到5项使用dplyr到组,即

#read data with stringsAsFactors = FALSE 
df<-data.frame('id'=c('1','1','1','1','1','1','1'), 
       'time'=c('1998','2000','2001','2002','2003','2004','2007'), 
                stringsAsFactors = FALSE) 

library(dplyr) 

df %>% 
mutate(time = as.integer(time)) %>% 
group_by(id, grp = cumsum(c(1, diff(time) != 1))) %>% 
filter(n() >= 5) 

这给

# A tibble: 5 x 3 
# Groups: id, grp [1] 
    id time grp 
    <chr> <int> <dbl> 
1  1 2000  2 
2  1 2001  2 
3  1 2002  2 
4  1 2003  2 
5  1 2004  2 
0

试穿的数据:

df[,] <- lapply(df, function(x) type.convert(as.character(x), as.is = TRUE)) 

IND1 <- (df$time - c(df$time[-1],df$time[length(df$time)-1])) %>% abs(.) 
IND2 <- (df$time - c(df$time[2],df$time[-(length(df$time))])) %>% abs(.) 

df <- df[IND1 %in% 1 | IND2 %in% 1,] 

df[ave(df$time, df$id, FUN = length) >= 5, ] 
+0

感谢您的回复,但根据我的理解,您使用的是连续行的起点和终点已知的信息,而我的实际问题并非如此。 –

+0

你试过我的代码吗?当值缺失时,它也应该工作(NA) –

+0

@JasonGoal请提供与您的实际数据相匹配的可复制代码。 –

0

dplyrtidyrdata.table溶液。

library(dplyr) 
library(tidyr) 
library(data.table) 

df2 <- df %>% 
    mutate(time = as.numeric(as.character(time))) %>% 
    arrange(id, time) %>% 
    right_join(data_frame(time = full_seq(.$time, 1)), by = "time") %>% 
    mutate(RunID = rleid(id)) %>% 
    group_by(RunID) %>% 
    filter(n() >= 5, !is.na(id)) %>% 
    ungroup() %>% 
    select(-RunID) 
df2 
# A tibble: 5 x 2 
     id time 
    <fctr> <dbl> 
1  1 2000 
2  1 2001 
3  1 2002 
4  1 2003 
5  1 2004 
0

类似以@Sotos回答,这个解决方案改为使用seqle(从cgwtools)作为分组变量:

library(dplyr) 
library(cgwtools) 

df %>% 
    mutate(time = as.numeric(time)) %>% 
    group_by(id, consec = rep(seqle(time)$length, seqle(time)$length)) %>% 
    filter(consec >= 5) 

结果:

# A tibble: 5 x 3 
# Groups: id, consec [1] 
    id time consec 
    <chr> <dbl> <int> 
1  1 2000  5 
2  1 2001  5 
3  1 2002  5 
4  1 2003  5 
5  1 2004  5 

要删除分组变量:

df %>% 
    mutate(time = as.numeric(time)) %>% 
    group_by(id, consec = rep(seqle(time)$length, seqle(time)$length)) %>% 
    filter(consec >= 5) %>% 
    ungroup() %>% 
    select(-consec) 

结果:

# A tibble: 5 x 2 
    id time 
    <chr> <dbl> 
1  1 2000 
2  1 2001 
3  1 2002 
4  1 2003 
5  1 2004 

数据:

df<-data.frame('id'=c('1','1','1','1','1','1','1'), 
       'time'=c('1998','2000','2001','2002','2003','2004','2007'), 
       stringsAsFactors = FALSE)