在R中,我试图读取具有时间戳的文件,并根据另一个字段的条件更新时间戳。下面的代码没有问题:
t <- data.frame(user = as.character(c("bshelton@email1.com", "lwong@email1.com")),
last_update = rep(as.POSIXlt(Sys.time(), tz = "America/Los_Angeles"), 2))
Sys.sleep(5)
t$last_update <- as.POSIXlt(ifelse(t$user == "bshelton@email1.com", Sys.time(), t$last_update), origin = "1970-01-01")
print(t)问题在于,当我读取一个现有文件并尝试动态地更改一个as.POSIXlt 值时,下面的代码会产生一个错误,该错误随后会出现在代码块中:
t <- data.frame(user = as.character(c("bshelton@email1.com", "lwong2@email1.com")),
last_update = rep(as.POSIXlt(Sys.time(), tz = "America/Los_Angeles"), 2))
write.csv(t, "so_question.csv", row.names = FALSE)
t <- read.csv("so_question.csv")
t$last_update <- as.POSIXlt(t$last_update)
Sys.sleep(5)
t$last_update <- as.POSIXlt(ifelse(t$user == "bshelton@email1.com", Sys.time(), t$last_update), origin = "1970-01-01") Error in as.POSIXlt.default(ifelse(t$user == "bshelton@email1.com", Sys.time(), :
do not know how to convert 'ifelse(t$user == "bshelton@email1.com", Sys.time(), t$last_update)' to class “POSIXlt”
In addition: Warning message:
In ans[!test & ok] <- rep(no, length.out = length(ans))[!test & :
number of items to replace is not a multiple of replacement length发布于 2019-07-29 04:12:22
奇怪的是,第一种情况之所以起作用是因为你没有你所想的--那些约会时间实际上是POSIXct,而不是POSIXlt:
last_update <- rep(as.POSIXlt(Sys.time(), tz = "America/Los_Angeles"), 2)
str(last_update)
#> POSIXlt[1:2], format: "2019-07-28 20:52:10" "2019-07-28 20:52:10"
t <- data.frame(user = as.character(c("bshelton@email1.com", "lwong@email1.com")),
last_update = last_update)
str(t)
#> 'data.frame': 2 obs. of 2 variables:
#> $ user : Factor w/ 2 levels "bshelton@email1.com",..: 1 2
#> $ last_update: POSIXct, format: "2019-07-28 20:52:10" "2019-07-28 20:52:10"如果你钻研?data.frame,上面写着
data.frame通过调用as.data.frame(optional = TRUE)将其每个参数转换为数据框架。因为这是一个泛型函数,所以可以编写方法来根据它们的类来改变参数的行为:r附带了许多这样的方法。传递给data.frame的字符变量被转换为因子列,除非受到I或参数stringsAsFactors的保护是假的。如果一个列表、数据帧或矩阵被传递给data.frame,那就好像每个组件或列都作为一个单独的参数被传递了一样(I保护的矩阵除外)。
这就是正在发生的事情:实际上,as.data.frame.POSIXlt转换为POSIXct:
now <- Sys.time()
str(now)
#> POSIXct[1:1], format: "2019-07-28 22:50:12"
str(data.frame(time = now))
#> 'data.frame': 1 obs. of 1 variable:
#> $ time: POSIXct, format: "2019-07-28 22:50:12"
as.data.frame.POSIXlt
#> function (x, row.names = NULL, optional = FALSE, ...)
#> {
#> value <- as.data.frame.POSIXct(as.POSIXct(x), row.names,
#> optional, ...)
#> if (!optional)
#> names(value) <- deparse(substitute(x))[[1L]]
#> value
#> }
#> <bytecode: 0x7fc938a11060>
#> <environment: namespace:base>更直接的是,因为Sys.time()返回一个POSIXct对象,所以在第二种情况下,ifelse(t$user == "bshelton@email1.com", Sys.time(), t$last_update)是为一个观察对象获取一个POSIXct对象,而对于另一个观察则是一个POSIXlt。POSIXlt对象的class属性被ifelse删除,显示下面的列表,ifelse不知道如何与未分类的POSIXct对象(只是一个数字)一起转换为向量。
因此,这里的解决方案是遵循data.frame给您的提示,使用POSIXct而不是POSIXlt。
如果您真的想让它与POSIXlt一起工作,您可以使用if/else来迭代条件和使用Map的POSIXlt向量(后者维护属性,包括类,但只处理标量条件),并将结果列表强制返回到带有do.call(c, ...)的向量中。
t <- data.frame(user = as.character(c("bshelton@email1.com", "lwong@email1.com")),
last_update = rep(as.POSIXlt(Sys.time(), tz = "America/Los_Angeles"), 2))
t$last_update <- as.POSIXlt(t$last_update)
t$last_update <- do.call(c, Map(
function(condition, last_update){
if (condition) {
as.POSIXlt(Sys.time() + 5)
} else {
last_update
}
},
condition = t$user == "bshelton@email1.com",
last_update = t$last_update
))
t
#> user last_update
#> 1 bshelton@email1.com 2019-07-28 23:11:04
#> 2 lwong@email1.com 2019-07-28 23:10:59...but,坦白说,这有点傻。只要使用POSIXct,你的生活就会更好。
https://stackoverflow.com/questions/57246739
复制相似问题