【问题标题】:How to remove subjects with missing yearly observations in R?如何删除 R 中缺少年度观察的主题?
【发布时间】:2017-10-15 18:14:40
【问题描述】:
     num Name  year   age       X 
1      1   A   2011    68  116292
2      1   A   2012    69   46132
3      1   A   2013    70    7042
4      1   A   2014    71 -100425
5      1   A   2015    72    6493
6      2   B   2011    20   -8484
7      3   C   2015    23 -120836
8      4   D   2011     3  -26523
9      4   D   2012     4    9923
10     4   D   2013     5   82432

我有 5 年内由各种主题代表的数据。我需要删除所有从 2011 年到 2015 年缺少任何年份的主题。我该如何完成它,所以在给定的数据中只剩下主题 A?

【问题讨论】:

    标签: r panel-data


    【解决方案1】:

    使用 data.table:

    data.table 解决方案可能如下所示:

    library(data.table)
    dt <- as.data.table(df)
    dt[, keep := identical(unique(year), 2011:2015), by = Name ][keep == T, ][,keep := NULL]
    #   num Name year age       X
    #1:   1    A 2011  68  116292
    #2:   1    A 2012  69   46132
    #3:   1    A 2013  70    7042
    #4:   1    A 2014  71 -100425
    #5:   1    A 2015  72    6493
    

    这更严格,因为它要求唯一年份完全等于 2011:2015。例如,如果有 2016 年,则该人将被排除在外。


    限制较少的解决方案是检查2011:2015 是否在您的独特年份。这应该有效:

    dt[, keep := all(2011:2015 %in% unique(year)), by = Name ][keep == T, ][,keep := NULL]
    

    因此,例如,如果 A 有 2016 年和 2010 年,它仍然会保留所有 A。但如果有人在 2011:2015 中缺少一年,这将排除他们。


    使用基础 R & 聚合:

    相同的选项,但使用来自基本 R 的aggregate

    agg <- aggregate(df$year, by = list(df$Name), FUN = function(x) all(2011:2015 %in% unique(x)))
    df[df$Name %in% agg[agg$x == T, 1] ,]
    

    【讨论】:

    • 感谢您的回答!我已经尝试了所有三种方法。出于某种原因,第一个放弃了所有观察结果。第二种方法(即使我只有 2011:2015,仍然尝试过)给出了预期的结果,但只有在我使用 id 号而不是名称之后。会不会是名字的问题?每个名称长度为 3 个单词,仅包含英文字符。
    • 这可能是名称的问题,但如果没有看到您的实际数据就很难说。您需要按数据集中的 unqiue 人进行分组
    【解决方案2】:

    这里有一个更简单的tidyverse 解决方案。 首先,扩展数据框以包含名称 + 年份的所有组合:

    df %>% complete(Name, year)
    
        # A tibble: 20 x 5
         Name  year   num   age       X
       <fctr> <int> <int> <int>   <int>
     1      A  2011     1    68  116292
     2      A  2012     1    69   46132
     3      A  2013     1    70    7042
     4      A  2014     1    71 -100425
     5      A  2015     1    72    6493
     6      B  2011     2    20   -8484
     7      B  2012    NA    NA      NA
     8      B  2013    NA    NA      NA
     9      B  2014    NA    NA      NA
    10      B  2015    NA    NA      NA
    ...
    

    然后将管道扩展到按“名称”分组,并过滤​​以仅保留具有 0 NA 值的那些:

    df %>% complete(Name, year) %>%
      group_by(Name) %>%
      filter(sum(is.na(age)) == 0)
    
    # A tibble: 5 x 5
    # Groups:   Name [1]
        Name  year   num   age       X
      <fctr> <int> <int> <int>   <int>
    1      A  2011     1    68  116292
    2      A  2012     1    69   46132
    3      A  2013     1    70    7042
    4      A  2014     1    71 -100425
    5      A  2015     1    72    6493
    

    【讨论】:

      【解决方案3】:

      只需检查哪些名称的条目数正确。

      ## Reproduce your data
      df = read.table(text="     num Name  year   age       X 
      1      1   A   2011    68  116292
      2      1   A   2012    69   46132
      3      1   A   2013    70    7042
      4      1   A   2014    71 -100425
      5      1   A   2015    72    6493
      6      2   B   2011    20   -8484
      7      3   C   2015    23 -120836
      8      4   D   2011     3  -26523
      9      4   D   2012     4    9923
      10     4   D   2013     5   82432",
      header=TRUE)
      
      Tab = table(df$Name)
      Keepers = names(Tab)[which(Tab == 5)]
      df[df$Name %in% Keepers,]
        num Name year age       X
      1   1    A 2011  68  116292
      2   1    A 2012  69   46132
      3   1    A 2013  70    7042
      4   1    A 2014  71 -100425
      5   1    A 2015  72    6493
      

      【讨论】:

      • 不知道你可以在read.table 中使用text 做到这一点,酷+1 :)
      • 谢谢,这行得通,但我必须使用 ID 而不是实际名称,这会导致不是矢量的错误。
      【解决方案4】:

      这是使用tidyverse 包的一种稍微不同的方法:

      library(tidyverse)
      
      df <- read.table(text = "     num Name  year   age       X 
      1      1   A   2011    68  116292
      2      1   A   2012    69   46132
      3      1   A   2013    70    7042
      4      1   A   2014    71 -100425
      5      1   A   2015    72    6493
      6      2   B   2011    20   -8484
      7      3   C   2015    23 -120836
      8      4   D   2011     3  -26523
      9      4   D   2012     4    9923
      10     4   D   2013     5   82432")
      
      df2 <- spread(data = df, key = Name, value = year)
      x <- colSums(df2[, 4:7], na.rm = TRUE) > 10000
      df3 <- select(df2, num, age, X, c(4:7)[x])
      df4 <- na.omit(df3)
      

      当然,所有步骤都可以使用%&gt;% 运算符构建为一个管道。

      【讨论】:

        猜你喜欢
        • 2021-11-11
        • 1970-01-01
        • 2015-04-10
        • 2021-05-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-25
        • 1970-01-01
        相关资源
        最近更新 更多