当我在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值矩阵的最佳方法是什么?
我不认为我曾经见过有人在创建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)