【问题标题】:Inside for loop take 1st and 5th element en each loop?在 for 循环中每个循环都取第一个和第五个元素吗?
【发布时间】:2020-02-22 18:03:03
【问题描述】:

我正在尝试生成一个开始和结束日期范围为 5 天的数据框。

这是我用来创建日期范围列表的函数:

from <- as.Date("2017-01-01")
to <- as.Date("2020-02-21")
d <- seq(from, to, by = "1 days")
n <- length(d)
chunk <- 5
f <- rep(1:((n %/% chunk) + 1), each = chunk, length.out = n)
head(split(d, f))

元素看起来像:

head(split(d, f), 4)
$`1`
[1] "2017-01-01" "2017-01-02" "2017-01-03" "2017-01-04" "2017-01-05"

$`2`
[1] "2017-01-06" "2017-01-07" "2017-01-08" "2017-01-09" "2017-01-10"

$`3`
[1] "2017-01-11" "2017-01-12" "2017-01-13" "2017-01-14" "2017-01-15"

$`4`
[1] "2017-01-16" "2017-01-17" "2017-01-18" "2017-01-19" "2017-01-20"

我需要获取列表中每个元素的第 1 天和第 5 天来制作我的数据框。我正在尝试制作一个 for 循环来捕获开始(第 1 个元素)和结束(第 5 个元素)。

我正在尝试像这样访问它们:

my_date_ranges <- split(d, f)

my_date_ranges[[1]][1] #first element start
my_date_ranges[[1]][5] #first element end
my_date_ranges[[2]][1] #second element start
my_date_ranges[[2]][5] #second element end
...

但是当我尝试像这样循环列表时:

for(i in my_date_ranges){
  print(my_date_ranges[[i]][1]) #this would be the starts
}

我收到此错误:

my_date_ranges[[i]] 中的错误:1 级没有这样的索引

期望的输出:

starts       ends
1  2017-01-01 2017-01-05
2  2017-01-06 2017-01-10
3  2017-01-11 2017-01-15
...
n  2020-02-17 today-minus-1-day  

【问题讨论】:

    标签: r


    【解决方案1】:

    我们可以使用lapply循环list,选择第一个元素为'start',第5个元素为'end'来创建'data.frame

    out <- do.call(rbind, lapply(split(d, f), function(x) 
            data.frame(start = x[1], end = x[5])))
    
    head(out)
    #    start        end
    #1 2017-01-01 2017-01-05
    #2 2017-01-06 2017-01-10
    #3 2017-01-11 2017-01-15
    #4 2017-01-16 2017-01-20
    #5 2017-01-21 2017-01-25
    #6 2017-01-26 2017-01-30
    
    
    
    str(out)
    #'data.frame':  230 obs. of  2 variables:
    #$ start: Date, format: "2017-01-01" "2017-01-06" "2017-01-11" ...
    #$ end  : Date, format: "2017-01-05" "2017-01-10" "2017-01-15" ...
    

    或者另一种选择不是在每个 list 元素内调用 data.frame,而是分别提取“日期”,然后执行最终的 data.frame

    lst1 <- split(d, f)    
    out1 <- data.frame(start = do.call(c, lapply(lst1, `[`, 1)), 
                end = do.call(c, lapply(lst1, `[`, 5)))
    
    i1 <- is.na(out1$end)
    out1$end[i1] <- out1$start[i1]
    

    或者如果项目较少,OP 想要获得 last 项目

    i1 <- lengths(lst1) < 5
    out1$end[i1] <-  do.call(c, lapply(lst1[i1], tail, 1))
    

    如果我们使用 OP 的代码,一种选择是使用 NA 初始化 listdata.frame,然后在每次循环运行时更新对象

    out2 <- as.data.frame(matrix(NA, nrow = length(my_date_ranges),
           ncol = 2, dimnames = list(NULL, c("start", "end"))))
    
    for(i in seq_along(my_date_ranges)) {
    
        out2$start[i] <- list(my_date_ranges[[i]][1])
        out2$end[i] <- list(my_date_ranges[[i]][5])
     }
    out2$start <- do.call(c, out2$start)
    out2$end <- do.call(c, out2$end)
    

    【讨论】:

    • 在索引工作中将 4 转换为 5。否则你的答案会错过几天。
    • @OmarGonzales 抱歉,之前我误读为 4 而不是 5。已更新
    • 列表的最后一行显示:2020-02-20 &lt;NA&gt; 最后一个列表元素可能少于 5 个元素。我们怎样才能把最后一个可用的项目放在这里?
    • @omarGonzales 您可以使用来自zoona,locf0。更新library(zoo)# lst1 &lt;- lapply(lst1, na.locf0)
    • @OmarGonzales 或创建长度小于 5 的条件并相应更新。 i1 &lt;- lengths(lst1) &lt; 5; out1$end[i1] &lt;- do.call(c, lapply(lst1[i1], tail, 1))我更新了答案
    猜你喜欢
    • 1970-01-01
    • 2014-08-28
    • 2013-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-22
    • 2022-01-21
    • 2011-06-07
    相关资源
    最近更新 更多