跨数据集在 SAS 中为 id 分配一个一致的随机数
Assign a consistent random number to id in SAS across datasets
我有两个数据集 data1
和 data2
,其中有一个 id
列。我想为每个 id 分配一个随机 id,但是这个随机数需要在数据集中保持一致。 (rand_id
for id=1
在两个数据集中必须相同)。 objective 是得到:
id
rand_id
1
0.4212
2
0.5124
3
0.1231
id
rand_id
1
0.4212
3
0.1231
2
0.5124
4
0.9102
请注意,Id 不需要排序,一些 Id 可能会出现在一个数据集中,但不会出现在另一个数据集中。我以为
DATA data1;
SET data1;
CALL STREAMINIT(id);
rand_id=RAND('uniform');
RUN;
和 data2
一样可以完成这项工作,但事实并非如此。它只是将第一个 id 作为种子并生成一系列随机数。
从 STREAMINIT 文档来看,似乎每个数据集只调用一次。我想在每一行都被称为它。这可能吗?
我们的想法是创建一个 table random_values
,并为我们稍后加入两个 table 的每个 ID 关联一个随机 ID。
*assign random seed;
%let random_seed = 71514218;
*list of unique id;
proc sql;
create table unique_id as
select distinct id
from (
select id from have1
union all
select id from have2
)
;
quit;
*add random values;
data random_values;
set unique_id;
call streaminit(&random_seed.);
rand = rand('uniform', 0, 1);
run;
*join back on have1;
proc sql;
create table have1 as
select t1.id, t2.rand as rand_id
from have1 t1 left join random_values t2
on t1.id = t2.id
;
quit;
*join back on have2;
proc sql;
create table have2 as
select t1.id, t2.rand as rand_id
from have2 t1 left join random_values t2
on t1.id = t2.id
;
quit;
已解决:
DATA data1;
SET data1;
seed = id;
CALL RANUNI(seed,rand_id);
DROP seed;
RUN;
生成所需的结果。
为什么不使用查找数据集。您可以 create/update 使用 HASH 对象。
首先制作一个空数据集:
data rand_id;
set one(keep=id);
rand_id=.;
stop;
run;
然后处理第一个数据集。将新的 RAND_ID 变量添加到该数据集,并使用所有唯一 ID 值填充 RAND_ID 数据集。
data one_random;
if _n_=1 then do;
declare hash h(dataset:'rand_id');
rc=h.definekey('id');
rc=h.definedata('id','rand_id');
rc=h.definedone();
end;
if eof then rc=h.output(dataset:'rand_id');
set one end=eof;
if h.find() then do;
rand_id=rand('uniform');
rc=h.add();
end;
drop rc;
run;
对共享相同 ID 变量的任何其他数据集重复上述步骤。
data two_random;
if _n_=1 then do;
declare hash h(dataset:'rand_id');
rc=h.definekey('id');
rc=h.definedata('id','rand_id');
rc=h.definedone();
end;
if eof then rc=h.output(dataset:'rand_id');
set two end=eof;
if h.find() then do;
rand_id=rand('uniform');
rc=h.add();
end;
drop rc;
run;
在我看来,最简单的方法是创建格式数据集。 Tom 的哈希示例也很好,但如果您不了解哈希表,这可能更容易。
不要从 ID 本身播种随机数 - 这不再是随机的。
data forfmt;
set data1;
call streaminit(7);
label = put(rand('Uniform'),12.9);
start = id;
fmtname = 'RANDIDF';
output;
if _n_ eq 1 then do;
hlo='o';
label='.';
output;
end;
run;
proc format cntlin=forfmt;
quit;
然后你可以使用put(id,randidf.)
分配随机ID(并使用input
而不是put
并使其成为一个信息,如果你希望它是数字,那就处理了通过 type='i';
并需要输入为字符或通过 put
转换为字符)。无需排序,大部分时间查找速度非常快。
我有两个数据集 data1
和 data2
,其中有一个 id
列。我想为每个 id 分配一个随机 id,但是这个随机数需要在数据集中保持一致。 (rand_id
for id=1
在两个数据集中必须相同)。 objective 是得到:
id | rand_id |
---|---|
1 | 0.4212 |
2 | 0.5124 |
3 | 0.1231 |
id | rand_id |
---|---|
1 | 0.4212 |
3 | 0.1231 |
2 | 0.5124 |
4 | 0.9102 |
请注意,Id 不需要排序,一些 Id 可能会出现在一个数据集中,但不会出现在另一个数据集中。我以为
DATA data1;
SET data1;
CALL STREAMINIT(id);
rand_id=RAND('uniform');
RUN;
和 data2
一样可以完成这项工作,但事实并非如此。它只是将第一个 id 作为种子并生成一系列随机数。
从 STREAMINIT 文档来看,似乎每个数据集只调用一次。我想在每一行都被称为它。这可能吗?
我们的想法是创建一个 table random_values
,并为我们稍后加入两个 table 的每个 ID 关联一个随机 ID。
*assign random seed;
%let random_seed = 71514218;
*list of unique id;
proc sql;
create table unique_id as
select distinct id
from (
select id from have1
union all
select id from have2
)
;
quit;
*add random values;
data random_values;
set unique_id;
call streaminit(&random_seed.);
rand = rand('uniform', 0, 1);
run;
*join back on have1;
proc sql;
create table have1 as
select t1.id, t2.rand as rand_id
from have1 t1 left join random_values t2
on t1.id = t2.id
;
quit;
*join back on have2;
proc sql;
create table have2 as
select t1.id, t2.rand as rand_id
from have2 t1 left join random_values t2
on t1.id = t2.id
;
quit;
已解决:
DATA data1;
SET data1;
seed = id;
CALL RANUNI(seed,rand_id);
DROP seed;
RUN;
生成所需的结果。
为什么不使用查找数据集。您可以 create/update 使用 HASH 对象。
首先制作一个空数据集:
data rand_id;
set one(keep=id);
rand_id=.;
stop;
run;
然后处理第一个数据集。将新的 RAND_ID 变量添加到该数据集,并使用所有唯一 ID 值填充 RAND_ID 数据集。
data one_random;
if _n_=1 then do;
declare hash h(dataset:'rand_id');
rc=h.definekey('id');
rc=h.definedata('id','rand_id');
rc=h.definedone();
end;
if eof then rc=h.output(dataset:'rand_id');
set one end=eof;
if h.find() then do;
rand_id=rand('uniform');
rc=h.add();
end;
drop rc;
run;
对共享相同 ID 变量的任何其他数据集重复上述步骤。
data two_random;
if _n_=1 then do;
declare hash h(dataset:'rand_id');
rc=h.definekey('id');
rc=h.definedata('id','rand_id');
rc=h.definedone();
end;
if eof then rc=h.output(dataset:'rand_id');
set two end=eof;
if h.find() then do;
rand_id=rand('uniform');
rc=h.add();
end;
drop rc;
run;
在我看来,最简单的方法是创建格式数据集。 Tom 的哈希示例也很好,但如果您不了解哈希表,这可能更容易。
不要从 ID 本身播种随机数 - 这不再是随机的。
data forfmt;
set data1;
call streaminit(7);
label = put(rand('Uniform'),12.9);
start = id;
fmtname = 'RANDIDF';
output;
if _n_ eq 1 then do;
hlo='o';
label='.';
output;
end;
run;
proc format cntlin=forfmt;
quit;
然后你可以使用put(id,randidf.)
分配随机ID(并使用input
而不是put
并使其成为一个信息,如果你希望它是数字,那就处理了通过 type='i';
并需要输入为字符或通过 put
转换为字符)。无需排序,大部分时间查找速度非常快。