Combinatorial Partial Amount

I am looking Rfor a function partial.sum()that takes a vector of numbers and returns an increasing sorted vector of all partial sums:

test=c(2,5,10)
partial.sum(test)

# 2 5 7 10 12 15 17
## 2 is the sum of element 2
## 5 is the sum of element 5    
## 7 is the sum of elements 2 & 5    
## 10 is the sum of element 10    
## 12 is the sum of elements 2 & 10    
## 15 is the sum of elements 5 & 10
## 17 is the sum of elements 2 & 5 & 10
+4
source share
3 answers

It uses recursion. (Without claiming to be effective)

partial.sum <- function(x) {
   slave <- function(x) {
      if (length(x)) {
         y <- Recall(x[-1])
         c(y + 0, y + x[1])
      } else 0
   }
   sort(unique(slave(x)[-1]))
}

partial.sum(c(2,5,10))
# [1]  2  5  7 10 12 15 17

Edit: well, it turns out that this is a little faster than I thought:

x <- 1:20
microbenchmark(flodel(x), dason(x), matthew(x), times = 10)
# Unit: milliseconds
#        expr        min        lq     median        uq       max neval
#   flodel(x)   86.31128   86.9966   94.12023  125.1013  163.5824    10
#    dason(x) 2407.27062 2461.2022 2633.73003 2846.2639 3031.7250    10
#  matthew(x) 3084.59227 3191.7810 3304.36064 3693.8595 3883.2767    10

(I added sortand / or uniquedason and matthew functions, if necessary for a fair comparison.)

+6
source

, , . unique , .

partial.sum <- function(x){
  n <- length(x)
  # Something that will help get us every possible subset
  # of the original vector
  out <- do.call(expand.grid, replicate(n, c(T,F), simplify = F))
  # Don't include the case where we don't grab any elements
  out <- head(out, -1)

  # ans <- apply(out, 1, function(row){sum(x[row])})
  # As flodel points out the following will be faster than
  # the previous line
  ans <- data.matrix(out) %*% x
  # If you want only unique value then add a call to unique here
  ans <- sort(unname(ans))
  ans
}
+3

It uses an iterative approach using combnto create combinations for summation. It works for vectors longer than 1.

partial.sum <- function(x) {
  sort(unique(unlist(sapply(seq_along(x), function(i) colSums(combn(x,i))))))
}
## [1]  2  5  7 10 12 15 17

To handle lengths less than 2, check the length:

partial.sum <- function(x) {
  if (length(x) > 1) {
    sort(unique(unlist(sapply(seq_along(x), function(i) colSums(combn(x,i))))))
  } else {
    x
  }
}

Some timings from rbenchmarkthat are not fully consistent with flodel results. I changed the Dason code by deleting comments and adding a call unique. The version of my code is the first, without if. Flodel Code is the clear winner here.

> test <- 1:10
> benchmark(matthew(test), flodel(test), dason(test), replications=100)
           test replications elapsed relative user.self sys.self user.child sys.child
3   dason(test)          100   0.180   12.857     0.175    0.004          0         0
2  flodel(test)          100   0.014    1.000     0.015    0.000          0         0
1 matthew(test)          100   0.244   17.429     0.242    0.001          0         0

> test <- 1:20
> benchmark(matthew(test), flodel(test), dason(test), replications=1)
           test replications elapsed relative user.self sys.self user.child sys.child
3   dason(test)            1   5.231   98.698     5.158    0.058          0         0
2  flodel(test)            1   0.053    1.000     0.053    0.000          0         0
1 matthew(test)            1   2.184   41.208     2.180    0.000          0         0

> test <- 1:25
> benchmark(matthew(test), flodel(test), dason(test), replications=1)
           test replications elapsed relative user.self sys.self user.child sys.child
3   dason(test)            1 288.957  163.345   264.068   23.859          0         0
2  flodel(test)            1   1.769    1.000     1.727    0.038          0         0
1 matthew(test)            1  75.712   42.799    74.745    0.847          0         0
+2
source

Source: https://habr.com/ru/post/1542774/


All Articles