2017-08-07 18 views
10

पर समूह वेक्टर n से कम या उसके बराबर तत्वों के योग के आधार पर वेक्टर को समूहबद्ध करना चाहते हैं। निम्नलिखित मान लें,सशर्त राशि

set.seed(1) 
x <- sample(10, 20, replace = TRUE) 
#[1] 3 4 6 10 3 9 10 7 7 1 3 2 7 4 8 5 8 10 4 8 

#Where, 
n = 15 

उम्मीद उत्पादन समूह मूल्यों के लिए किया जाएगा, जबकि उनके योग < = 15 है, यानी

y <- c(1, 1, 1, 2, 2, 3, 4, 5 ,5, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10) 

आप देख सकते हैं योग 15 से कभी नहीं अधिक है,

sapply(split(x, y), sum) 
# 1 2 3 4 5 6 7 8 9 10 
#13 13 9 10 15 12 12 13 14 8 

नोट: मैं इसे विशाल डेटासेट (आमतौर पर> 150 - 200 जीबी) पर चला रहा हूं इसलिए दक्षता जरूरी है।

एक विधि है कि मैं कोशिश की और करीब आता है लेकिन विफल रहता है है,

as.integer(cut(cumsum(x), breaks = seq(0, max(cumsum(x)) + 15, 15))) 
#[1] 1 1 1 2 2 3 3 4 4 4 5 5 5 6 6 6 7 8 8 8 
+4

क्या आपने [यहां] (https://stackoverflow.com/questions/34531568/conditional-cumsum-with-reset) और आरसीपीपी कार्यान्वयन [यहां] (https://stackoverflow.com/questions/29054459) की जांच की है/कैसे-टू-स्पीड-अप-या-वेक्टरिज-ए-फॉर-लूप/2 9 055443 # 2 9 055443) – akrun

+3

@akrun लिंक के लिए धन्यवाद। मैं उन्हें एक एएसएपी – Sotos

+1

हां दूंगा, यह एक डुप्लिकेट है, @क्रुन, यहां आपके पास एक समाधान था जिसे सामान्यीकृत भी किया जा सकता है: https://stackoverflow.com/questions/44512075/resetting-cumsum-if-value-goes-to- नकारात्मक-इन-आर –

उत्तर

4

यहाँ मेरी Rcpp -solution (Khashaa's के पास समाधान लेकिन थोड़ा कम/नीचे छीन) है, क्योंकि आप ने कहा कि गति महत्वपूर्ण था, Rcpp शायद जाने का रास्ता है:

:

# create the data 
set.seed(1) 
x <- sample(10, 20, replace = TRUE) 
y <- c(1, 1, 1, 2, 2, 3, 4, 5 ,5, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10) 

# create the Rcpp function 
library(Rcpp) 
cppFunction(' 
IntegerVector sotosGroup(NumericVector x, int cutoff) { 
IntegerVector groupVec (x.size()); 
int group = 1; 
double runSum = 0; 
for (int i = 0; i < x.size(); i++) { 
    runSum += x[i]; 
    if (runSum > cutoff) { 
    group++; 
    runSum = x[i]; 
    } 
    groupVec[i] = group; 
} 
return groupVec; 
} 
') 

# use the function as usual 
y_cpp <- sotosGroup(x, 15) 
sapply(split(x, y_cpp), sum) 
#> 1 2 3 4 5 6 7 8 9 10 
#> 13 13 9 10 15 12 12 13 14 8 


all.equal(y, y_cpp) 
#> [1] TRUE 

मामले में किसी को भी गति द्वारा आश्वस्त होने की जरूरत है

# Speed Benchmarks 
library(data.table) 
library(microbenchmark) 
dt <- data.table(x) 

frank <- function(DT, n = 15) { 
DT[, xc := cumsum(x)] 
b = DT[.(shift(xc, fill=0) + n + 1), on=.(xc), roll=-Inf, which=TRUE] 
z = 1; res = z 
while (!is.na(z)) 
    res <- c(res, z <- b[z]) 
DT[, g := cumsum(.I %in% res)][] 
} 

microbenchmark(
frank(dt), 
sotosGroup(x, 15), 
times = 100 
) 
#> Unit: microseconds 
#>    expr  min  lq  mean median  uq  max neval cld 
#>   frank(dt) 1720.589 1831.320 2148.83096 1878.0725 1981.576 13728.830 100 b 
#> sotosGroup(x, 15) 2.595 3.962 6.47038 7.5035 8.290 11.579 100 a 
+0

बहुत बहुत धन्यवाद डेविड। यह डेटा.table से वास्तव में बहुत तेज है – Sotos

3

यह काम करता है, लेकिन शायद सुधार किया जा सकता:

x <- c(3L, 4L, 6L, 10L, 3L, 9L, 10L, 7L, 7L, 1L, 3L, 2L, 7L, 4L, 8L, 5L, 8L, 10L, 4L, 8L) 
y <- as.integer(c(1, 1, 1, 2, 2, 3, 4, 5 ,5, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10)) 
n = 15 
library(data.table) 
DT = data.table(x,y) 
DT[, xc := cumsum(x)] 
b = DT[.(shift(xc, fill=0) + n + 1), on=.(xc), roll=-Inf, which=TRUE] 
z = 1; res = logical(length(x)) 
while (!is.na(z) && z <= length(x)){ 
    res[z] <- TRUE 
    z <- b[z] 
} 
DT[, g := cumsum(res)] 
    x y xc g 
1: 3 1 3 1 
2: 4 1 7 1 
3: 6 1 13 1 
4: 10 2 23 2 
5: 3 2 26 2 
6: 9 3 35 3 
7: 10 4 45 4 
8: 7 5 52 5 
9: 7 5 59 5 
10: 1 5 60 5 
11: 3 6 63 6 
12: 2 6 65 6 
13: 7 6 72 6 
14: 4 7 76 7 
15: 8 7 84 7 
16: 5 8 89 8 
17: 8 8 97 8 
18: 10 9 107 9 
19: 4 9 111 9 
20: 8 10 119 10 

DT[, all(y == g)] # TRUE 

यह कैसे काम करता

रोलिंग पूछें "अगर यह एक समूह की शुरुआत है, तो अगला अगला कहां से शुरू होगा?" फिर आप सभी समूहों को खोजने के लिए, पहली स्थिति से शुरू होने के परिणामस्वरूप फिर से शुरू कर सकते हैं।

अंतिम पंक्ति DT[, g := cumsum(res)] भी शामिल होने के एक रोलिंग के रूप में किया जा सकता है (हो सकता है तेजी से?):

DT[, g := data.table(r = which(res))[, g := .I][.(.I), on=.(r), roll=TRUE, x.g ]] 
+0

मेरे थोड़ा संपादित फ़ंक्शन के साथ बेंचमार्क, बेशक अभी भी डेविड की तेज़ी से खोज रहा है: https://chat.stackoverflow.com/transcript/message/38542501#38542501 – Frank

+0

धन्यवाद फ्रैंक। मैं समझने की कोशिश कर रहा हूं कि वहां क्या हो रहा है और मैं 'तार्किक (लंबाई (एक्स)) पर अटक गया हूं। लंबाई को तार्किक रूप में कैसे परिवर्तित किया जाता है? – Sotos

+1

@ सोटोस एनपी। यह 'प्रतिनिधि (गलत, लंबाई (एक्स))' जैसा ही है; वेक्टरों के लिए उन कार्यों का एक सेट है http://franknarf1.github.io/r-tutorial/_book/basics.html#initializing – Frank

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