Skip to content

head.ts, tail.ts loses time

9 messages · Spencer Graves, Josiah Parry, Gabor Grothendieck +1 more

#
Hello, All:


	  The 'head' and 'tail' functions strip the time from a 'ts' object. 
Example:


 > head(presidents)
[1] NA 87 82 75 63 50


 > window(presidents, 1945, 1946.25)
      Qtr1 Qtr2 Qtr3 Qtr4
1945   NA   87   82   75
1946   63   50


	  Below please find code for 'head.ts' and 'tail.ts' that matches 
'window'.


	  Comments?
	  Spencer Graves

head.ts <- function(x, n=6L, ...){
   tmx <- as.numeric(time(x))
#
   utils:::checkHT(n, d <- dim(x))
   if(is.na(n[1]) || n[1]==0)ts(NULL)
#
   firstn <- head(tmx, n[1])
   if(is.null(d)){
     return(window(x, firstn[1], tail(firstn, 1)))
   } else{
     if(length(n)<2){
       return(window(x, firstn[1], tail(firstn, 1)))
     } else {
       Cols <- head(1:d[2], n[2])
       xn2 <- x[, Cols[1]:tail(Cols, 1)]
       return(window(xn2, firstn[1], tail(firstn, 1)))
     }
   }
}


tail.ts <- function (x, n = 6L, ...)
{
   utils:::checkHT(n, d <- dim(x))
   tmx <- as.numeric(time(x))
#
   if(is.na(n[1]) || n[1]==0)ts(NULL)
#
   lastn <- tail(tmx, n[1])
   if(is.null(d)){
     return(window(x, lastn[1], tail(lastn, 1)))
   } else{
     if(length(n)<2){
       return(window(x, lastn[1], tail(lastn, 1)))
     } else {
       Cols <- head(1:d[2], n[2])
       xn2 <- x[, Cols[1]:tail(Cols, 1)]
       return(window(xn2, lastn[1], tail(lastn, 1)))
     }
   }
}


# examples
head(presidents)

head(presidents, 2)

npresObs <- length(presidents)
head(presidents, 6-npresObs)

try(head(presidents, 1:2)) # 'try-error'

try(head(presidents, 0)) # 'try-error'

# matrix time series
str(pres <- cbind(n=1:length(presidents), presidents))
head(pres, 2)

head(pres, 2-npresObs)

head(pres, 1:2)
head(pres, 2:1)
head(pres, 1:3)

# examples
tail(presidents)

tail(presidents, 2)

npresObs <- length(presidents)
tail(presidents, 6-npresObs)

try(tail(presidents, 1:2)) # 'try-error'

try(tail(presidents, 0)) # 'try-error'

# matrix time series
str(pres <- cbind(n=1:length(presidents), presidents))
tail(pres, 2)

tail(pres, 2-npresObs)

tail(pres, 1:2)
tail(pres, 2:1)
tail(pres, 1:3)

# for unit testing:
headPres <- head(presidents)
pres6 <- ts(presidents[1:6], time(presidents)[1],
             frequency=frequency(presidents))
stopifnot(all.equal(headPres, pres6))

headPres2 <- head(presidents, 2)
pres2 <- ts(presidents[1:2], time(presidents)[1],
             frequency=frequency(presidents))
stopifnot(all.equal(headPres2, pres2))

npresObs <- length(presidents)
headPres. <- head(presidents, 6-npresObs)
stopifnot(all.equal(headPres., pres6))

headPresOops <- try(head(presidents, 1:2))
stopifnot(class(headPresOops) == 'try-error')

headPres0 <- try(head(presidents, 0))
stopifnot(class(headPres0) == 'try-error')

str(pres <- cbind(n=1:length(presidents), presidents))
headP2 <- head(pres, 2)

p2 <- ts(pres[1:2, ], time(presidents)[1],
          frequency=frequency(presidents))
stopifnot(all.equal(headP2, p2))

headP2. <- head(pres, 2-npresObs)
stopifnot(all.equal(headP2., p2))


#############


sessionInfo()
R version 4.4.0 (2024-04-24)
Platform: aarch64-apple-darwin20
Running under: macOS Sonoma 14.5

Matrix products: default
BLAS: 
/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib 

LAPACK: 
/Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib; 
  LAPACK version 3.12.0

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: America/Chicago
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets
[6] methods   base

loaded via a namespace (and not attached):
[1] compiler_4.4.0 tools_4.4.0
#
It looks like to me the class is being removed explicitly due to the use of
as.numeric()

On Sun, Jun 9, 2024 at 12:04?PM Spencer Graves <spencer.graves at prodsyse.com>
wrote:

  
  
#
zoo overcomes many of the limitations of ts:

  library(zoo)
  as.ts(head(as.zoo(presidents)))
  ##      Qtr1 Qtr2 Qtr3 Qtr4
  ## 1945   NA   87   82   75
  ## 1946   63   50

xts also works here.

On Sun, Jun 9, 2024 at 12:04?PM Spencer Graves
<spencer.graves at prodsyse.com> wrote:

  
    
#
Hi, Gabor et al.:


	  Thanks for this. I should change my current application to use either 
zoo or xts, as Gabor suggests.


	  However, I was surprised to learn that "[.ts" does NOT return an 
object of class "ts". I see that "head.default" and "head.matrix" both 
call "[", so "head" cannot return a ts object, because "[" doesn't.


	  Best Wishes,
	  Spencer Graves
On 6/9/24 8:40 PM, Gabor Grothendieck wrote:
#
> Hi, Gabor et al.: Thanks for this. I should change my
    > current application to use either zoo or xts, as Gabor
    > suggests.


    > 	  However, I was surprised to learn that "[.ts" does NOT
    > return an object of class "ts". I see that "head.default"
    > and "head.matrix" both call "[", so "head" cannot return a
    > ts object, because "[" doesn't.

Yes, the default head() and tail() are built on  `[` very much
on purpose.
Note that   `[`  should *not* keep the "ts"  property  in
general, e.g.,  
	 lynx[c(1:3, 7)]
cannot be a regular time series 

I think I'd consider using  windows() for a head.ts() and tail.ts(),
but in any case, I am sympathetic adding such methods to "base R"'s
utils package.


Martin

    > 	  Best Wishes, Spencer Graves
> On 6/9/24 8:40 PM, Gabor Grothendieck wrote:
>> zoo overcomes many of the limitations of ts:
    >> 
    >> library(zoo) as.ts(head(as.zoo(presidents))) ## Qtr1 Qtr2
    >> Qtr3 Qtr4 ## 1945 NA 87 82 75 ## 1946 63 50
    >> 
    >> xts also works here.
    >> 
    >> On Sun, Jun 9, 2024 at 12:04?PM Spencer Graves
>> <spencer.graves at prodsyse.com> wrote:
>>> 
    >>> Hello, All:
    >>> 
    >>> 
    >>> The 'head' and 'tail' functions strip the time from a
    >>> 'ts' object.  Example:
    >>> 
    >>> 
    >>> > head(presidents) [1] NA 87 82 75 63 50
    >>> 
    >>> 
    >>> > window(presidents, 1945, 1946.25) Qtr1 Qtr2 Qtr3 Qtr4
    >>> 1945 NA 87 82 75 1946 63 50
    >>> 
    >>> 
    >>> Below please find code for 'head.ts' and 'tail.ts' that
    >>> matches 'window'.
    >>> 
    >>> 
    >>> Comments?  Spencer Graves
    >>> 
    >>> head.ts <- function(x, n=6L, ...){ tmx <-
    >>> as.numeric(time(x))
    >>> #
    >>> utils:::checkHT(n, d <- dim(x)) if(is.na(n[1]) ||
    >>> n[1]==0)ts(NULL)
    >>> #
    >>> firstn <- head(tmx, n[1]) if(is.null(d)){
    >>> return(window(x, firstn[1], tail(firstn, 1))) } else{
    >>> if(length(n)<2){ return(window(x, firstn[1],
    >>> tail(firstn, 1))) } else { Cols <- head(1:d[2], n[2])
    >>> xn2 <- x[, Cols[1]:tail(Cols, 1)] return(window(xn2,
    >>> firstn[1], tail(firstn, 1))) } } }
    >>> 
    >>> 
    >>> tail.ts <- function (x, n = 6L, ...)  {
    >>> utils:::checkHT(n, d <- dim(x)) tmx <-
    >>> as.numeric(time(x))
    >>> #
    >>> if(is.na(n[1]) || n[1]==0)ts(NULL)
    >>> #
    >>> lastn <- tail(tmx, n[1]) if(is.null(d)){
    >>> return(window(x, lastn[1], tail(lastn, 1))) } else{
    >>> if(length(n)<2){ return(window(x, lastn[1], tail(lastn,
    >>> 1))) } else { Cols <- head(1:d[2], n[2]) xn2 <- x[,
    >>> Cols[1]:tail(Cols, 1)] return(window(xn2, lastn[1],
    >>> tail(lastn, 1))) } } }
    >>> 
    >>> 
    >>> # examples head(presidents)
    >>> 
    >>> head(presidents, 2)
    >>> 
    >>> npresObs <- length(presidents) head(presidents,
    >>> 6-npresObs)
    >>> 
    >>> try(head(presidents, 1:2)) # 'try-error'
    >>> 
    >>> try(head(presidents, 0)) # 'try-error'
    >>> 
    >>> # matrix time series str(pres <-
    >>> cbind(n=1:length(presidents), presidents)) head(pres, 2)
    >>> 
    >>> head(pres, 2-npresObs)
    >>> 
    >>> head(pres, 1:2) head(pres, 2:1) head(pres, 1:3)
    >>> 
    >>> # examples tail(presidents)
    >>> 
    >>> tail(presidents, 2)
    >>> 
    >>> npresObs <- length(presidents) tail(presidents,
    >>> 6-npresObs)
    >>> 
    >>> try(tail(presidents, 1:2)) # 'try-error'
    >>> 
    >>> try(tail(presidents, 0)) # 'try-error'
    >>> 
    >>> # matrix time series str(pres <-
    >>> cbind(n=1:length(presidents), presidents)) tail(pres, 2)
    >>> 
    >>> tail(pres, 2-npresObs)
    >>> 
    >>> tail(pres, 1:2) tail(pres, 2:1) tail(pres, 1:3)
    >>> 
    >>> # for unit testing: headPres <- head(presidents) pres6
    >>> <- ts(presidents[1:6], time(presidents)[1],
    >>> frequency=frequency(presidents))
    >>> stopifnot(all.equal(headPres, pres6))
    >>> 
    >>> headPres2 <- head(presidents, 2) pres2 <-
    >>> ts(presidents[1:2], time(presidents)[1],
    >>> frequency=frequency(presidents))
    >>> stopifnot(all.equal(headPres2, pres2))
    >>> 
    >>> npresObs <- length(presidents) headPres. <-
    >>> head(presidents, 6-npresObs)
    >>> stopifnot(all.equal(headPres., pres6))
    >>> 
    >>> headPresOops <- try(head(presidents, 1:2))
    >>> stopifnot(class(headPresOops) == 'try-error')
    >>> 
    >>> headPres0 <- try(head(presidents, 0))
    >>> stopifnot(class(headPres0) == 'try-error')
    >>> 
    >>> str(pres <- cbind(n=1:length(presidents), presidents))
    >>> headP2 <- head(pres, 2)
    >>> 
    >>> p2 <- ts(pres[1:2, ], time(presidents)[1],
    >>> frequency=frequency(presidents))
    >>> stopifnot(all.equal(headP2, p2))
    >>> 
    >>> headP2. <- head(pres, 2-npresObs)
    >>> stopifnot(all.equal(headP2., p2))
    >>> 
    >>> 
    >>> #############
    >>> 
    >>> 
    >>> sessionInfo() R version 4.4.0 (2024-04-24) Platform:
    >>> aarch64-apple-darwin20 Running under: macOS Sonoma 14.5
    >>> 
    >>> Matrix products: default BLAS:
    >>> /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
    >>> 
    >>> LAPACK:
    >>> /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib;
    >>> LAPACK version 3.12.0
    >>> 
    >>> locale: [1]
    >>> en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
    >>> 
    >>> time zone: America/Chicago tzcode source: internal
    >>> 
    >>> attached base packages: [1] stats graphics grDevices
    >>> utils datasets [6] methods base
    >>> 
    >>> loaded via a namespace (and not attached): [1]
    >>> compiler_4.4.0 tools_4.4.0
    >>> 
    >>> ______________________________________________
    >>> R-devel at r-project.org mailing list
    >>> https://stat.ethz.ch/mailman/listinfo/r-devel
    >> 
    >> 
    >> 

    > ______________________________________________
    > R-devel at r-project.org mailing list
    > https://stat.ethz.ch/mailman/listinfo/r-devel
#
Hi, Martin et al.:
On 6/10/24 9:32 AM, Martin Maechler wrote:
Agreed.
The code I provided below for head.ts() and tail.ts() does that: I 
took the code for head.default and head.matrix, etc., computed tmx <- 
as.numeric(time(x)), and then used head(tmx) [and tail(tmx)] in "window()".


	  Thanks for your reply.
	  sg
#
It isn't really clear that it can't work.  This does work by inserting NA's.

  library(zoo)
  as.ts(as.zoo(lynx)[ c(1:3, 7) ] )
  ## Time Series:
  ## Start = 1821
  ## End = 1827
  ## Frequency = 1
  ## [1]  269  321  585   NA   NA   NA 3928


On Mon, Jun 10, 2024 at 10:32?AM Martin Maechler
<maechler at stat.math.ethz.ch> wrote:

  
    
1 day later
#
> Hi, Martin et al.:
> On 6/10/24 9:32 AM, Martin Maechler wrote:
>>>>>>> Spencer Graves
    >>>>>>> on Mon, 10 Jun 2024 07:50:13 -0500 writes:
    >> 
    >> > Hi, Gabor et al.: Thanks for this. I should change my
    >> > current application to use either zoo or xts, as Gabor
    >> > suggests.
    >> 
    >> 
    >> > 	  However, I was surprised to learn that "[.ts" does NOT
    >> > return an object of class "ts". I see that "head.default"
    >> > and "head.matrix" both call "[", so "head" cannot return a
    >> > ts object, because "[" doesn't.
    >> 
    >> Yes, the default head() and tail() are built on  `[` very much
    >> on purpose.
    >> Note that   `[`  should *not* keep the "ts"  property  in
    >> general, e.g.,
    >> lynx[c(1:3, 7)]
    >> cannot be a regular time series


    > Agreed.

    >> 
    >> I think I'd consider using  windows() for a head.ts() and tail.ts(),
    >> but in any case, I am sympathetic adding such methods to "base R"'s
    >> utils package.


    > The code I provided below for head.ts() and tail.ts() does that: I 
    > took the code for head.default and head.matrix, etc., computed tmx <- 
    > as.numeric(time(x)), and then used head(tmx) [and tail(tmx)] in "window()".

Indeed.  I've found that the new methods really belong to pkg
'stats' (where "ts" are), and hence renamed and exported  the internal
.checkHT(), and shence the change became somewhat more extensive:

------------------------------------------------------------------------
r86728 | maechler | 2024-06-13 10:36:51 +0200 (Thu, 13 Jun 2024) | 1 line
Changed paths:
   M doc/NEWS.Rd
   M src/library/stats/NAMESPACE
   M src/library/stats/R/ts.R
   M src/library/stats/man/ts.Rd
   M src/library/utils/NAMESPACE
   M src/library/utils/R/head.R
   M src/library/utils/man/head.Rd
   M tests/Examples/stats-Ex.Rout.save

add head() & tail() methods for "ts"(time series) ==> export .checkHT() utility
------------------------------------------------------------------------

With thanks to Spencer Graves,

Martin


    > Thanks for your reply.
    > sg
    >> 
    >> 
    >> Martin
    >> 
    >> > 	  Best Wishes, Spencer Graves
    >> 
    >>
>> > On 6/9/24 8:40 PM, Gabor Grothendieck wrote:
>> >> zoo overcomes many of the limitations of ts:
    >> >>
    >> >> library(zoo) as.ts(head(as.zoo(presidents))) ## Qtr1 Qtr2
    >> >> Qtr3 Qtr4 ## 1945 NA 87 82 75 ## 1946 63 50
    >> >>
    >> >> xts also works here.
    >> >>
    >> >> On Sun, Jun 9, 2024 at 12:04?PM Spencer Graves
>> >> <spencer.graves at prodsyse.com> wrote:
>> >>>
    >> >>> Hello, All:
    >> >>>
    >> >>>
    >> >>> The 'head' and 'tail' functions strip the time from a
    >> >>> 'ts' object.  Example:
    >> >>>
    >> >>>
    >> >>> > head(presidents) [1] NA 87 82 75 63 50
    >> >>>
    >> >>>
    >> >>> > window(presidents, 1945, 1946.25) Qtr1 Qtr2 Qtr3 Qtr4
    >> >>> 1945 NA 87 82 75 1946 63 50
    >> >>>
    >> >>>
    >> >>> Below please find code for 'head.ts' and 'tail.ts' that
    >> >>> matches 'window'.
    >> >>>
    >> >>>
    >> >>> Comments?  Spencer Graves
    >> >>>
    >> >>> head.ts <- function(x, n=6L, ...){ tmx <-
    >> >>> as.numeric(time(x))
    >> >>> #
    >> >>> utils:::checkHT(n, d <- dim(x)) if(is.na(n[1]) ||
    >> >>> n[1]==0)ts(NULL)
    >> >>> #
    >> >>> firstn <- head(tmx, n[1]) if(is.null(d)){
    >> >>> return(window(x, firstn[1], tail(firstn, 1))) } else{
    >> >>> if(length(n)<2){ return(window(x, firstn[1],
    >> >>> tail(firstn, 1))) } else { Cols <- head(1:d[2], n[2])
    >> >>> xn2 <- x[, Cols[1]:tail(Cols, 1)] return(window(xn2,
    >> >>> firstn[1], tail(firstn, 1))) } } }
    >> >>>
    >> >>>
    >> >>> tail.ts <- function (x, n = 6L, ...)  {
    >> >>> utils:::checkHT(n, d <- dim(x)) tmx <-
    >> >>> as.numeric(time(x))
    >> >>> #
    >> >>> if(is.na(n[1]) || n[1]==0)ts(NULL)
    >> >>> #
    >> >>> lastn <- tail(tmx, n[1]) if(is.null(d)){
    >> >>> return(window(x, lastn[1], tail(lastn, 1))) } else{
    >> >>> if(length(n)<2){ return(window(x, lastn[1], tail(lastn,
    >> >>> 1))) } else { Cols <- head(1:d[2], n[2]) xn2 <- x[,
    >> >>> Cols[1]:tail(Cols, 1)] return(window(xn2, lastn[1],
    >> >>> tail(lastn, 1))) } } }
    >> >>>
    >> >>>
    >> >>> # examples head(presidents)
    >> >>>
    >> >>> head(presidents, 2)
    >> >>>
    >> >>> npresObs <- length(presidents) head(presidents,
    >> >>> 6-npresObs)
    >> >>>
    >> >>> try(head(presidents, 1:2)) # 'try-error'
    >> >>>
    >> >>> try(head(presidents, 0)) # 'try-error'
    >> >>>
    >> >>> # matrix time series str(pres <-
    >> >>> cbind(n=1:length(presidents), presidents)) head(pres, 2)
    >> >>>
    >> >>> head(pres, 2-npresObs)
    >> >>>
    >> >>> head(pres, 1:2) head(pres, 2:1) head(pres, 1:3)
    >> >>>
    >> >>> # examples tail(presidents)
    >> >>>
    >> >>> tail(presidents, 2)
    >> >>>
    >> >>> npresObs <- length(presidents) tail(presidents,
    >> >>> 6-npresObs)
    >> >>>
    >> >>> try(tail(presidents, 1:2)) # 'try-error'
    >> >>>
    >> >>> try(tail(presidents, 0)) # 'try-error'
    >> >>>
    >> >>> # matrix time series str(pres <-
    >> >>> cbind(n=1:length(presidents), presidents)) tail(pres, 2)
    >> >>>
    >> >>> tail(pres, 2-npresObs)
    >> >>>
    >> >>> tail(pres, 1:2) tail(pres, 2:1) tail(pres, 1:3)
    >> >>>
    >> >>> # for unit testing: headPres <- head(presidents) pres6
    >> >>> <- ts(presidents[1:6], time(presidents)[1],
    >> >>> frequency=frequency(presidents))
    >> >>> stopifnot(all.equal(headPres, pres6))
    >> >>>
    >> >>> headPres2 <- head(presidents, 2) pres2 <-
    >> >>> ts(presidents[1:2], time(presidents)[1],
    >> >>> frequency=frequency(presidents))
    >> >>> stopifnot(all.equal(headPres2, pres2))
    >> >>>
    >> >>> npresObs <- length(presidents) headPres. <-
    >> >>> head(presidents, 6-npresObs)
    >> >>> stopifnot(all.equal(headPres., pres6))
    >> >>>
    >> >>> headPresOops <- try(head(presidents, 1:2))
    >> >>> stopifnot(class(headPresOops) == 'try-error')
    >> >>>
    >> >>> headPres0 <- try(head(presidents, 0))
    >> >>> stopifnot(class(headPres0) == 'try-error')
    >> >>>
    >> >>> str(pres <- cbind(n=1:length(presidents), presidents))
    >> >>> headP2 <- head(pres, 2)
    >> >>>
    >> >>> p2 <- ts(pres[1:2, ], time(presidents)[1],
    >> >>> frequency=frequency(presidents))
    >> >>> stopifnot(all.equal(headP2, p2))
    >> >>>
    >> >>> headP2. <- head(pres, 2-npresObs)
    >> >>> stopifnot(all.equal(headP2., p2))
    >> >>>
    >> >>>
    >> >>> #############
    >> >>>
    >> >>>
    >> >>> sessionInfo() R version 4.4.0 (2024-04-24) Platform:
    >> >>> aarch64-apple-darwin20 Running under: macOS Sonoma 14.5
    >> >>>
    >> >>> Matrix products: default BLAS:
    >> >>> /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
    >> >>>
    >> >>> LAPACK:
    >> >>> /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib;
    >> >>> LAPACK version 3.12.0
    >> >>>
    >> >>> locale: [1]
    >> >>> en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
    >> >>>
    >> >>> time zone: America/Chicago tzcode source: internal
    >> >>>
    >> >>> attached base packages: [1] stats graphics grDevices
    >> >>> utils datasets [6] methods base
    >> >>>
    >> >>> loaded via a namespace (and not attached): [1]
    >> >>> compiler_4.4.0 tools_4.4.0
    >> >>>
    >> >>> ______________________________________________
    >> >>> R-devel at r-project.org mailing list
    >> >>> https://stat.ethz.ch/mailman/listinfo/r-devel
    >> >>
    >> >>
    >> >>
    >> 
    >> > ______________________________________________
    >> > R-devel at r-project.org mailing list
    >> > https://stat.ethz.ch/mailman/listinfo/r-devel
#
> It isn't really clear that it can't work.  This does work by inserting NA's.
    > library(zoo)
    > as.ts(as.zoo(lynx)[ c(1:3, 7) ] )
    > ## Time Series:
    > ## Start = 1821
    > ## End = 1827
    > ## Frequency = 1
    > ## [1]  269  321  585   NA   NA   NA 3928

You are right,  Gabor, such an implementation of  `[.ts`
*would* make sense, too.

But given that head.ts() and tail.ts() -- slightly compactified
from Spencer's proposal,  are now simple and "robust",

I did not want to make such a "strong" change to such a basic class and its `[` operator.
(I'm not *against* it either currently, but I'm not convinced
 it's worth the effort with possible subsequent changes needed
 in code which has relied on the old behavior for > 30 years
 if you count the pre-R  S version, too.)

Best, Martin


    > On Mon, Jun 10, 2024 at 10:32?AM Martin Maechler
> <maechler at stat.math.ethz.ch> wrote:
>> 
    >> >>>>> Spencer Graves
    >> >>>>>     on Mon, 10 Jun 2024 07:50:13 -0500 writes:
    >> 
    >> > Hi, Gabor et al.: Thanks for this. I should change my
    >> > current application to use either zoo or xts, as Gabor
    >> > suggests.
    >> 
    >> 
    >> >     However, I was surprised to learn that "[.ts" does NOT
    >> > return an object of class "ts". I see that "head.default"
    >> > and "head.matrix" both call "[", so "head" cannot return a
    >> > ts object, because "[" doesn't.
    >> 
    >> Yes, the default head() and tail() are built on  `[` very much
    >> on purpose.
    >> Note that   `[`  should *not* keep the "ts"  property  in
    >> general, e.g.,
    >> lynx[c(1:3, 7)]
    >> cannot be a regular time series
    >> 
    >> I think I'd consider using  windows() for a head.ts() and tail.ts(),
    >> but in any case, I am sympathetic adding such methods to "base R"'s
    >> utils package.
    >> 
    >> 
    >> Martin
    >> 
    >> >     Best Wishes, Spencer Graves
    >> 
    >>
>> > On 6/9/24 8:40 PM, Gabor Grothendieck wrote:
>> >> zoo overcomes many of the limitations of ts:
    >> >>
    >> >> library(zoo) as.ts(head(as.zoo(presidents))) ## Qtr1 Qtr2
    >> >> Qtr3 Qtr4 ## 1945 NA 87 82 75 ## 1946 63 50
    >> >>
    >> >> xts also works here.
    >> >>
    >> >> On Sun, Jun 9, 2024 at 12:04?PM Spencer Graves
>> >> <spencer.graves at prodsyse.com> wrote:
>> >>>
    >> >>> Hello, All:
    >> >>>
    >> >>>
    >> >>> The 'head' and 'tail' functions strip the time from a
    >> >>> 'ts' object.  Example:
    >> >>>
    >> >>>
    >> >>> > head(presidents) [1] NA 87 82 75 63 50
    >> >>>
    >> >>>
    >> >>> > window(presidents, 1945, 1946.25) Qtr1 Qtr2 Qtr3 Qtr4
    >> >>> 1945 NA 87 82 75 1946 63 50
    >> >>>
    >> >>>
    >> >>> Below please find code for 'head.ts' and 'tail.ts' that
    >> >>> matches 'window'.
    >> >>>
    >> >>>
    >> >>> Comments?  Spencer Graves
    >> >>>
    >> >>> head.ts <- function(x, n=6L, ...){ tmx <-
    >> >>> as.numeric(time(x))
    >> >>> #
    >> >>> utils:::checkHT(n, d <- dim(x)) if(is.na(n[1]) ||
    >> >>> n[1]==0)ts(NULL)
    >> >>> #
    >> >>> firstn <- head(tmx, n[1]) if(is.null(d)){
    >> >>> return(window(x, firstn[1], tail(firstn, 1))) } else{
    >> >>> if(length(n)<2){ return(window(x, firstn[1],
    >> >>> tail(firstn, 1))) } else { Cols <- head(1:d[2], n[2])
    >> >>> xn2 <- x[, Cols[1]:tail(Cols, 1)] return(window(xn2,
    >> >>> firstn[1], tail(firstn, 1))) } } }
    >> >>>
    >> >>>
    >> >>> tail.ts <- function (x, n = 6L, ...)  {
    >> >>> utils:::checkHT(n, d <- dim(x)) tmx <-
    >> >>> as.numeric(time(x))
    >> >>> #
    >> >>> if(is.na(n[1]) || n[1]==0)ts(NULL)
    >> >>> #
    >> >>> lastn <- tail(tmx, n[1]) if(is.null(d)){
    >> >>> return(window(x, lastn[1], tail(lastn, 1))) } else{
    >> >>> if(length(n)<2){ return(window(x, lastn[1], tail(lastn,
    >> >>> 1))) } else { Cols <- head(1:d[2], n[2]) xn2 <- x[,
    >> >>> Cols[1]:tail(Cols, 1)] return(window(xn2, lastn[1],
    >> >>> tail(lastn, 1))) } } }
    >> >>>
    >> >>>
    >> >>> # examples head(presidents)
    >> >>>
    >> >>> head(presidents, 2)
    >> >>>
    >> >>> npresObs <- length(presidents) head(presidents,
    >> >>> 6-npresObs)
    >> >>>
    >> >>> try(head(presidents, 1:2)) # 'try-error'
    >> >>>
    >> >>> try(head(presidents, 0)) # 'try-error'
    >> >>>
    >> >>> # matrix time series str(pres <-
    >> >>> cbind(n=1:length(presidents), presidents)) head(pres, 2)
    >> >>>
    >> >>> head(pres, 2-npresObs)
    >> >>>
    >> >>> head(pres, 1:2) head(pres, 2:1) head(pres, 1:3)
    >> >>>
    >> >>> # examples tail(presidents)
    >> >>>
    >> >>> tail(presidents, 2)
    >> >>>
    >> >>> npresObs <- length(presidents) tail(presidents,
    >> >>> 6-npresObs)
    >> >>>
    >> >>> try(tail(presidents, 1:2)) # 'try-error'
    >> >>>
    >> >>> try(tail(presidents, 0)) # 'try-error'
    >> >>>
    >> >>> # matrix time series str(pres <-
    >> >>> cbind(n=1:length(presidents), presidents)) tail(pres, 2)
    >> >>>
    >> >>> tail(pres, 2-npresObs)
    >> >>>
    >> >>> tail(pres, 1:2) tail(pres, 2:1) tail(pres, 1:3)
    >> >>>
    >> >>> # for unit testing: headPres <- head(presidents) pres6
    >> >>> <- ts(presidents[1:6], time(presidents)[1],
    >> >>> frequency=frequency(presidents))
    >> >>> stopifnot(all.equal(headPres, pres6))
    >> >>>
    >> >>> headPres2 <- head(presidents, 2) pres2 <-
    >> >>> ts(presidents[1:2], time(presidents)[1],
    >> >>> frequency=frequency(presidents))
    >> >>> stopifnot(all.equal(headPres2, pres2))
    >> >>>
    >> >>> npresObs <- length(presidents) headPres. <-
    >> >>> head(presidents, 6-npresObs)
    >> >>> stopifnot(all.equal(headPres., pres6))
    >> >>>
    >> >>> headPresOops <- try(head(presidents, 1:2))
    >> >>> stopifnot(class(headPresOops) == 'try-error')
    >> >>>
    >> >>> headPres0 <- try(head(presidents, 0))
    >> >>> stopifnot(class(headPres0) == 'try-error')
    >> >>>
    >> >>> str(pres <- cbind(n=1:length(presidents), presidents))
    >> >>> headP2 <- head(pres, 2)
    >> >>>
    >> >>> p2 <- ts(pres[1:2, ], time(presidents)[1],
    >> >>> frequency=frequency(presidents))
    >> >>> stopifnot(all.equal(headP2, p2))
    >> >>>
    >> >>> headP2. <- head(pres, 2-npresObs)
    >> >>> stopifnot(all.equal(headP2., p2))
    >> >>>
    >> >>>
    >> >>> #############
    >> >>>
    >> >>>
    >> >>> sessionInfo() R version 4.4.0 (2024-04-24) Platform:
    >> >>> aarch64-apple-darwin20 Running under: macOS Sonoma 14.5
    >> >>>
    >> >>> Matrix products: default BLAS:
    >> >>> /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
    >> >>>
    >> >>> LAPACK:
    >> >>> /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/lib/libRlapack.dylib;
    >> >>> LAPACK version 3.12.0
    >> >>>
    >> >>> locale: [1]
    >> >>> en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
    >> >>>
    >> >>> time zone: America/Chicago tzcode source: internal
    >> >>>
    >> >>> attached base packages: [1] stats graphics grDevices
    >> >>> utils datasets [6] methods base
    >> >>>
    >> >>> loaded via a namespace (and not attached): [1]
    >> >>> compiler_4.4.0 tools_4.4.0
    >> >>>
    >> >>> ______________________________________________
    >> >>> R-devel at r-project.org mailing list
    >> >>> https://stat.ethz.ch/mailman/listinfo/r-devel
    >> >>
    >> >>
    >> >>
    >> 
    >> > ______________________________________________
    >> > R-devel at r-project.org mailing list
    >> > https://stat.ethz.ch/mailman/listinfo/r-devel



    > -- 
    > Statistics & Software Consulting
    > GKX Group, GKX Associates Inc.
    > tel: 1-877-GKX-GROUP
    > email: ggrothendieck at gmail.com