Wenn Ihr data.frame ziemlich groß ist, die Geschwindigkeit kann eine Frage für Sie sein. Sie können doppelte Sätze viel schneller mit der folgenden Idee finden.
Lassen Sie uns imaginären jeden möglichen Wert in Zeilen eine Primzahl zuweisen und Produkte für jede Zeile zählen. Zum Beispiel können wir für df
primenums = c(2,3,5,7)
akzeptieren und Produkte c(30,30,70)
zählen. Dann entsprechen die Duplikate in diesem Produktvektor doppelten Datensätzen in unserem Datenrahmen. Da die Multiplikation viel schneller als jede Art von Sortierung berechnet wird, können Sie effizienter werden. Der Code folgt.
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,]
Hier initialisieren wir Vektor primenums
mit Hilfe der Funktion Primes
von Paket numbers
, aber Sie können in anderer Weise manuell tun.
Schauen Sie sich das Beispiel an. Hier zeige ich einen Vergleich der Effizienz.
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)),]
Jetzt, wenn data.frame fertig ist, können wir verschiedene Algorithmen testen.
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? ;)
Es gibt eine wichtige Voraussetzung hier - wir verwenden as.matrix(df)
, aber was, wenn es nicht nur numerische Variablen in unserem data.frame
? Eine unificated Lösung wird wie folgt sein:
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
Und was ist, wenn wir sehr viel Spalten oder sehr unterschiedliche Variablen? In diesem Fall können wir anstelle von prod()
sum(log())
verwenden (was wahrscheinlich noch schneller für große Zahlen berechnet wird). Schau dir das an.
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
Es ist schwer df
mit 3 Millionen Spalten vorstellen, aber hier ist es in Ordnung. Auf diese Weise können wir df
jeder unglaublich großen Größe mit so vielen Spalten tragen, wie unser RAM aufnehmen kann.
Das ist ein netter, aber nicht sicher, ob Sie ein bisschen schummeln, indem Sie 'as.matrix (df)' hier tun. –
+ 1 Sehr schnell und ich mag die Idee, Primfaktorzerlegung zu verwenden, aber es gibt zwei Einschränkungen bei dieser Methode: 1) Wenn es eine große Anzahl von Spalten gibt, wird das Produkt von Primzahlen nicht funktionieren (zB 'prod (Primes (200)) 'eques' prod (Primes (201)) ') und 2) Es wird nicht funktionieren, wenn der Datenrahmen eine große Anzahl von verschiedenen Elementen enthält (weil Sie für jeden einen Primzahl generieren müssen, was mühsam sein kann und auch weil das Produkt nicht vom Computer unterscheidbar sein wird wie im vorherigen Punkt) – konvas
Um ruhig zu bleiben und nicht Betrüger anstelle von 'as.matrix' zu bleiben, können wir' apply (df, 2, function (colmn) as.integer (Faktor (colmn, levels = unique (c (as.matrix (df)))))). Es wird langsamer, aber nicht sehr viel, ich werde Zeit geben und die Antwort morgen aktualisieren, denn jetzt bin ich weg vom PC. Und ich stimme zu, die Verwendung von Primzahlen hat Einschränkungen, aber vielleicht können Sie verschiedene Pakete ausprobieren, die es erlauben, mit sehr großen Zahlen zu arbeiten? – inscaven