如何删除 R 中缺少年度观察的对象?

How to remove subjects with missing yearly observations in R?

     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?

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

## 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

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

这是一种使用 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)

当然可以使用 %>% 运算符将所有步骤构建为一个管道。

这里有一个更直接的 tidyverse 解决方案。 首先,扩展数据框以包含 Name + year 的所有组合:

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
...

然后将管道扩展到按 "Name" 分组,并过滤​​以仅保留 NA 值为 0 的那些:

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