2013-06-21 29 views
1

如何在R中矢量化這個過程而不使用太多循環?如何在R中矢量化這個過程?

我有這樣的功能:

HM=function(CO,CS,CD,CSD){ 
    if(CO-CS)>1){ 
    return(2^(CS)/(2^(CO)-2^(CSD))) 
    } 
    else if(CO-CD)>1){ 
    return(1-2^(CD)/(2^(CO)-2^(CSD))) 
    } 
return(0) 
} 

基本上我需要在放入系統值來獲得HM值{CO,CS,CD,CSD}的每個組合:

CO 25.76031685 25.71126747 25.90163231 
CS 24.40528297 24.09929848 23.51999092 
CD 25.99405861 25.72906113 25.61374474 
CSD 35.94195557 36.07263184 34.00024414 

所以我需要以獲得這些值:

HM(25.76031685,24.40528297,25.99405861,35.94195557) 
HM(25.71126747,24.40528297,25.99405861,35.94195557) 
HM(25.90163231,24.40528297,25.99405861,35.94195557) 
HM(25.76031685,24.09929848,25.99405861,35.94195557) 
HM(25.71126747,24.09929848,25.99405861,35.94195557) 
HM(25.90163231,24.09929848,25.99405861,35.94195557) 
HM(25.76031685,23.51999092,25.99405861,35.94195557) 
HM(25.71126747,23.51999092,25.99405861,35.94195557) 
HM(25.90163231,23.51999092,25.99405861,35.94195557) 
etc... 

基本上它是與3個元素的4個向量的所有組合:

Vectors : 
a=c(1,2,3) 
b=c(1,2,3) 
c=c(1,2,3) 
d=c(1,2,3) 

Combinations : 
1,1,1,1 
2,1,1,1 
1,2,1,1 
1,1,2,1 
1,1,1,2 
3,1,1,1 
1,3,1,1 
etc... 

我不知道如何計算組合數。當然,我可以使用4個嵌套循環,但我想學習如何使用矢量化,因爲R對於循環來說太慢。我認爲我們可以使用expand.grid,但我不知道如何。此外,該表是在Excel中,我可以導出爲.csv,但我不確定實現這種東西的最佳方式,所以感謝您的幫助!

回答

1

您可以使用expand.grid得到所有組合。但是,你首先需要矢量化你的函數HM,採用ifelse代替if

HM2 <- function(CO,CS,CD,CSD) 
{ 
    den <- 2^CO-2^CSD 

    ifelse(CO-CS>1, 2^CS/den, 
     ifelse(CO-CD>1, 1-2^CD/den, 0)) 
} 

注意den是常見的兩種結果。

你現在的數據:

CO <- c(25.76031685, 25.71126747, 25.90163231) 
CS <- c(24.40528297, 24.09929848, 23.51999092) 
CD <- c(25.99405861, 25.72906113, 25.61374474) 
CSD <- c(35.94195557, 36.07263184, 34.00024414) 

的組合:

cmbs <- expand.grid(CO, CS, CD, CSD) 
names(cmbs) <- c("CO", "CS", "CD", "CSD") 

實施例:

> head(cmbs) 
     CO  CS  CD  CSD 
1 25.76032 24.40528 25.99406 35.94196 
2 25.71127 24.40528 25.99406 35.94196 
3 25.90163 24.40528 25.99406 35.94196 
4 25.76032 24.09930 25.99406 35.94196 
5 25.71127 24.09930 25.99406 35.94196 
6 25.90163 24.09930 25.99406 35.94196 

可使用within,進行數據幀的內部計算來獲得的最終結果:

result <- within(cmbs, HM <- HM2(CO, CS, CD, CSD)) 

例子:

> head(result) 
     CO  CS  CD  CSD   HM 
1 25.76032 24.40528 25.99406 35.94196 -0.0003368911 
2 25.71127 24.40528 25.99406 35.94196 -0.0003368814 
3 25.90163 24.40528 25.99406 35.94196 -0.0003369210 
4 25.76032 24.09930 25.99406 35.94196 -0.0002725079 
5 25.71127 24.09930 25.99406 35.94196 -0.0002725000 
6 25.90163 24.09930 25.99406 35.94196 -0.0002725321 
+0

真棒,我在這個晚上得出了同樣的結論。謝謝 !但是,當我添加第三個ifelse()到HM()時,它不再工作了,你知道爲什麼嗎? http://stackoverflow.com/questions/17252466/why-with-in-r-is-doing-vector-operation-in-one-case-and-not-in-the-other – Wicelo

+0

@Wicelo,它看起來像你已經知道了。問題是'&&'。羅蘭的答案非常好,採用完全矢量化的方法。再見! –

1

答案就在這種情況下,相當無趣,因爲沒有條件適用於這些價值和全部爲零返回:

> tdat # dataframe version of that data. 
     CO  CS  CD  CSD 
V2 25.76032 24.40528 25.99406 35.94196 
V3 25.71127 24.09930 25.72906 36.07263 
V4 25.90163 23.51999 25.61374 34.00024 
> with(tdat, 
     ifelse((CS-CO) > 1, 2^(CS)/(2^(CO)-2^(CSD)), #1st consequent 
       ifelse ((CD-CO) > 1, 1-2^(CD)/(2^(CO)-2^(CSD)), # 2nd 
              0))) # default 
[1] 0 0 0 

要做到這一點對一個矩陣versioon您需要首先糾正該數據在你的代碼,然後不匹配的括號使用申請,同時引用一個傳遞x值與rownames:

mdat <- 
structure(c(25.76032, 24.40528, 25.99406, 35.94196, 25.71127, 
24.0993, 25.72906, 36.07263, 25.90163, 23.51999, 25.61374, 34.00024 
), .Dim = c(4L, 3L), .Dimnames = list(c("CO", "CS", "CD", "CSD" 
), NULL)) 

> apply(mdat, 2, function(x){ 
+ if((x['CS']-x['CO'])>1){ 
+  return(2^(x['CS'])/(2^(x['CO'])-2^(x['CSD']))) 
+ } 
+ else if((x['CD']-x['CO'])>1){ 
+  return(1-2^(x['CD'])/(2^(x['CO'])-2^(x['CSD']))) 
+ } 
+ return(0) 
+ }) 
[1] 0 0 0 
+0

謝謝您的回覆!不過,我不明白這個列表{3,3,3,3}有3^4個可能的組合,那麼爲什麼只有3個返回?順便說一句,你是對的,我犯了一個錯誤,條件是CO-CS | CD不是相反的。 – Wicelo

+0

它不是3^4其實我不確定如何計算,但我添加了一些我需要的HM值的例子。 – Wicelo

+1

感嘆。這可能會涉及'擴大網格',但沒有一個例子,我沒有看到很多點繼續這個猜謎遊戲。 –