Sas 将所有数组值设置为单个值

Sas 将所有数组值设置为单个值,sas,Sas,如果满足某种条件,我想将数组中的所有值设置为1,如果不满足该条件,则执行计算。我正在使用一个非常慢的do循环 我想知道有没有更快的办法 data test2; set test1; array blah_{*} blah1-blah100; array a_{*} a1-a100; array b_{*} b1-b100; do i=1 to 100; blah_{i}=a_{i}/b_{i}; if b1=0 then blah_{i}=1; end; run; 我觉得if语句效率很低,

如果满足某种条件,我想将数组中的所有值设置为1,如果不满足该条件,则执行计算。我正在使用一个非常慢的do循环

我想知道有没有更快的办法

data test2;
set test1;
array blah_{*} blah1-blah100;
array a_{*} a1-a100;
array b_{*} b1-b100;

do i=1 to 100;
blah_{i}=a_{i}/b_{i};
if b1=0 then blah_{i}=1;
end;

run;

我觉得if语句效率很低,因为我一次将值设置为1个单元格。有更好的方法吗?

你有100*NOB作业要做。看不出在数组上使用DO循环比任何其他方法都更低效

但是,当你知道不需要计算时,就没有必要进行计算

do i=1 to 100;
  if b1=0 then blah_{i}=1;
  else blah_{i}=a_{i}/b_{i};
end;

本例使用数据集“设置”数组的所有值,而不在数组上执行任何操作。请注意,以这种方式使用SET会将数组BLAH的INIT-TO-MISSING更改为not。我不能评论性能,您需要自己进行测试

data one;
   array blah[10];
   retain blah 1;
   run;
proc print;
   run;

data test1;
   do b1=0,1,0;
      output;
      end;
   run;

data test2;
   set test1;
   array blah[10]; 
   array a[10];
   array b[10];

   if b1 eq 0 then set one nobs=nobs point=nobs;
   else do i = 1 to dim(blah);
      blah[i] = i;
      end;
   run;
proc print;
   run;

这不是对原始问题的回答,而是对使用循环与设置多个变量值之间的效率的讨论的回答

下面是我做的一个简单的实验:

%let size = 100; /* Controls size of dataset */
%let iter = 1;   /* Just to emulate different number of records in the base dataset */

data static;
  array aa{&size} aa1 - aa&size (&size * 1);
run;

data inp;
  do ii = 1 to &iter;
    x = ranuni(234234);
    output;
  end;
run;

data eg1;
  set inp;

  array aa{&size} aa1 - aa&size;
  set static nobs=nobs point=nobs;

run;

data eg2;
  set inp;
  array aa{&size} aa1 - aa&size;
  do ii = 1 to &size;
    aa(ii) = 1;
  end;
run;

当我使用不同的&iter和&size值运行时,我看到的情况如下:

随着&iter值为1时&size的增加,赋值方法比集合更快

然而,对于给定的&size,随着iter的增加(即set语句/循环被调用的次数),set方法的速度增加,而赋值方法在它们交叉的某个点开始降低。我认为这是因为从物理磁盘到缓冲区的传输只发生一次(因为静态数据集相对较小),而分配循环成本是固定的


对于这个用例,用于设置值的固定数据集将更小,我承认set将更快,特别是当逻辑需要在输入上的多个记录上执行,并且需要分配的变量数量相对较少时。但是,如果数据集不能缓存在两个记录之间的内存中,则情况就不会如此。在这种情况下,必须将数据集读入缓冲区的额外开销可能会降低数据集的速度。

我认为此测试隔离了感兴趣的语句

总结: 设置+创建初始数组0.40秒+0.03秒, 在阵列上运行11.64秒

NOTE: Additional host information:

 X64_SRV12 WIN 6.2.9200  Server

NOTE: SAS initialization used:
      real time           4.70 seconds
      cpu time            0.07 seconds

1          options fullstimer=1;
2          %let d=1e4; /*array size*/
3          %let s=1e5; /*reps (obs)*/
4          data one;
5             array blah[%sysevalf(&d,integer)];
6             retain blah 1;
7             run;

NOTE: The data set WORK.ONE has 1 observations and 10000 variables.
NOTE: DATA statement used (Total process time):
      real time           0.03 seconds
      user cpu time       0.03 seconds
      system cpu time     0.00 seconds
      memory              7788.90k
      OS Memory           15232.00k
      Timestamp           08/17/2019 06:57:48 AM
      Step Count                        1  Switch Count  0


8          
9          sasfile one open;
NOTE: The file WORK.ONE.DATA has been opened by the SASFILE statement.
10         data _null_;
11            array blah[%sysevalf(&d,integer)];
12            do _n_ = 1 to &s;
13               set one nobs=nobs point=nobs;
14               end;
15            stop;
16            run;

NOTE: DATA statement used (Total process time):
      real time           0.40 seconds
      user cpu time       0.40 seconds
      system cpu time     0.00 seconds
      memory              7615.31k
      OS Memory           16980.00k
      Timestamp           08/17/2019 06:57:48 AM
      Step Count                        2  Switch Count  0


2                                                      The SAS System                         06:57 Saturday, August 17, 2019

17         sasfile one close;
NOTE: The file WORK.ONE.DATA has been closed by the SASFILE statement.
18         
19         data _null_;
20            array blah[%sysevalf(&d,integer)];
21            do _n_ = 1 to &s;
22               do i=1 to dim(blah); blah[i]=1; end;
23               end;
24            stop;
25            run;

NOTE: DATA statement used (Total process time):
      real time           11.64 seconds
      user cpu time       11.64 seconds
      system cpu time     0.00 seconds
      memory              3540.65k
      OS Memory           11084.00k
      Timestamp           08/17/2019 06:58:00 AM
      Step Count                        3  Switch Count  0


NOTE: SAS Institute Inc., SAS Campus Drive, Cary, NC USA 27513-2414
NOTE: The SAS System used:
      real time           16.78 seconds
      user cpu time       12.10 seconds
      system cpu time     0.04 seconds
      memory              15840.62k
      OS Memory           16980.00k
      Timestamp           08/17/2019 06:58:00 AM
      Step Count                        3  Switch Count  16

已经有几个很好的答案,但是为了完整起见,这里有一个非常好的方法,可以在不使用循环的情况下一次更改所有数组值:

data test2;
set test1;
array blah_{*} blah1-blah100 (100*1);
array a_{*} a1-a100;
array b_{*} b1-b100;

/*Make a character copy of what an array of 100 1s looks like*/
length temp $800; *Allow 8 bytes per numeric variable;
retain temp;
if _n_ = 1 then temp = peekclong(addrlong(blah1), 800);

do i=1 to 100;
  blah_{i}=a_{i}/b_{i};
end;

/*Overwrite the array using the stored value from earlier*/
if b1=0 then call pokelong(temp,addrlong(blah1),800);

run;

一些更有趣的测试结果基于DataNull的原始测试。我还添加了以下测试:

%macro loop;

   data _null_;
     array blah[%sysevalf(&d,integer)] blah1 - blah&d;
     do _n_ = 1 to &s;
       %do i = 1 %to &d;
         blah&i = 1; 
       %end;
     end;
     stop;
   run;

%mend;

%loop;
因此,对于基于数组的赋值,赋值本身并不是罪魁祸首。由于数组使用内存映射来映射原始内存位置,因此对于给定下标的内存位置查找似乎是真正影响性能的因素。直接分配可以避免这种情况,并显著提高性能


因此,如果您的数组大小在100秒以下,那么直接赋值可能不是一个好方法。当数组大小超过几百个时,SET就会生效。

我认为在SAS中不可能同时为多个变量赋值。事实上,数组被用作反问题的解决方案,在反问题中,变量不是编写100条赋值语句,而是分组到一个数组中,然后通过一个循环(如您的循环)进行赋值。如果我仍然正确地记得我的本科汇编语言课程,我不认为任何好的编译器实际上会使这种赋值的效率低于在其他语言中可以同时赋值的代码。语法将更加紧凑。为什么不规范您的数据结构呢?每个人都有100个A和B变量的值吗?通过使用垂直结构,您可能会节省空间和复杂性。这使得代码有点紧凑(少2行),但肯定比循环中的赋值效率低很多。您如何知道它“肯定效率低很多”?对于初学者来说,SET语句附带某些开销任务,如指针初始化等。,而赋值只是将一个值复制到内存中。此外,在使用SET语句时,您现在正在执行其他操作,如将数据移动到缓冲区,然后再移动到PDV中,而在执行简单赋值时,这些移动将完全消除。当处理小型数据集时,差异可能不大,但当涉及的数据量变大时,您将开始看到差异。使用
retainarray\u name常量\u值将多个变量初始化为相同值的语法。使用数据集作为默认值的来源,可以将此方法推广到其他问题,其中每个变量的初始值不是常数,可能是由前面的步骤生成的。@python因为您仍然只是在猜测。编写一个测试程序,你会发现你的假设是错误的,事实恰恰相反。这就是性能讨论必须始终包括测试的原因。任何关于语句和函数处理速度的测试都不应包括输出数据集,如果可能,还应排除与基准无关的其他i/o诱导语句(如SET、MERGE、UPDATE、MODIFY、OPEN等)。我的推测是,很少会遇到
设置
读取导致
静态
的SAS或磁盘缓存被刷新的情况。通过先用
SASFILE
static test和
else
预加载
static,可以确保进一步保护
static
。数组处理涉及运行时算法来计算PDV中的内存地址或值位置或变量插槽的句柄。极限“编码”将使用宏编码生成100条语句,其中变量直接用于
d          s          SET Method (real/cpu)    %Loop (real/cpu)     array based(real/cpu)
100        1e5        0.03/0.01                0.00/0.00            0.07/0.07
100        1e8        11.16/9.51               4.78/4.78            1:22.38/1:21.81
500        1e5        0.03/0.04                0.02/0.01            Did not measure
500        1e8        16.53/15.18              32.17/31.62          Did not measure
1000       1e5        0.03/0.03                0.04/0.03            0.74/0.70
1000       1e8        20.24/18.65              42.58/42.46          Did not measure