[Rd] Define how diff methods in base R treat lag that is not a whole number?
Suharto Anggono Suharto Anggono
@uh@rto_@nggono @end|ng |rom y@hoo@com
Fri May 22 12:38:07 CEST 2026
R documentation doesn't state what happens if the supplied 'lag' (or 'differences') to the default, "POSIXt", "Date", "difftime" or "ts" method of 'diff' is not a whole number.
S-PLUS 3.4 help on 'diff' has such a statement:
lag:
Non-integer values are rounded to the nearest integer.
differences:
Non-integer values are rounded to the nearest integer.
In R 4.6.0:
> diff(1:10, 1.25)
[1] 1 1 1 1 1 1 1 1 9
Warning message:
In r[i1] - `length<-`(r, max(length(r) - lag, 0L)) :
longer object length is not a multiple of shorter object length
> diff(1:10, 1.75)
[1] 1 1 1 1 1 1 1 1 9
Warning message:
In r[i1] - `length<-`(r, max(length(r) - lag, 0L)) :
longer object length is not a multiple of shorter object length
9 in the result is because of recycling. It is because
'i1', which is -seq_len(lag) , is -1 and r[i1] has length 9, and
max(length(r) - lag, 0L) is between 8 and 9 and `length<-`(r, max(length(r) - lag, 0L)) has length 8.
In R 4.5.3 (and previous R versions):
> diff(1:10, 1.25)
[1] 1 1 1 1 1 1 1 1 1
> diff(1:10, 1.75)
[1] 1 1 1 1 1 1 1 1 1
"POSIXt", "Date" and "difftime" cases are similar.
In R 4.6.0:
> diff(.POSIXct(1:10), 1.25)
Time differences in secs
[1] 1 1 1 1 1 1 1 1 9
Warning message:
In unclass(time1) - unclass(time2) :
longer object length is not a multiple of shorter object length
> diff(.POSIXct(1:10), 1.75)
Time differences in secs
[1] 1 1 1 1 1 1 1 1 9
Warning message:
In unclass(time1) - unclass(time2) :
longer object length is not a multiple of shorter object length
> diff(.Date(1:10), 1.25)
Time differences in days
[1] 1 1 1 1 1 1 1 1 9
Warning message:
In unclass(time1) - unclass(time2) :
longer object length is not a multiple of shorter object length
> diff(.Date(1:10), 1.75)
Time differences in days
[1] 1 1 1 1 1 1 1 1 9
Warning message:
In unclass(time1) - unclass(time2) :
longer object length is not a multiple of shorter object length
> diff(.difftime(1:10, "secs"), 1.25)
Time differences in secs
[1] 1 1 1 1 1 1 1 1 9
Warning message:
In r[i1] - `length<-`(r, max(length(r) - lag, 0L)) :
longer object length is not a multiple of shorter object length
> diff(.difftime(1:10, "secs"), 1.75)
Time differences in secs
[1] 1 1 1 1 1 1 1 1 9
Warning message:
In r[i1] - `length<-`(r, max(length(r) - lag, 0L)) :
longer object length is not a multiple of shorter object length
In R 4.5.3:
> diff(.POSIXct(1:10), 1.25)
Time differences in secs
[1] 1 1 1 1 1 1 1 1 1
> diff(.POSIXct(1:10), 1.75)
Time differences in secs
[1] 1 1 1 1 1 1 1 1 1
> diff(.Date(1:10), 1.25)
Time differences in days
[1] 1 1 1 1 1 1 1 1 1
> diff(.Date(1:10), 1.75)
Time differences in days
[1] 1 1 1 1 1 1 1 1 1
> diff(.difftime(1:10, "secs"), 1.25)
Time differences in secs
[1] 1 1 1 1 1 1 1 1 1
> diff(.difftime(1:10, "secs"), 1.75)
Time differences in secs
[1] 1 1 1 1 1 1 1 1 1
"ts" case is different.
In R 4.5.3 and 4.6.0:
> diff(ts(1:10), 1.25)
Time Series:
Start = 2
End = 10
Frequency = 1
[1] 1 1 1 1 1 1 1 1 1
Warning message:
In lag.default(r, -lag) : 'k' is not an integer
> diff(ts(1:10), 1.75)
Time Series:
Start = 3
End = 10
Frequency = 1
[1] 2 2 2 2 2 2 2 2
Warning message:
In lag.default(r, -lag) : 'k' is not an integer
In R 4.0.3 (or any versions up to 4.5.2):
> diff(ts(1:10), 1.25)
Error in .cbind.ts(list(e1, e2), c(deparse(substitute(e1))[1L], deparse(substitute(e2))[1L]), :
not all series have the same phase
> diff(ts(1:10), 1.75)
Error in .cbind.ts(list(e1, e2), c(deparse(substitute(e1))[1L], deparse(substitute(e2))[1L]), :
not all series have the same phase
It is because, since R 4.5.3, in 'diff.ts', 'lag' is used to replace 'tsLag', and 'lag.default' rounds 'k'.
The rounding of 'k' by 'lag.default' in R happens since the beginning, but is not documented. S-PLUS 3.4 help on 'lag' (https://sites.oxy.edu/lengyel/m150/Sueselbeck/helpfiles/lag.html) has a statement:
Non-integer, values of 'k' are rounded to the nearest integer.
How about defining how to treat the supplied 'lag' argument to the default, "POSIXt", "Date", "difftime" or "ts" method that is not a whole number? Maybe following 'lag.default' that rounds? Maybe having the same treatment in the default and "ts" method of 'diffinv'? Also, I think it is good to emit a warning for non-integer.
Because of
for (i in seq_len(differences))
or
for (i in 1L:differences)
, 'differences' is implicitly truncated. It hasn't changed.
The early return in 'diff.ts' doesn't consider rounding.
In R 4.5.3 and 4.6.0:
> diff(ts(1:10), 1.25, 7)
Time Series:
Start = 8
End = 10
Frequency = 1
[1] 0 0 0
Warning messages:
1: In lag.default(r, -lag) : 'k' is not an integer
2: In lag.default(r, -lag) : 'k' is not an integer
3: In lag.default(r, -lag) : 'k' is not an integer
4: In lag.default(r, -lag) : 'k' is not an integer
5: In lag.default(r, -lag) : 'k' is not an integer
6: In lag.default(r, -lag) : 'k' is not an integer
7: In lag.default(r, -lag) : 'k' is not an integer
> diff(ts(1:10), 1.25, 8)
integer(0)
> diff(ts(1:10), 1.75, 5)
Error in ts(r, end = xtsp[2L], frequency = xtsp[3L]) :
'ts' object must have one or more observations
In addition: Warning messages:
1: In lag.default(r, -lag) : 'k' is not an integer
2: In lag.default(r, -lag) : 'k' is not an integer
3: In lag.default(r, -lag) : 'k' is not an integer
4: In lag.default(r, -lag) : 'k' is not an integer
5: In lag.default(r, -lag) : 'k' is not an integer
6: In .cbind.ts(list(e1, e2), c(deparse(substitute(e1))[1L], deparse(substitute(e2))[1L]), :
non-intersecting series
More information about the R-devel
mailing list