R根据分层数据中的儿子删除父亲行

R delete fathers row based on sons in hierarchycal data

我正在处理像这样的一些数据:

id <- c(1,1,1,2,2,2,3,3,3,4,4)                         # fathers
name <- c('a','b','k','b','e','g','e','f','k','f','u') # sons
data <- data.frame(id,name)
data

   > data
    id name
1   1    a
2   1    b
3   1    k
4   2    b
5   2    e
6   2    g
7   3    e
8   3    f
9   3    k
10  4    f
11  4    u

我的目标是:如果只有一个我不想要的儿子,删除所有与不喜欢的儿子相同父亲的行。比如我不喜欢儿子e,结果应该是:

> data_e
    id name
1   1    a
2   1    b
3   1    k
# 4   2    b
# 5   2    e
# 6   2    g
# 7   3    e
# 8   3    f
# 9   3    k
10  4    f
11  4    u

因为 id 为 2 和 3 的行的名称为 e。
这也可以是像“我不喜欢 ef 在一起”这样的任务:

    > data_eandf
    id name
1   1    a
2   1    b
3   1    k
4   2    b
5   2    e
6   2    g
# 7   3    e
# 8   3    f
# 9   3    k
10  4    f
11  4    u

或者,"I don't want you if you have e or f":

> data_eorf
    id name
1   1    a
2   1    b
3   1    k
# 4   2    b
# 5   2    e
# 6   2    g
# 7   3    e
# 8   3    f
# 9   3    k
# 10  4    f
# 11  4    u

如您所见,更清楚地说,我已经 "commented" 了必须删除的行。

我已经搜索过,但我发现很多问题仅基于一列,例如 data[which(data$name=='e'),],但这只会在儿子级别删除,而不是亲属父亲的所有行。

我还想过将数据放在宽格式中,将 id 的所有名称粘贴到一个唯一的单元格中,如果有 e,例如使用 grepl() 之类的函数,则获取,但我认为这可能是大型数据集的问题(这些数据是一个例子)。

你知道如何管理这个吗?
提前致谢

data[!(data$id %in% unique(data[data$name == 'e', 'id'])),]

unique(data[data$name == 'e', 'id']) 将获得名称字段中具有 'e' 的唯一 ID。然后您可以使用 %in% 运算符查找具有这些 ID 的所有行。这 !是一个否定运算符。

我有一个data.table解决方案

require(data.table)

id <- c(1,1,1,2,2,2,3,3,3,4,4)                         # fathers
name <- c('a','b','k','b','e','g','e','f','k','f','u') # sons
data <- data.table(id,name)

# names to be deleted
to_del <- c("e","f")

# returns only id's without any of the names to be deleted
data[ , .SD[ !any(name %in% to_del) ,name ] , by = "id"]

   id V1
1:  1  a
2:  1  b
3:  1  k

这是一个处理不同情况的函数

dislike1 <- c('e')
dislike2 <- c('e', 'f')

myfun <- function(df, dislike, ops = NULL) {
    require(dplyr)
    if (is.null(ops) || ops == 'OR') {
        df %>%
            group_by(id) %>%
            filter(!any(name %in% dislike)) %>%
            ungroup
    } else if (ops == 'AND') {
        df %>%
            group_by(id) %>%
            filter(!all(dislike %in% name)) %>%
            ungroup
    }
}

myfun(data, dislike1)
# A tibble: 5 x 2
     # id name 
  # <dbl> <fct>
# 1     1 a    
# 2     1 b    
# 3     1 k    
# 4     4 f    
# 5     4 u    
myfun(data, dislike2, 'AND')
# A tibble: 8 x 2
     # id name 
  # <dbl> <fct>
# 1     1 a    
# 2     1 b    
# 3     1 k    
# 4     2 b    
# 5     2 e    
# 6     2 g    
# 7     4 f    
# 8     4 u    
myfun(data, dislike2, 'OR')
# A tibble: 3 x 2
     # id name 
  # <dbl> <fct>
# 1     1 a    
# 2     1 b    
# 3     1 k