2015-11-04 12 views
6

निम्नलिखित आर data.frame कन्वर्ट करने के लिए कोशिश कर रहा है:Dplyr सशर्त विंडोइंग

structure(list(Time=c("09:30:01" ,"09:30:29" ,"09:35:56", "09:37:17" ,"09:37:21" ,"09:37:28" ,"09:37:35" ,"09:37:51" ,"09:42:11" ,"10:00:31"), 
      Price=c(1,2,3,4,5,6,7,8,9,10), 
      Volume=c(100,200,300,100,200,300,100,200,600,100)), 
     .Names = c("Time", "Price", "Volume"), 
     row.names = c(NA,10L), 
     class = "data.frame") 

      Time Price Volume 
    1 09:30:01  1 100 
    2 09:30:29  2 200 
    3 09:35:56  3 300 
    4 09:37:17  4 100 
    5 09:37:21  5 200 
    6 09:37:28  6 300 
    7 09:37:35  7 100 
    8 09:37:51  8 200 
    9 09:42:11  9 600 
    10 10:00:31 10 100 
इस

 Time Price Volume Bin 
1 09:30:01  1  100 1 
2 09:30:29  2  200 1 
3 09:35:56  3  200 1 
4 09:35:56  3  100 2 
5 09:37:17  4  100 2 
6 09:37:21  5  200 2 
7 09:37:28  6  100 2 
8 09:37:28  6  200 3 
9 09:37:35  7  100 3 
10 09:37:51  8  200 3 
11 09:42:11  9  500 4 
12 09:42:11  9  100 5 
13 10:00:31 10  100 5 

अनिवार्य रूप में

, यह मात्रा पर संचयी रकम गणना कर रहा है और eachtime 500 binning का उल्लंघन कर रहा है। तो, बिन 1 100 + 200 + 200 है, वॉल्यूम के साथ 09:35:56 को 200/100 में विभाजित किया गया और एक नई पंक्ति डाली गई और बिन काउंटर बढ़ गया।

यह आधार आर के साथ अपेक्षाकृत सरल है लेकिन मैं सोच रहा था कि वहां एक और अधिक सुरुचिपूर्ण और उम्मीदवार तेजी से तेज तरीका है।

चीयर्स

अद्यतन:

धन्यवाद @Frank और @AntoniosK।

अपने प्रश्न को हल करने के लिए वॉल्यूम मानों की सीमा सभी सकारात्मक पूर्णांक मान 1 से 10k तक है।

मैं दोनों दृष्टिकोणों और dplyr microbenchmarked थोड़ा तेज था, लेकिन इसमें अधिक नहीं, ~ 200k पंक्तियों के साथ ऊपर के डेटासेट पर।

सच तेज प्रतिक्रिया और सहायता

+3

शायद आपको "अपेक्षाकृत सरल" तरीका दिखाना चाहिए जिसकी आपने कोशिश की है। मुझे लगता है कि एक सुरुचिपूर्ण डिपर दृष्टिकोण नहीं है, लेकिन आपके बेस आर टाइल में सुधार के लिए जगह हो सकती है। – Frank

+0

क्या आपके पास हमेशा 100,200 आदि जैसे मान हैं? या यह एक सरलीकृत मामला है? – AntoniosK

+0

http://stackoverflow.com/questions/15466880/cumulative-sum-until-maximum-reached-then-repeat-from-zero-in-the-next-row पर एक नज़र डालें –

उत्तर

4

सुनिश्चित नहीं हैं कि अगर यह सबसे अच्छा या सबसे तेज़ तरीका है, लेकिन उन Volume मूल्यों के लिए तेजी से लगता है की सराहना करते हैं। दर्शन सरल है। Volume मान के आधार पर आपने Time और Price के Volume = 1 के साथ कई पंक्तियां बनाई हैं। तो cumsum हर बार जब आप एक नया 500 बैच रखते हैं तो नंबर और ध्वज जोड़ें। अपने Bin मान बनाने के लिए उन झंडे का उपयोग करें।

structure(list(Time=c("09:30:01" ,"09:30:29" ,"09:35:56", "09:37:17" ,"09:37:21" ,"09:37:28" ,"09:37:35" ,"09:37:51" ,"09:42:11" ,"10:00:31"), 
       Price=c(1,2,3,4,5,6,7,8,9,10), 
       Volume=c(100,200,300,100,200,300,100,200,600,100)), 
      .Names = c("Time", "Price", "Volume"), 
      row.names = c(NA,10L), 
      class = "data.frame") -> dt 

library(dplyr) 

dt %>% 
    group_by(Time, Price) %>%      ## for each Time and Price 
    do(data.frame(Volume = rep(1,.$Volume))) %>% ## create as many rows, with Volume = 1, as the value of Volume 
    ungroup() %>%         ## forget about the grouping 
    mutate(CumSum = cumsum(Volume),    ## cumulative sums 
     flag_500 = ifelse(CumSum %in% seq(501,sum(dt$Volume),by=500),1,0), ## flag 500 batches (at 501, 1001, etc.) 
     Bin = cumsum(flag_500)+1) %>%   ## create Bin values 
    group_by(Bin, Time, Price) %>%    ## for each Bin, Time and Price 
    summarise(Volume = sum(Volume)) %>%   ## get new Volume values 
    select(Time, Price, Volume, Bin) %>%   ## use only if you want to re-arrange column order 
    ungroup()          ## use if you want to forget the grouping 

#  Time Price Volume Bin 
#  (chr) (dbl) (dbl) (dbl) 
# 1 09:30:01  1 100  1 
# 2 09:30:29  2 200  1 
# 3 09:35:56  3 200  1 
# 4 09:35:56  3 100  2 
# 5 09:37:17  4 100  2 
# 6 09:37:21  5 200  2 
# 7 09:37:28  6 100  2 
# 8 09:37:28  6 200  3 
# 9 09:37:35  7 100  3 
# 10 09:37:51  8 200  3 
# 11 09:42:11  9 500  4 
# 12 09:42:11  9 100  5 
# 13 10:00:31 10 100  5 
3

यह शायद ही कभी "सीधा" है।

library(data.table) 
setDT(DF) 
DF[, c("cV","cVL") := shift(cumsum(Volume), 0:1, type="lag", fill=0) ] 
DF[, end := (cV %/% 500) - (cV %% 500 == 0) ] 
DF[, start := shift(end, type = "lag", fill = -1) + (cVL %% 500 == 0) ] 

badcols = c("Volume","cV","cVL","start","end") 
DF[,{ 
    V = 
    if (start==end) Volume 
    else c((start+1)*500-cVL, rep(500, max(end-start-2,0)), cV - end*500) 

    c(.SD[, !badcols, with=FALSE], list(Volume = V, Bin = 1+start:end)) 
}, by=.(r=seq(nrow(DF)))][,!"r",with=FALSE] 

जो देता है

 Time Price Volume Bin 
1: 09:30:01  1 100 1 
2: 09:30:29  2 200 1 
3: 09:35:56  3 200 1 
4: 09:35:56  3 100 2 
5: 09:37:17  4 100 2 
6: 09:37:21  5 200 2 
7: 09:37:28  6 100 2 
8: 09:37:28  6 200 3 
9: 09:37:35  7 100 3 
10: 09:37:51  8 200 3 
11: 09:42:11  9 500 4 
12: 09:42:11  9 100 5 
13: 10:00:31 10 100 5 
3

यहाँ एक ही रास्ता data.table का उपयोग कर है और यह रोलिंग है मिलती है सुविधा::

require(data.table) # v1.9.6+ 
setDT(df)[, csum := cumsum(Volume)] 
ans = rbind(df, df[.(csum=500 * seq_len(max(csum)%/% 500L)), roll=-Inf, on="csum"]) 
setorder(ans, Price, csum) 
ans = ans[, `:=`(Volume = c(csum[1L], diff(csum)), 
       id  = (csum-1L) %/% 500L + 1L, 
       csum = NULL)][Volume > 0L] 

data.table के साथ, यह कोड की अभी भी कई लाइनों है

पहला कदम एक नया सह जोड़ता है Volume के संचयी योग के साथ शरद ऋतु।

दूसरा चरण शायद सबसे महत्वपूर्ण है। आइए दूसरे भाग को देखें। 500 के प्रत्येक एकाधिक के लिए max(csum) तक, यह पहले मान> = df$csum पर 500 के एकाधिक में शामिल हो जाता है। यह रोलिंग एनओसीबी (अगला अवलोकन पिछड़ा हुआ) में शामिल है। इसके साथ ही हम पाते हैं:

#  Time Price Volume csum 
# 1: 09:35:56  3 300 500 
# 2: 09:37:28  6 300 1000 
# 3: 09:37:51  8 200 1500 
# 4: 09:42:11  9 600 2000 

ये ब्रेक अंक अपने मूल data.table में जोड़े जाने की जरूरत है। हम rbind() के साथ यही करते हैं।

फिर, हम सभी को Price, csum द्वारा ऑर्डर करना है, Volume कॉलम वापस उत्पन्न करें। वहां से, दिखाए गए csum कॉलम का उपयोग करके id कॉलम उत्पन्न किया जा सकता है।