5

Despite the similar title, this is not the same question as Vectorizing rep and seq in R.

My immediate goal: Given a vector, I want to generate a new vector containing the original values plus regularly-spaced intervals between each of the values in the old value. This is not difficult.

One strategy is to use a more general function which, given two vectors and a specified by interval, repeatedly applies seq to pairs of numbers from the two original vectors, using the same by value. I have not found a built-in function that does this. seq seems resistant to handling vectors as arguments. Here is a function that performs the more general operation (which I can then use for my immediate need):

multiseq <- function(froms, tos, by){
  x <- c(); 
  for (i in seq_along(froms)){
    x <- c(x, seq(from=froms[i], to=tos[i], by=by))
  }
  x
}

For example:

> multiseq(1:2, 1.75:2.75, .25)
[1] 1.00 1.25 1.50 1.75 2.00 2.25 2.50 2.75

(This is just a simple example. What I really want is to do this with an arbitrary sequence, e.g.

-0.89115386 -0.75346155 -0.61576924 -0.47807693 -0.34038463 -0.20269232 -0.06500001  0.07269230  0.21038460  0.34807691  0.48576922  0.62346153  0.76115383

And I want to subdivide each of the intervals into five, to create a new sequence with 5 times as many elements.)

As long as the sequences are not too long, repeatedly extending a vector should not be too slow, I believe. If I need large sequences, I can rewrite to pre-extend the vector and fill it. However, it still bugs me to do this with a loop at all. Is there a more elegant, functional-programming, R-ly way?

Thanks.

Community
  • 1
  • 1
Mars
  • 8,689
  • 2
  • 42
  • 70
  • I don't get what you want `seq(1, 2.75, by=.25)` does the same thing? – Tyler Rinker Apr 10 '13 at 04:59
  • Thanks @TylerRinker. I have edited to clarify. Um, but now that I think about it, you're right. I just wasn't thinking about it properly. For the new example, I can use `seq(-0.89115386, 0.76115383, 0.1376923/5)`. I also realized that I could use `c(mapply(seq, firstseq, secondseq, MoreArgs=list(by=0.1376923/5))`. Not sure whether to withdraw the question or answer it. – Mars Apr 10 '13 at 05:08
  • Answer it and accept your answer, it's perfectly valid (although you will have to wait a couple of days to accept it). I was just about to suggest the same thing. `multiseq <- function(froms, tos, ...) as.vector(mapply(seq, froms, tos, ...))`, then do `multiseq(froms, tos, by=0.1)` (say). – mathematical.coffee Apr 10 '13 at 05:10

3 Answers3

16

In R, one of the easiest way to vectorize a function is to use the Vectorize function.

Basically, you can vectorize the from an to argument and give all the starter as a vector in the from argument and do the same thing for the to argument.

Using your example, you can do something like this

seq2 <- Vectorize(seq.default, vectorize.args = c("from", "to"))

unlist(seq2(from = c(1, 1.75), to = c(2, 2.75), by = 0.25))

## [1] 1.00 1.25 1.50 1.75 2.00 1.75 2.00 2.25 2.50 2.75
Community
  • 1
  • 1
dickoa
  • 18,217
  • 3
  • 36
  • 50
  • + 1 and delete my half written response. You should post this as an answer to the linked `not duplicate` in the original question. – mnel Apr 10 '13 at 05:33
  • @mnel, maybe it should be posted there, too, but that question is much more specific than the title suggests. – Mars Apr 10 '13 at 16:07
  • Thanks dickoa. I had tried using `Vectorize` with `seq`, which generates an error. What is `seq.default`? What's the general rule for when such functions exist, and what they are? A pointer to a good source (or even an appropriate search string) would be appreciated. – Mars Apr 10 '13 at 16:11
1

Try following

x <- c(1, 2, 4, 8)
y <- unlist(mapply(FUN = function(from, to) {
    seq(from = from, to = to, by = 0.25)
}, head(x, -1), tail(x, -1)))
y
##  [1] 1.00 1.25 1.50 1.75 2.00 2.00 2.25 2.50 2.75 3.00 3.25 3.50 3.75 4.00 4.00 4.25 4.50 4.75 5.00 5.25 5.50 5.75 6.00
## [24] 6.25 6.50 6.75 7.00 7.25 7.50 7.75 8.00

result <- y[!duplicated(y)]
result
##  [1] 1.00 1.25 1.50 1.75 2.00 2.25 2.50 2.75 3.00 3.25 3.50 3.75 4.00 4.25 4.50 4.75 5.00 5.25 5.50 5.75 6.00 6.25 6.50
## [24] 6.75 7.00 7.25 7.50 7.75 8.00
CHP
  • 16,981
  • 4
  • 38
  • 57
1

As @TylerRinker suggested in a comment on my question, for my particular needs there's a solution that's simpler than what's suggested by my formulation of the problem--I was too focused on a particular way of thinking about it. Since I want regularly spaced numbers interpolated between numbers that are already regularly spaced, I can just apply seq to the initial and terminal values in the vector, using a by value that divides evenly into the interval between values in the the original vector:

subdiv <- function(x, by) seq(x[1], x[length(x)], by)
subdiv(1:4, .25)
[1] 1.00 1.25 1.50 1.75 2.00 2.25 2.50 2.75 3.00 3.25 3.50 3.75 4.00
subdiv(c(-0.20269232, -0.06500001,  0.07269230), 0.1376923/3)
[1] -0.20269232 -0.15679489 -0.11089745 -0.06500002 -0.01910259  0.02679485  0.07269228

where 0.1376923 is the difference between successive elements in the second application. This solution is OK as long as I don't need that the elements carried over from the original vector to be exactly equal to their original values--as you can see, there are some differences due to floating point arithmetic. (What I'm actually doing is constructing bins for histograms; the precise boundaries won't matter.)

@dickoa's and @geektrader's answers have broader use, though, and preserve the exact values of the original numbers from the input vector.

Mars
  • 8,689
  • 2
  • 42
  • 70