2017-04-06 45 views
4

我想在連續組之間使用setdiff而不使用循環,如果可能的話使用數據表或應用系列函數。多次使用setdiff()連續組而不循環使用

數據幀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,則L5和是新聞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")) 
+0

你可以,也建立一些關閉[此帖](的http://stackoverflow.com/questions/19891278/r-table-of-interactions-case-與寵物和房子) - 例如'tab = table(df)> 0; (colSums(tab) - crossprod(tab))[cbind(2:5,1:4)]'(並相應地調整子集中的硬編碼) –

回答

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
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 
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") 
2

這是方式,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 
+1

這可以使用反連接和.N代替length-setdiff :'d [!。(group = group + 1L,id = id),on =。(group,id),.N,by = group]' – Frank

+1

@Frank,使用not-join比我的答案簡潔得多。我總是從與data.table有關的答案中學到很多東西。 – mt1022

+0

@Frank你能解釋一下這段代碼嗎? :[!。(group = group + 1L,id = id),on =。(group,id)]'? –