【问题标题】:Multiple uses of setdiff() on consecutive groups without for looping在没有 for 循环的情况下在连续组上多次使用 setdiff()
【发布时间】:2017-04-06 14:38:05
【问题描述】:

我想在连续组之间setdiff 不使用 for 循环,如果可能的话,使用数据表方式或应用族功能。

数据框 df :

   id group
1  L1     1
2  L2     1
3  L1     2
4  L3     2
5  L4     2
6  L3     3
7  L5     3
8  L6     3
9  L1     4
10 L4     4
11 L2     5

我想知道连续组之间有多少新 ID。因此,例如,如果我们比较第 1 组和第 2 组,有两个新的 id:L3L4,所以如果我们比较第 2 组和3,L5L6 是新闻 id,所以它返回 2,依此类推。

预期结果:

new_id
  2
  2
  2
  1

数据:

structure(list(id = structure(c(1L, 2L, 1L, 3L, 4L, 3L, 5L, 6L, 
1L, 4L, 2L), .Label = c("L1", "L2", "L3", "L4", "L5", "L6"), class = "factor"), 
    group = c(1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5)), class = "data.frame", row.names = c(NA, 
-11L), .Names = c("id", "group"))

【问题讨论】:

  • 你也可以基于this post 构建一些东西——例如tab = table(df) > 0; (colSums(tab) - crossprod(tab))[cbind(2:5, 1:4)](并相应调整子集中的硬编码)

标签: r dataframe


【解决方案1】:

这是mapply的选项:

lst <- with(df, split(id, group))   
mapply(function(x, y) length(setdiff(y, x)), head(lst, -1), tail(lst, -1))

#1 2 3 4 
#2 2 2 1 

【讨论】:

    【解决方案2】:

    这是data.tablemerge 的方式。假设原来的data.frame被命名为dt

    library(data.table)
    
    setDT(dt)
    dt2 <- copy(dt)[, group := group + 1]
    
    merge(
        dt, dt2, by = 'group', allow.cartesian = T
    )[, .(n = length(setdiff(id.x, id.y))), by = group]
    
    #    group n
    # 1:     2 2
    # 2:     3 2
    # 3:     4 2
    # 4:     5 1
    

    【讨论】:

    • 这可以使用反连接和 .N 代替 length-setdiff 来简化:d[!.(group = group + 1L, id = id), on=.(group, id), .N, by=group]
    • @Frank,使用 not-join 比我的回答简洁得多。我总是从您与 data.table 相关的答案中学到很多东西。
    • @Frank 你能解释一下这部分代码吗? :[!.(group = group + 1L, id = id), on=.(group, id)]?
    • @MbrMbr 它是针对包含 group+1、id 形式的元组的表的反连接,其中 group 和 id 是从表本身中提取的。还没有关于连接的小插曲,但我在这里的笔记可能有助于直觉:franknarf1.github.io/r-tutorial/_book/tables.html#dt-joins
    【解决方案3】:

    您可以使用Reduce 对列表中的成对元素运行比较函数。例如

    xx<-Reduce(function(a, b) {
        x <- setdiff(b$id, a$id); 
        list(id=b$id, new=x, newcount=length(x))
      }, split(df, df$group), 
      acc=TRUE)[-1]
    

    然后你可以得到新元素的数量

    sapply(xx, '[[', "newcount")
    

    你可以得到新的值

    sapply(xx, '[[', "new")
    

    【讨论】:

      【解决方案4】:
      L = split(d, d$group) #Split data ('d') by group and create a list
      
      #use lapply to access 'id' for each sub group in the list and obtain setdiff
      sapply(2:length(L), function(i)
           setNames(length(setdiff(L[[i]][,1], L[[i-1]][,1])),
           nm = paste(names(L)[i], names(L)[i-1], sep = "-")))
      #2-1 3-2 4-3 5-4 
      #  2   2   2   1 
      

      【讨论】:

        猜你喜欢
        • 2012-05-23
        • 2021-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-25
        • 1970-01-01
        相关资源
        最近更新 更多