2013-03-19 49 views
2

你好我想下面的遞歸僞高清轉換成一個功能編程結構中R:轉換簡單的遞歸關係,以功能性程序

a = [ random numbers between 0 and 10 ] 
b = [ random numbers between -5 and 5 ] 
c = [ random numbers between 0 and -10 ] 

x0 = 200 
index = 0 

function f(x) { 
    index = index + 1 
    if(x is between 200 and 220) return f(x + a[index]) 
    else if(x is between 220 and 250) return f(x + b[index]) 
    else if(x is 250 and above) return f(x + c[index]) 
} 

可執行R代碼裏面是:

a <- sample(1:10,size=50, replace=TRUE) 
b <- sample(-5:5,size=50, replace=TRUE) 
c <- sample(-1:-10,size=50, replace=TRUE) 

index <- 0; 


myfunc <- function(x){ 
    index <<- index + 1; 
    if(index == 50) return(x) 
    if(x <= 220){ return(myfunc(x + a[index])) } 
    else if(x > 220 & x < 250){ return(myfunc(x + b[index])) } 
    else {return(myfunc(x + c[index]))} 
} 
print(myfunc(200)); 

想討論任何方法,包括Map/Filter/Reduce或Vectorisation。提前謝謝了。此外,我如何保留50個x元素的整個路徑(而不是隻看x的一個答案)。

+3

iiuc,你提到的所有這些功能在這裏都沒有用...... – Arun 2013-03-19 17:51:13

+2

說實話,你的代碼看起來有點奇怪,目前還不清楚你想實現什麼。你能用統計術語解釋你想要模擬的隨機變量(或向量)嗎? 「50個元素的整個路徑」是什麼意思? – 2013-03-19 18:06:04

+0

大家好,感謝您的期待。它是一個以200開頭的路徑相關值。然後根據x的前一個值(因此遞歸定義),它將在200到300之間移動50次。通過50個元素的整個路徑意味着我想通過函數myfunc知道x的所有中間值。例如,如果我使用for循環重寫了這個,我會聲明一個50的結果向量,然後在我到達我的最終值x之前迭代地填充它。你想讓我寫一個for-loop版本嗎? – user1480926 2013-03-19 18:10:53

回答

4

您可以使用Reduce功能和accumulate選項來保存所有中間值。

要看到這是如何工作,嘗試一下在簡單的「求和」功能

x = rep(200, 50) 
Reduce(x=x, f=sum) 
Reduce(x=x, f=sum, accumulate=T) 

你正在尋找的答案需要你重寫你的特殊功能,因此它可以被傳遞到降低:

foo <- function(x, y = 0){ 
    if (200 <= x & x < 220){ 
     x + sample(1:10, 1) 
    } 
    else if(220 <= x & x < 250){ 
     x + sample(-5:5, 1) 
    } 
    else if (250 <= x){ 
     x + sample(-1:-10, 1) 
    } 
} 

Reduce(x=rep(200, 50), f=foo, accumulate=T) 
+0

謝謝你,那太棒了。這正是我期待的洞察力。那麼我不能使用樣本並且不得不從列表中查找的場景呢?我也不明白你爲什麼將x初始化爲200? – user1480926 2013-03-19 19:39:17

+0

如果使用向量200,0,0,0,... 進行初始化,它就會起作用,這只是第一個重要的元素。 – kith 2013-03-19 19:46:58

+0

Gotcha - 我將如何做查找?會宣佈一個全局變量並跟蹤索引工作? – user1480926 2013-03-19 20:29:03

3

我還沒有得到它變成一個功能的形式,但我可以做什麼,我想你中的R想:

x=200; index=0; while (index < 50) {index <- index + 1; 
    if(tail(x,1) <= 220){ x <-c(x, tail(x,1)+a[index]) } else 
    { if(tail(x,1) & tail(x,1) < 250) { x <-c(x , tail(x,1)+b[index]) } else 
     {x <-c(x , tail(x,1)+c[index])} } 
    } 
x 
[1] 200 204 206 210 213 215 216 219 227 222 219 220 223 221 224 229 231 227 226 229 224 223 221 221 
[25] 216 218 223 220 226 221 217 224 228 228 231 236 233 234 229 227 230 229 227 227 225 225 228 232 
[49] 227 230 228 

也許這將有助於看到一個方法來「功能化」了。我認爲Reducereplicate或者一個Reference Class對象可能提供機制。這只是將x向量擴展1個元素,然後在下一次迭代中使用該元素來選擇要使用哪個增量向量。如果你想超過50長度的輸出,你可以使用模餘數學的索引。

+1

謝謝@DWin我有一種鬼鬼祟祟的感覺,你可能會回答這個:)。我想我的問題瀰漫在函數式編程中,以解決更嚴峻的現實世界問題 - 特別是對於一直以來完成OO /程序性事務的人來說。 – user1480926 2013-03-19 18:48:49

+1

我承認這種模擬也有困難。 「常用」索引方法沒有任何效果。 'cumsum'和'cumprod'應該有遞歸/增量版本。如果我是C++程序員,我會用Rcpp包來做。 – 2013-03-19 20:53:50

+0

你的代碼縮進讓我的眼睛流血;) – hadley 2013-03-20 13:14:27

2

首先,我將首先對函數進行參數化以匹配您的原始描述,並在仿真參數更改時更容易更改。

foo_cat <- function(x) { 
    if (200 <= x & x < 220) return("a") 
    if (220 <= x & x < 250) return("b") 
    if (250 <= x) return("c") 

    stop("x out of range") 
} 
ranges <- list(a = 1:10, b = -5:5, c = -(1:10)) 

foo_sample <- function(x, n = 1) { 
    sample(ranges[[foo_cat(x)]], n, rep = TRUE) 
} 

對我來說,這是函數式編程中最重要的部分:編寫封裝瞭解決方案重要組件的函數。

接下來我們將使用foo_sample來解決for循環的問題。這使得明確了當前和以前的值之間的關係:

n <- 50 
out <- c(200, rep(NA, n - 1)) 

for(i in seq(2, n)) { 
    out[i] <- out[i - 1] + foo_sample(out[i - 1]) 
} 

接下來,你可以考慮一下for循環取出,並用functional取代它。不幸的是,沒有封裝這個模式的內置函數,所以你可以寫自己的代碼(如果這是代碼中非常常見的模式,這是一個好主意),或者堅持使用for循環(如果你想要的話,一個好主意你的代碼很容易閱讀)。

+0

這看起來很有趣。讓我測試一下。謝謝 !! – user1480926 2013-03-20 13:49:39