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

时间:2019-08-16 14:06:37

标签: 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单元格。有更好的方法吗?

6 个答案:

答案 0 :(得分:1)

已经有好几个答案,但是为了完整起见,这是一种非常silly and dangerous的方式,无需循环即可一次更改所有数组值:

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;

答案 1 :(得分:0)

您需要分配100 * NOBS。没有看到在ARRAY上使用DO循环比其他方法效率更低。

但是当您知道不需要时就不需要进行计算。

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

答案 2 :(得分:0)

此示例使用数据集来“设置”数组的所有值,而无需对数组进行DOINGOVER。请注意,以这种方式使用SET可以将阵列BLAH的INIT-TO-MISSING更改为不更改。我无法评论您需要进行自己的测试的性能。

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;

答案 3 :(得分:0)

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

这是我运行的一个简单实验:

%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的增加,分配方法比SET更快。

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

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

答案 4 :(得分:0)

我认为该测试可以隔离感兴趣的陈述。

摘要: 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

答案 5 :(得分:0)

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

%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;
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

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

因此,如果您的数组大小在100s以下,那么直接分配可能不是一个坏方法。当数组大小超过几百时,SET才有效。