2017-10-10 40 views
6

考虑以下两个data.frames确切行和data.frame的行频:删除在另一data.frame r中

a1 <- data.frame(A = c(1:5, 2, 4, 2), B = letters[c(1:5, 2, 4, 2)]) 
a2 <- data.frame(A = c(1:3,2), B = letters[c(1:3,2)]) 

我想删除的a1确切行时,在a2,这样的结果应该是:

A B 
4 d 
5 e 
4 d 
2 b 

注意,在A1一行与2 b保留在最终结果。目前,我使用循环语句,因为我的data.frames中有很多变量和数千行,所以变得非常慢。有没有内置的函数来获得这个结果?

+0

目前还不清楚你的输出是否正确,'2b'是在两个开始,我是否错过了什么? – steveb

+0

@steveb'2b'在'a1'中是两次,所以只有一个被取消,一个留在输出中。 –

+0

啊,这就是我读得太快。 – steveb

回答

1

我想这是类似于DWal's solution但在基础R

a1_temp = Reduce(paste, a1) 
a1_temp = paste(a1_temp, ave(seq_along(a1_temp), a1_temp, FUN = seq_along)) 

a2_temp = Reduce(paste, a2) 
a2_temp = paste(a2_temp, ave(seq_along(a2_temp), a2_temp, FUN = seq_along)) 

a1[!a1_temp %in% a2_temp,] 
# A B 
#4 4 d 
#5 5 e 
#7 4 d 
#8 2 b 
2

你可以使用dplyr做到这一点。我设置了stringsAsFactors = FALSE以摆脱因素不匹配的警告。

library(dplyr) 

a1 <- data.frame(A = c(1:5, 2, 4, 2), B = letters[c(1:5, 2, 4, 2)], stringsAsFactors = FALSE) 
a2 <- data.frame(A = c(1:3,2), B = letters[c(1:3,2)], stringsAsFactors = FALSE) 

## Make temp variables to join on then delete later. 
# Create a row number 
a1_tmp <- 
    a1 %>% 
    group_by(A, B) %>% 
    mutate(tmp_id = row_number()) %>% 
    ungroup() 
# Create a count 
a2_tmp <- 
    a2 %>% 
    group_by(A, B) %>% 
    summarise(count = n()) %>% 
    ungroup() 

## Keep all that have no entry int a2 or the id > the count (i.e. used up a2 entries). 
left_join(a1_tmp, a2_tmp, by = c('A', 'B')) %>% 
    ungroup() %>% filter(is.na(count) | tmp_id > count) %>% 
    select(-tmp_id, -count) 

## # A tibble: 4 x 2 
##  A  B 
## <dbl> <chr> 
## 1  4  d 
## 2  5  e 
## 3  4  d 
## 4  2  b 

EDIT

这里是一个类似的解决方案,短一点。这将做到以下几点:(1)添加一个行号的列来加入data.frame两个项目(2)a2(第2个data.frame)中的一个临时列,该列将在连接中显示为空到a1(即表示它对于a1是唯一的) 。

library(dplyr) 

left_join(a1 %>% group_by(A,B) %>% mutate(rn = row_number())    %>% ungroup(), 
      a2 %>% group_by(A,B) %>% mutate(rn = row_number(), tmpcol = 0) %>% ungroup(), 
      by = c('A', 'B', 'rn')) %>% 
filter(is.na(tmpcol)) %>% 
select(-tmpcol, -rn) 

## # A tibble: 4 x 2 
##  A  B 
## <dbl> <chr> 
## 1  4  d 
## 2  5  e 
## 3  4  d 
## 4  2  b 

我觉得这个解决方案比第一个更简单一点(也许很少)。

+0

是的,Steveb;欣赏它。 – RBL

+0

棒极了!非常紧凑!欣赏它! – RBL

2

这个想法是,为每个文件添加一个重复计数器,以便您可以为每一行的出现获得唯一匹配。数据表很好,因为它很容易计数重复项(与.N),并且它还为设置操作提供了必要的功能(fsetdiff)。

library(data.table) 

a1 <- data.table(A = c(1:5, 2, 4, 2), B = letters[c(1:5, 2, 4, 2)]) 
a2 <- data.table(A = c(1:3,2), B = letters[c(1:3,2)]) 

# add counter for duplicates 
a1[, i := 1:.N, .(A,B)] 
a2[, i := 1:.N, .(A,B)] 

# setdiff gets the exception 
# "all = T" allows duplicate rows to be returned 
fsetdiff(a1, a2, all = T) 

# A B i 
# 1: 4 d 1 
# 2: 5 e 1 
# 3: 4 d 2 
# 4: 2 b 3 
+0

这也适用于!欣赏它。 – RBL

1

下面是与dplyr另一种解决方案:

library(dplyr) 
a1 %>% 
    arrange(A) %>% 
    group_by(A) %>% 
    filter(!(paste0(1:n(), A, B) %in% with(arrange(a2, A), paste0(1:n(), A, B)))) 

结果:

# A tibble: 4 x 2 
# Groups: A [3] 
     A  B 
    <dbl> <fctr> 
1  2  b 
2  4  d 
3  4  d 
4  5  e 

过滤这种方式避免了创造,你必须在后面的最终输出中删除多余的不需要的列。该方法也对输出进行排序。不知道这是你想要的。