无法找出R中的嵌套for循环

时间:2017-08-05 13:19:27

标签: r

我无法弄清楚如何在R中使用嵌套for循环来解决我的问题。这是我试图解决的缩影版本:

我有两个文件, test1 test2 ,如下所示:

head(test1)

      Date Settlement
2008-08-28     138.29
2008-08-29     135.34
2008-09-01     135.23
2008-09-02     123.36
2008-09-03     126.41
2008-09-04     128.68
2008-09-05     123.70
2008-09-08     124.60
2008-09-09     122.33
2008-09-10     120.85
2008-09-11     120.15
2008-09-12     121.17
2008-09-15     118.97
2008-09-16     114.90
2008-09-17     115.78
2008-09-18     115.60
2008-09-19     115.90
2008-09-22     120.49
2008-09-23     124.10

这是 test2

test2

X1         X2         X3
2008-08-31 2008-09-05 2008-09-11
2008-09-05 2008-09-11 2008-09-14
2008-09-11 2008-09-14 2008-09-18
2008-09-14 2008-09-18 2009-09-22

我需要提出的逻辑是:

  1. test2
  2. 中选择日期[1,1]和[1,2]
  3. test1
  4. 中查找这两个日期之间的所有结算价格
  5. 获取这些价格的平均值,将其放在新数据框的[1,1]中。
  6. 重复增加列,然后增加pt1中的行。
  7. 最终结果如下:

    X1          X2
    128.42  122.87
    122.87  120.66
    120.66  116.55
    116.55  115.75
    

    因此,X1中的第一个值是08年8月31日(含)和08年9月5日(不包括)之间结算价格的平均值,中的第1个值X2 是08年9月5日(包括)和08年9月11日(不包括)之间的结算价格的平均值,以下是等等。

    这是我的代码有效(如果我从test2传递固定日期,如下所示):

    temp1 <- test1 %>%
      group_by(Date >= test2$X1[1] & Date < test2$X2[1]) %>%
      summarise(AvgPrice2 = mean(Settlement, na.rm = T))
    
    temp1 <- filter(temp1, temp1[,1]==TRUE)
    

    然而,无论我尝试什么(过去3天!),我都无法弄清楚如何将它放入for循环中。即使尝试rollapplysapply ...也无法获得任何效果。代码不需要时间效率,我只需要自动执行此过程。

    我已经和R一起工作了一段时间,但很明显这对于高级用户来说是一个问题...非常感谢任何帮助。

    非常感谢提前。

4 个答案:

答案 0 :(得分:1)

我会在sqldf包中使用类似SQL的方法(允许您将SQL sintax应用于data.frame s

ds = data.frame(Date = c("2008-08-28", "2008-08-29", "2008-09-01", "2008-09-02", "2008-09-03", "2008-09-04", "2008-09-05", "2008-09-08", "2008-09-09", "2008-09-10", "2008-09-11", "2008-09-12", "2008-09-15", "2008-09-16", "2008-09-17", "2008-09-18", "2008-09-19", "2008-09-22", "2008-09-23"), 
                Settlement = c(138.29, 135.34, 135.23, 123.36, 126.41, 128.68, 123.70, 124.60, 122.33, 120.85, 120.15, 121.17, 118.97, 114.90, 115.78, 115.60, 115.90, 120.49, 124.10))

dr = data.frame(d1=c("2008-08-31", "2008-09-05", "2008-09-11", "2008-09-14"),
                d2=c("2008-09-05", "2008-09-11", "2008-09-14", "2008-09-18"),
                d3=c("2008-09-11", "2008-09-14", "2008-09-18", "2009-09-22"))
# add a variable which I will use to identify the rows
dr$g = 1:NROW(dr);


library(sqldf);
output = sqldf("SELECT dr.g, AVG(s1.Settlement) AS X1, AVG(s2.Settlement) AS X2
                FROM dr 
                    JOIN ds AS s1 ON dr.d1 <= s1.Date AND s1.Date < dr.d2
                    JOIN ds AS s2 ON dr.d2 <= s2.Date AND s2.Date < dr.d3
                GROUP BY dr.g");

我在this post找到了建议的包裹。在同一篇文章中,另一位用户建议使用data.table包,但我对data.table sintax不像SQL那样自信:)

可以找到sqldf的文档和一些使用示例on GitHub project page

答案 1 :(得分:0)

我不确定是否得到了它,我的一个结果与您想要的输出结果不同。首先,确保日期属于Date类。

test1$Date <- as.Date(test1$Date)
test2$X1 <- as.Date(test2$X1)
test2$X2 <- as.Date(test2$X2)
test2$X3 <- as.Date(test2$X3)

现在,对于你所描述的计算。

res1 <- numeric(nrow(test2))
res2 <- numeric(nrow(test2))
for(i in seq_len(nrow(test2))){
    inx <- test2$X1[i] <= test1$Date & test1$Date < test2$X2[i]
    res1[i] <- mean(test1$Settlement[inx])
    inx <- test2$X2[i] <= test1$Date & test1$Date < test2$X3[i]
    res2[i] <- mean(test1$Settlement[inx])
}

result <- data.frame(X1 = res1, X2 = res2)
result
      X1       X2
1 128.42 122.8700
2 122.87 120.6600
3 120.66 116.5500
4 116.55 119.0225

不同的值是最后一个,result$X2[4]。您的输出为115.75,此处为119.0225

答案 2 :(得分:0)

您的数据

确保日期为Dates

library(lubridate)

test1 = data.frame(Date = ymd(c("2008-08-28", "2008-08-29", "2008-09-01", "2008-09-02", "2008-09-03", "2008-09-04", "2008-09-05", "2008-09-08", "2008-09-09", "2008-09-10", "2008-09-11", "2008-09-12", "2008-09-15", "2008-09-16", "2008-09-17", "2008-09-18", "2008-09-19", "2008-09-22", "2008-09-23")), 
            Settlement = c(138.29, 135.34, 135.23, 123.36, 126.41, 128.68, 123.70, 124.60, 122.33, 120.85, 120.15, 121.17, 118.97, 114.90, 115.78, 115.60, 115.90, 120.49, 124.10))

test2 = data.frame(d1=ymd(c("2008-08-31", "2008-09-05", "2008-09-11", "2008-09-14")),
            d2=ymd(c("2008-09-05", "2008-09-11", "2008-09-14", "2008-09-18")),
            d3=ymd(c("2008-09-11", "2008-09-14", "2008-09-18", "2009-09-22")))

tidyverse解决方案

library(tidyverse)
result <- map_df(1:nrow(test2), ~data.frame(X1=(filter(test1, Date >= test2$d1[.x] & Date < test2$d2[.x]) %>% summarise(m=mean(Settlement)))$m,
                                            X2=(filter(test1, Date >= test2$d2[.x] & Date < test2$d3[.x]) %>% summarise(m=mean(Settlement)))$m)) 

输出

      X1       X2
1 128.42 122.8700
2 122.87 120.6600
3 120.66 116.5500
4 116.55 119.0225

答案 3 :(得分:0)

非常感谢所有的答案,我尝试了所有这些,但似乎没有一个符合我的需求,因为上面的文件是实际文件的小型化版本 - 因此通过列名称/手动将数据拆分成行而不是'对我来说似乎是个不错的选择。

但我终于弄明白在这种情况下会有什么用处:

  library(lubridate)
  Makingrows <- function(test1, test2, j){
     res<<- NULL
     m1 = nrow(test2)

     for(i in 1:m1){
        d1 <- ymd(test2[i,j])
        d2 <- ymd(test2[i,j+1])
        X1 <- filter(test1, Date < d2 & Date >= d1)
        res[i] <- mean(X1$Settlement, na.rm = T)
  }
  return(res)
}

 mcol1 <- ncol(test2)-1
 finalres <- lapply(1:mcol1, function(x) Makingrows(test1, test2, x))
 finalres <- as.data.frame(finalres)

是的,我的最后一个值也是119.02 ......我意识到错误的是我把2009年作为2009年的最后一个单元放在了test2文件中。因此,代码将所有值都提升到最后。

非常感谢大家。我希望你能同意我的意见,因为我将此标记为我的问题的答案。