在连续组上多次使用setdiff()而不进行循环

时间:2017-04-06 14:38:05

标签: r dataframe

我希望在连续组之间setdiff而不进行循环,如果可能的话,使用数据表方式或应用族的函数。

Dataframe 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(不是直接使用setdiff,而是使用length() ),如果我们比较第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"))

4 个答案:

答案 0 :(得分:3)

以下是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 

答案 1 :(得分:2)

这是data.table方式merge。假设原始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

答案 2 :(得分:1)

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 

答案 3 :(得分:1)

您可以使用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")