【问题标题】:How can I assign the value from one of two POSIXct columns in a data.frame to a new POSIXct column?如何将 data.frame 中两个 POSIXct 列之一的值分配给新的 POSIXct 列?
【发布时间】:2016-09-01 22:42:36
【问题描述】:

我有一个包含两列 POSIXct 类型的 data.frame,但对于每一行,只有一列会有一个值,例如,

dd <- data.frame(date1 = c(now(), NA), date2 = c(as.POSIXct(NA), now()))
> dd
                date1               date2
1 2016-05-06 11:30:04                <NA>
2                <NA> 2016-05-06 11:30:04

我现在想创建第三列,该列将包含具有非 NA 值的任何列的值,即结果应如下所示

> dd
                date1               date2               date3
1 2016-05-06 11:26:36                <NA> 2016-05-06 11:26:36
2                <NA> 2016-05-06 11:26:36 2016-05-06 11:26:36 

我尝试过使用 ifelse(),但它不起作用:

> mutate(dd, date3 = ifelse(!is.na(date1), date1, date2))
                date1               date2      date3
1 2016-05-06 11:30:04                <NA> 1462559405
2                <NA> 2016-05-06 11:30:04 1462559405

也没有基于逻辑向量的赋值:

> dd[!is.na(dd$date1), "date3"] <- dd[!is.na(dd$date1), "date1"]
> dd[!is.na(dd$date2), "date3"] <- dd[!is.na(dd$date2), "date2"]
> dd
                date1               date2      date3
1 2016-05-06 11:30:04                <NA> 1462559405
2                <NA> 2016-05-06 11:30:04 1462559405

谁能解释这种行为?

我是否坚持使用 POSIXct 类的空列创建一个新的 data.frame,然后分配给它?这并不理想,因为它打破了只能分配到 data.frame 并让它神奇地工作的规则。

或者我应该先完成分配,然后再更改列类(如solution 中所建议的那样)?这并不理想,因为在分配过程中转换为数字会降低时区,然后在调用 as.POSIXct() 时我必须再次提供时区。

提前致谢!

【问题讨论】:

  • POSIXct 真的只是一个数字。使用as.POSIXct like so: dd$date3 &lt;- as.POSIXct(ifelse(is.na(dd$date1), dd$date2, dd$date1), origin = origin) 转换回日期格式。也不错:dd[!is.na(dd)]...但这是按列排列的,所以t(dd)[!is.na(t(dd))],也许吧。
  • 谢谢!但是,你能解释一下或指出为什么会发生这种情况吗?我幼稚的理解是 POSIXct 是一个与数字类不同且不同的类。如果我分配到 data.frame 中,为什么会发生对数字的强制?
  • ifelse 剥离属性,包括类;请参阅?ifelse,其中有一个非常类似于您的示例。 [] 选项更复杂,但因为您要分配给不存在的列的一部分(而不是全部),所以会发生强制以填充列。 ?`[.data.frame` 有一些信息,但不多。如果您首先将具有适当类的内容分配给整个列(例如dd$date3 &lt;- as.POSIXct(NA)),它将正常工作。
  • 好的,这似乎已经足够将各个部分组合在一起了。我尝试搜索 R 文档,但找不到任何东西。谢谢!

标签: r dataframe posixct


【解决方案1】:

以下解决方案对我有用,虽然它的代码不是很干净:

dd<-read.csv("dd.csv",stringsAsFactors = F,na.strings = c("", " "))

dd[,1]<-as.POSIXct(dd[,1],"%m/%d/%Y %H:%M",tz = "GMT")
dd[,2]<-as.POSIXct(dd[,2],"%m/%d/%Y %H:%M",tz = "GMT")
dd[,'Date3']<-dd[,1]


dd[which(!is.na(dd$Date1)),'Date3']<-dd$Date1[!is.na(dd$Date1)]
dd[which(!is.na(dd$Date2)),'Date3']<-dd$Date2[!is.na(dd$Date2)]

str(dd)
'data.frame':   6 obs. of  3 variables:
 $ Date1: POSIXct, format: "2016-05-20 11:30:00" ...
 $ Date2: POSIXct, format: NA ...
 $ Date3: POSIXct, format: "2016-05-20 11:30:00" .

sum(is.na(dd$Date3))
[1] 0

我使用的技巧是使用Date1 创建Date3,这反过来意味着该列的类是POSIXct

【讨论】:

    【解决方案2】:

    另一种方法,假设 date1 是“正确的”,然后在适用的情况下用 date2 覆盖

    dd <- data.frame(date1 = c(now(), NA), date2 = c(as.POSIXct(NA), now()))
    dd2 <- dd$date1
    dd2[is.na(dd2)]<-dd$date2[is.na(dd2)]
    

    【讨论】:

    • 虽然在精神上与其他建议的答案相同,但我会接受这个,因为它更简洁。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-21
    • 2019-11-17
    • 2020-10-29
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    相关资源
    最近更新 更多