将因子转换为R中的日期对象,无需NA

3

问题: 如何将factor类型的数据转换为date类型的对象而不产生NA值。

这里有一篇类似的帖子:在R中将Factor类型数据转换为Date/Time类型数据

在那篇文章中,用户在将数据转换成date类型之前先将其转换成了character类型。使用as.character函数将数据转换成character类型后,在as.Date函数内部进行操作时会出现NA值。

我有一个包含日期的列,以factor格式存储在数据框中,具有不同的出现次数。下面是数据框中包含的信息:

> head(fraud, 5)
  TRANSACTION.DATE TRANSACTION.AMOUNT AIR.TRAVEL.DATE POSTING.DATE
1 2/27/14                  25.00                 <NA>          2/28/14
2 2/28/14                  25.00                 <NA>          2/28/14
3 2/27/14                  25.00                 <NA>          2/28/14
4 2/27/14                  20.00              2/27/14          2/28/14
5 2/27/14                  12.13                 <NA>          2/28/14

> str(fraud$TRANSACTION.DATE)
 Factor w/ 519 levels "1/1/14","1/1/15",..: 228 230 228 228 228 230 226 228 230 228 ...

> summary(fraud$TRANSACTION.DATE, 5)
9/30/14 9/17/14 11/4/14 9/23/14 (Other) 
    197     187     171     160   19221 

将因子转换为日期对象导致了NA值的产生。
> fraud$TRANSACTION.DATE <- as.Date(as.character(fraud$TRANSACTION.DATE), 
+                                       format = "%m/%d/%Y")
> head(fraud$TRANSACTION.DATE, 5)
[1] NA NA NA NA NA

检查 as.character 函数是否有效。

> fraud$TRANSACTION.DATE <- as.character(fraud$TRANSACTION.DATE)
> head(fraud$TRANSACTION.DATE)
[1] NA NA NA NA NA NA

编辑:我使用了as.Date函数,但却得到了错误的格式

> fraud$TRANSACTION.DATE <- as.Date(fraud$TRANSACTION.DATE, format = "%m/%d/%Y")
> str(fraud$TRANSACTION.DATE)
 Date[1:19936], format: "0014-02-27" "0014-02-28" "0014-02-27" "0014-02-27" "0014-02-27" ...
> head(fraud$TRANSACTION.DATE, 5)
[1] "0014-02-27" "0014-02-28" "0014-02-27" "0014-02-27" "0014-02-27"

EDIT 2: 这是dput值

> dput(droplevels(head(fraud$TRANSACTION.DATE)))
structure(c(1L, 2L, 1L, 1L, 1L, 2L), .Label = c("2/27/14", "2/28/14"
), class = "factor")

解决方案:使用%y代替%Y。
> fraud$TRANSACTION.DATE <- as.Date(fraud$TRANSACTION.DATE, "%m/%d/%y")
> head(fraud$TRANSACTION.DATE, 5)
[1] "2014-02-27" "2014-02-28" "2014-02-27" "2014-02-27" "2014-02-27"

3
你正在使用$d而不是%d。另外,只需要使用as.Date函数即可,即可能不需要使用as.character。例如:as.Date(fraud$TRANSACTION.DATE, '%m/%d/%y')将会输出以下结果:"2014-02-27" "2014-02-28" "2014-02-27" "2014-02-27" "2014-02-27"。 - akrun
1
一个dput的输出可能更加可重现, 即 dput(droplevels(head(fraud))). - akrun
1
@BenjaminHofner 我尝试使用factor列,而不需要转换为character,效果很好。我正在使用R 3.2.1。 - akrun
1
@BenjaminHofner,你不需要使用as.character(),因为对于类“factor”,有一个S3方法可以有效地为你调用as.Date(as.character(x)) - Gavin Simpson
1
@ScottDavis 要格式化日期(R将使用YYYY-MM-DD进行显示),请查看strftime()以获取详细信息。但请注意,您希望将其保留为“Date”对象,并仅在需要绘图或输出表格时进行格式化。 - Gavin Simpson
显示剩余14条评论
1个回答

5
现在的问题是,您的格式字符串表示日期包括带有世纪的年份,而您的日期仅包含不带世纪的年份。您需要使用“%y”占位符,而不是“%Y”占位符。
dates <- factor(c("2/27/14","2/28/14","2/27/14","2/27/14","2/27/14"))
as.Date(dates, format = "%m/%d/%y") # correct lowercase y
as.Date(dates, format = "%m/%d/%Y") # incorrect uppercase y

> as.Date(dates, format = "%m/%d/%y")
[1] "2014-02-27" "2014-02-28" "2014-02-27" "2014-02-27" "2014-02-27"
> as.Date(dates, format = "%m/%d/%Y")
[1] "14-02-27" "14-02-28" "14-02-27" "14-02-27" "14-02-27"

当使用正确的占位符(小写y)时,R会得到正确的结果。

如果没有具有世纪的年份,则使用%Y会受操作系统影响。如在Linux(Fedora 22)中,年份部分不会补零,但也有可能会补零。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接