【问题标题】:Select rows such that multiple columns have no duplicated values选择行,使多列没有重复值
【发布时间】:2014-03-03 20:32:54
【问题描述】:

我有一个包含这些值的数据框(以这种方式构建):

id1 = (c(1,1,2,2))
id2 = (c(10,11,10,11))
value =c(50,50,50,50)
df = data.frame(id1,id2,value)

df : 
  value id1 id2
1    50   1  10
2    50   1  11
3    50   2  10
4    50   2  11

我想只保留 id1 和 id2 都是唯一的行(id1 和 id2 的每个值必须只出现一次),而且每个 id 可能有多个重复:

df_unique : 
value id1 id2
1    50   1  10
4    50   2  11

如果我在其中一列上使用重复的命令,然后在另一列上使用,我会丢弃想要的行。

返回 (1,11) 和 (2,10) 的解决方案也很好,只要其中的每个元素 id1 和 id2 是唯一的。

另一个有更多行的例子:

id1 = (c(1,1,1,2,2,2,3,3,3))
id2 = (c(10,11,12,10,11,12,10,11,12))
value =rep(50,9)
df = data.frame(id1,id2,value)

df:
  id1 id2 value
1   1  10    50
2   1  11    50
3   1  12    50
4   2  10    50
5   2  11    50
6   2  12    50
7   3  10    50
8   3  11    50
9   3  12    50

一个好的答案是:(1,10),(2,11),(3,12),但任何其他 id1 和 id2 都出现一次的答案都是好的。

谢谢,

雅各布

【问题讨论】:

  • 如何决定是否1,10; 2,11被保留或者可以是1,11; 2,10?
  • 在您的示例中,这两个值都出现了两次。我不明白你的问题。
  • 可能只是简单地做"unique(df)"。
  • Ananta - 我编辑的问题 (1,11) (2,10) 也很好。 Davide- unique(df) 将返回相同的矩阵,因为每一行都是唯一的
  • 类似:x <- lapply(df[, -1], duplicated); df[!xor(x$id1, x$id2), ]

标签: r dataframe unique duplicate-removal


【解决方案1】:

如果您知道数据的排列方式如您的示例所示,循环遍历 id2 的每个值 id1 并以相同的顺序,解决方案很简单:

N <- 3 # Number of rows in the result
idx <- seq(1, N*N, by=N) + seq(0,to=N-1)
df[idx,]
##   id1 id2 value
## 1   1  10    50
## 5   2  11    50
## 9   3  12    50

我怀疑这就是你要问的。如果行的顺序未知,或者另一列中的每个值并非所有值都出现在另一列中,则必须检查 N 行的每个组合。

# Maximum number of result rows
N <- with(df, min(length(unique(id1)), length(unique(id2))))
N
## [1] 3

# Potential indices
index <- combn(seq(nrow(df)), N)

index 是一个矩阵,其中每列代表df 中的三行。现在检查重复值:

good <- apply(index, 2, function(x) !any(duplicated(df[x,'id1']) | duplicated(df[x,'id2'])))

good 的值 TRUE 表示通过测试的行组合。

which(good)
## [1] 22 24 39 44 53 56
index[, good]
##      [,1] [,2] [,3] [,4] [,5] [,6]
## [1,]    1    1    2    2    3    3
## [2,]    5    6    4    6    4    5
## [3,]    9    8    9    7    8    7

上述矩阵的每一列代表通过测试的行组合。

这会找到所有的组合。您可能只想找到第一个组合,这样您就不会在找到匹配项后继续测试其他组合。那么for就合适了:

for (i in seq(ncol(index))) {
  x <- index[,i]
  if (!any(duplicated(df[x,'id1']) | duplicated(df[x,'id2']))) {
    rows <- x
    break
  }
}

df[rows,]
##   id1 id2 value
## 1   1  10    50
## 5   2  11    50
## 9   3  12    50

注意:根据数据,使用N=3,您可能不会得到通过测试的行。在这种情况下,使用N=2 重复该过程,依此类推。我将这个循环留给读者作为练习。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-06
    • 1970-01-01
    • 2021-05-18
    • 2015-03-04
    相关资源
    最近更新 更多