0

我编写了一个宏来proc univariate计算数据集中变量的自定义分位数(比如dsn1%cust_quants(dsn= , varlist= , quant_list= )。输出是一个汇总数据集(比如dsn2),如下所示:

q_1      q_2.5      q_50      q_80      q_97.5      q_99      var_name
1        2.5        50        80        97.5        99        ex_var_1_100
-2       10         25        150       500         20000     ex_var_pos_skew
-20000   -500       -150      0         10          50        ex_var_neg_skew

我想做的是使用汇总数据集来限制/限制原始数据集中的极值。我的想法是提取感兴趣的列(例如q_99)并将其放入宏变量向量中(例如q_99_1, q_99_2, ..., q_99_n)。然后我可以执行以下操作:

/* create summary of dsn1 as above example */
%cust_quants(dsn= dsn1, varlist= ex_var_1_100 ex_var_pos_skew ex_var_neg_skew, 
             quant_list= 1 2.5 50 80 97.5 99);

/* cap dsn1 var's at 99th percentile */
data dsn1_cap;
  set dsn1;

  if ex_var_1_100 > &q_99_1 then ex_var_1_100 = &q_99_1;
  if ex_var_pos_skew > &q_99_2 then ex_var_pos_skew = &q_99_2;
  /* don't cap neg skew */
run;

R中,很容易做到这一点。可以使用像索引这样的矩阵从数据帧中提取子数据,并将该子数据分配给一个对象。然后可以稍后引用第二个对象。R示例——b从数据帧中提取a

> a <- as.data.frame(cbind(c(1,2,3), c(4,5,6)))
> print(a)
  V1 V2
1  1  4
2  2  5
3  3  6
> a[, 2]
[1] 4 5 6
> b <- a[, 2]
> b[1]
[1] 4

是否可以在 SAS 中做同样的事情?我希望能够将一列子数据分配给宏变量/数组,这样我就可以在第二个数据步骤中使用宏/数组。一种想法是proc sql into:

proc sql noprint;
  select v2 into :v2_macro separated by " "
  from a;
run;

但是,当我真正想要的是变量向量(或数组——SAS 中没有向量)时,这会创建一个字符串变量。另一个想法是添加%scan(假设这是在宏内):

proc sql noprint;
  select v2 into :v2_macro separated by " "
  from a;
run;

%let i = 1;
%do %until(%scan(&v2_macro, &i) = "");
  %let var_&i = %scan(&v2_macro, &i);
  %let &i = %eval(&i + 1);
%end;

这似乎效率低下并且需要大量代码。它还要求程序员记住哪个var_&i对应于每个未​​来的目的。有没有更简单/更清洁的方法来做到这一点?

**如果这是足够的背景/示例,请在评论中告诉我。如果需要,我很乐意更完整地描述我为什么要做我正在尝试的事情。

4

1 回答 1

0

首先,我假设您在谈论 SAS/Base 而不是 SAS/IML;SAS/IML 本质上类似于 R,并且具有以相同方式可用的相同类型的操作。

SAS/Base 更像是一种数据库语言而不是一种矩阵语言(尽管两者都有一些元素,以及 OOP 语言的一些元素,并且是一种功能齐全的函数式编程语言)。

结果,为了实现相同的目标,您做的事情会有所不同。此外,由于在大型数据表中移动数据的成本,您可以使用多种方法来实现相同的结果;您可以根据需要选择合适的方法。

首先,您通常不应该按照您建议的方式将数据存储在宏变量中。这是不好的编程习惯,而且效率低下(正如您已经注意到的那样)。存在 SAS 数据集来存储数据;SAS 宏变量的存在有助于简化您的编程任务并驱动代码。

如上所述创建数据集“b”在 Base SAS 中是微不足道的:

data b;
set a;
keep v2;
run;

这将创建一个与 A 具有相同行但只有第二列的新数据集。KEEP 和 DROP 允许您控制数据集中的列。

但是,除非您打算修改数据,否则此数据集的意义很小;毕竟,它包含与 A 相同的信息,只是更少。因此,例如,如果您想将 V2 合并到另一个数据集中,而不是创建 b,您可以简单地使用带有 A 的数据集选项:

data c;
merge z a(keep=v2);
by id;
run;

(注意:我预先假设某种形式的 ID 变量来组合 A 和 Z。)这种合并将 v2 列组合到 z 上,在一个新的数据集 c 中。这相当于垂直连接两个矩阵(尽管直接连接会删除“by id;”要求,在数据库中您通常不会这样做,因为不能保证顺序是您所期望的)。

如果您打算用b它来做其他事情,那么您如何创建和/或使用它取决于该用途。您可以创建一个format,它是值的映射 [即 1='Hello' 2='Goodbye'] ,因此允许您使用单个编程语句将一个值转换为另一个值。您可以将其加载到哈希表中。您可以将其转置为一行 ( proc transpose)。提供更多细节,可以提供更具体的答案。

于 2013-03-27T06:54:01.587 回答