【问题标题】:Create 10,000 date data.frames with fake years based on 365 days window根据 365 天窗口创建 10,000 个带有假年份的日期数据帧
【发布时间】:2017-05-01 11:41:22
【问题描述】:

这里是我的时间段范围:

start_day = as.Date('1974-01-01', format = '%Y-%m-%d')
end_day = as.Date('2014-12-21', format = '%Y-%m-%d')

df = as.data.frame(seq(from = start_day, to = end_day, by = 'day'))
colnames(df) = 'date'

我需要创建 10,000 个数据帧,每个数据帧具有 365 天的不同假年份。这意味着 10,000 个 data.frame 中的每一个都需要有不同的开始和结束年份。

df 总共有 14,965 天,除以 365 天 = 41 年。换句话说,df 需要按 41 年(每个 365 天)分组10,000 次不同。 每年的开始必须是随机的,所以可以是1974-10-03, 1974-08-30, 1976-01-03, 等等...结束的剩余日期df需要循环使用与开始的。

分组的假年份需要出现在 data.frames 的第三列。

我会将所有 data.frames 放入一个列表,但我不知道如何创建生成 10,000 个不同年份的开始日期并随后将每个 data.frames 与 365 天窗口分组 41 次的函数。

谁能帮帮我?


@gringer 给出了一个很好的答案,但它只解决了 90% 的问题:

dates.df <- data.frame(replicate(10000, seq(sample(df$date, 1),
                                            length.out=365, by="day"),
                                 simplify=FALSE))
colnames(dates.df) <- 1:10000

我需要的是 10,000 列和 14,965 行,日期取自 df,在到达 df 末尾时需要最终回收。

我尝试更改 length.out = 14965,但 R 不回收日期。


另一种选择可能是更改 length.out = 1 并最终通过保持相同的顺序为每列添加剩余的 df

dates.df <- data.frame(replicate(10000, seq(sample(df$date, 1),
                                            length.out=1, by="day"),
                                 simplify=FALSE))
colnames(dates.df) <- 1:10000

如何将剩余的 df 行添加到每个列?

【问题讨论】:

  • 也许 sample(df$date, 10000) 可以帮助您获得 10000 个不同的随机开始日期?

标签: r date dataframe grouping montecarlo


【解决方案1】:

seq 方法也适用于未指定 to 参数的情况,因此它可用于生成从特定日期开始的特定天数:

> seq(from=df$date[20], length.out=10, by="day")
[1] "1974-01-20" "1974-01-21" "1974-01-22" "1974-01-23" "1974-01-24"
[6] "1974-01-25" "1974-01-26" "1974-01-27" "1974-01-28" "1974-01-29"

当与replicatesample 结合使用时,我认为这将给出您想要的列表:

> replicate(2,seq(sample(df$date, 1), length.out=10, by="day"), simplify=FALSE)
[[1]]
 [1] "1985-07-24" "1985-07-25" "1985-07-26" "1985-07-27" "1985-07-28"
 [6] "1985-07-29" "1985-07-30" "1985-07-31" "1985-08-01" "1985-08-02"

[[2]]
 [1] "2012-10-13" "2012-10-14" "2012-10-15" "2012-10-16" "2012-10-17"
 [6] "2012-10-18" "2012-10-19" "2012-10-20" "2012-10-21" "2012-10-22"

如果没有 simplify=FALSE 参数,它会生成一个整数数组(即 R 的内部日期表示),将其转换回日期有点棘手。一个稍微复杂的方法是生成 Date 输出是在未简化的replicate 结果上使用data.frame。这是一个示例,它将生成一个 10,000 列的数据框,每列中有 365 个日期(在我的计算机上生成大约需要 5 秒):

dates.df <- data.frame(replicate(10000, seq(sample(df$date, 1),
                                            length.out=365, by="day"),
                                 simplify=FALSE));
colnames(dates.df) <- 1:10000;
> dates.df[1:5,1:5];
           1          2          3          4          5
1 1988-09-06 1996-05-30 1987-07-09 1974-01-15 1992-03-07
2 1988-09-07 1996-05-31 1987-07-10 1974-01-16 1992-03-08
3 1988-09-08 1996-06-01 1987-07-11 1974-01-17 1992-03-09
4 1988-09-09 1996-06-02 1987-07-12 1974-01-18 1992-03-10
5 1988-09-10 1996-06-03 1987-07-13 1974-01-19 1992-03-11

要使日期环绕正常工作,可以对原始数据框进行轻微修改,在末尾粘贴其自身的副本:

df <- as.data.frame(c(seq(from = start_day, to = end_day, by = 'day'),
                      seq(from = start_day, to = end_day, by = 'day')));
colnames(df) <- "date";

这更容易为下游编码;另一种方法是为每个结果列添加一个双 seq,并对 start/end 和 if 语句进行额外计算以处理边界情况。

现在不再进行日期算术,而是从原始数据框(算术已经完成)中提取结果列子集。从帧前半部分的一个日期开始,然后选择接下来的 14965 个值。我使用nrow(df)/2 代替更通用的代码:

dates.df <-
    as.data.frame(lapply(sample.int(nrow(df)/2, 10000),
                         function(startPos){
                             df$date[startPos:(startPos+nrow(df)/2-1)];
                         }));
colnames(dates.df) <- 1:10000;

>dates.df[c(1:5,(nrow(dates.df)-5):nrow(dates.df)),1:5];
               1          2          3          4          5
1     1988-10-21 1999-10-18 2009-04-06 2009-01-08 1988-12-28
2     1988-10-22 1999-10-19 2009-04-07 2009-01-09 1988-12-29
3     1988-10-23 1999-10-20 2009-04-08 2009-01-10 1988-12-30
4     1988-10-24 1999-10-21 2009-04-09 2009-01-11 1988-12-31
5     1988-10-25 1999-10-22 2009-04-10 2009-01-12 1989-01-01
14960 1988-10-15 1999-10-12 2009-03-31 2009-01-02 1988-12-22
14961 1988-10-16 1999-10-13 2009-04-01 2009-01-03 1988-12-23
14962 1988-10-17 1999-10-14 2009-04-02 2009-01-04 1988-12-24
14963 1988-10-18 1999-10-15 2009-04-03 2009-01-05 1988-12-25
14964 1988-10-19 1999-10-16 2009-04-04 2009-01-06 1988-12-26
14965 1988-10-20 1999-10-17 2009-04-05 2009-01-07 1988-12-27

现在这需要更少的时间,大概是因为日期值已经预先计算好了。

【讨论】:

  • 好的,谢谢。我们快到了。缺少的是,对于 10,000 列中的每一列,我需要 365*41 个后续行,其日期取自原始 data.frame。当行到达 data.frame 的末尾(即 2014-12-21)时,它们应该从头开始。换句话说,10,000 列和 14,965 个日期行取自 df.做到这一点很难吗?谢谢
  • 好的,您还希望原始范围的日期环绕。轻松做到这一点的一种方法是从原始表中复制原始表和子集,而不是标准日期算术;我将添加一个代码示例。
【解决方案2】:

试试这个,改用子集:

start_day = as.Date('1974-01-01', format = '%Y-%m-%d')
end_day = as.Date('2014-12-21', format = '%Y-%m-%d')

date_vec <- seq.Date(from=start_day, to=end_day, by="day")

现在,我创建了一个足够长的向量,以便以后可以使用简单的子集:

date_vec2 <- rep(date_vec,2)

现在,为 100 个实例创建随机开始日期(将您的应用程序替换为 10000):

random_starts <- sample(1:14965, 100)

现在,只需将date_vec2 设置为您想要的长度,即可创建一个日期列表:

dates <- lapply(random_starts, function(x) date_vec2[x:(x+14964)])
date_df <- data.frame(dates)
names(date_df) <- 1:100

date_df[1:5,1:5]

           1          2          3          4          5
1 1997-05-05 2011-12-10 1978-11-11 1980-09-16 1989-07-24
2 1997-05-06 2011-12-11 1978-11-12 1980-09-17 1989-07-25
3 1997-05-07 2011-12-12 1978-11-13 1980-09-18 1989-07-26
4 1997-05-08 2011-12-13 1978-11-14 1980-09-19 1989-07-27
5 1997-05-09 2011-12-14 1978-11-15 1980-09-20 1989-07-28

【讨论】:

  • 好的...谢谢,但您错过了一个非常快速的步骤。 date_df 有一个额外的行,其中引入了重复项。所以....如果您使用以下内容更新您的答案: date_df = date_df[-c(14966),] 我会将其标记为正确。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-06
  • 1970-01-01
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
  • 2021-08-24
  • 2012-03-03
相关资源
最近更新 更多