İki işlevin verimliliğini Check if list contains another list in R numaralı yanıtla karşılaştırırken ilginç bir sonuçla karşılaştım. Sıralama, vektör büyük olduğunda duplicated
'un verimliliğini büyük ölçüde artırır. Bu, kendi çalışmamda duplicated
'u kullanarak önemli bir fark görmediğim için bir sürpriz oldu. Gerçekten de, her gün çalıştığım boyutlar için bir fark yok. Gözlemleyin: Vektör sıralanır zamanR çiftleri neden sıralanmış veriler üzerinde daha iyi performans gösteriyor?
set.seed(1007)
s1 <- sample(10^2, 10^3, replace = TRUE)
s1_sort <- sort(s1)
library(microbenchmark)
microbenchmark(dp=duplicated(s1), dp_sort=duplicated(s1_sort), times=1000)
Unit: microseconds
expr min lq mean median uq max neval cld
dp 16.459 16.9425 22.06371 17.2965 22.5050 1541.137 1000 a
dp_sort 17.007 17.5005 25.54953 17.8200 23.3655 1549.198 1000 a
Gördüğünüz gibi, zamanlamaları hiçbir fark edilebilir bir fark yoktur. Bununla birlikte, çok büyük vektörlerde, sonuçlar çok farklıdır. Aşağıdakileri gözlemleyin:
s2 <- sample(10^6, 10^7, replace = TRUE)
s2_sort <- sort(s2)
microbenchmark(dp=duplicated(s2), dp_sort=duplicated(s2_sort), times=100)
Unit: milliseconds
expr min lq mean median uq max neval cld
dp 816.6883 847.9231 869.6829 861.8210 882.3978 1019.6339 100 b
dp_sort 287.6779 305.4779 322.8830 315.1198 324.9249 449.1734 100 a
Neredeyse 3 kat daha hızlı !!! Bu beni burada başlayan tavşan deliğine götürdü: r-source.../duplicated.R. Buradan, çoğaltmanın .Internal(duplicated(x,...))
numaralı telefonu aradığını görüyoruz. Daha sonra pryr::show_c_source(.Internal(duplicated(x)))
ve workaround @ 0 (show_c_source
'un şu anda sorunlu olduğunu bildiren workaround) işlevini kullanarak duplicated
'un do_duplicated numaralı telefonu aradığını görüyoruz. Son olarak, duplicated
'un heart'u ortaya çıkar (667 satırından başlar ve 988'de sona erer). Tüm vektör üzerine geçirilir ve sonra bazı karma meydana geldiği göstermektedir: ben tam tüm kodu anlamıyorum
724 /* count unique entries */
725 k = 0;
726 for (i = 0; i < n; i++)
727 if (LOGICAL(dup)[i] == 0)
728 k++;
776 /* Build a hash table, ignoring information on duplication */
777 static void DoHashing(SEXP table, HashData *d)
ama önemli olmamalı sıralama gibi görünüyor. Her iki durumda da vektöre göre (sıralanmış ve karşılaştırılmamış) dönüyoruz ve sonuçta bir vektörün sıralanıp sıralanmadığına bağlı olmayan hash fonksiyonlarının bir çeşidini çağırıyoruz. İlk düşüncem, bir tür dal tahmininin devam ettiğini (bkz. this question), fakat güncellemeden this answer'a, bu şeylerin artık önemli olmaması gerektiği görünüyordu.
Neler oluyor?
DÜZENLEME
boşluk vektörün büyüklüğü ve çiftleri sayısı arttıkça her iki şekilde arttırabilmektedir.
set.seed(496)
s3 <- sample(10^6, 10^8, replace = TRUE)
s3_sort <- sort(s3)
microbenchmark(dp=duplicated(s3), dp_sort=duplicated(s3_sort), times = 10)
Unit: seconds
expr min lq mean median uq max neval cld
dp 12.149932 12.175665 12.848843 12.495599 12.719861 15.589190 10 b
dp_sort 2.395636 2.401837 2.706674 2.551375 2.677556 4.373653 10 a
@alexis_laz hiçbir çoğaltmaları olup olmadığını, sıralama etkisi büyük ölçüde azalır, belirttiği üzere.
s4 <- sample(10^8)
s4_sort <- sort(s4)
microbenchmark(dp=duplicated(s4), dp_sort=duplicated(s4_sort), times = 10)
Unit: seconds
expr min lq mean median uq max neval cld
dp 8.013995 8.130565 8.593626 8.197501 8.438703 10.639452 10 b
dp_sort 6.135788 6.158140 6.751101 6.256739 7.241381 8.913507 10 a
Sana hattı 717, 'dup = Yinelenen (x, fL, nazm) önemini kaçırdığınızı düşünüyorum;' adresini [lütfen "Çoğaltılmış kalbinde"] (içinde https://github.com/ wch/r-kaynak/damla/6e7a2ed989027f3800d2e2d64e60e6d700034c6b/src/unique.c/ana # L667). Bu, her bir öğenin yinelenen durumunu gerçekten belirleyen çağrı gibi görünüyor. "Benzersiz girdileri say" sadece "Çoğaltılmış" çağrısının "dup" sonuçlarının eklenmesidir. – Gregor
Ayrıca, "bir karma tablosu oluştur", "DoHashing" in tanımıdır - mutlaka "ne olacak" değil, sadece bir işlevin tanımıdır. Kıvırcık parantezlerinizi sayarsanız, bunun “do_duplicated” nin bir parçası olmadığını görürsünüz. – Gregor
Ne kadar ilgili olduğundan emin değilsiniz, ama karma tablosuna dahili olarak erişme yolunun bir parçası olabilir mi? R'nin iç indeksini hash tablosuna girerken geri döndürmek için bir kod kopyalamak/filtrelemek için denedim (bir şey özlemediğimden emin değilim) - Rihash = inline :: cfunction (sig = c (x = "integer"), body = 'int K = 1; size_t n = 2U * (size_t) LENGTH (x), M = 2 iken (M> (32 - K); (ans); ') '. (devamı ..) –