2017-02-19 31 views
2

例如我有以下代碼:斷裂cumsum()函數

cumsum(1:100) 

並且我想要打破它,如果一個元素i + 1會比3000更大。我怎樣才能做到這一點?

因此,不是這樣的結果:

[1] 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 210 231 253 276 300 
[25] 325 351 378 406 435 465 496 528 561 595 630 666 703 741 780 820 861 903 946 990 1035 1081 1128 1176 
[49] 1225 1275 1326 1378 1431 1485 1540 1596 1653 1711 1770 1830 1891 1953 2016 2080 2145 2211 2278 2346 2415 2485 2556 2628 
[73] 2701 2775 2850 2926 3003 3081 3160 3240 3321 3403 3486 3570 3655 3741 3828 3916 4005 4095 4186 4278 4371 4465 4560 4656 
[97] 4753 4851 4950 5050 

我希望得到以下結果:

[1] 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 210 231 253 276 300 
[25] 325 351 378 406 435 465 496 528 561 595 630 666 703 741 780 820 861 903 946 990 1035 1081 1128 1176 
[49] 1225 1275 1326 1378 1431 1485 1540 1596 1653 1711 1770 1830 1891 1953 2016 2080 2145 2211 2278 2346 2415 2485 2556 2628 
[73] 2701 2775 2850 2926 
+2

沒有什麼R中,我所知道的內置。你可能很容易在Rcpp中寫一些東西。 –

回答

4

正如我在評論中提到,寫一些簡單的RCPP即使對於像我這樣不應該是一個大問題。這裏有一個,似乎工作(感謝@ MatthewLundberg的改進建議)非常原始的實現

library(Rcpp) 
cppFunction('NumericVector cumsumCPP(NumericVector x, int y = 0){ 

    // y = 0 is the default 
    // Need to do this in order to avoid modifying the original x 
    int n = x.size(); 
    NumericVector res(n); 
    res[0] = x[0]; 

    for (int i = 1 ; i < n ; i++) { 
     res[i] = res[i - 1] + x[i]; 
     if (res[i] > y && (y != 0)) { 
     // This breaks the loop if condition met 
     return res[seq(0, i - 1)]; 
     } 
    } 

    // This handles cases when y== 0 OR y != 0 and y > cumsum(res) 
    return res; 
}') 

cumsumCPP(1:100, 3000) 
# [1] 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153 171 190 210 231 253 276 300 
# [25] 325 351 378 406 435 465 496 528 561 595 630 666 703 741 780 820 861 903 946 990 1035 1081 1128 1176 
# [49] 1225 1275 1326 1378 1431 1485 1540 1596 1653 1711 1770 1830 1891 1953 2016 2080 2145 2211 2278 2346 2415 2485 2556 2628 
# [73] 2701 2775 2850 2926 

同樣基地盧比cumsum,這同時適用於整數和浮點數,不處理NA秒。 treshhold的默認值設置爲0 - 如果您想限制負值cumsum,這並不理想,但現在我想不出任何更好的值(您可以自行決定)。

雖然可以使用一些優化...

set.seed(123) 
x <- as.numeric(sample(1:1e3, 1e7, replace = TRUE)) 
microbenchmark::microbenchmark(cumsum(x), cumsumCPP(x)) 
# Unit: milliseconds 
#   expr  min  lq  mean median  uq  max neval cld 
# cumsum(x) 58.61942 61.46836 72.50915 76.7568 80.97435 99.01264 100 a 
# cumsumCPP(x) 98.44499 100.09979 110.45626 112.1552 119.22958 131.97619 100 b 

identical(cumsum(x), cumsumCPP(x)) 
## [1] TRUE 
+1

您可以通過將內部測試更改爲'if(y && res [i]> y)來移除外部「if」。 –

+0

Thanks @MatthewLundberg,編輯。 –

+0

@DavidArenburg感謝您對我的回答(使用base R)的評論。你是對的 - 我完全錯誤地測試了它。已刪除,以免別人誤入歧途! –

1

我們可以在cumsum輸出使用<=

v1[v1 <=3000] 

或者另一個o ption是

setdiff(pmin(cumsum(1:100), 3000), 3000) 

其中

v1 <- cumsum(1:100)