3

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

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鼓励用户使用periodduration提供的对象lubridate来指定时间,而不是基础 R 的difftime对象?或者这是一个意外的错误?

使用tibble::data_frame, 和时也会出现同样的问题dplyr::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)
4

2 回答 2

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函数试图回收 columnb时,它首先检查该列是否实际上是一个向量(with 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对象,您可能必须使用listfor 列b,如下所示:

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

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

于 2017-06-25T15:46:08.573 回答
0

我不认为tibble鼓励使用lubridate(即使我鼓励你使用它)确实处理日期之类的类型,但更多的是当你回收时如何在内部创建向量的问题。事实上,当您使用c和时,您可以重现相同的回收行为list。例如使用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

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

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在这种情况下使用。

于 2017-06-25T02:11:46.043 回答