2016-11-17 7 views
5

मेरे पास फ्लोट्स का वेक्टर है। मैं बार-बार विभिन्न श्रेणियों के भीतर उस वेक्टर के सबसेट ढूंढना चाहता हूं। मेरा वर्तमान वाक्यविन्यास (DT[x > 1.8 & x < 2.9]) वेक्टर स्कैन प्रतीत होता है (यह अपेक्षाकृत धीमी है)।क्या डेटाटेबल बाइनरी खोज के आधार पर तेज़ रेंज सबसेटिंग लागू करता है? वह वाक्यविन्यास क्या है?

क्या डेटा टेम्पलेट की श्रेणी/अंतराल आधारित उप-सेटिंग के लिए बाइनरी खोज का उपयोग करने वाला एक तेज वाक्यविन्यास है?

उदाहरण:

set.seed(123L) 
x = runif(1E6) 
DT = data.table(x, key = "x") 

# For foverlaps() 
DT[,xtemp:=x] 
range = data.table(start = 0.04, end = 0.5, key=c("start", "end")) 


microbenchmark::microbenchmark(
    DT[x < 0.5 & x > 0.04], 
    x[x < 0.5 & x > 0.04], 
    foverlaps(DT, range, by.x = c("x", "xtemp")) 
    ) 

Unit: milliseconds 
             expr  min  lq  mean median  uq  max neval 
         DT[x < 0.5 & x > 0.04] 12.65391 16.10852 18.43412 17.23268 17.76868 104.1112 100 
         x[x < 0.5 & x > 0.04] 16.48126 19.63882 21.65813 20.31534 20.95264 113.7965 100 
foverlaps(DT, range, by.x = c("x", "xtemp")) 116.72732 131.93093 145.56821 140.09218 146.33287 226.6069 100 
+0

कोई खोज कर चुके हैं? http://stackoverflow.com/search?q=data.table+ranges मुझे पता है कि अरुंकुमार ने डेटाटेबल में व्यापक कार्य निर्माण श्रेणी-उन्मुख कार्यों को किया है और वह SO में नियमित योगदानकर्ता है। –

+0

हां, सबसे प्रासंगिक पोस्ट 2 साल पहले से था: http://stackoverflow.com/questions/22320284/subsetting-a-data-table-by-range-making-use-of-binary- खोज और अभी तक पेश किया गया है समाधान लागू किया जाना चाहिए। मैं उम्मीद कर रहा था कि एक लागू किया गया था और मैं इसे खोजने में असमर्थ था। – nate

+0

हालांकि, मैं देख रहा हूं। अर्नकुमार टिप कुंजी थी - मुझे लगता है कि मुझे कुछ मिला। – nate

उत्तर

3

एक:

vs <- function() x[x <= 0.5 & x > 0.04] 

दो तरीकों से परिणाम एक ही हैं डेटाटेबल के हाल के संस्करण ने %between% और %inrange% ऑपरेटर जो इस व्यवहार को समाहित करते हैं, को जोड़ा। ऐसा लगता है कि साइडोम के रोल-आधारित समाधान में मामूली धीमी गति से प्रतीत होता है लेकिन उम्मीद के अनुसार सभी प्रकार (संख्यात्मक/पूर्णांक) को संभालता है और यह अधिक संक्षिप्त होता है। निचे देखो।

# data.table version 1.10.4 
# R version 3.3.1 (2016-06-21) 

set.seed(123L) 
library(data.table) 
x = runif(1E6) 
DT = data.table(x) 

#Psidom Answer 
psidom <- function() DT[{ind <- DT[.(c(0.04, 0.5)), which=TRUE, roll=TRUE, on=.(x)]; (ind[1]+1):ind[2]}] 

# Unkeyed 
microbenchmark::microbenchmark(
    DT[x <= 0.5 & x >= 0.04], 
    x[x <= 0.5 & x >= 0.04], 
    DT[x %between% c(0.04, 0.5)], 
    DT[x %inrange% c(0.04, 0.5)], 
    DT[.(0.04, 0.5), on = .(x >= V1, x <= V2), .(x.x)] 
) 

# Unit: milliseconds 
#            expr  min   lq  mean median  uq  max neval cld 
#       DT[x <= 0.5 & x >= 0.04] 20.346712 23.983928 34.69493 25.21085 26.73657 281.4747 100 b 
#        x[x <= 0.5 & x >= 0.04] 19.581049 22.935144 31.61551 23.83557 25.99587 145.3632 100 b 
#      DT[x %between% c(0.04, 0.5)] 8.024091 9.293261 12.19035 11.38171 12.75843 116.5132 100 a 
#      DT[x %inrange% c(0.04, 0.5)] 77.108485 79.871207 91.05544 81.83722 84.66684 188.8674 100 c 
# DT[.(0.04, 0.5), on = .(x >= V1, x <= V2), .(x.x)] 189.488658 195.487681 217.55708 198.52696 205.80428 318.1696 100 d 

# Keyed 
setkey(DT,x) 

#Psidom Answer 
psidom <- function() DT[{ind <- DT[.(c(0.04, 0.5)), which=TRUE, roll=TRUE, on=.(x)]; (ind[1]+1):ind[2]}] 

microbenchmark::microbenchmark(
    DT[x <= 0.5 & x >= 0.04], 
    x[x <= 0.5 & x >= 0.04], 
    DT[x %between% c(0.04, 0.5)], 
    DT[x %inrange% c(0.04, 0.5)], 
    DT[.(0.04, 0.5), on = .(x >= V1, x <= V2), .(x.x)], 
    psidom() 
) 

# Unit: milliseconds 
#            expr  min  lq  mean median  uq  max neval cld 
#       DT[x <= 0.5 & x >= 0.04] 14.550788 18.092458 21.012992 18.934781 20.055428 123.1174 100 b 
#        x[x <= 0.5 & x >= 0.04] 19.403718 22.401709 27.296872 23.707688 24.608270 128.9123 100 b 
#      DT[x %between% c(0.04, 0.5)] 5.439340 6.819262 10.789330 9.490118 10.561789 111.6523 100 a 
#      DT[x %inrange% c(0.04, 0.5)] 12.871260 13.894918 21.434823 16.888748 18.128147 123.4275 100 b 
# DT[.(0.04, 0.5), on = .(x >= V1, x <= V2), .(x.x)] 49.277678 53.516350 61.422212 54.499675 55.869354 158.1861 100 c 
#           psidom() 4.615421 5.095880 9.482131 5.325707 8.316817 109.9318 100 a 
+0

कृपया, सीमाओं की दोबारा जांच करें। कुछ मामलों में यह 'x < 0.5 & x > 0.04' है, लेकिन' x%% c (0.05, 0.5) '(नोट 0.04 बनाम 0.05) के बीच भी है। इसके अतिरिक्त, '% के बीच'% और '%%% का उपयोग डिफ़ॉल्ट रूप से बंद अंतराल का उपयोग करें। समान परिणामों के लिए, कृपया '(x, 0.04, 0.5, incbounds = FALSE) के बीच 'का उपयोग करें। – Uwe

+0

वैसे भी, अच्छा बेंचमार्क। शायद, आप तुलना के लिए * गैर-इक्विटी * संस्करण 'डीटी [। (0.04, 0.5), =। (X> V1, x Uwe

+0

देखें। Psidom का समाधान * एक क्रमबद्ध डेटा.table पर काम करने के लिए * की आवश्यकता है। अन्यथा, हमें गलत परिणाम मिलते हैं। तो, गैर-कुंजी वाले डेटा.table पर psidom के लिए बीएम परिणाम हटा दिए जाने चाहिए। – Uwe

7

पर the answer here आधार पर, इस सुधार के कुछ प्रकार हो रहा है। 0.5 के बराबर मान इस परिदृश्य हालांकि में शामिल किया जाएगा:

bs <- function() DT[{ind <- DT[.(c(0.04, 0.5)), which=TRUE, roll=TRUE]; (ind[1]+1):ind[2]}] 
vs <- function() x[x < 0.5 & x > 0.04] 

x = runif(1E6) 
DT = data.table(x, key = "x") 

microbenchmark::microbenchmark(
    bs(), 
    vs() 
) 

#Unit: milliseconds 
# expr  min  lq  mean median  uq  max neval 
# bs() 3.594993 4.150932 5.002947 4.44695 4.952283 9.750284 100 
# vs() 15.054460 16.217198 18.999877 17.45298 19.554958 113.623699 100 

हम vs() संशोधित करते हैं होने के लिए:

identical(bs()$x, sort(vs())) 
# [1] TRUE 
+0

अभी भी यह पता लगाना कि यह कैसे काम करता है। (और एक मूल समाधान प्रकट होने की उम्मीद है।) धन्यवाद! यदि कुछ तेज़ी से नहीं बढ़ता है तो मैं आपका जवाब स्वीकार करूंगा। – nate

+4

विशेष रूप से, खिलौना डेटा पर यह समाधान यह समाधान 4x गति था। मेरे वास्तविक डेटा (4E6 पंक्तियों) पर यह 50x गति था। – nate

संबंधित मुद्दे