在 R 中的每个实体的最小行要求条件下插入具有 NA 值的行数

inserting numbers of rows with NA value with the condition of minimum row requirement for each entity in R

我有一个数据框如下。我想为每个 ID 设置一个最小行变量(让我们称之为 min_row),这意味着每个 ID 应该至少有 min_row 条记录。如果没有,我想为该 ID 插入一行,另一列为 NA 值(这里是 subject 列)。

min_row_id=3
df
ID    subject
1      A1
1      A2
2      A1
3      A1
3      A2
3      A3
3      A4

resutl:

ID   subject
1     A1
1     A2
1     NA
2     A1
2     NA
2     NA
3     A1
3     A2
3     A3
3     A4

所以每个ID至少有3条记录。
我怎样才能在 R 中做到这一点?谢谢

一种只使用基数 R 的方法是

#Get number of rows for each ID and subtract it from min_row_id
#keep only those which we need to add 
temp <- subset(aggregate(subject~ID, df, function(x) min_row_id - length(x)), 
               subject < min_row_id & subject > 0)

#Add those new rows and rbind the original dataframe
new_df <- rbind(df, do.call(rbind, mapply(function(x, y) 
                    data.frame(ID = x, subject = rep(NA, y)), 
                    temp$ID, temp$subject, SIMPLIFY = FALSE)))

#If needed order them according to ID
new_df[order(new_df$ID), ]

#   ID subject
#1   1      A1
#2   1      A2
#8   1    <NA>
#3   2      A1
#9   2    <NA>
#10  2    <NA>
#4   3      A1
#5   3      A2
#6   3      A3
#7   3      A4

这是使用 tidyr::complete 的一种方法。我们创建了一个 record_number 列来计算每个 ID 组的记录。然后 complete 将让我们填写所有缺失的行,因此每个组的记录数与记录数最多的组一样多(或者如果没有组有 3 条记录,则最多填充 3 行)。然后我们过滤掉每组添加的超过 3 行的无关行。

library(tidyverse)
tbl <- read_table2(
"ID    subject
1      A1
1      A2
2      A1
3      A1
3      A2
3      A3
3      A4" 
)

tbl %>%
  group_by(ID) %>%
  mutate(record_number = row_number()) %>%
  ungroup() %>%
  complete(ID, record_number = 1:max(3, max(record_number))) %>%
  filter(record_number <=3 | !is.na(subject))
#> # A tibble: 10 x 3
#>       ID record_number subject
#>    <dbl>         <int> <chr>  
#>  1     1             1 A1     
#>  2     1             2 A2     
#>  3     1             3 <NA>   
#>  4     2             1 A1     
#>  5     2             2 <NA>   
#>  6     2             3 <NA>   
#>  7     3             1 A1     
#>  8     3             2 A2     
#>  9     3             3 A3     
#> 10     3             4 A4

reprex package (v0.2.1)

于 2019-02-06 创建

另一个base备选方案。使用 tapply 在每个 'ID' 中索引 ([) 'subject',从组 length 的 1 到 max 和 3 (min_row_id).对于超过组长的索引,对应的值为NA.

通过rep将列表元素的名称与每个元素的长度关联起来 (lengths),重新创建正确长度的 'ID'。使用 unlist 创建一个 'subject' 列。

l <- tapply(d$subject, d$ID, function(x) x[1:(max(c(length(x), 3)))])
data.frame(id = rep(names(l), lengths(l)), subject = unlist(l, use.names = FALSE))
#    id subject
# 1   1      A1
# 2   1      A2
# 3   1    <NA>
# 4   2      A1
# 5   2    <NA>
# 6   2    <NA>
# 7   3      A1
# 8   3      A2
# 9   3      A3
# 10  3      A4