简体   繁体   中英

Sum different elements of a vector into a new vector without using a for loop? (R programming)

I need to take an existing vector and create a new vector that contains the values;

(x1+2x2−x3, x2+2x3−x4, . . . , xn−2+2xn−1 − xn)

I've tried using xVec[n-2] + 2* xVec[n-1] - xVec[n] but this doesn't work!

You need a rolling calculation , something that the zoo package provides:

vec <- 1:10
zoo::rollapply(vec, width = 3, FUN = function(z) z[1]+2*z[2]-z[3])
# [1]  2  4  6  8 10 12 14 16

Validation, using first three and last three:

1 + 2*2 - 3
# [1] 2
8 + 2*9 - 10
# [1] 16

Explanation: each time the function (passed to FUN= ) is called, it is given a vector with width= elements in it. The first call is effectively z=1:3 , the second call z=2:4 , third z=3:5 , etc.

You should know that by default it will return length(vec) - width + 1 elements in its return value. You can control this with fill= and align= arguments:

zoo::rollapply(1:10, width = 3, FUN = function(z) z[1]+2*z[2]-z[3], fill = NA)
#  [1] NA  2  4  6  8 10 12 14 16 NA
zoo::rollapply(1:10, width = 3, FUN = function(z) z[1]+2*z[2]-z[3], fill = NA, align = "right")
#  [1] NA NA  2  4  6  8 10 12 14 16

Without zoo :

n <- 10
xVec <- seq(n)
idx <- seq(1, n-2)
xVec[idx] + 2* xVec[idx+1] - xVec[idx+2]
[1]  2  4  6  8 10 12 14 16

In a comment , B. Go has suggested to "reshape" the vector and wonders if this can be done in R as well.

In R, two packages provide functions to shift the elements of a vector: data.table and dplyr . (The lag() function from base R deals with times series objects.)

data.table

x <- 1:10
library(data.table)
shift(x, 2L) + 2 * shift(x) - x
 [1] NA NA 2 4 6 8 10 12 14 16

dplyr

x <- 1:10
library(dplyr)
lag(x, 2L) + 2 * lag(x) - x
 [1] NA NA 2 4 6 8 10 12 14 16

By default, both functions do fill up missing values after shifting with NA . This explains why the first two elements of the result vector are NA.

To get rid of the leading NA s, the tail() function can be used, eg,

tail(shift(x, 2L) + 2 * shift(x) - x, -2L)
 [1] 2 4 6 8 10 12 14 16

If you are up for a bit of matrix math:

xVec <- 1:10
linear_combo <- c(1, 2, -1)

m <- matrix(0, length(xVec), length(xVec))
for (index in seq_along(linear_combo)) {
  m[row(m) == col(m) - index + 1] <- linear_combo[index]
}

m %*% xVec

Note in this case the last two elements are incomplete and should probably be dropped or replaced by NA.

head(m %*% xVec, -(length(linear_combo) - 1))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM