扩展POSIXct时间序列的意外dplyr::right_join()行为

扩展POSIXct时间序列的意外dplyr::right_join()行为,r,join,dplyr,time-series,R,Join,Dplyr,Time Series,我有一个数据框,其中包含一些每天午夜的时间戳数据和一些一天中每小时开始时的时间戳数据。我想扩展数据,使其每小时都有一次,我想在tidyverse“管道链”中这样做 我的想法是创建一个包含整小时时间序列的数据帧,然后根据这个时间序列创建我的数据。我认为这将在每日数据匹配的地方(午夜)填充适当的值,并在不匹配的地方(午夜以外的任何时间)填充NA。这似乎只有在我的数据中的时间序列是每日的,而不是每日和每小时值的混合时才起作用,这是出乎意料的。当右连接与另一个小时时间序列共存于一个数据帧中时,为什么它不

我有一个数据框,其中包含一些每天午夜的时间戳数据和一些一天中每小时开始时的时间戳数据。我想扩展数据,使其每小时都有一次,我想在tidyverse“管道链”中这样做

我的想法是创建一个包含整小时时间序列的数据帧,然后根据这个时间序列创建我的数据。我认为这将在每日数据匹配的地方(午夜)填充适当的值,并在不匹配的地方(午夜以外的任何时间)填充
NA
。这似乎只有在我的数据中的时间序列是每日的,而不是每日和每小时值的混合时才起作用,这是出乎意料的。当右连接与另一个小时时间序列共存于一个数据帧中时,为什么它不扩展每日时间序列

我在下面生成了一个最小的示例。我要扩展的代表性数据集名为
allData
,包含来自两个不同时间序列变量的每日和每小时数据集的混合,
daily TS
hourly TS

dailyData <- data.frame( 
  DateTime = seq.POSIXt(lubridate::ymd_hms('2019-01-01', truncated=3), 
                        lubridate::ymd_hms('2019-01-07', truncated=3), 
                        by='day'),
  Name = 'Daily TS'
  )

allHours <- data.frame(
  DateTime = seq.POSIXt(lubridate::ymd_hms('2019-01-01', truncated=3), 
                        lubridate::ymd_hms('2019-01-07 23:00:00'), 
                        by='hour')
)

hourlyData <- allHours %>%
  dplyr::mutate( Name = 'Hourly TS' )

allData <- rbind( dailyData, hourlyData )
现在,我认为
dplyr::right_join()
针对
allData$DateTime
POSIXct
值的整小时序列会扩展每日时间序列,使得任何小时的NA值都不会显式出现在数据中。然后我可以使用
tidyr::fill()
在一天中填写这些内容。但是,以下代码不会以这种方式运行:

expanded_BAD <- allData %>%
  dplyr::right_join( allHours, by='DateTime' ) %>%
  tidyr::fill( dplyr::everything(), .direction='down' ) %>%
  dplyr::arrange( Name, DateTime )
有趣的是,如果我们只对每日数据执行完全相同的右连接,我们会得到期望的结果:

dailyData_expanded_GOOD <- dailyData %>%
  dplyr::right_join( allHours, by='DateTime' ) %>%
  tidyr::fill( dplyr::everything(), .direction='down' )

为什么正确的连接对完整数据的作用与仅对每日数据的作用不同?

我认为问题在于您试图过早地将数据帧绑定在一起。我相信这会给你你想要的:

结果日期时间名称
#>2019-01-01 00:00:00每日TS
#>2 2019-01-01:00:00每日TS
#>3 2019-01-01 02:00:00每日TS
#>4 2019-01-01 03:00:00每日TS
#>5 2019-01-01 04:00:00每日TS
#>6 2019-01-01 05:00:00每日TS
right\u join()
不起作用的原因是所有小时都与 小时时间序列的所有数据中的行。从哪里来的?对吧

从y返回所有行,从x和y返回所有列。y中与x中不匹配的行将在新列中具有NA值。如果x和y之间存在多个匹配项,则返回所有匹配项的组合

您希望x中与y中不匹配的行将具有NA值,但y中的行已经与x中的行匹配。实际上有多个匹配项,一个用于每日,一个用于每小时,但是
right\u join()
只返回这两个匹配项,而不展开每日时间序列行

这与中的情况不同,在中,要展开的日期时间不出现在左侧数据帧中。然后,合并策略将按预期扩展您的结果

这就解释了为什么裸
右join()
不起作用,但解决不了问题 这个问题是因为您必须手动拆分数据,这将 如果有不同数量的时间序列,快速变老。在评论中有几个解决方案,然后我将在下面添加一个额外的解决方案

tidyr::expand()
expandedData%
tidyr::展开(日期时间,名称)%>%
dplyr::arrange(名称、日期时间)
这是可行的,但仅当两个时间序列都存在时。只要有 dailyData,则结果不会展开

厨房的水槽
扩展数据1%
dplyr::right_join(allHours,by='DateTime')%>%
tidyr::填充(所有内容())%>%
tidyr::展开(日期时间,名称)%>%
dplyr::arrange(名称、日期时间)
正如评论中指出的,这适用于所有情况——两种类型, 仅每日数据,仅每小时数据。此解决方案和下一个解决方案生成 警告,除非在
data.frame()中使用
stringsAsFactors=FALSE
上面的电话

此解决方案的唯一问题是
fill()
right\u join()
是 只处理边缘案件。我不知道这是否是一个真正的问题 或者不是

管道中的“分裂” 简单的解决方案分割数据集,这可以在 用两种方式吹管

扩展数据2%
tidyr::nest(-Name)%%>%
mutate(data=purrr::map(data,~right_join(,allHours,by='DateTime'))%%>
tidyr::unnest()
另一种方法是使用
base::split()
,然后使用
purrr::map\u dfr()


由(v0.2.0)于2019-03-24创建。

我认为问题在于您试图过早地将数据帧绑定在一起。我相信这会给你你想要的:

结果日期时间名称
#>2019-01-01 00:00:00每日TS
#>2 2019-01-01:00:00每日TS
#>3 2019-01-01 02:00:00每日TS
#>4 2019-01-01 03:00:00每日TS
#>5 2019-01-01 04:00:00每日TS
#>6 2019-01-01 05:00:00每日TS
right\u join()
不起作用的原因是所有小时都与 小时时间序列的所有数据中的行。从哪里来的?对吧

从y返回所有行,从x和y返回所有列。y中与x中不匹配的行将在新列中具有NA值。如果x和y之间存在多个匹配项,则返回所有匹配项的组合

您希望x中与y中不匹配的行将具有NA值,但y中的行已经与x中的行匹配。实际上有多个匹配项,一个用于每日,一个用于每小时,但是
right\u join()
只返回这两个匹配项,而不展开每日时间序列行

这与中的情况不同,在中,要展开的日期时间不出现在左侧数据帧中。然后,合并策略将按预期扩展您的结果

所以t
head(expanded_BAD, n=15)
              DateTime      Name
1  2019-01-01 00:00:00  Daily TS
2  2019-01-02 00:00:00  Daily TS
3  2019-01-03 00:00:00  Daily TS
4  2019-01-04 00:00:00  Daily TS
5  2019-01-05 00:00:00  Daily TS
6  2019-01-06 00:00:00  Daily TS
7  2019-01-07 00:00:00  Daily TS
8  2019-01-01 00:00:00 Hourly TS
9  2019-01-01 01:00:00 Hourly TS
10 2019-01-01 02:00:00 Hourly TS
11 2019-01-01 03:00:00 Hourly TS
12 2019-01-01 04:00:00 Hourly TS
13 2019-01-01 05:00:00 Hourly TS
14 2019-01-01 06:00:00 Hourly TS
15 2019-01-01 07:00:00 Hourly TS
dailyData_expanded_GOOD <- dailyData %>%
  dplyr::right_join( allHours, by='DateTime' ) %>%
  tidyr::fill( dplyr::everything(), .direction='down' )
head(dailyData_expanded_GOOD, n=15)
              DateTime    Value
1  2019-01-01 00:00:00 Daily TS
2  2019-01-01 01:00:00 Daily TS
3  2019-01-01 02:00:00 Daily TS
4  2019-01-01 03:00:00 Daily TS
5  2019-01-01 04:00:00 Daily TS
6  2019-01-01 05:00:00 Daily TS
7  2019-01-01 06:00:00 Daily TS
8  2019-01-01 07:00:00 Daily TS
9  2019-01-01 08:00:00 Daily TS
10 2019-01-01 09:00:00 Daily TS
11 2019-01-01 10:00:00 Daily TS
12 2019-01-01 11:00:00 Daily TS
13 2019-01-01 12:00:00 Daily TS
14 2019-01-01 13:00:00 Daily TS
15 2019-01-01 14:00:00 Daily TS