删除r中另一个data.frame中的data.frame行的确切行和频率

时间:2017-10-10 01:35:18

标签: r dataframe merge

考虑以下两个data.frames:

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)])

我想删除a1a2的确切行,以便结果应为:

A  B
4  d
5  e
4  d
2  b

请注意,a1中包含2 b的一行将保留在最终结果中。目前,我使用循环语句,由于我的data.frames中有许多变量和数千行,因此变得非常慢。是否有任何内置函数可以获得此结果?

4 个答案:

答案 0 :(得分:3)

这个想法是,为每个文件添加一个重复计数器,这样你就可以获得每一行的唯一匹配。数据表很好,因为很容易计算重复项(使用.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

答案 1 :(得分:2)

您可以使用vendor.fa8737033d56bf5e7c33.bundle.js:17 ERROR TypeError: Cannot read property 'city' of undefined at Object.eval [as updateDirectives] (e.ngfactory.js:163) at Object.updateDirectives (vendor.fa8737033d56bf5e7c33.bundle.js:136) at ur (vendor.fa8737033d56bf5e7c33.bundle.js:136) at wr (vendor.fa8737033d56bf5e7c33.bundle.js:136) at br (vendor.fa8737033d56bf5e7c33.bundle.js:136) at ur (vendor.fa8737033d56bf5e7c33.bundle.js:136) at wr (vendor.fa8737033d56bf5e7c33.bundle.js:136) at br (vendor.fa8737033d56bf5e7c33.bundle.js:136) at ur (vendor.fa8737033d56bf5e7c33.bundle.js:136) at wr (vendor.fa8737033d56bf5e7c33.bundle.js:136) 执行此操作。我设置dplyr以消除有关因素不匹配的警告。

stringsAsFactors = FALSE

修改

这是一个类似的解决方案,有点短。这将执行以下操作:(1)为行号添加一列以加入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 个项目(2)data.frame(第二个a2)中的临时列,该列将显示为null加入data.frame(即表示它对a1是唯一的。)

a1

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

答案 2 :(得分: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

答案 3 :(得分: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

这种过滤方式可以避免创建额外的不需要的列,以后必须在最终输出中删除这些列。此方法还对输出进行排序。不确定它是不是你想要的。