如何创建POSIXct矩阵

tho*_*asw 2 r matrix posixct

当我在R 3.1.2中创建给定POSIXct向量的矩阵时,矩阵的条目是数字而不是POSIXct:

x <- as.POSIXct("2012-02-25 19:00:00")
x
attributes(x)

m <- matrix(x, nrow=2, ncol=3)
m
attributes(m)
Run Code Online (Sandbox Code Playgroud)

创建POSIXct值矩阵的最佳方法是什么?

bgo*_*dst 9

我不认为我曾经见过有人在创建POSIXct值的矩阵之前,虽然不难想象这样一个对象的用例.

R似乎不太支持这种类型的对象.S3对象系统非常有限,并且创建POSIXct矩阵需要设置矩阵和POSIXct(以及POSIXt,它似乎总是与POSIXct一起标记)S3类.事实上,根据我的经验,任何对象都可以从多个显式S3类继承,这可能与POSIXct + POSIXt和POSIXlt + POSIXt的情况不同.

我已经通过创建一个新的矩阵构造函数来试图填充这种类型的对象matrix.POSIXct().为方便起见,为了提供S3调度,我还创建了一个新的泛型matrix()和默认matrix.default()委托给普通的base::matrix().请注意,这种通用化matrix()有时由R软件包完成,例如gmp.他们将通用化功能限制在他们的包环境中,但我只是将这些功能转储到全局环境中.

不幸的是,默认的POSIXct打印功能print.POSIXct()不够智能,无法处理也被归类为矩阵的POSIXct向量,因此任何此类矩阵都将打印为普通的旧向量.为了解决这个问题,我还创建了一个新print.POSIXct()函数,它拦截任何POSIXct类对象的打印并检查它是否也被归类为矩阵,在这种情况下,为了提供一个合理的实现,只需要很少的工作,我构建了一个新的矩阵,数据值由POSIXct值的字符表示组成,然后我打印该矩阵.如果它没有被归类为矩阵,我只需将参数传递给普通base::print.POSIXct()函数来打印普通的旧矩阵POSIXct向量.

我试图尽可能地遵循base::matrix()关于默认缺失论点的设计matrix.POSIXct().

matrix <- function(x,...) UseMethod('matrix');
matrix.default <- function(...) base::matrix(...);

matrix.POSIXct <- function(data=NA,nrow,ncol,byrow=F,dimnames=NULL,...) {
    if (missing(nrow)) {
        if (missing(ncol)) {
            nrow <- length(data);
            ncol <- 1L;
        } else {
            nrow <- ceiling(length(data)/ncol);
        }; ## end if
    } else {
        if (missing(ncol))
            ncol <- ceiling(length(data)/nrow);
    }; ## end if
    data <- rep(as.POSIXct(data,tz=attr(data,'tzone'),...),len=nrow*ncol);
    if (byrow) {
        dim(data) <- c(ncol,nrow);
        data <- t(data);
    } else
        dim(data) <- c(nrow,ncol);
    if (!is.null(dimnames))
        base::dimnames(data) <- dimnames;
    class(data) <- c(class(data),'matrix');
    data;
}; ## end matrix.POSIXct()

print.POSIXct <- function(x,...) {
    if (inherits(x,'matrix') && !is.null(nrow(x))) {
        print(matrix(as.character(x,usetz=T),nrow(x),dimnames=dimnames(x)),...);
        invisible(x);
    } else
        base::print.POSIXct(x,...);
}; ## end print.POSIXct()
Run Code Online (Sandbox Code Playgroud)

演示您的数据:

x <- as.POSIXct('2012-02-25 19:00:00');
m <- matrix(x,2L,3L);
m;
##      [,1]                      [,2]                      [,3]
## [1,] "2012-02-25 19:00:00 EST" "2012-02-25 19:00:00 EST" "2012-02-25 19:00:00 EST"
## [2,] "2012-02-25 19:00:00 EST" "2012-02-25 19:00:00 EST" "2012-02-25 19:00:00 EST"
attributes(m);
## $class
## [1] "POSIXct" "POSIXt"  "matrix"
##
## $tzone
## [1] ""
##
## $dim
## [1] 2 3
Run Code Online (Sandbox Code Playgroud)

这是一个format.POSIXct():

format.POSIXct <- function(x,...) {
    if (inherits(x,'matrix') && !is.null(nrow(x)))
        matrix(base::format.POSIXct(x,...),nrow(x),dimnames=dimnames(x))
    else
        base::format.POSIXct(x,...);
}; ## end format.POSIXct()
Run Code Online (Sandbox Code Playgroud)

对,忘记了索引.这是另一个有问题的案例.默认base::`[.POSIXct`()索引函数有点便宜(有点像上面的一些我的填充代码,不可否认),它只是暂时删除向量的类,将其传递给下一个特定的S3,然后恢复原始类.这意味着drop遵循矩阵的参数,如果设置为TRUE(默认值)并且下标使得矩阵性被删除,则意味着dim从返回的对象中删除该属性.

问题是廉价包装器中的类恢复会恢复我们的矩阵类,因此,当便宜的包装器返回时,我们会收到一个没有dim属性的矩阵类对象.

我们遇到的确切错误print.POSIXct(),当我们尝试打印子集向量时,实际上是由垫片发出的("在选择函数'print'的方法时评估参数'x'时出错:base :: matrix中的错误(...):非数字矩阵范围")是由nrow(x)返回NULL 引起的,因此matrix()调用接收nrow = NULL.

我已经做了两件事来解决这个问题.首先,我改进了print.POSIXct()函数以防止nrow(x)返回NULL 的情况,在这种情况下,它毕竟不会将对象作为矩阵处理.因此,如果它接收到没有dim属性的矩阵分类对象(虽然这不应该发生),它会将其打印为普通的旧POSIXct向量.

其次,我编写了另一个索引函数来检测dim属性的删除,并在此情况下删除矩阵类.

由于廉价包装器用于NextMethod()调用下一个S3特定的事实,这个新函数的创建变得复杂,如果从直接调用的调用调用它,则无效,独立于S3调度过程.因此,正如您在下面的代码中所看到的,我使用了一些hack来将廉价包装器的主体"插入"到我们的shim函数中,从而将NextMethod()调用移动到我们的垫片中,因此必须通过泛型调用`[`()(照常):

`[.POSIXct` <- function(x,...) {
    res <- blah;
    if (inherits(x,'matrix') && !'dim'%in%names(attributes(res)))
        class(res) <- class(res)[class(res)!='matrix'];
    res;
};
body(`[.POSIXct`)[[2]][[3]] <- body(base::`[.POSIXct`);
Run Code Online (Sandbox Code Playgroud)

演示:

x <- as.POSIXct('2016-02-05 00:00:00')+0:8;
m <- matrix(x,3L,byrow=T);
m;
##      [,1]                      [,2]                      [,3]
## [1,] "2016-02-05 00:00:00 EST" "2016-02-05 00:00:01 EST" "2016-02-05 00:00:02 EST"
## [2,] "2016-02-05 00:00:03 EST" "2016-02-05 00:00:04 EST" "2016-02-05 00:00:05 EST"
## [3,] "2016-02-05 00:00:06 EST" "2016-02-05 00:00:07 EST" "2016-02-05 00:00:08 EST"
m[1];
## [1] "2016-02-05 EST"
m[1:3];
## [1] "2016-02-05 00:00:00 EST" "2016-02-05 00:00:03 EST" "2016-02-05 00:00:06 EST"
m[1:3,1];
## [1] "2016-02-05 00:00:00 EST" "2016-02-05 00:00:03 EST" "2016-02-05 00:00:06 EST"
m[1:3,1,drop=F];
##      [,1]
## [1,] "2016-02-05 00:00:00 EST"
## [2,] "2016-02-05 00:00:03 EST"
## [3,] "2016-02-05 00:00:06 EST"
m[1:3,1:2];
##      [,1]                      [,2]
## [1,] "2016-02-05 00:00:00 EST" "2016-02-05 00:00:01 EST"
## [2,] "2016-02-05 00:00:03 EST" "2016-02-05 00:00:04 EST"
## [3,] "2016-02-05 00:00:06 EST" "2016-02-05 00:00:07 EST"
Run Code Online (Sandbox Code Playgroud)

这是一个as.data.frame.POSIXct():

as.data.frame.POSIXct <- function(x,...) {
    if (inherits(x,'matrix') && !is.null(dim(x))) {
        class(x) <- class(x)[!class(x)%in%c('POSIXct','POSIXt')];
        res <- as.data.frame(x,...);
        for (ci in seq_along(res))
            res[[ci]] <- as.POSIXct(res[[ci]],tz=attr(x,'tzone'),origin='1970-01-01');
        res;
    } else
        base::as.data.frame.POSIXct(x,...);
}; ## end as.data.frame.POSIXct()
Run Code Online (Sandbox Code Playgroud)

演示:

m <- matrix(as.POSIXct('2016-02-05 00:00:00')+0:8,3);
m;
##      [,1]                      [,2]                      [,3]
## [1,] "2016-02-05 00:00:00 EST" "2016-02-05 00:00:03 EST" "2016-02-05 00:00:06 EST"
## [2,] "2016-02-05 00:00:01 EST" "2016-02-05 00:00:04 EST" "2016-02-05 00:00:07 EST"
## [3,] "2016-02-05 00:00:02 EST" "2016-02-05 00:00:05 EST" "2016-02-05 00:00:08 EST"
as.data.frame(m);
##                    V1                  V2                  V3
## 1 2016-02-05 00:00:00 2016-02-05 00:00:03 2016-02-05 00:00:06
## 2 2016-02-05 00:00:01 2016-02-05 00:00:04 2016-02-05 00:00:07
## 3 2016-02-05 00:00:02 2016-02-05 00:00:05 2016-02-05 00:00:08
Run Code Online (Sandbox Code Playgroud)

这是一个summary.POSIXct():

summary.POSIXct <- function(x,...) {
    if (inherits(x,'matrix') && !is.null(dim(x)))
        summary(as.data.frame(x),...)
    else
        base::summary.POSIXct(x,...);
}; ## end summary.POSIXct()
Run Code Online (Sandbox Code Playgroud)

  • 这是非常好的,虽然其他一些方法,例如`format`,`difftime`,...,需要进行调整才能真正发挥作用. (3认同)