Сбросить поток случайных чисел

Похоже, что SAS/IML имеет возможность сбросить свой поток случайных чисел (ссылка на документ) .

Есть ли аналогичная функция для процедур случайных чисел на этапе данных SAS?

На основе этот пост кажется, что последующие вызовы streaminit игнорируются в рамках одного шага данных.

Например, приведенный ниже код создает разные случайные числа для каждой строки:

data want;
  do i = 1 to 2;
    call streaminit(123);  * <-- WANT THIS TO RESET THE STREAM;
    ran1 = rand('uniform');      
    ran2 = rand('uniform');      
    ran3 = rand('uniform');      
    put _all_;
    output;
  end;
run;

Выход:

i=1 ran1=0.5817000773 ran2=0.0356216603 ran3=0.0781806207 
i=2 ran1=0.3878454913 ran2=0.3291709244 ran3=0.3615948586 

Я хотел бы, чтобы вывод был:

i=1 ran1=0.5817000773 ran2=0.0356216603 ran3=0.0781806207 
i=2 ran1=0.5817000773 ran2=0.0356216603 ran3=0.0781806207 

person Robert Penridge    schedule 04.12.2017    source источник
comment
Используйте подпрограммы CALL для случайных чисел вместо функций RAN*. Подпрограммы позволяют управлять независимыми потоками случайных значений. Вариант использования для вас заключается в том, что когда два или более потока инициализируются с одним и тем же начальным числом, они будут доставлять одну и ту же последовательность значений.   -  person Richard    schedule 04.12.2017
comment
Из любопытства, почему вы хотите это сделать?   -  person Rick    schedule 29.12.2017
comment
@Rick Я тестировал несколько разных алгоритмов шифрования и хотел иметь возможность воспроизводить одни и те же случайные значения в функции fcmp всякий раз, когда она вызывается.   -  person Robert Penridge    schedule 30.01.2018


Ответы (3)


Вы не можете сбросить потоки для функции RAND в SAS 9.4M4. Однако вы можете перематывать поток в SAS 9.4M5 (отправлено в сентябре 2017 г.), используя новый подпрограмма STREAMREWIND. Следующая программа демонстрирует синтаксис:

data want;
  call streaminit(123);  
  do i = 1 to 2;
    call streamrewind;
    ran1 = rand('uniform');      
    ran2 = rand('uniform');      
    ran3 = rand('uniform');      
    put _all_;
    output;
  end;
run;
person Rick    schedule 05.12.2017
comment
Идеальный. Спасибо, Рик. Ранее на этой неделе мы обновились до 9.4M5. - person Robert Penridge; 05.12.2017

Однако вы можете обойти это, используя сгенерированный код, с помощью CALL EXECUTE или, возможно, DOSUBL, например:

data _null_;
  do i = 1 to 2;
    rc=dosubl(cats("data want_",i,";
    call streaminit(123);  * <-- WANT THIS TO RESET THE STREAM;
    ran1 = rand('uniform');      
    ran2 = rand('uniform');      
    ran3 = rand('uniform');    
    i=",i,"; 
    put _all_;
    output;
    run;
    "));
  end;
  rc = dosubl("data want; set want_1 want_2; run;");
run;

Очевидно, проще/лучше написать макрос для выполнения этой части.

К сожалению, это ограничение «новой» процедуры RAND; со старым было намного легче работать в этом отношении (поскольку на самом деле у него было только одно семя). Начальные свойства нового более сложны, поэтому, хотя вы можете инициализировать его одним числом, это не так просто, отсюда и сложности.

person Joe    schedule 04.12.2017
comment
Randseed принимает необязательный второй параметр для повторной инициализации потока. Я связал документ в своем вопросе, но его довольно легко пропустить. Вот снова: documentation.sas.com/ - person Robert Penridge; 04.12.2017
comment
Ах, мои извинения, я пропустил это. Удалил эту часть; остальная часть моего ответа, хотя я думаю, что в конечном итоге отвечает на ваш вопрос. - person Joe; 04.12.2017
comment
Без проблем. Я предполагаю, что окончательный ответ: нет, нет встроенного способа добиться этого на шаге данных начиная с 9.4TS1M5. Спасибо. - person Robert Penridge; 04.12.2017
comment
Я думаю, что это задумано... но да, вам придется обойти это. Вы даже не можете использовать FCMP, чтобы обойти это, к сожалению, вам действительно нужно запускать отдельные шаги данных (либо буквально, либо с помощью обходного пути, такого как DOSUBL или CALL EXECUTE, который запускает несколько шагов данных). - person Joe; 04.12.2017
comment
Да, к сожалению, обнаружил это сейчас, когда столкнулся с проблемой при попытке создать функцию fcmp. - person Robert Penridge; 04.12.2017
comment
Может быть, RUN_MACRO в FCMP может заставить его работать? Или DS2 — возможно, каждый поток отдельно инициализировал бы свой собственный поток? - person Joe; 04.12.2017
comment
В любом случае я бы оставил это открытым на данный момент; Рик периодически публикует здесь сообщения, и он был бы здесь экспертом. Я видел эту проблему в прошлом, и я не думаю, что есть ответ, но если бы он был, он бы знал. - person Joe; 04.12.2017
comment
Вот почему я добавил тег IML ;-) - person Robert Penridge; 04.12.2017

Вы можете использовать call ranuni, чтобы использовать одно и то же начальное число для двух разных потоков случайных чисел.

Обратите внимание, что здесь используется другой, более низкий PRNG с гораздо более коротким циклом и худшими статистическими свойствами, чем функция rand().

Пример:

data x;
  seed1 = 123;
  seed2 = 123;
  do i =1 to 3;
    call ranuni(seed1, x); 
    call ranuni(seed2, y); 
    output;
  end;
run;

Выход:

i=1 x=0.7503960881 y=0.7503960881
i=2 x=0.3209120251 y=0.3209120251
i=3 x=0.178389649 y=0.178389649
person Robert Penridge    schedule 04.12.2017
comment
Это правда, но следует пояснить, что это не то же самое, что PRNG в вопросе; это другой, более низкий PRNG, с гораздо более коротким циклом и худшими статистическими свойствами. Он вполне может быть использован для ваших целей, в зависимости от того, каковы эти цели. Это то, что я имел в виду в своем ответе как старую рутину. - person Joe; 04.12.2017
comment
Да, TBH, я не уверен, что это решает мою текущую проблему. Хотя есть ощущение, что он на шаг ближе. Я подумал, что это может помочь кому-то еще, поэтому я решил опубликовать это как ответ. Я думаю, что подход dosubl по-прежнему остается самым «правильным». - person Robert Penridge; 04.12.2017