data.table内赋值lubridate的fast_strptime结果触发长度不匹配报错
问题复现
先构造测试用data.table对象:
library(data.table) library(lubridate) df <- data.table(a = c('2022-01-20', '2022-01-21')) df
控制台输出:
a 1: 2022-01-20 2: 2022-01-21
直接对列向量调用fast_strptime()可以得到预期的日期时间结果:
fast_strptime(df$a, "%Y-%m-%d")
控制台输出:
[1] "2022-01-20 UTC" "2022-01-21 UTC"
但在data.table的:=更新语法中直接赋值会触发报错:
df[, a := fast_strptime(a, "%Y-%m-%d") ]
完整报错信息:
Error in `[.data.table`(df, , `:=`(a, fast_strptime(a, "%Y-%m-%d"))) : Supplied 9 items to be assigned to 2 items of column 'a'. If you wish to 'recycle' the RHS please use rep() to make this intent clear to readers of your code.
报错字面含义为:目标列a只有2行,但赋值输入了9个元素,若需要循环填充请显式调用rep()说明意图。
报错根因
fast_strptime()默认返回POSIXlt类型对象,这类对象本质是长度为9的列表,9个元素分别对应秒、分、时、月内日期、月份、年份、周内日序、年内日序、夏令时标记字段,不是和行数等长的原子向量。data.table执行:=赋值时会校验右侧输入的长度,直接传入POSIXlt对象会被判定为长度9的列表输入,和目标列2行的长度不匹配,因此抛出错误。单独在全局环境调用fast_strptime()时,控制台的打印方法会把POSIXlt列表渲染为熟悉的日期时间字符串,视觉上看起来是长度2的向量,很容易造成误判。
解决方法
两种方案都可以正常运行,按需选择即可:
- 方案1:显式将
fast_strptime返回的POSIXlt对象转换为data.table兼容的POSIXct原子向量类型:
df[, a := as.POSIXct(fast_strptime(a, "%Y-%m-%d"))]
- 方案2:直接使用lubridate包中默认返回POSIXct类型的解析函数,无需手动做类型转换,代码更简洁。针对
%Y-%m-%d格式的日期字符串,直接用ymd()即可自动识别解析:
df[, a := ymd(a)]
两种方式运行后都可以正确将字符列更新为日期时间类型,不会触发长度不匹配的报错。
内容的提问来源于stack exchange,提问作者Sweepy Dodo
相关产品推荐
相关产品推荐

