1

我正在寻找一种在 sas 中使用 proc iml 估算未来两个月销售额平均值的方法。如您所见,有时我没有 201901 的销售额,有时在 201902 上缺少例如对于第一个条形码,我想找到 sales[1]= mean(sales[2],sales[3]) 并且我想对每个唯一的条形码执行此操作。

“表A”是这样的:

Obs. |  Barcode  |    date   |   sales   | Position
---------------------------------------------------------------
1    |21220000000|  201901   |     .     |   1

2   |21220000000|   201902|      311     |   2

3   |21220000000|   201903|      349     |   3

4   |21220000000|   201904|      360     |   4

5   |21220000000|   201905|      380     |   5

6   |21220000000|   201906|      440     |   6

7   |21220000000|   201907|      360     |   7

8   |21220000000|   201908|      390     |   8

9   |21220000000|   201909|      410     |   9

10  |21220000000|   201910|      520     |  10

11  |21220000000|   201911|      410     |  11

12  |21220000000|   201912|      390     |  12

13  |31350000000|   201901|      360     |   1

14  |31350000000|   201902|      .       |   2


                   .etc.
24  |31350000000|   201912|       .      |   12

25  |45480000000|   201901|      310     |   1     

26  |45480000000|   201902|        .     |   2

                   .etc.

我尝试过这样的事情,但它不起作用:

proc iml;
t_a= TableCreateFromDataSet("work","table_a");
call TablePrint(t_a); 

do i =1 to nrow(t_a);
  
      if t_a[i,4]=. and t_a[i,5]=1 then t_a[1,4]= mean(t_a[i+1,4],t_a[i+2,4]) ;
      
   i=i+1;
end;
run;

有没有办法在 proc iml 中使用矩阵或列表来做到这一点,或者你会推荐任何其他方式吗?先感谢您!

4

2 回答 2

2

这个问题只涉及一个ID变量(='BarCode')和一个有缺失值的变量(='Sales'),所以你真的只需要读取和处理两个向量。

一种有效的方法是迭代“条形码”变量(一个 ID 变量)的唯一级别并处理每个缺失值。因此,您可以将问题简化为“按组分析”,依次处理每个 ID 值。有几种方法可以在 IML 中执行 BY-group 分析。最容易理解和实施的是UNIQUE-LOC 技术。对于大数据,UNIQUEBY 技术效率更高

以下示例使用 UNIQUE-LOC 技术:

proc iml;
use table_a;
   read all var {"BarCode"} into ID;
   read all var {"Sales"} into X;
close;

imputeX = X;             /* make copy of X */
u = unique(ID);          /* unique categories of the ID variable */
do i = 1 to ncol(u);     /* for each ID level */
   groupIdx = loc(ID=u[i]);
   y = x[groupIdx];      /* get the values for this level */
   k = loc( y=. );       /* which are missing? */
   if ncol(k)>0 then do; /* if some are missing, do imputation */
      n = nrow(y);
      startIdx = ((k+1) >< n);  /* starting location, don't exceed n */
      stopIdx  = ((k+2) >< n);  /* ending location, don't exceed n */
      values = y[ startIdx ] || y[ stopIdx ];
      mean = values[ , :];      /* find mean of each row */
      y[k] = mean;              /* copy mean to missing values */
      imputeX[groupIdx] = y;    /* update imputed vector (optional: write data) */
   end;
end;

print ID[F=Z11.] X imputeX;
于 2021-01-14T18:36:01.243 回答
1

我认为这不是解决PROC IML您的问题的好方法,但我可以告诉您在您的特定方法中哪里出了问题。希望 Rick 或其他人可以停下来展示使用矩阵运算解决此问题的正确 IML 方法,或者您可以浏览Do Loop,因为我很确定 Rick 那里有关于插补的文章。

也就是说,您的问题是 SAS IML 对表作为数据结构的支持并不多。它们是最近添加的,主要是为了更轻松地将数据集从 SAS 导入 IML,而不会遇到很多麻烦。但是,您不能将它们视为 Pandas 数据帧或类似的;它们实际上只是您需要从中提取内容的数据存储设备。您需要将数据移动到矩阵中才能实际使用它们。

以下是我将您的非功能代码直接转换为功能代码的方法。再一次,请记住这可能不是一个好方法——矩阵有很多特性可以让它们擅长这种事情,如果你正确使用它们,你可能不需要使用 DO 循环来在这里迭代 - 你应该使用矩阵乘法来做你想做的事。这就是使用 IML 的真正意义所在。如果您只是进行迭代,则使用基本 SAS 来执行此操作,在基本 SAS 中编写相同的程序要容易得多(或者,如果您获得许可,使用插补程序更好)。

data table_a;
input Obs Barcode   date  :$6.  sales  Position;
datalines;
1    21220000000    201901         .         1
2    21220000000    201902       311         2
3    21220000000    201903       349         3
4    21220000000    201904       360         4
5    21220000000    201905       380         5
6    21220000000    201906       440         6
7    21220000000    201907       360         7
8    21220000000    201908       390         8
9    21220000000    201909       410         9
10   21220000000    201910       520        10
11   21220000000    201911       410        11
12   21220000000    201912       390        12
13   31350000000    201901       360         1
14   31350000000    201902        .          2
24   31350000000    201912        .          12
25   45480000000    201901       310         1     
26   45480000000    201902         .         2
;;;;
run;

proc iml;
t_a= TableCreateFromDataSet("work","table_a");
call TablePrint(t_a); 

sales = TableGetVarData(t_a,4);
barcode = TableGetVarData(t_a,2);
do i =1 to nrow(sales);
     if missing(sales[i])  then do;    *if the sales value is missing, then ...;
      if i <= (nrow(sales) - 2) then do;    *make sure we are not going over the total;     
        if all(j(2,1,barcode[i])=barcode[i+1:i+2]) then do;  *and see if the rows are all the same barcode;
            sales[i] = mean(sales[i+1:i+2]);   *compute the mean!;
        end;
       end;
     end;
end;
      
call TableAddVar(t_a,'sales_i',sales);  *Put the matrix back in the table;

call TablePrint(t_a);  *Take a peek!;
quit;

我首先要做的是将 Barcode 和 Sales 列提取到矩阵中。条形码用于检查以确保我们是从同一个 ID 输入的。然后,我们检查该迭代是否缺少销售,并进一步确保我们不在最后两次迭代中(否则会给出超出范围的错误)。最后,我们将条形码与接下来的两个条形码进行比较,并确保它们相同。(老实说,我这样做的方式非常愚蠢,但这是我能想到的最快的方式。)如果这些都通过,那么我们计算平均值。

最后,我们将矩阵重新添加到 t_a 表中,您可以在闲暇时将其导出回 SAS 数据集,或者做任何您想做的事情!

再一次 - 这并不是一个真正的好方法,它更像是“你的代码有什么问题”的直接答案。找到比这更好的插补解决方案!

于 2021-01-13T17:35:20.227 回答