Create matrix from vector's rolling window [duplicate] - r

This question already has an answer here:
Create all subvectors of a certain length (moving window)
(1 answer)
Closed 1 year ago.
I would like to do something like this question but in R.
Given:
> my_vector
[1] 1 2 3 4 5 6
And window_size = 3, I would like to get the following matrix:
> my_matrix
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 2 3 4
[3,] 3 4 5
[4,] 4 5 6
As you can see, every row of the matrix is a window of the vector.
Is there any efficient way to do it in R without for loop?

We can use embed
apply(embed(my_vector, 4), 1, rev)
# [,1] [,2] [,3]
#[1,] 1 2 3
#[2,] 2 3 4
#[3,] 3 4 5
#[4,] 4 5 6
Or it can be modified to
t(embed(rev(my_vector), 4))[, 3:1]
Or as #lmo suggested
embed(my_vector, 3)[, 3:1]
Or with matrix
matrix(my_vector, 7, 3)[1:4,]

sapply(1:3, function(i) my_vector[i:(i+3)])
# [,1] [,2] [,3]
#[1,] 1 2 3
#[2,] 2 3 4
#[3,] 3 4 5
#[4,] 4 5 6

This can be done using rollapply in zoo:
library(zoo)
rollapply(my_vector, 3, c)
giving:
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 2 3 4
[3,] 3 4 5
[4,] 4 5 6
Note: The input used above, in reproducible form, is:
my_vector <- 1:6

Related

Restore matrix row and column names to defaults in R (e.g., [1,], [2,]...)

Can matrix row and column names be set to defaults (e.g., [1,], [2,]... [,1], [,2]...) in R?
For example, is there a quick way to transform a matrix like this
x1 <- matrix(1:9,nrow=3,ncol=3,dimnames=list(1:3,letters[1:3]))
> x1
a b c
1 1 4 7
2 2 5 8
3 3 6 9
into this
> x1
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
You're looking for dimnames<-:
dimnames(x1) <- NULL
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
You can see the help file by typing ?dimnames. It is also linked from ?matrix.

How to remove column names from a matrix in R?

M = matrix(1:9,3,3)
colnames(M)=c('a','b','c')
Suppose I have a matrix M , with column names 'a','b','c'. And I want to remove the names, so that M
M [,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
Rather than
a b c
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
How do I do this?
I know it's been a while since this was asked, but seeing as it is a highly trafficked question, I thought this might be useful.
If you want to perform this action on M instead of its column names, you could try
M <- unname(M)
>M
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
This would be more efficient if you want to pipe or nest the output into subsequent functions because colnames does not return M.
You can try
colnames(M) <- NULL
Using your example:
> M
# a b c
#[1,] 1 4 7
#[2,] 2 5 8
#[3,] 3 6 9
> colnames(M) <- NULL
> M
# [,1] [,2] [,3]
#[1,] 1 4 7
#[2,] 2 5 8
#[3,] 3 6 9
However, if your data is stored in a data.frame instead of a matrix, this won't work. As explained in ?data.frame:
The column names should be non-empty, and attempts to use empty names will have unsupported results
If your data is stored as a data.frame (this can be checked with class(my_data)), you could try to convert it into a matrix with M <- as.matrix(my_data). Hope this helps.
If you want to delete row names use row.names() function
>M
a b c
1[1,] 1 4 7
2[2,] 2 5 8
3[3,] 3 6 9
>row.names(M)<- NULL ; colnames(M)<- NULL
>M
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9

R - Concisely add vector to each vector element

Let's say I have a simple vector
v <- 1:5
I can add the vector to each element within the vector with the following code to generate the resulting matrix.
matrix(rep(v, 5), nrow=5, byrow=T) + matrix(rep(v, 5), nrow=5)
[,1] [,2] [,3] [,4] [,5]
[1,] 2 3 4 5 6
[2,] 3 4 5 6 7
[3,] 4 5 6 7 8
[4,] 5 6 7 8 9
[5,] 6 7 8 9 10
But this seems verbose and inefficient. Is there a more concise way to accomplish this? Perhaps some linear algebra concept that is evading me?
outer should do what you want
outer(v, v, `+`)
# [,1] [,2] [,3] [,4] [,5]
# [1,] 2 3 4 5 6
# [2,] 3 4 5 6 7
# [3,] 4 5 6 7 8
# [4,] 5 6 7 8 9
# [5,] 6 7 8 9 10
Posting this answer not for up votes but to highlight Franks comment. You can use
sapply(v,"+",v)

Draw a Hankel matrix with R

I want to draw a Hankel matrix with R use only matrix(), seq() and rep() function of R. Until now, I draw this in some way:
#Do this exercise with other packages, need to rework
install.packages("matrixcalc")
library(matrixcalc)
E1 <- hankel.matrix( 5, seq( 1, 9 ) )
print(E1)
#Use matrix() only, not efficient
E2 <- matrix(c(1,2,3,4,5,2,3,4,5,6,3,4,5,6,7,4,5,6,7,8,5,6,7,8,9), ncol=5)
print(E2)
#Use seq() but not worked
E3 <- matrix(c(seq(1:5),seq(2:6),seq(3:7),seq(4:8),seq(5:9)), ncol=5)
print(E3)
E1 used a library to draw a Hankel matrix and in E2, I tried to put the number manually to draw one but it will take a lot of time if I want a new big matrix. I tried to use seq() but it not worked. It will draw like this:
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
[4,] 4 4 4 4 4
[5,] 5 5 5 5 5
I am still very new with R so every idea is welcome.
You can do this :
matrix(rep(1:5,5)+rep(0:4,each=5),ncol=5)
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 2 3 4 5
# [2,] 2 3 4 5 6
# [3,] 3 4 5 6 7
# [4,] 4 5 6 7 8
# [5,] 5 6 7 8 9
Or more elegant but using outer:
outer(0:4,1:5,'+')
EDIT :
the rep solution works like this:
12345 12345 12345 ... (rep times, repeat the vector n times
+ 00000 11111 22222 ... (rep with each , repeat each element n times
= 12345 23456 34567 .....
outer can be tricky at first, maybe this answer here can help you to understand it and to general debug.
I'm reversing the order of the two different solutions so that the qualifying one is at the top:
A general function (meaning on that doesn't depend on the values being sequential) that only uses a couple of extra functions (like c() and "[") to do the work:
N <- c(9L, 7L, 3L, 2L, 1L, 8L, 4L, 5L, 6L, 10L)
hankel2 <- function(N, n){stopifnot(length(N)==2*n);
matrix( rep(N,n)[c(rep(TRUE,n),rep(FALSE,n+1))], n) }
hankel2(N,5)
[,1] [,2] [,3] [,4] [,5]
[1,] 9 7 3 2 1
[2,] 7 3 2 1 8
[3,] 3 2 1 8 4
[4,] 2 1 8 4 5
[5,] 1 8 4 5 6
The trick with that first (of three) efforts was to depend on argument recycling of logical vectors when used inside the "[" function. It creates a gap of n+1 items after choosing n items by indexing with FALSE ( which has the effect of omitting items.)
Embed is a cute little function that has a fairly opaque help file but occasionally delivers very compact code:
> x <- 1:10
> embed (x, 5)[1:5, 5:1]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 2 3 4 5 6
[3,] 3 4 5 6 7
[4,] 4 5 6 7 8
[5,] 5 6 7 8 9
You could make a function:
> hankel <- function( n ) embed(1:(2*n),5)[1:n, n:1]
> hankel(5)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 2 3 4 5 6
[3,] 3 4 5 6 7
[4,] 4 5 6 7 8
[5,] 5 6 7 8 9
(Admittedly not playing by the specifications although I wondered if any of the solutions so far would stand up to a vector that wasn't sequential. This one does:)
> hankel5 <- function( n ) embed(sample(1:10,10),5)[1:n, n:1]
> hankel5(5)
[,1] [,2] [,3] [,4] [,5]
[1,] 3 5 7 9 4
[2,] 5 7 9 4 10
[3,] 7 9 4 10 1
[4,] 9 4 10 1 8
[5,] 4 10 1 8 2
So this is the other general function:
hankel <- function( N, n ) {stopifnot(length(N) == 2*n); embed(N,n)[1:n, n:1]

In R, using `unique()` with extra conditions to extract submatrices: easy solution without plyr

In R, let M be the matrix
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 1 3 3
[3,] 2 4 5
[4,] 6 7 8
I would like to select the submatrix m
[,1] [,2] [,3]
[1,] 1 3 3
[2,] 2 4 5
[3,] 6 7 8
using unique on M[,1], specifying to keep the row with the maximal value in the second columnM.
At the end, the algorithm should keep row [2,] from the set \{[1,], [2,]\}. Unfortunately unique() returns me a vector with actual values, and not row numbers, after elimination of duplicates.
Is there a way to get the asnwer without the package plyr?
Thanks a lot,
Avitus
Here's how:
is.first.max <- function(x) seq_along(x) == which.max(x)
M[as.logical(ave(M[, 2], M[, 1], FUN = is.first.max)), ]
# [,1] [,2] [,3]
# [1,] 1 3 3
# [2,] 2 4 5
# [3,] 6 7 8
You're looking for duplicated.
m <- as.matrix(read.table(text="1 2 3
1 3 3
2 4 5
6 7 8"))
m <- m[order(m[,2], decreasing=TRUE), ]
m[!duplicated(m[,1]),]
# V1 V2 V3
# [1,] 6 7 8
# [2,] 2 4 5
# [3,] 1 3 3
Not the most efficient:
M <- matrix(c(1,1,2,6,2,3,4,7,3,3,5,8),4)
t(sapply(unique(M[,1]),function(i) {temp <- M[M[,1]==i,,drop=FALSE]
temp[which.max(temp[,2]),]
}))
# [,1] [,2] [,3]
#[1,] 1 3 3
#[2,] 2 4 5
#[3,] 6 7 8

Resources