2011-10-23 66 views
1

我有一個大約25000條記錄和10列的數據框。我正在使用代碼來確定在同一列(NewVal)中基於另一列(y)已更改百分比已更改爲以前的值。有更快的方法來獲得百分比變化嗎?

x=c(1:25000) 
y=rpois(25000,2) 
z=data.frame(x,y) 
z[1,'NewVal']=z[1,'x'] 

於是我就這樣:

for(i in 2:nrow(z)){z$NewVal[i]=z$NewVal[i-1]+(z$NewVal[i-1]*(z$y[i]/100))} 

這大大超過我預期需要。誠然,我可能是一個不耐煩的人 - 正如我曾經說過的一封嚴厲的信件 - 但我試圖逃避Excel的世界(在我讀http://www.burns-stat.com/pages/Tutor/spreadsheet_addiction.html之後,由於我開始懷疑數據,這導致了更多問題 - 那封信也提到了我的信任問題)。

我想這樣做,而不使用軟件包中的任何函數,因爲我想知道創建值的公式是什麼 - 或者如果您願意,根據該友好信函我是一個要求苛刻的控制怪胎。

我也想知道如何在caTools中獲得像rollmean一樣的移動平均值。無論是或如何找出他們的公式是什麼?我試着輸入rollmean,我認爲它是指另一個函數(我是R的新手)。這應該可能是另一個問題 - 但正如那封信所說,我從來沒有在我的生活中做出正確的決定。

回答

7

R中的祕密是矢量化。在您的例子中,你可以使用cumprod做繁重:

z$NewVal2 <- x[1] * cumprod(with(z, 1 +(c(0, y[-1]/100)))) 

all.equal(z$NewVal, z$NewVal2) 
[1] TRUE 

head(z, 10) 
    x y NewVal NewVal2 
1 25 4 25.00000 25.00000 
2 24 3 25.75000 25.75000 
3 23 0 25.75000 25.75000 
4 22 1 26.00750 26.00750 
5 21 3 26.78773 26.78773 
6 20 2 27.32348 27.32348 
7 19 2 27.86995 27.86995 
8 18 3 28.70605 28.70605 
9 17 4 29.85429 29.85429 
10 16 2 30.45138 30.45138 

在我的機器,環路只需不到3分鐘的運行,而cumprod聲明實際上是瞬時的。

+0

它只要作品爲'X = C(1:25000)'但如果'X = C(25000:1)'我得到不同的結果。 – thequerist

+0

編輯答案。我相信它現在適用於這兩種情況。 – Andrie

+0

我討厭這樣做給你,但是當'z $ x [1] = 0'時,一切都出來了0.無論如何,我也會檢查'cumprod'和'with',看看我能不能拿出任何東西。 – thequerist

6

我得到了約800倍的改善與Reduce

system.time(z[, "NewVal"] <-Reduce("*", c(1, 1+z$y[-1]/100), accumulate=T)) 
    user system elapsed 
    0.139 0.008 0.148 

> head(z) 
    x y NewVal 
1 1 1 1.000 
2 2 1 1.010 
3 3 1 1.020 
4 4 5 1.071 
5 5 1 1.082 
6 6 2 1.103 
7 7 2 1.126 
8 8 3 1.159 
9 9 0 1.159 
10 10 1 1.171 
> system.time(for(i in 2:nrow(z)){z$NewVal[i]=z$NewVal[i-1]+ 
               (z$NewVal[i-1]*(z$y[i]/100))}) 
    user system elapsed 
    37.29 106.38 143.16 
+0

你的'Reduce'函數只返回24999個值,我認爲在插入'z [,'Newval']'之前,應該先將'1(1)'加入到它。無論如何,我真的很喜歡你的解決方案(+1),請給出一些解釋,爲什麼你在'z NewVal [-1]'的調用中使用'z $ NewVal [-nrow(z)]'?我必須深入瞭解'Reduce' ... – daroczig

+0

@DWin這看起來很有趣,很有前景。但我無法實現它的工作。所提供的代碼僅適用於已經計算了「z $ NewValues」的值的情況,即當在具有「z $ NewValues < - 1」的原始數據上運行時,結果毫無意義。解決方案中是否存在缺失的代碼行? – Andrie

+0

我有遞歸公式錯誤。 「Reduce」方法可以應用@Andrie的相同策略。但是比他慢十倍。 (對於for循環仍然有很大的改進。) –