Skip to content

Generic 'diff'

9 messages · Stavros Macrakis, Wacek Kusnierczyk, Gabor Grothendieck

#
You can define a new class for the object diff operates
on and then define your own diff method for that. For
some examples see:

methods(diff)
On Mon, May 18, 2009 at 4:24 PM, Stavros Macrakis <macrakis at alum.mit.edu> wrote:
#
I understood what you were asking but R is an oo language so
that's the model to use to do this sort of thing.
On Mon, May 18, 2009 at 5:48 PM, Stavros Macrakis <macrakis at alum.mit.edu> wrote:
#
Stavros Macrakis wrote:
perhaps 'diff' would not be the best name, something like 'lag' would be
better for the more generic function, but 'lag' is already taken.

i agree it would be reasonable to have diff (lag) to accept an extra
argument for the function to be applied.  the solution of wrapping the
vector into a new class to be diff'ed with a non-default diff does not
seem to make much sense, as (a) what you seem to want is to custom-diff
plain vectors, (b) to keep the diff family coherent, you'd need to
upgrade the other diffs to have the extra argument anyway.

as you say, it's trivial to implement an extended diff, say difff,
reusing code from diff:

    difff = function(x, ...)
       UseMethod('difff')
    difff.default = function(x, lag=1, differences=1, fun=`-`, ...) {
       ismat = is.matrix(x)
       xlen = if (ismat) dim(x)[1L] else length(x)
    if (length(lag) > 1L || length(differences) > 1L || lag < 1L ||
differences < 1L)
       stop("'lag' and 'differences' must be integers >= 1")
    if (lag * differences >= xlen) return(x[0])
    r = unclass(x)
    i1 = -1L:-lag
    if (ismat)
        for (i in 1L:differences)
            r = fun(r[i1, , drop = FALSE], r[-nrow(r):-(nrow(r) - lag +
1), , drop = FALSE])
    else
        for (i in 1L:differences) r = fun(r[i1],
r[-length(r):-(length(r) - lag + 1)])
    class(r) = oldClass(x)
    r }

now, this naive version seems to work close to what you'd like:

    difff(1:4)
    # 1 1 1

    difff(1:4, fun=`+`)
    # 3 5 7

it might be useful if the original diff were working this way.

vQ
#
Wacek Kusnierczyk wrote:
[...]
[...]
btw., the error message here is confusing:

    lag = 1:2
    diff(1:10, lag=lag)
    # Error in diff.default(1:10, lag = lag) :
    #  'lag' and 'differences' must be integers >= 1

    is.integer(lag)
    # TRUE
    all(lag >= 1)
    # TRUE
  
what is meant is that lag and differences must be atomic 1-element
vectors of positive integers.  or rather integer-representing numerics:

    lag = 1
    diff(1:5, lag=1)
    # fine
    is.integer(lag)
    # FALSE

(the usual confusion between 'integer' as the underlying representation
and 'integer' as the represented number.)

vQ
#
Wacek Kusnierczyk wrote:
... and even non-integer-representing non-integers are fine:

    diff(1:5, lag=pi)
    # 3 3


vQ
#
Note that this could be done like this for ordinary
vectors:
[1] 3 5 7
[1]  5 13 25

or a method to rollapply in zoo could be added for ordinary vectors.
Here it is applied to zoo objects:
1 2 3
3 5 7
1  2  3
 5 13 25


On Tue, May 19, 2009 at 4:23 AM, Wacek Kusnierczyk
<Waclaw.Marcin.Kusnierczyk at idi.ntnu.no> wrote: