我惊讶地发现R中有以下行为:
as.character(c(Sys.Date()))
#> [1] "2018-02-05"
as.character(list(Sys.Date()))
#> [1] "17567"
Run Code Online (Sandbox Code Playgroud)
为什么会这样?也就是说,显然"17567"是结果as.integer(Sys.Date),但我没有遵循为什么as.character(list(Sys.Date()))应该最终调用的逻辑as.integer().
(通常将字符串视为整数可归咎于未设置
options(stringsAsFactors=FALSE),但这似乎不是这种情况.)
编辑:正如乔希所说,这是由于as.vector的基本行为,但我没有发现更直观:
as.vector(Sys.Date())
#> 17567
as.vector(Sys.Date(), "character")
#> "17567"
Run Code Online (Sandbox Code Playgroud)
为什么?(是的,我相信日期在较低级别的内部存储为整数,但在这种情况下,这种强制到一个字面整数而没有警告似乎让我感到惊讶).
这也体现在更微妙的方式:
tbl <- tibble:::as_data_frame(list(col1 = list(Sys.Date(), "stuff")))
df <- as.data.frame(tbl)
df
#> col1
#> 1 17567
#> 2 stuff
df[1, 1]
#> [[1]]
#> [1] "2018-02-05"
Run Code Online (Sandbox Code Playgroud)
请注意,print方法data.frame将日期显示为整数,实际上它是一个列表列,日期仍然是日期.
目前还不清楚在这种情况下打印方法是怎么回事,以及它为什么会显示这种误导性的数据表示.
编辑:
Date类令人惊讶地脱落的其他示例,暴露了基础数字基类型:
vapply(list(Sys.Date()), I, Sys.Date())
vapply(list(Sys.Date()), lubridate::as_date, Sys.Date())
Run Code Online (Sandbox Code Playgroud)
到目前为止我最喜欢的:
unlist(list(Sys.Date()))
Run Code Online (Sandbox Code Playgroud)
似乎带Date(和POSIX对象)的向量操作是脆弱的; 一个人应该专注于mode/ typeof而不是class预测矢量将如何表现.
Jos*_*ien 13
问题最终与函数的行为有关as.vector().
当您应用于as.character()列表时,它会看到类的对象"list"(不是类的对象"Date").由于没有as.character()列表方法,因此as.character.default将调度默认方法.它做了以下事情:
as.character.default
# function (x, ...)
# .Internal(as.vector(x, "character"))
# <bytecode: 0x0000000006793e88>
# <environment: namespace:base>
Run Code Online (Sandbox Code Playgroud)
如您所见,它首先通过将数据对象强制转换为向量来准备数据对象.as.vector()直接在Date对象列表上运行,反过来显示它是产生整数然后到字符的强制.
as.vector(list(Sys.Date()), "character")
# [1] "17567"
Run Code Online (Sandbox Code Playgroud)
正如卡尔指出的那样,上面的解释,即使是准确的,也并不令人满意.更完整的答案需要在调用执行的C代码中查看引擎盖下发生的情况.Internal(as.vector(x, "character")).所有相关的C代码都在源文件coerce.c中.
首先是do_asvector()哪个调用ascommon()调用coerceVector()哪个调用coerceVectorList()然后最后调用coerceToString().coerceToString() 检查它正在处理的元素的"typeof",在我们的例子中,看到它是一个"REAL"切换到这个代码块:
case REALSXP:
PrintDefaults();
savedigits = R_print.digits; R_print.digits = DBL_DIG;/* MAX precision */
for (i = 0; i < n; i++) {
// if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt();
SET_STRING_ELT(ans, i, StringFromReal(REAL(v)[i], &warn));
}
R_print.digits = savedigits;
break;
Run Code Online (Sandbox Code Playgroud)
为什么它将块用于具有typeof的对象REALSXP?因为那是R Date对象的存储模式(通过做mode(Sys.Date())或可以看出typeof(Sys.Date())).
带回家是这样的:在上面描述的事件链中,在"Date"R函数调用和方法调度领域中,列表的元素不会以某种方式被捕获并被视为对象.相反,它们作为"list"(又名VECSXP)传递给一系列C函数.在那一点上,它太迟了,因为处理该列表的C函数"Date"对其元素的类一无所知.特别是,最终执行转换为字符的功能,coerceToCharacter()只看到的元素存储模式,这是REAL /数字/双,并对其进行处理,就好像这是所有,他们.