无论位置如何,都能找到独特的组合

时间:2015-04-23 09:55:25

标签: r duplicates combinations

我确定它很简单,但我有一个数据框

package.json

我想要一个新的数据框,其中包含行中值的唯一组合,无论它们属于哪个列。所以在上面的情况下我想要

{
  "name": "QAWebApp3",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "^1.12.3",
    "cookie-parser": "^1.3.4",
    "debug": "^2.1.3",
    "express": "^4.12.3",
    "jade": "^1.9.2",
    "jquery": "^2.1.3",
    "jquery-ui": "^1.10.5",
    "morgan": "^1.5.2",
    "serve-favicon": "^2.2.0"
  }
}

我已经尝试了

      df <- data.frame(a = c(1, 2, 3),
                       b = c(2, 3, 1),
                       c = c(3, 1, 4))

但它看到(1,2,3)与(2,3,1)中的唯一,我不想要。

3 个答案:

答案 0 :(得分:6)

如果您的data.frame非常大,速度可能适合您。您可以通过以下想法更快地找到重复集。

让我们假设为行中的每个可能值分配素数并计算每行的产品。例如,对于给定的df,我们可以接受primenums = c(2,3,5,7)并计算产品c(30,30,70)。然后,此products-vector中的重复项对应于data.frame中的重复集。由于乘法计算速度比任何类型的排序快得多,因此可以提高效率。 代码如下。

require("numbers")
primenums <- Primes(100)[1:4]
dfmult <- apply(as.matrix(df), 1, function(z) prod(primenums[z]) )
my_indx <- !duplicated(dfmult)
df[my_indx,]

此处我们在包primenums的函数Primes的帮助下初始化了向量numbers,但您可以通过其他方式手动执行。

看看这个例子。在这里,我展示了效率的比较。

require("numbers")

# generate all unique combinations 10 out of 20
allcomb <- t(combn(20,10))
# make sample of 1 million rows
set.seed(789)
df <- allcomb[sample(nrow(allcomb), 1e6, T),]
# lets sort matrix to show we have duplicates
df <- df[do.call(order, lapply(1:ncol(df), function(i) df[, i])), ]
head(df, 10)
#       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
#  [1,]    1    2    3    4    5    6    7    8    9    10
#  [2,]    1    2    3    4    5    6    7    8    9    10
#  [3,]    1    2    3    4    5    6    7    8    9    10
#  [4,]    1    2    3    4    5    6    7    8    9    10
#  [5,]    1    2    3    4    5    6    7    8    9    11
#  [6,]    1    2    3    4    5    6    7    8    9    11
#  [7,]    1    2    3    4    5    6    7    8    9    11
#  [8,]    1    2    3    4    5    6    7    8    9    11
#  [9,]    1    2    3    4    5    6    7    8    9    11
# [10,]    1    2    3    4    5    6    7    8    9    11

# to be fair need to permutate numbers in rows before searching for identical sets
df <- t(apply(df, 1, function(z) z[sample(10,10)] ))
df <- as.data.frame(df)
names(df) <- letters[1:10]
# how does it look like now?
head(df, 10)
#     a b c  d  e  f  g h  i j
# 1   2 3 7  9 10  1  4 8  5 6
# 2   4 2 6  3  8 10  9 1  5 7
# 3   4 2 6  8  5  1 10 7  3 9
# 4   6 8 5  4  2  1 10 9  7 3
# 5  11 2 7  6  8  1  9 4  5 3
# 6   9 6 3 11  4  2  8 7  5 1
# 7   5 2 3 11  1  8  6 9  7 4
# 8   3 9 7  1  2  5  4 8 11 6
# 9   6 2 8  3  4  1 11 5  9 7
# 10  4 6 3  9  7  2  1 5 11 8

# now lets shuffle rows to make df more plausible
df <- df[sample(nrow(df), nrow(df)),]

现在,当data.frame准备就绪时,我们可以测试不同的算法。

system.time(indx <- !duplicated(t(apply(df, 1, sort))) )
#   user  system elapsed 
# 119.75    0.06  120.03
# doesn't impress, frankly speaking

library(sets)
system.time(indx <- !duplicated(apply(df, 1, as.set)) )
#  user  system elapsed 
# 91.60    0.00   91.89
# better, but we want faster! =)

# now lets check out the method with prime numbers
primenums <- Primes(100)[1:20]
# [1]  2  3  5  7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71
system.time({
  dfmult <- apply(as.matrix(df), 1, function(z) prod(primenums[z]) )
  my_indx <- !duplicated(dfmult) })
# user  system elapsed 
# 6.44    0.16    6.61
# not bad, isn't it? but lets compare results
identical(indx, my_indx)
# [1] TRUE

# So, if there is no difference, why wait more? ;)

这里有一个重要的假设 - 我们使用as.matrix(df),但如果data.frame中不仅有数字变量,该怎么办?一个更加统一的解决方案如下:

system.time({
  dfmult <- apply(
    apply(df, 2, function(colmn) as.integer(factor(colmn, 
                                                   levels = unique(c(as.matrix(df)))))),
    1, function(z) prod(primenums[z]) )
  my_indx <- !duplicated(dfmult) })
#  user  system elapsed 
# 27.48    0.34   27.84
# is distinctly slower but still much faster then previous methods

如果我们有很多列或非常不同的变量呢?在这种情况下,我们可以使用prod()代替sum(log())(对于大数字,这可能会更快地计算)。看看这个。

pr <- Primes(5e7)
length(pr)   
# [1] 3001134
system.time(N <- sum(log(pr)))
# user  system elapsed 
# 0.12    0.00    0.13
N
# [1] 49993718

很难想象df有3百万列,但这里还可以。通过这种方式,我们可以携带任意数量巨大的df,并且可以容纳我们的RAM。

答案 1 :(得分:5)

也许是那样的

indx <- !duplicated(t(apply(df, 1, sort))) # finds non - duplicates in sorted rows
df[indx, ] # selects only the non - duplicates according to that index
#   a b c
# 1 1 2 3
# 3 3 1 4

答案 2 :(得分:1)

作为替代方法,包sets提供了检查集合相等性的快速方法:

library(sets)
df.sets <- apply(df, 1, as.set)
#[[1]]
#{1, 2, 3}
#[[2]]
#{1, 2, 3}
#[[3]]
#{1, 3, 4}
df[!duplicated(df.sets),]
#  a b c
#1 1 2 3
#3 3 1 4