2016-06-23 30 views
3

示例數據:抗加入,但只返回「上一個」失蹤一行

library(dplyr) 
x <- data.frame(name = c(rep('Alice', 4), rep('Bob', 3)), 
       timestamp = c(1, 5, 10, 11, 1, 3, 4), stringsAsFactors = F) 

y <- 
    base::merge(I(c('Alice', 'Bob')), c(1:3, 5:15)) # note missing time stamp = 4 
names(y) <- names(x) 
y <- 
    y %>% 
    arrange(name,timestamp) 

我想了解,如果存在的話,在每個連續的塊中的最後一行中的數據幀anti_join(y,x)(使用timestamp訂購) 。

使用數據。例如,構建anti_join

x_missing <- 
    dplyr::anti_join(y, x) %>% 
    arrange(name,timestamp) 

其給出

> head(x_missing, 11) 
    name timestamp 
1 Alice   2 
2 Alice   3 
3 Alice   6 
4 Alice   7 
5 Alice   8 
6 Alice   9 
7 Alice  12 
8 Alice  13 
9 Alice  14 
10 Alice  15 
11 Bob   2 

我想解決方案爲:

name timestamp 
    Alice   3 
    Alice   9 
    Alice  15 
    ... 

該解決方案需要更快比計算anti_join(y,x),這在時過於緩慢都很大。

+0

的三個連續時間戳愛麗絲塊是(2,3),(6,7,8,9)和(12,13,14,15) – Alex

+0

'Y%:沒有關於相對速度想法>%anti_join(x)%>%group_by(name)%>%filter(!timestamp%in%(timestamp - 1))%>%arrange(name,timestamp)'? – alistaire

+0

@alistaire你應該把它放在一個答案,很好 –

回答

2

這提高了反連接的速度,並使用一個循環來獲取所需的行,但當然有一些更好的方法來選擇行,而不是使用我的hack-ish循環。

library(dplyr) 
x <- data.frame(name = c(rep('Alice', 4), rep('Bob', 3)), 
       timestamp = c(1, 5, 10, 11, 1, 3, 4), stringsAsFactors = F) 

y <- 
    base::merge(I(c('Alice', 'Bob')), c(1:3, 5:15)) # note missing time stamp = 4 
names(y) <- names(x) 


y <- 
    y %>% 
    arrange(name,timestamp) 

x$nt <- paste(x$name,x$timestamp) 
y$nt <- paste(y$name,y$timestamp) 

ynt <- y[!y$nt %in% x$nt,] # should be faster 

tmp <- data.frame(name=NA,timestamp=NA) 
for(i in 2:nrow(ynt)){ 
     if((ynt[i-1,2]+1) < (ynt[i,2])){tmp <- rbind(ynt[i-1,1:2],tmp)} 
     if(!((ynt[i-1,1]) == (ynt[i,1]))){tmp <- rbind(ynt[i-1,1:2],tmp)} 
     if(i == nrow(ynt)){tmp <- rbind(ynt[i,1:2],tmp)} 
} 

tmp <- tmp[order(tmp$name,tmp$timestamp),]; tmp <- tmp[!is.na(tmp$name),] 
tmp 

    name timestamp 
    Alice   3 
    Alice   9 
    Alice  15 
    ... 
2

一個簡單的方法來過濾到一個等差數列的最後一行是篩選到的序列中排移回一個術語,即減去其差異(這裏只是1)。雖然這簡化了從A到B的過程,但它不會加速anti_join,除非您可以利用數據的模式,否則這是一項更大的工作。

y %>% anti_join(x) %>% 
    group_by(name) %>% 
    filter(!timestamp %in% (timestamp - 1)) %>% 
    arrange(name, timestamp) 

# Source: local data frame [5 x 2] 
# Groups: name [2] 
# 
#  name timestamp 
# (AsIs)  (int) 
# 1 Alice   3 
# 2 Alice   9 
# 3 Alice  15 
# 4 Bob   2 
# 5 Bob  15 

如果你喜歡,你可以做與filter,這同時爲樣本數據的速度更快,可擴展不佳手動反連接; %in%不是非常有效。

y %>% group_by(name) %>% 
    filter(!timestamp %in% x[x$name == unique(name), 'timestamp']) %>% 
    filter(!timestamp %in% (timestamp - 1)) 

或者無%in%

y %>% anti_join(x) %>% 
    group_by(name) %>% 
    arrange(timestamp) %>% 
    filter(c(diff(timestamp), 0) != 1) 

結果是相同的。

1

A data.table的可能性。

library(data.table) 
setDT(x) 
setDT(y) 
keycols = c("name","timestamp") 
setkeyv(x,keycols) 
setkeyv(y,keycols) 

y[!x][c(diff(timestamp)!= 1,TRUE)] 

# name timestamp 
#1: Alice   3 
#2: Alice   9 
#3: Alice  15 
#4: Bob   2 
#5: Bob  15