如何通过IML替换在SAS文件上工作的整个观察

时间:2016-02-09 10:30:28

标签: database sas sas-iml

长时间用户,第一次发布海报。我是IML的新手,之前在R中玩过。我目前正在尝试创建一个邻接列表,以便更轻松地计算SAS / IML中的网络。我正在处理的文件非常庞大。我正在做一个涉及使用SAS文件但没有内存中的邻接列表的实现。创建一个空文件并从特定行(对应于特定代理)读取所有内容都很顺利,直到" final"步骤:更新整个观察。

以下是可用的IML代码,直到最后阶段。

    proc iml;
    /* initialize vars*/
    checkObs = 2;
    numCol = 5;
    db = "myTestDataBase";
    nObs = 5;
    temp = {};
    myList = J(1, numCol, 0);
    nVarToUpdate = 2;

    /* create empty database */
    create (db) from myList;
        append from myList;
    close (db);
    do i = 1 to (nObs-1);
        edit (db);
            append from myList;
        close (db);
    end;

    /* read index checkObs and write to temp*/
    edit (db);
        read point (checkObs) into temp; /* Read an entire row*/
        temp[nVarToUpdate] = 1; /* I would like to update some values*/
        /* I want to replace point chekObs with the whole of vector temp*/
        replace point checkObs var _all_;
    close (db);
    print temp;

我的目标是更换/更新整个观察(行),同时保持行的顺序完整。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

你的问题来自the documentation for REPLACE

  

REPLACE语句用当前具有相同名称的矩阵值替换SAS数据集中的观察值。

所以这会奏效:

edit (db);
    read point (checkObs) into temp; /* Read an entire row*/
    col2 = 1; /* I would like to update some values*/
    /* I want to replace point chekObs with the whole of vector temp*/
    replace point (checkObs) var('col2');
close (db);

当然,这可能不是你想到的。

我不知道是否有IML方法可以做到这一点 - 也许Rick会发生并得到答案。我不确定为什么会有这种情况,但我不是IML的专家,所以也许是 - 或者是没有理由的原因。我的感觉是,你想要做的事情可能会以完全不同的方式做得更好;但是,目前还不清楚你到底在做什么。如果你正在做一个神经网络或类似的,那里有很多代码 - 另一种方法可能会出现。我发现从其他语言进入SAS的人经常期望用其他语言工作的东西可以在这里工作 - 当有效的方式在SAS中完全不同的时候(如果不是更好的话也能很好地工作 - 只需要意识到它是什么)

无论如何,您可以使用一些设置和宏语言来完成此操作。这是一个例子。您必须提前进行设置 - 如果您有动态变量列表,这可能很复杂(例如,您可能必须具有双重解析的宏变量名称)。

宏观方法要记住的主要事情是在IML运行之前,宏值必须完全可用;所以你不能把变量放在参数中,它必须是一个硬编码的值或一个宏变量,它在IML运行之前就已知。 DOSUBL / RUN_MACRO可能会让你在某种程度上解决这个问题,但以这种方式做事可能会很复杂。

proc sql;
  select name into :namelist separated by ','
    from dictionary.columns
    where libname='WORK' and memname='MYTESTDATABASE';
quit;

%macro replace_var(num_Vars=1);
        %do _i = 1 %to &num_vars.;
          %let _var = %scan(%bquote(&namelist),&_i,%str(,));
          &_var. = temp[&_i.];
        %end;
%mend;

proc iml;
    /* initialize vars*/
    checkObs = 4;
    numCol = 5;
    db = "myTestDataBase";
    nObs = 5;
    temp = {};
    myList = J(1, numCol, 0);
    nVarToUpdate = 2;

    /* create empty database */
    create (db) from myList;
        append from myList;
    close (db);

    do i = 2 to (nObs);
        edit (db);
            append from myList;
        close (db);
    end;
    /* read index checkObs and write to temp*/
    edit (db);
        read point (checkObs) into temp[colname=temp_names]; /* Read an entire row*/
        temp[nVarToUpdate] = 1; /* I would like to update some values*/
        %replace_var(num_vars=&sqlobs.);   *call the macro which sets the various variable names to their values.  Semicolon is just for syntax coloring to work.;
        /* I want to replace point chekObs with the whole of vector temp*/
        replace point (checkObs) var _all_;
    close (db);
    print temp;
    print temp_names;
  quit;

答案 1 :(得分:1)

@ Joe的解决方案可以解决这个问题,但是以这种方式结合宏观和IML就像亲吻你的妹妹:它不愉快,人们会奇怪地看着你。乔有正确的想法得到变量的名称,但他忘记了you can use the VALSET call to perform indirect assignment。换句话说,通过拥有变量的名称,您可以更改它的值。

如果你想避开宏,可以一次获取变量的名称(在EDIT循环之外),然后遍历变量的名称,如下所示:

/* get column names ONE TIME */
use (db);
   read next var _ALL_ into temp[colname=varNames]; /* get names of cols */
close (db);

/* read index checkObs and write to temp*/
edit (db);
read point (checkObs) into temp; /* Read an entire row*/
temp[nVarToUpdate] = 1; /* I would like to update some values*/
do i = 1 to ncol(temp);
   call valset(varNames[i], temp[i]); /* update scalar variables */
end;
replace point (checkObs) var _all_;
close (db);

此技术的主要优点是您可以在运行时发现变量名称。

请注意,此方法(创建变量名称)可能很危险,因为如果数据集中包含名为X的变量,则会覆盖程序中该名称的任何预先存在的变量。

另外请注意,在一个巨大的数据集上使用EDIT和READ POINT一次更改一行将比在冬季流动上坡的糖蜜慢。如果可能,您应read in a big block of data对该块中的所有行进行操作,并写出该块。

如果磁盘空间允许,您可能想尝试将SETIN和SETOUT语句用于read from one data set while writing to another。那会 完全不需要REPLACE语句和VALSET调用。通常,以只读方式打开数据集并按顺序处理它比打开读​​/写并使用随机访问处理它更有效。