2013-06-21 4 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} над thoses значений:

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... 

в основном это все комбинации с 4-векторов 3-х элементов:

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, чтобы получить все комбинации. Но вам нужно сначала Vectorize вашей функции 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, для выполнения вычислений внутри dataframe:

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^4 комбинации {3,3,3,3}, так почему же только 3 возвращения? Кстати, вы были правы, я сделал ошибку, состояние CO-CS | CD не наоборот. – Wicelo

+0

Это не 3^4, на самом деле я не уверен, как считать это, но я добавил несколько примеров значений HM, которые мне нужны. – Wicelo

+1

Вздох.Вероятно, это будет связано с расширением сетки, но без примера я не вижу большого смысла в продолжении этой игры гадания. –