如何在不丢失日期格式的情况下将日期从一个变量复制到 R data.table 中的另一个变量?
How do I copy a date from one variable to another in R data.table without losing the date format?
我有一个包含两个日期变量的 data.table。数据集从 .csv 文件(最初是 .xlsx 文件)作为 data.frame 读入 R,然后使用 as.Date() 将两个变量转换为日期格式,以便它们显示如下:
df
id specdate recdate
1 1 2014-08-12 2014-08-17
2 2 2014-08-15 2014-08-20
3 3 2014-08-21 2014-08-26
4 4 <NA> 2014-08-28
5 5 2014-08-25 2014-08-30
6 6 <NA> <NA>
然后我将 data.frame 转换为 data.table:
df <- data.table(df)
然后我想创建第三个变量,如果存在 "specdate",它将包含 "specdate",但如果缺少 "specdate",则将其替换为 "recdate" (NA)。这是我遇到一些困难的地方,因为似乎无论我如何处理,data.table 仅在复制已经采用日期格式的完整变量时才以日期格式显示日期。否则,单个值将显示为数字(即使使用 as.IDate),我认为需要一个原始日期来更正此问题。有什么方法可以避免提供起始日期,而是将日期显示为 data.table?
中的日期
下面是我尝试用 recdate 日期填充 specdate 的 NAs:
# Function to fill NAs:
fillnas <- function(dataref, lookupref, nacol, replacecol, replacelist=NULL) {
nacol <- as.character(nacol)
if(!is.null(replacelist)) nacol <- factor(ifelse(dataref==lookupref & (is.na(nacol) | nacol %in% replacelist), replacecol, nacol))
else nacol <- factor(ifelse(dataref==lookupref & is.na(nacol), replacecol, nacol))
nacol
}
# Fill the NAs in specdate with the function:
df[, finaldate := fillnas(dataref=id, lookupref=id, nacol=specdate, replacecol=as.IDate(recdate, format="%Y-%m-%d"))]
事情是这样的:
> df
id specdate recdate finaldate
1: 1 2014-08-12 2014-08-17 2014-08-12
2: 2 2014-08-15 2014-08-20 2014-08-15
3: 3 2014-08-21 2014-08-26 2014-08-21
4: 4 <NA> 2014-08-28 16310
5: 5 2014-08-25 2014-08-30 2014-08-25
6: 6 <NA> <NA> NA
如果我使用 ifelse 从头开始创建新变量,显示问题会更加复杂:
df[, finaldate := ifelse(!is.na(specdate), specdate, recdate)]
这给出:
> df
id specdate recdate finaldate
1: 1 2014-08-12 2014-08-17 16294
2: 2 2014-08-15 2014-08-20 16297
3: 3 2014-08-21 2014-08-26 16303
4: 4 <NA> 2014-08-28 16310
5: 5 2014-08-25 2014-08-30 16307
6: 6 <NA> <NA> NA
或者,如果我尝试查找和替换类型的方法,我会收到有关要替换的项目数量与替换长度不匹配的错误(我猜这是因为该方法未矢量化?), recdate 中的值被回收并最终出现在错误的位置:
> df$finaldate <- df$specdate
> df$finaldate[is.na(df$specdate)] <- df$recdate
Warning message:
In NextMethod(.Generic) :
number of items to replace is not a multiple of replacement length
> df
id specdate recdate finaldate
1: 1 2014-08-12 2014-08-17 2014-08-12
2: 2 2014-08-15 2014-08-20 2014-08-15
3: 3 2014-08-21 2014-08-26 2014-08-21
4: 4 <NA> 2014-08-28 2014-08-17
5: 5 2014-08-25 2014-08-30 2014-08-25
6: 6 <NA> <NA> 2014-08-20
所以总而言之 - 我应用的函数使我最接近我想要的,除了 NA 被替换的地方,替换值显示为数字而不是日期格式。一旦显示为数字,原点就需要再次将其显示为日期(我想避免提供原点,因为我通常不知道它,而且在最初的日期时必须提供它似乎是不必要的重复格式正确)。
任何关于我哪里出错的见解都将不胜感激。
适合我。您可能需要测试以确保您的 NA 值不是字符串或因子 "<NA>"
;它们看起来像真实的 NA
值:
dt[, finaldate := ifelse(is.na(specdate), recdate, specdate)][
,finaldate := as.POSIXct(finaldate*86400, origin="1970-01-01", tz="UTC")]
# id specdate recdate finaldate
# 1: 1 2014-08-12 2014-08-17 2014-08-12
# 2: 2 2014-08-15 2014-08-20 2014-08-15
# 3: 3 2014-08-21 2014-08-26 2014-08-21
# 4: 4 NA 2014-08-28 2014-08-28
# 5: 5 2014-08-25 2014-08-30 2014-08-25
# 6: 6 NA NA NA
数据
df <- read.table(text=" id specdate recdate
1 1 2014-08-12 2014-08-17
2 2 2014-08-15 2014-08-20
3 3 2014-08-21 2014-08-26
4 4 NA 2014-08-28
5 5 2014-08-25 2014-08-30
6 6 NA NA", header=T, stringsAsFactors=F)
dt <- as.data.table(df)
我会这样处理,也许 :
DT <- data.table(df)
DT[, finaldate := specdata]
DT[is.na(specdata), finaldate := recdate]
您似乎想添加一个新列,这样您也可以保留原来的列。我也经常这样做。有时,我只是原地更新 :
DT <- data.table(df)
DT[!is.na(specdate), specdate:=recdate]
setnames(DT, "specdate", "finaldate")
像这样使用 i
可以避免创建可能非常大的全新列的数据价值。取决于保留原始列对您有多重要,它们有多少以及您的数据大小。 (请注意,整个列的数据价值仍然由 is.na()
调用创建,然后由 !
再次创建,但至少新的 finaldate
没有第三列的价值。会很高兴在将来优化 i=!is.na()
(#1386),如果您现在以这种方式使用 data.table,您将来无需更改代码即可受益。)
您可能有多个要替换的 "NA" 字符串。请注意,CRAN 上的 v1.9.6 中的 fread 对此进行了修复。来自 README :
- correctly handles na.strings argument for all types of columns - it detect possible NA values without coercion to character, like in base read.table. fixes #504. Thanks to @dselivanov for the PR. Also closes #1314, which closes this issue completely, i.e., na.strings = c("-999", "FALSE") etc. also work.
顺便说一句,您犯了这里提到的前 3 个错误之一:https://github.com/Rdatatable/data.table/wiki/Support
我有一个包含两个日期变量的 data.table。数据集从 .csv 文件(最初是 .xlsx 文件)作为 data.frame 读入 R,然后使用 as.Date() 将两个变量转换为日期格式,以便它们显示如下:
df
id specdate recdate
1 1 2014-08-12 2014-08-17
2 2 2014-08-15 2014-08-20
3 3 2014-08-21 2014-08-26
4 4 <NA> 2014-08-28
5 5 2014-08-25 2014-08-30
6 6 <NA> <NA>
然后我将 data.frame 转换为 data.table:
df <- data.table(df)
然后我想创建第三个变量,如果存在 "specdate",它将包含 "specdate",但如果缺少 "specdate",则将其替换为 "recdate" (NA)。这是我遇到一些困难的地方,因为似乎无论我如何处理,data.table 仅在复制已经采用日期格式的完整变量时才以日期格式显示日期。否则,单个值将显示为数字(即使使用 as.IDate),我认为需要一个原始日期来更正此问题。有什么方法可以避免提供起始日期,而是将日期显示为 data.table?
中的日期下面是我尝试用 recdate 日期填充 specdate 的 NAs:
# Function to fill NAs:
fillnas <- function(dataref, lookupref, nacol, replacecol, replacelist=NULL) {
nacol <- as.character(nacol)
if(!is.null(replacelist)) nacol <- factor(ifelse(dataref==lookupref & (is.na(nacol) | nacol %in% replacelist), replacecol, nacol))
else nacol <- factor(ifelse(dataref==lookupref & is.na(nacol), replacecol, nacol))
nacol
}
# Fill the NAs in specdate with the function:
df[, finaldate := fillnas(dataref=id, lookupref=id, nacol=specdate, replacecol=as.IDate(recdate, format="%Y-%m-%d"))]
事情是这样的:
> df
id specdate recdate finaldate
1: 1 2014-08-12 2014-08-17 2014-08-12
2: 2 2014-08-15 2014-08-20 2014-08-15
3: 3 2014-08-21 2014-08-26 2014-08-21
4: 4 <NA> 2014-08-28 16310
5: 5 2014-08-25 2014-08-30 2014-08-25
6: 6 <NA> <NA> NA
如果我使用 ifelse 从头开始创建新变量,显示问题会更加复杂:
df[, finaldate := ifelse(!is.na(specdate), specdate, recdate)]
这给出:
> df
id specdate recdate finaldate
1: 1 2014-08-12 2014-08-17 16294
2: 2 2014-08-15 2014-08-20 16297
3: 3 2014-08-21 2014-08-26 16303
4: 4 <NA> 2014-08-28 16310
5: 5 2014-08-25 2014-08-30 16307
6: 6 <NA> <NA> NA
或者,如果我尝试查找和替换类型的方法,我会收到有关要替换的项目数量与替换长度不匹配的错误(我猜这是因为该方法未矢量化?), recdate 中的值被回收并最终出现在错误的位置:
> df$finaldate <- df$specdate
> df$finaldate[is.na(df$specdate)] <- df$recdate
Warning message:
In NextMethod(.Generic) :
number of items to replace is not a multiple of replacement length
> df
id specdate recdate finaldate
1: 1 2014-08-12 2014-08-17 2014-08-12
2: 2 2014-08-15 2014-08-20 2014-08-15
3: 3 2014-08-21 2014-08-26 2014-08-21
4: 4 <NA> 2014-08-28 2014-08-17
5: 5 2014-08-25 2014-08-30 2014-08-25
6: 6 <NA> <NA> 2014-08-20
所以总而言之 - 我应用的函数使我最接近我想要的,除了 NA 被替换的地方,替换值显示为数字而不是日期格式。一旦显示为数字,原点就需要再次将其显示为日期(我想避免提供原点,因为我通常不知道它,而且在最初的日期时必须提供它似乎是不必要的重复格式正确)。
任何关于我哪里出错的见解都将不胜感激。
适合我。您可能需要测试以确保您的 NA 值不是字符串或因子 "<NA>"
;它们看起来像真实的 NA
值:
dt[, finaldate := ifelse(is.na(specdate), recdate, specdate)][
,finaldate := as.POSIXct(finaldate*86400, origin="1970-01-01", tz="UTC")]
# id specdate recdate finaldate
# 1: 1 2014-08-12 2014-08-17 2014-08-12
# 2: 2 2014-08-15 2014-08-20 2014-08-15
# 3: 3 2014-08-21 2014-08-26 2014-08-21
# 4: 4 NA 2014-08-28 2014-08-28
# 5: 5 2014-08-25 2014-08-30 2014-08-25
# 6: 6 NA NA NA
数据
df <- read.table(text=" id specdate recdate
1 1 2014-08-12 2014-08-17
2 2 2014-08-15 2014-08-20
3 3 2014-08-21 2014-08-26
4 4 NA 2014-08-28
5 5 2014-08-25 2014-08-30
6 6 NA NA", header=T, stringsAsFactors=F)
dt <- as.data.table(df)
我会这样处理,也许 :
DT <- data.table(df)
DT[, finaldate := specdata]
DT[is.na(specdata), finaldate := recdate]
您似乎想添加一个新列,这样您也可以保留原来的列。我也经常这样做。有时,我只是原地更新 :
DT <- data.table(df)
DT[!is.na(specdate), specdate:=recdate]
setnames(DT, "specdate", "finaldate")
像这样使用 i
可以避免创建可能非常大的全新列的数据价值。取决于保留原始列对您有多重要,它们有多少以及您的数据大小。 (请注意,整个列的数据价值仍然由 is.na()
调用创建,然后由 !
再次创建,但至少新的 finaldate
没有第三列的价值。会很高兴在将来优化 i=!is.na()
(#1386),如果您现在以这种方式使用 data.table,您将来无需更改代码即可受益。)
您可能有多个要替换的 "NA" 字符串。请注意,CRAN 上的 v1.9.6 中的 fread 对此进行了修复。来自 README :
- correctly handles na.strings argument for all types of columns - it detect possible NA values without coercion to character, like in base read.table. fixes #504. Thanks to @dselivanov for the PR. Also closes #1314, which closes this issue completely, i.e., na.strings = c("-999", "FALSE") etc. also work.
顺便说一句,您犯了这里提到的前 3 个错误之一:https://github.com/Rdatatable/data.table/wiki/Support