2010-07-12 90 views
6

大家好, 我是新來的R.如何避免環路

我有兩個面板數據文件,與列「ID」,「日期」和「RET」

文件A有一個比文件B更多的數據, 但我主要使用文件B數據。

「id」和「date」的組合是unqiue唯一標識。

是否有一種在B中查找每個(id,date)的elegent方法,我需要從文件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 
} 

但環需要永遠。

真的很感謝你的想法。

非常感謝。

+1

ķ麻煩:以供將來參考:這是真正有用的人想幫你,如果你的代碼問題的文本匹配你問。 – 2010-07-12 15:35:24

+1

sry我的壞。感謝您的幫助 – 2010-07-12 15:49:00

+0

解釋它是否符合是開放的。代碼只是澄清...按照慣例。 – John 2010-07-12 20:54:46

回答

0

這是否更快? (我假設B $ ID和B $日期的組合是一個唯一的標識符不會複製任何地方 - 你的代碼暗示)

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)}) 
+0

感謝您的回覆john。它看起來非常整齊。 但當我上的數據,我得到: 錯誤:無法分配6.8 MB 工作太多大小的向量爲B $ past10傢伙? – 2010-07-12 13:08:55

+0

這不應該比你的方法更強大的記憶力。嘗試用ls()和rm()命令清除內存中的某些內容。或者,嘗試重新啓動R並再次執行。 – John 2010-07-12 14:59:07

+0

tks!我會嘗試..但我忘了提及我的天真方法從來沒有完成循環..:S – 2010-07-12 15:35:10

1

你嘗試合併?

「合併由公共列或行名稱,兩個數據幀或做數據庫的其他版本的連接操作。」

此外,我建議如果汽車無使用一點本地的MySQL/PostgreSQL的(RMySQL/RPostgreSQL)數據庫運動複合PK或任何唯一標識符。對我來說,SQL重新排列數據和事後使用視圖中的data.frames比循環要容易得多。

+0

嗯..我可能需要看看sql。 謝謝! – 2010-07-12 13:09:35

+0

RMySQL更容易開始...... – 2010-07-12 13:25:33

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) 
+0

從現在開始,您已經過去了10天,但是他的代碼需要在每個可能日期的過去10天內使用符合該日期的標識符進行限定。 – John 2010-07-12 14:52:35

+0

@John:斑點。我似乎已經回答了問題的文本,但不是隱藏在代碼中的問題。 **嘆息** – 2010-07-12 15:32:56

0

一般而言,您應該避免在R中循環。如果您的代碼在向量上運行,則速度會更快。

我會使用合併,由ran2建議。您可以設置all.x = T(或all.yall)以從一個(或其他或兩個)數據框中獲取所有行。這很快,通常會解決哪些字段需要自行匹配。否則,您需要指定by.x(和by.yby)作爲查找字段。通過它的聲音,你可能需要自己創建這個領域(按照約翰的評論)。

然後,您可以按日期過濾。

+0

tks! B實際上是A的一個小得多的子集,所以如果我理解'合併'正確,那麼A將是合併的結果。 – 2010-07-12 13:11:37

+0

這將佔用比原來的解決方案更多的內存。鑑於你的記憶力限制與我的建議,這將不太可能奏效。此外,所有這一切都是讓你的數據到一個地方。它並不能解決你將過去10天變成單一價值的問題......你的代碼建議這是必要的。 – John 2010-07-12 21:03:51

+0

啊!我的錯。我以爲你得到了一組從A到B的行。我沒有意識到你真的想要總結產品。您也可能對聚合(sapply的便利功能)感興趣。如果你有內存問題,那麼你可能需要一個小樣本,你可以練習,直到你確信代碼有效(另見:http://www.r-bloggers.com/memory-management -in-RA-幾個小竅門,和技巧/)。 – RobinGower 2010-07-13 08:52:33

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) 
0

鑑於您有內存問題,也許削減第一個可能會幫助。首先,擺脫外來的艾滋病。

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

完全減少A數據集仍然想要獲取更多內存。沒有存儲一些變量是不可能的。儘管如此,我們可以通過削減每一個日期低於絕對最小值並高於絕對最大值的方式來擺脫它所希望的一堆。

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

當然,通過不受ID排位這一點,我們沒有得到一個可能的最小的版本,但希望它足夠小。

現在來看,我首先提出的代碼,看看您是否仍然有一個內存錯誤

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)}) 
+0

謝謝約翰,這兩行幫助在A中減少很多,但是在我嘗試了500行之後,它仍然給了我錯誤:無法分配6.8 Mb大小的向量。我認爲問題可能在'安樂死'。不知何故,它將id和date數據作爲向量並試圖比較A $ id和B $ id等,而不是元素 – 2010-07-13 13:47:43

+0

看起來像是sapply(B $ idDate),這就是創建問題,我將B $ idDate更改爲字符和代碼一直在運行........聞起來像一個循環 – 2010-07-13 17:09:42

+0

儘量不要把過去10放在B中(在第二行開始時刪除B $)。這是否也有記憶問題? sapply()將B的每個元素都取出來,然後使用它來重新選擇A並得到產品......就像在原始代碼中那樣。我演示了我的代碼,但在我的電腦上6.8meg是一個微不足道的內存(我只用了大約200行)。如果它報告了錯誤消息,那麼確切的消息是什麼? – John 2010-07-13 17:10:55

0
library(data.table) 
#create data 
A <- data.table(id=rep(1:10, each=40000), date=rep(Sys.Date()-99:0, 4000), ret=rnorm(400000)) 
B <- data.table(id=rep(1:5, each=10), date=rep(Sys.Date()-99:0), ret=rnorm(50)) 

#find dates to compare against 
n <- NROW(B) 
B_long <- B[,.(id = rep(id,each=10),date = rep(date,each=10))] 
s <- rep(-10:-1,n) 
B_long[,date:=date + s] 

#information in one column 
B_long$com <- as.numeric(paste0(B_long$id,as.numeric(B$date))) 
A$com <- as.numeric(paste0(A$id,as.numeric(A$date))) 

#compare 
setkey(A,com) 
X <- A[com %in% B_long$com,] 

這個答案建立在理查茲的答案,但更有針對性的問題。

主要想法是構建一個id日期組合向量進行比較。這發生在第二個代碼塊中。

我的解決方案使用data.table包,但應該在語法更改時使用data.frame。但是使用data.table包具有keycolumns的優點。

如果你仍然有可以配對,這種方法與約翰的第二個答案,第一批A.