【问题标题】:keep only consecutive observations只保留连续的观察
【发布时间】:2018-03-20 16:02:27
【问题描述】:

正如标题中所说,我有一个如下所示的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

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

我想对这个数据集做两件事,首先,在这里找到所有至少连续观察5次的id,这可以通过以下解决方案here来完成。其次,我只想在第一步选择的id 的至少连续五行中保留这些观察结果。理想的结果是:

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

我可以使用 for 循环和 diff 函数编写一个复杂的函数,但是如果 id 有一个更大的数据集,那么这在编写函数和获取结果时可能会非常耗时。但这似乎不像 R,我相信应该有一个或两个行的解决方案。

有人知道如何实现吗?您的时间和知识将不胜感激。提前致谢。

【问题讨论】:

  • 是的,我希望它是数字@bouncyball
  • 我复制你的代码并重新运行它,只有 #A tibble: 0 x 3 # Groups: id, grp [0] # ... with 3 variables: id , time , grp ,我错过了什么重要的东西吗?不熟悉tidyr

标签: r dataframe


【解决方案1】:

在您的数据上尝试一下:

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, ]

【讨论】:

  • 感谢您的回复,但据我了解,您使用的是已知连续行的起点和终点的信息,而我的实际问题并非如此。
  • 你试过我的代码了吗?当缺少值时它也应该工作(NA)
  • @JasonGoal 然后请提供与您的实际数据匹配的可重现代码。
  • 当然我做到了,除了这一行之外,其他人工作得很好:df &lt;- df[IND1 %in% 1 | IND2 %in% 1,] 只有第一个条件会被应用。恕我直言,但这里的问题不在于可重现的代码,它关于您的解决方案是硬编码的,基于事先知道起始点和结束点。我的意思不是真正的问题是,对于另一个id,time 向量中的特定时间和位置将发生变化,然后您的代码将不再适用。
【解决方案2】:

来自dplyr、tidyr 和 data.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

【讨论】:

    【解决方案3】:

    您可以使用dplyr按id和连续时间进行分组,filter分组少于5个条目,即

    #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
    

    【讨论】:

      【解决方案4】:

      类似于@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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多