2016-02-09 25 views
1

长时间用户,第一次张贴海报。我对IML非常陌生,并曾在R之前玩过。我目前正在尝试创建一个邻接表,以便于SAS/IML中的网络计算。我正在处理的文件非常庞大。我正在做一个涉及使用SAS文件的实现,并且在内存中没有邻接列表。创建一个空文件并从特定行(对应于特定代理)读取一切都很顺利,直到“最终”步骤:更新整个观察。如何通过IML替换在SAS文件上工作的整个观察结果

下面是工作的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; 

我的目的是取代/更新整个观察(行),同时保持行的顺序不变。有任何想法吗?

+0

在我的iphone上:我看到的解决方案是将col1作为索引,删除我正在更新的行,并在文件末尾附加新的观察值。为了保持磁盘的快乐,我可以将它们分块。 –

+0

我不知道太多的IML,但唯一能让它工作的方法是分配变量COL2 = 1;我正在研究如何知道变量的名称。当然你有默认名称(COL1 = COLn),但我认为你会需要更通用的解决方案。 –

+0

是的,它的列名 - 对于这个具有预定目标结构的特定数据集 - 是有问题的。我需要计算每个添加数据的下一条信息的位置。我已经厌倦了宏变量来为列创建动态的“名称”,但我无法“动态地”更新它。因为它似乎编译在运行代码之前。 –

回答

1

@乔的解决方案将针对此问题的工作,但以这种方式结合宏观和IML就象吻你妹妹:这不是令人愉快的,人们会看着你奇怪。乔有正确的想法来获取变量的名称,但他忘记了you can use the VALSET call to perform indirect assignment。换句话说,通过具有变量的名称,您可以更改它的值。

如果你想避免宏,你可以得到的变量名称一次(在编辑循环外),然后遍历所有的variales的名字,像这样:

/* 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,对该块中的所有行进行操作,并写出块。

如果磁盘空间允许,您可能要尝试使用read from one data set while writing to another的SETIN和SETOUT语句。那 完全消除了对REPLACE语句和VALSET调用的需要。通常,打开一个只读数据集并按顺序处理数据集比打开读写数据集并使用随机访问处理效率更高。

+0

我真的很感谢你的回答,里克。非常优雅的解决方案,我很高兴“新眼睛”看到了我的问题。我会在阅读和编写I/O文件的大块“块”时进行阅读,因为我已经注意到了当前解决方案的运行时间。再次 - 感谢您的时间和知识。 –

+0

很好的答案,我认为一定是可能的,但看不到。而且,忘记一些事情意味着人们必须首先了解它。 – Joe

+0

我很想知道为什么REPLACE不会将矩阵/向量用作参数,但是 - 上面是一个很好的解决方案,但仍然比能够说'替换点(checkobs)var _all_矩阵temp ;'(将临时列1:1映射到变量)或('替换点(checkobs)var _all_ vnames temp_varnames;'其中'temp_varnames'有两列,一个varnames和两个要映射的向量。 – Joe

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的方式来做到这一点 - 也许里克会发生,并有一个答案。我不确定为什么不会有,但我远不及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; 
+0

这里有一点需要注意:如果你有一列/多行,而不是一行/多列,看起来很容易做到这一点。如果你以转置的方式存储所有东西(所以你的'temp'向量只有一列,而不是一行),那么你可以以可预测的方式命名你的变量,也许更容易做到这一点。我说也许因为我还不知道你在做什么...... – Joe

+0

就是这样!非常感谢!花费8-10小时尝试不同的解决方案! –