Sum every x elements in a vector - r

I have a vector v like:
v <- c(1, 2, 46, 6, 3, 5, 67, 2, ..., 9)
I want to add the numbers three by three, so I would have the results of adding 1+6+67...
Thank you!

I would suggest creating a sequence by the width you want (in this case 3) which will start from 1 to the length of your vector and then sum:
#Data
v <- c(1, 2, 46, 6, 3, 5, 67, 2, 9)
#Seq
seqv <- seq(1,length(v),by = 3)
#Sum
sum(v[seqv])
Output:
[1] 74

You could create a sequence of values by three and use that to index the vector v and then sum the result.
v <- 10:19
s <- seq(1,9, by=3)
> v
[1] 10 11 12 13 14 15 16 17 18 19
> s
[1] 1 4 7
> sum(v[s])
[1] 39

Related

Examine if a value is in an interval using R

Having the following vector:
t <- c(2, 6, 8, 20, 22, 30, 40, 45, 60)
I would like to find the values that fall between the following intervals:
g <- list(c(1,20), c(20, 40))
The desired output is:
1, 20 c(2, 6, 8)
20, 40 c(20, 22, 30)
Using the dplyr library, I do the following:
library(dplyr)
for(i in t){
for(h in g){
if(between(i, h[[1]], h[[2]])==TRUE){print(c(i, h[[1]], h[[2]]))}
}}
Is there a better way of doing this in R?
We can loop over the list 'g' and extract the 't' elements based on the first and second values by creating a logical vector with >/< and extract the elements of 't'
lapply(g, function(x) t[t >= x[1] & t < x[2]])
-output
[[1]]
[1] 2 6 8
[[2]]
[1] 20 22 30
library(purrr)
library(dplyr)
map(g,~keep(t,between(t,.[1],.[2])))
[[1]]
[1] 2 6 8 20
[[2]]
[1] 20 22 30 40
You may find findInterval() from base R useful:
g <- c(1, 20, 40)
t <- c(2, 6, 8, 20, 22, 30, 40, 45, 60)
findInterval(t, g)
#> [1] 1 1 1 2 2 2 3 3 3
So t[1], t[2] and t[3] are in the first interval, t[4], t[5] and
t[6] in the second, and t[7], t[8] and t[9] the third (meaning that
these values are bigger than the right end point of the second interval.)
If you had values lower than one they would be labelled by 0:
t2 <- c(-1, 0, 2, 6, 8, 20, 22, 30, 40, 45, 60)
findInterval(t2, g)
#> [1] 0 0 1 1 1 2 2 2 3 3 3
You can save the result of findInterval() as e.g. y and use which(y==1) to find which entries correspond to the first interval.
We can try cut + is.na like below
lapply(
g,
function(x) {
t[!is.na(cut(t, x, include.lowest = TRUE))]
}
)
which gives
[[1]]
[1] 2 6 8 20
[[2]]
[1] 20 22 30 40

Avoid for loops in R/ vectorize

Suppose I have a vector
a <- c(1, 3, 4, 5, 6, 1, 2, 1, 1, 1)
I want to make a new vector that stores the sum of values before every element after the 3rd element like the vector below:
b <- c(8, 13, 19, 20, 22, 23, 24, 25)
How can I do this without a for loop?
We can use cumsum on the vector and index to remove the first two elements
b1 <- cumsum(a)[-(1:2)]
b1
#[1] 8 13 19 20 22 23 24 25
Or another option is Reduce
b1 <- Reduce(`+`, a, accumulate = TRUE)[-(1:2)]
Another base R option with Reduce (#akrun's cumsum answer is the most concise one, I believe)
> tail(Reduce(`+`,a,accumulate = TRUE),-2)
[1] 8 13 19 20 22 23 24 25

Multiplication of several vectors

I have 10 vectors (v_1 to v_10) and I need all of them multiplied with another vector v_mult (i.e. v_1*v_mult, v_2*v_mult etc.). How to I solve this problem within a for-loop? Im stuck to the loop-solution (which I do not find) because it is part of a larger analysis.
v_10<-c(2, 3, 5, 8)
v_20<-c(3, 9, 0, 1)
v_30<-c(15, 9, 6, 0)
v_40<-c(4, 9, 6, 1)
v_50<-c(1, 7, 3, 9)
v_60<-c(5, 9, 5, 1)
v_70<-c(5, 8, 2, 6)
v_80<-c(5, 8, 1, 6)
v_90<-c(5, 0, 1, 6)
v_10<-c(2, 8, 1, 0)
v_mult<-c(8, 5, 1, 9)
Those vectors should be all together in a matrix:
vlist <- mget(ls(pattern = "v_[[:digit:]*]"))
m <- do.call(cbind, vlist)
m * v_mult
# v_10 v_20 v_30 v_40 v_50 v_60 v_70 v_80 v_90
#[1,] 16 24 120 32 8 40 40 40 40
#[2,] 40 45 45 45 35 45 40 40 0
#[3,] 1 0 6 6 3 5 2 1 1
#[4,] 0 9 0 9 81 9 54 54 54
You can of course extract each vector from the matrix using column subsetting, e.g., m[, "v_10"] or m[, 1].
We can get all the vector objects in a list using mgetand multiply each element of the list with 'v_mult' using Map.
Map('*',mget(paste('v', seq(10, 100, by=10), sep="_")), list(v_mult))
Or use set from data.table which would be very fast as it doesn't have the .[data.table overhead.
library(data.table)
DT <- setDT(mget(paste('v', seq(10, 100, by=10), sep="_")))
for(j in seq_along(DT)){
set(DT, i=NULL, j= j, value= DT[[j]]*v_mult)
}

Order function returns different values as vector

I want to rearrange this vector decreasingly:
x <- c(10, 10, 7, 3, 6, 2, 2, 7, 8, 1, 3, 1, 1, 1, 5, 5, 5, 4, 4, 2, 1, 4, 4, 3, 3, 2, 2, 1)
order(x)
But it returns numbers which are different:
## [1] 10 12 13 14 21 28 6 7 20 26 27 4 11 24 25 18 19 22 23 15 16 17 5 3 8 9 1 2
order function returns permutation, not sorted vector:
http://stat.ethz.ch/R-manual/R-patched/library/base/html/order.html
> x <- c (3, 2, 4, 1)
> order(x)
[1] 4 2 1 3
The result (4 2 1 3) means that the smallest item is the 4th (that's 1), the second smallest is the 2nd (2)... and the biggest is the 3d item (which is 4)
if you want to sort the vector, use sort function:
> sort(x)
[1] 1 2 3 4
To sort in decreasing order specify decreasing parameter:
> sort(x, decreasing = TRUE)
[1] 4 3 2 1
order(x) returns indices of the elements of x in increasing order. You'll note that the smallest element of x is in 10th position in x, the second smallest (actually just as small) is at position 12 and so on.
to get x in decreasing order you can either use
sort(x, decreasing=TRUE)
or use order as an index:
x[order(-x)]
(why -x? Because order returns indices in increasing order. by flipping the numbers around zero you get the indices in decreasing order)

Finding repeated patterns in R

Say I have a matrix of 5 x 100 of numbers between 0 and 100 for instance:
1 5 10 15 3
2 15 3 8 27
1 22 34 45 35
28 27 32 3 8
......
I would like to find repeated "patterns" of numbers (mainly couples or triplets).
So in my example I would have the couple 3,15 appearing twice and the triplet 3, 8, 27 also appearing twice (I don't care about the order).
How would you implement that in R?
I would like to have couples and triplets separately and have their count.
thanks
nico
Here is one way. For each row of your 100-row matrix, you find all pairs/triples of numbers (using combn ) and do a frequency-count (using table) of the pairs/triples. The pasteSort function I defined creates a string out of a vector after sorting it. We apply this function to each pair/tuple in each row, and collect all pairs/tuples from the matrix before doing the frequency-count. Note that if a pair repeats on the same row, it's counted as a "repeat".
> mtx <- matrix( c(1,5,10,15,3,
2, 15, 3, 8, 27,
1, 22, 34, 45, 35,
28, 27, 32, 3, 8), ncol=5, byrow=TRUE)
> pasteSort <- function( x ) do.call(paste, as.list( sort( x) ) )
> pairs <- c( apply(mtx, 1, function(row) apply( combn(row, 2), 2, pasteSort)) )
> pairFreqs <- table(pairs)
> pairFreqs[ pairFreqs > 1 ]
3 15 3 27 3 8 8 27
2 2 2 2
> triples <- c( apply(mtx, 1, function(row) apply( combn(row, 3), 2, pasteSort)) )
> tripleFreqs <- table( triples )
> tripleFreqs[ tripleFreqs > 1 ]
3 8 27
2

Resources