Tibble默默地改变回收的difftime变量

时间:2017-06-25 00:45:09

标签: r tidyverse tibble

如果tibble中包含difftime变量,并且指定的观察数等于其他变量,则保持变量的类。

tibble::tibble(a = c(1,2), b = as.difftime(c(1,2), units = "hours"))

# A tibble: 2 x 2
      a       b
  <dbl>  <time>
1     1 1 hours
2     2 1 hours

但是,如果difftime变量中指定的观察数量是另一个变量中观察数量的适当因子,那么difftime变量将被回收,那么变量以静默方式更改为numeric

tibble::tibble(a = c(1,2), b = as.difftime(1, units = "hours"))

# A tibble: 2 x 2
      a     b
  <dbl> <dbl>
1     1     1
2     2     1

是否会出现这种行为差异,因为鼓励tidyverse用户使用period提供的durationlubridate个对象来指定时间,而不是基于R&#39 ; s difftime个对象?或者这是一个意想不到的错误?

使用tibble::data_framedplyr::data_frame时会出现同样的问题,但我相信将来可能会弃用这些问题。

要清楚,以下调用不会以静默方式更改时间类型变量的类:

tibble::tibble(a = c(1,2), b = lubridate::as.period("1H"))

# A tibble: 2 x 2
      a            b
  <dbl> <S4: Period>
1     1     1H 0M 0S
2     2     1H 0M 0S

tibble::tibble(a = c(1,2), b = lubridate::as.duration("1H"))

# A tibble: 2 x 2
      a                b
  <dbl>   <S4: Duration>
1     1 3600s (~1 hours)
2     2 3600s (~1 hours)

2 个答案:

答案 0 :(得分:2)

您所看到的行为源于数据帧创建过程中矢量回收过程中非常特殊的行为。如您所知,传递给data.frame函数的对象应具有相同的行数。但是如果需要, 原子矢量 将被重复使用多次。这提出了以下问题:以下不起作用:

dff <- data.frame(a=c(1,2), b=as.difftime(1, units="hours"))

上面的代码引发了以下错误:

  

data.frame出错(a = c(1,2),b = as.difftime(1,units =“hours”))   :参数意味着行数不同:2,1

事实证明,这不起作用的原因是因为difftime个对象的向量不被识别为原子向量。您可以查看以下内容:

is.vector(as.difftime(1, units="hours"))

返回:

[1] FALSE

结果,当data.frame函数尝试回收列b时,它首先检查该列是否实际上是一个向量(带is.vector)。由于返回FALSE,回收不会继续;因此返回了错误。

因此,随后的问题是: 为什么不将{b}列转换为as.vector

这实际上是一个好主意,期望as.vector 删除结果向量的所有属性 ,包括名称。你可以看到以下内容:

as.vector(as.difftime(1, units="hours"))

返回:

[1] 1

强制过程中difftime对象的所有属性都丢失了。这使我认为tibble::data_frame函数在生成as.vector的过程中实际使用data_frame。因此,我们看到以下行为:

data_frame(a=c(1,2), b=as.difftime(1, units="hours"))

返回

# A tibble: 2 x 2
      a     b
  <dbl> <dbl>
1     1     1
2     2     1

我猜结论与@agstudy达到的结论相同:要维护difftime对象,您可能必须使用listb,如下所示:

tibble::tibble(a = c(1,2), b = list(as.difftime(1, units = "hours")))

我希望这在某种程度上证明是有用的。

答案 1 :(得分:0)

我不认为tibble鼓励使用lubridate(即使我鼓励你使用它)做类似日期的处理,但它更像是矢量如何的问题在回收时在内部创建。事实上,当您使用clist时,您可以重现相同的回收行为。例如,使用c您将失去输入:

c(as.difftime(c(1), units = "hours"),1)
### Time differences in hours
### [1] 1 1

但使用list会保留时差类型:

list(as.difftime(c(1), units = "hours"),2)

# [[1]]
# Time difference of 1 hours
# 
# [[2]]
# [1] 2

list应用于tibble,您可以“保存”类类型:

tibble::tibble(a = c(1,2), 
               b = list(as.difftime(c(1), units = "hours")))

# A tibble: 2 x 2
# a          b
# <dbl>     <list>
#   1     1 <time [1]>
#   2     2 <time [1]>

但这很难在以后操纵。在这种情况下最好使用lubridate