Двойной для петель в R

Как правильно написать двойной цикл for в R?

Например, в C я бы сделал

int i, j;
for (i = 1; i < 6; i++) {
    for (j=i; j <= 3; j++) {
        printf("%i,%i\n",i,j);
    }
    // Do more operations for i > 3...
}

который будет генерировать (искусственную) последовательность:

1,1
1,2
1,3
2,2
2,3
3,3

В R вы не получаете такого же поведения, когда пишете

for (i in 1:6) {
    for (j in i:3) {
        print(paste(i,j,sep=","))
    }
}

поэтому я был вынужден делать что-то вроде

for (i in 1:6) {
    j <- i
    while (j <= 3) {
        print(paste(i,j,sep=","))
        j <- j+1
    }
}       

Есть ли способ лучше?

Как упомянул Шейн, возможно, мне следует пояснить: меня особенно интересует стиль кода, соответствующий математике, чтобы ученикам было легче его понять. Кажется, что ученикам удобнее всего for петель.

В частности, я хочу, чтобы мои студенты смоделировали модель рынка LIBOR. Динамика форвардного курса моделируется при той же вероятностной мере. Таким образом, для каждого временного шага и каждой скорости движения необходимо рассчитать и добавить соответствующую поправку на дрейф \mu_i.


person Community    schedule 12.10.2009    source источник
comment
Вы имеете в виду я в 1: (2 * N). В противном случае ваш i-индекс будет принимать только значения N и 2*N.   -  person Rob Hyndman    schedule 13.10.2009
comment
Да, спасибо. Я взял значения сейчас, чтобы сделать это более ясным.   -  person    schedule 13.10.2009
comment
Вы могли бы сделать свою цель немного яснее: вы пытаетесь научить R студентов, которые знают C (например)? Вероятно, есть много эффективных способов создать эту последовательность, но похоже, что вас особенно интересуют циклы for()...   -  person Shane    schedule 13.10.2009
comment
Я преподаю курс для студентов магистратуры по финансовой математике. Они происходят из разных слоев общества, и большинство из них никогда раньше не программировали. Я бы хотел, чтобы они все хорошо знали C или хотя бы какой-то другой язык... :)   -  person    schedule 13.10.2009


Ответы (3)


Извините за потенциально глупый вопрос, но в каком смысле R не может этого сделать? Это прекрасно работает для меня:

N <- 5
for (i in 0:(2*N)) {
   for (j in i:N) {
        print(paste(i,j,sep=","))
    }
}

Может быть, вы просто не поставили круглые скобки в конце своей последовательности?

Редактировать: понятно... вы хотите, чтобы последовательность i:3 всегда была ‹= 3? Я не думаю, что это возможно ни с последовательностью, ни с предложением оператора for. Вы можете установить разрыв внутри цикла, но это не лучше, чем ваш текущий подход:

for (i in 1:6) {
    for (j in i:3) {
        if(j > 3) break()
        print(paste(i,j,sep=","))
    }
}  

Вот еще один способ сгенерировать эту последовательность без цикла for:

x <- cbind(rep(c(1,2,3), 3),
    rep(c(1,2,3), each=3))

Или с помощью expand.grid (согласно предложению Дирка):

x <- expand.grid(x=1:3, y=1:3)

Затем удалите нежелательные случаи:

x[x[,1] >= x[,2],]

Редактировать 2: Это может не соответствовать вашим потребностям, но я считаю, что в Quantlib реализована модель рынка Libor. Я не уверен, что он представлен в RQuantlib.

person Shane    schedule 12.10.2009
comment
Я отредактировал свой вопрос, чтобы, надеюсь, теперь стало понятнее. Спасибо. - person ; 13.10.2009
comment
Использование перерыва приятно, это означает, что мне не нужно объяснять время. Спасибо. - person ; 13.10.2009
comment
break скобки не нужны (). - person Gregor Thomas; 18.05.2016

Конечно, вы можете вкладывать циклы:

R> for (i in 1:3) for (j in 1:3) cat(i,j,i*j, "\n")
1 1 1 
1 2 2 
1 3 3 
2 1 2 
2 2 4 
2 3 6 
3 1 3 
3 2 6 
3 3 9 
R> 

Есть общий смысл, что вы не должны, так как векторизованные вызовы легче читать и писать:

R> outer(1:3,1:3, "*")
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    2    4    6
[3,]    3    6    9
R> 

но если легче разрабатывать с nexted петлями, то делайте так.

Что касается проблемы «второй индекс, зависящий от первого индекса», вы также можете использовать lower.tri(), upper.tri() или индексирование для достижения этого.

R> X <- expand.grid(x=1:3, y=1:3)
R> X <- X[ X$x >= X$y, ]
R> outer(X$x, X$y, "*")
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    1    1    2    2    3
[2,]    2    2    2    4    4    6
[3,]    3    3    3    6    6    9
[4,]    2    2    2    4    4    6
[5,]    3    3    3    6    6    9
[6,]    3    3    3    6    6    9
R> 
person Dirk Eddelbuettel    schedule 12.10.2009
comment
Спасибо, использование external, вероятно, является хорошим способом сделать это, я попробую. Хотя из-за этого алгоритм больше не выглядит как математика, поэтому моим ученикам его трудно понять. - person ; 13.10.2009

Проблема здесь в том, что i:3 имеет смысл, когда i>3. Например, 5:3 дает (5,4,3). Все, что вам нужно, это простой оператор if, чтобы предотвратить запуск второго цикла, когда i>3.

for (i in 1:6) {
    if(i < 4) {
        for (j in i:3) {
            print(paste(i,j,sep=","))
        }
    }
    # Do more operations for i > 3...
}

Однако по возможности старайтесь избегать явного зацикливания. Ответы Дирка и Шейна дают некоторые идеи о том, как это сделать.

person Rob Hyndman    schedule 13.10.2009
comment
Это хорошо, это означает, что мне не нужно объяснять, что делает while. - person ; 13.10.2009