Sequence expansion question - r

I have a sequence of 'endpoints', e.g.:
c(7,10,5,11,15)
that I want to expand to a sequence of 'elapsed time' between the endpoints, e.g.
c(7,1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,1,2,3,4,5,6,7,8,9,10,11,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
Whats the most efficient way to do this in R? I'm imagining some creative use of the embed function, but I can't quite get there without using a ugly for loop.
Here's the naive way to do this:
expandSequence <- function(x) {
out <- x[1]
for (y in (x[-1])) {
out <- c(out,seq(1,y))
}
return(out)
}
expandSequence(c(7,10,5,11,15))

There is a base function to do this, called, wait for it, sequence:
sequence(c(7,10,5,11,15))
[1] 1 2 3 4 5 6 7 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 1 2 3
[26] 4 5 6 7 8 9 10 11 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
In your case it seems your first endpoint is in fact not part of the sequence, so it becomes:
c(7, sequence(c(10,5,11,15)))
[1] 7 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 1 2 3 4 5 6 7 8 9
[26] 10 11 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

How about this:
> unlist(sapply(x,seq))
[1] 1 2 3 4 5 6 7 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 1 2
[25] 3 4 5 6 7 8 9 10 11 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
With the first element added on at the end:
c( x[1], unlist( sapply( x[seq(2,length(x))], seq ) ) )
And a slightly more readable version:
library(taRifx)
c( x[1], unlist( sapply( shift(x,wrap=FALSE), seq ) ) )

A combination of lapply() and seq_len() is useful here:
expandSequence <- function(x) {
out <- lapply(x[-1], seq_len)
do.call(c, c(x[1], out))
}
Which gives for
pts <- c(7,10,5,11,15)
> expandSequence(pts)
[1] 7 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 1 2 3 4
[21] 5 6 7 8 9 10 11 1 2 3 4 5 6 7 8 9 10 11 12 13
[41] 14 15
(An alternative is:
expandSequence <- function(x) {
out <- lapply(x[-1], seq_len)
unlist(c(x[1], out), use.names = FALSE)
}
)

Related

Use rep() and seq() to create a vector

I am new to R. In JAVA I would introduce a control variable to create a sequence such as
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
I was thinking on doing something like
seq(from=c(1:5),to=c(5,10),by=1)
However that does not work...
Can that be solved purely with seq and rep?
How about this?
rep(0:4, each=5)+seq(from=1, to=5, by=1)
[1] 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
Try this. You can create a function to create the sequence and apply to an initial vector v1. Here the code:
#Data
v1 <- 1:5
#Code
v2 <- c(sapply(v1, function(x) seq(from=x,by=1,length.out = 5)))
Output:
[1] 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
And the way using seq() and rep() can be:
#Code2
rep(1:5, each = 5) + 0:4
Output:
[1] 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
Using outer is pretty concise:
c(outer(1:5, 0:4, `+`))
#> [1] 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
Note, 0:4 is short for seq(from = 0, to = 4, by = 1)
A perfect use case for Map or mapply. I always prefer Map because it does not simplify the output by default.
Map(seq, from = 1:5, to = 5:9)
[[1]]
[1] 1 2 3 4 5
[[2]]
[1] 2 3 4 5 6
[[3]]
[1] 3 4 5 6 7
[[4]]
[1] 4 5 6 7 8
[[5]]
[1] 5 6 7 8 9
You can use unlist() to get it the way you want.
unlist(Map(seq, from = 1:5, to = 5:9))
[1] 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
Note that `by = 1`, the default.

How to roll the order of a fixed length vector [duplicate]

This question already has answers here:
Circular shift of vector (equivalent to numpy.roll)
(7 answers)
Closed 2 years ago.
I have this vector:
1:12
and I want to roll the order of the values in this way:
#Iter 1
1 2 3 4 5 6 7 8 9 10 11 12
#Iter 2
12 1 2 3 4 5 6 7 8 9 10 11
#Iter 3
11 12 1 2 3 4 5 6 7 8 9 10
#Iter 3
10 11 12 1 2 3 4 5 6 7 8 9
#Iter 4
...
#Iter 12
1 2 3 4 5 6 7 8 9 10 11 12
I try dplyr:lead, seq(to = 1, by = -1, length.out = 12) and a loop, but I don't know how to do backwards (reverse) slicing in R.
You can try this:
vec <- 1:12
#List
List <- list()
List[[1]] <- vec
#Loop
for(i in 2:length(vec))
{
List[[i]] <- vec[c((length(vec)-2)+2,1:length(vec)-1)]
vec <- List[[i]]
}
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10 11 12
[[2]]
[1] 12 1 2 3 4 5 6 7 8 9 10 11
[[3]]
[1] 11 12 1 2 3 4 5 6 7 8 9 10
[[4]]
[1] 10 11 12 1 2 3 4 5 6 7 8 9
[[5]]
[1] 9 10 11 12 1 2 3 4 5 6 7 8
[[6]]
[1] 8 9 10 11 12 1 2 3 4 5 6 7
[[7]]
[1] 7 8 9 10 11 12 1 2 3 4 5 6
[[8]]
[1] 6 7 8 9 10 11 12 1 2 3 4 5
[[9]]
[1] 5 6 7 8 9 10 11 12 1 2 3 4
[[10]]
[1] 4 5 6 7 8 9 10 11 12 1 2 3
[[11]]
[1] 3 4 5 6 7 8 9 10 11 12 1 2
[[12]]
[1] 2 3 4 5 6 7 8 9 10 11 12 1

R Subtracting columns within a list

I'd like to subtract specific columns within a list. I'm still learning how to properly use the apply functions. For example, given
> b <- list(data.frame(12:16, 3*2:6), data.frame(10:14, 2*1:5))
> b
[[1]]
X12.16 X3...2.6
1 12 6
2 13 9
3 14 12
4 15 15
5 16 18
[[2]]
X10.14 X2...1.5
1 10 2
2 11 4
3 12 6
4 13 8
5 14 10
I'd like some function x so that I get
> x(b)
[[1]]
X12.16 X3...2.6 <newcol>
1 12 6 6
2 13 9 4
3 14 12 2
4 15 15 0
5 16 18 -2
[[2]]
X10.14 X2...1.5 <newcol>
1 10 2 8
2 11 4 7
3 12 6 6
4 13 8 5
5 14 10 4
Thanks in advance.
If your data.frames had nice and consistent names, you could use transform with lapply
b <- list(data.frame(a=12:16, b=3*2:6), data.frame(a=10:14, b=2*1:5))
lapply(b, transform, c=a-b)
Here is a solution:
lapply(b, function(x) {
x[, 3] <- x[, 1] - x[, 2]
x
})
[[1]]
X12.16 X3...2.6 V3
1 12 6 6
2 13 9 4
3 14 12 2
4 15 15 0
5 16 18 -2
[[2]]
X10.14 X2...1.5 V3
1 10 2 8
2 11 4 7
3 12 6 6
4 13 8 5
5 14 10 4
with dplyr:
library(dplyr)
lapply(b, function(x) x %>% mutate(new_col = .[[1]]-.[[2]]))
Result:
[[1]]
X12.16 X3...2.6 new_col
1 12 6 6
2 13 9 4
3 14 12 2
4 15 15 0
5 16 18 -2
[[2]]
X10.14 X2...1.5 new_col
1 10 2 8
2 11 4 7
3 12 6 6
4 13 8 5
5 14 10 4

Sequentially reorganize a vector in R

I have a numeric element z as below:
> sort(z)
[1] 1 5 5 5 6 6 7 7 7 7 7 9 9
I would like to sequentially reorganize this element so to have
> z
[1] 1 2 2 2 3 3 4 4 4 4 4 5 5
I guess converting z to a factor and use it as an index should be the way.
You answered it yourself really:
as.integer(factor(sort(z)))
I know this has been accepted already but I decided to look inside factor() to see how it's done there. It more or less comes down to this:
x <- sort(z)
match(x, unique(x))
Which is an extra line I suppose but it should be faster if that matters.
This should do the trick
z = sort(sample(1:10, 100, replace = TRUE))
cumsum(diff(z)) + 1
[1] 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3
[26] 3 3 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6
[51] 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 8 8
[76] 8 8 8 8 8 9 9 9 9 9 9 9 9 9 9 9 9 9 9 10 10 10 10 10
Note that diff omits the first element of the series. So to compensate:
c(1, cumsum(diff(z)) + 1)
Alternative using rle:
z = sort(sample(1:10, 100, replace = TRUE))
rle_result = rle(sort(z))
rep(rle_result$values, rle_result$lengths)
> rep(rle_result$values, rle_result$lengths)
[1] 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3
[26] 3 3 3 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 6 6 6
[51] 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 8
[76] 8 8 8 8 8 8 9 9 9 9 9 9 9 9 9 9 9 9 9 9 10 10 10 10 10
rep(seq_along(rle(x)$l), rle(x)$l)

R, Using reshape to pull pre post data

I have a simple data frame as follows
x = data.frame(id = seq(1,10),val = seq(1,10))
x
id val
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
I want to add 4 more columns. The first 2 are the previous two rows and the next two are the next two rows. For the first two rows and last two rows it needs to write out as NA.
How do I accomplish this using cast in the reshape package?
The final output would look like
1 1 NA NA 2 3
2 2 NA 1 3 4
3 3 1 2 4 5
4 4 2 3 5 6
... and so on...
Thanks much in advance
After your give the example , I change the solution
mat <- cbind(dat,
c(c(NA,NA),head(dat$id,-2)),
c(c(NA),head(dat$val,-1)),
c(tail(dat$id,-1),c(NA)),
c(tail(dat$val,-2),c(NA,NA)))
colnames(mat) <- c('id','val','idp','valp','idn','valn')
id val idp valp idn valn
1 1 1 NA NA 2 3
2 2 2 NA 1 3 4
3 3 3 1 2 4 5
4 4 4 2 3 5 6
5 5 5 3 4 6 7
6 6 6 4 5 7 8
7 7 7 5 6 8 9
8 8 8 6 7 9 10
9 9 9 7 8 10 NA
10 10 10 8 9 NA NA
Here is a soluting with sapply. First, choose the relative change for the new columns:
lags <- c(-2, -1, 1, 2)
Create the new columns:
newcols <- sapply(lags,
function(l) {
tmp <- seq.int(nrow(x)) + l;
x[replace(tmp, tmp < 1 | tmp > nrow(x), NA), "val"]})
Bind together:
cbind(x, newcols)
The result:
id val 1 2 3 4
1 1 1 NA NA 2 3
2 2 2 NA 1 3 4
3 3 3 1 2 4 5
4 4 4 2 3 5 6
5 5 5 3 4 6 7
6 6 6 4 5 7 8
7 7 7 5 6 8 9
8 8 8 6 7 9 10
9 9 9 7 8 10 NA
10 10 10 8 9 NA NA

Resources