如何避免循环

时间:2010-07-12 02:43:17

标签: r loops vectorization

全部, 我是R的新手。

我有两个面板数据文件,列“id”,“date”和“ret”

文件A的数据比文件B多得多, 但我主要使用文件B数据。

“id”和“date”的组合是unqiue标识符。

是否有一种在B中查找每个(id,date)的优雅方式,我需要从文件A中获取过去10天,然后将它们存回B中?

我天真的做法是循环B中的所有行,

for i in 1:length(B) {
    B$past10d[i] <- prod(1+A$ret[which(A$id == B$id[i] & A$date > B$date[i]-10 & A$date < B$date[i])])-1
}

但循环需要永远。

真的很感激你的想法。

非常感谢。

7 个答案:

答案 0 :(得分:1)

你试过吗?合并?

“按公共列或行名称合并两个数据框,或执行其他版本的数据库联接操作。”

此外,如果您继续使用复合PK或任何唯一标识符,我建议使用一些本地MySQL / PostgreSQL(RMySQL / RPostgreSQL)数据库。对我来说,SQL重新排列数据,然后使用视图中的data.frames比循环更容易。

答案 1 :(得分:1)

我认为关键是向量化并使用%in%运算符来对数据框A进行子集化。而且,我知道,价格不是随机数,但我不想编写随机游戏......我使用paste创建了股票日期索引,但我确信你可以使用pdata.frame库中的plm,这是我在面板数据中找到的最好的。

A  <- data.frame(stock=rep(1:10, each=100), date=rep(Sys.Date()-99:0, 10), price=rnorm(1000))
B <- A[seq(from=100, to=1000, by=100), ]
A <- cbind(paste(A$stock, A$date, sep="-"), A)
B <- cbind(paste(B$stock, B$date, sep="-"), B)
colnames(A) <- colnames(B) <- c("index", "stock", "date", "price")
index <- which(A[, 1] %in% B[, 1])
returns <- (A$price[index] - A$price[index-10]) / A$price[index-10]
B <- cbind(B, returns)

答案 2 :(得分:0)

这更快吗? (我假设B $ id和B $ date的组合是一个未在任何地方复制的唯一标识符 - 由您的代码暗示)

B$idDate <- factor(B$id):factor(B$date)
B$past10 <- sapply(B$idDate, function(x){with(B[B$idDate == x,], 
    prod(1+A$ret[A$id == id & A$date > date-10 & A$date < date])-1)})

答案 3 :(得分:0)

如果您没有在A和B中复制的数据,那么rbind是最简单的解决方案。

#Sample data
A <- data.frame(
  id = rep(letters[1:3], each = 13),
  date = Sys.Date() + -12:0,
  ret = runif(39)
)

B <- data.frame(
  id = rep(letters[5:6], each = 5),
  date = Sys.Date() + -4:0,
  ret = runif(10)
)

#Only take the last ten days from A
A_past_10_days <- A[A$date > Sys.Date() - 10,]

#Bind by rows
rbind(A_past_10_days, B)

答案 4 :(得分:0)

一般来说,你应该避免在R中循环。如果你的代码在向量上运行,它会快得多。

我会使用merge,正如ran2所建议的那样。您可以设置all.x = T(或all.yall)以从一个(或其他或两个)数据帧中获取所有行。这很快,通常可以确定哪些字段可以自行匹配。否则,您需要将by.x(和by.yby)指定为查找字段。根据它的声音,您可能需要自己创建此字段(根据John的评论)。

然后您可以按日期过滤。

答案 5 :(得分:0)

鉴于你有记忆问题或许削减第一个可能有所帮助。首先,摆脱无关的ids。

A <- A[A$id %in% B$id,]

完全减少A数据集仍然想要获取更多内存。没有存储一些变量是不可能的。尽管如此,我们还是可以摆脱一堆我希望将每一个日期都低于绝对最小值并高于我们的绝对最大值。

A <- A[A$date > (min(B$date) - 10) & A$date <= max(B$date),]

当然,如果没有通过id来限定它,我们没有得到A的最小版本,但希望它足够小。

现在运行我最初提出的代码,看看你是否还有内存错误

B$idDate <- factor(B$id):factor(B$date)
B$past10 <- sapply(B$idDate, function(x){with(B[B$idDate == x,], 
    prod(1+A$ret[A$id == id & A$date > date-10 & A$date < date])-1)})

答案 6 :(得分:0)

jalr

这个答案建立在理查兹的答案之上,但更多的是针对这个问题。

关键思想是构建一个id日期组合向量来进行比较。这发生在第二个代码块中。

我的解决方案使用data.table包,但是一些语法更改应该与data.frame一起使用。但是使用data.table包具有keycolumns的优势。

如果你还有问题,你可以将这种方法与约翰的第二个答案和第一个作物A配对。