我有一个数组t,它指定我想从file.txt中读取的行数。所以我的代码应该是这样的:
data a;
do i = 1 to dim(t);
infile "C:\sas\file.txt" firstobs = t(i) obs = t(i);
input x1-x10;
output;
end;
run;
当然,此解决方案(firstobs)仅在列数为常数时才有效。如何使用数组(也可以从同一个文件中读取 - 从第一行开始)?
例如,如果file.txt看起来像这样:
2 4 6 . . . . . . .
2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5
6 6 6 6 6 6 6 6 6
然后我希望输出为:
2 2 2 2 2 2 2 2 2 2
4 4 4 4 4 4 4 4 4 4
6 6 6 6 6 6 6 6 6 6
答案 0 :(得分:1)
听起来第一行包含要保留的行列表。从单独的文件中读取它可能更容易,但您可以使用单个文件。您没有提到如何知道数据列数或第一行中可能存在的最大行数。现在让我们假设您可以在宏变量中设置这些数字。
让我们将您的示例数据放入文件中:
options parmcards=tempdata ;
filename tempdata temp;
parmcards;
2 4 6 . . . . . . .
2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5
6 6 6 6 6 6 6 6 6
;
现在让我们将其读入数据集。
%let ncol=9 ;
%let maxrows=1000;
data want ;
infile tempdata truncover ;
array rows (&maxrows) _temporary_;
if _n_=1 then do i=1 by 1 until (rows(i)=.);
input rows(i) @;
drop i;
end;
else do;
input x1-x&ncol;
if whichn(_n_,of rows(*)) then output;
end;
run;
如果文件的其他行具有无效数据,使得INPUT语句会导致错误,则可以跳过尝试从ELSE块中稍作修改的那些行读取数据。
else do;
input @;
if whichn(_n_,of rows(*)) then do;
input x1-x&ncol;
output;
end;
end;
如果您发现您经常不想在文件末尾读取大量记录,则可以将此行添加到数据步骤的末尾,以便在读取所需的最后一行后停止。
if _n_ > max(of rows(*)) then stop;
答案 1 :(得分:1)
这是一个类似汤姆的答案,但不会尝试读取路径外数据。对于跳过的行的数据格式与路径数据的格式不同的情况,这可能会更好。它使用Tom的parmcards和结构,因此您可以更轻松地看到差异。
options parmcards=tempdata ;
filename tempdata temp;
parmcards;
2 4 6 . . . . . . .
2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5
6 6 6 6 6 6 6 6 6
;
%let ncol=9 ;
%let maxrows=1000;
data want ;
infile tempdata truncover end=eof;
array rows (&maxrows) _temporary_;
do i=1 by 1 until (rows(i)=.); *read in first line, just like Toms answer;
input rows(i) @;
drop i;
end;
input ; * stop inputting on the first line;
* Here you may need to use CALL SORTN to sort row array if it is not already sorted;
_currow = 2; * current row indicator;
do _i = 1 to dim(rows); * iterate through row array;
if rows[_i]=. then leave; * leave if row array is empty;
do while (_currow lt rows[_i] and not eof); * skip rows not in row array;
input;
_currow = _currow + 1;
end;
input x1-x&ncol; * now you know you are on a desired row, so input it;
output; * and output it;
_currow = _currow + 1;
end;
run;
如上所述,您可能必须使用CALL SORTN,如果数组尚未排序(即,如果缺失不在最后且数字无序)。
答案 2 :(得分:0)
如果您的文件是结构化的(即相同的分隔符/一个连续的'行'输入数据),则下面的方法应该有效。我确信你可以调整一下以提高效率,但我会提出一些意见来解释每个部分正在做什么。我还建议阅读infile
文档,了解_infile_
自动变量的解释以及操作输入数据缓冲区的其他方法。此外,如果您的输入数据文件本身需要拆分为单独的行,那么您需要对其进行调整。
filename in_data 'C:\sas\file.txt';
data out_data (keep=x1-x10);
infile in_data;
input fn;
/*get the number of vars based on delimiter*/
count = count(strip(_infile_), ' ') + 1;
/*iterate through vars*/
do i =1 to count;
/*set new value to current var*/
rec = scan(strip(_infile_), i, ' ');
/*set array values to new value*/
array obs(10) x1-x10;
do j=1 to dim(obs);
obs(j) = rec;
end;
/*output to dataset*/
output out_data;
end;
run;
2 4 6 7 8 9 10 11 2 3
x1 x2 x3 x4 x5 x6 x7 x8 x9 x10
2 2 2 2 2 2 2 2 2 2
4 4 4 4 4 4 4 4 4 4
6 6 6 6 6 6 6 6 6 6
7 7 7 7 7 7 7 7 7 7
8 8 8 8 8 8 8 8 8 8
9 9 9 9 9 9 9 9 9 9
10 10 10 10 10 10 10 10 10 10
11 11 11 11 11 11 11 11 11 11
2 2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3 3
希望这会有所帮助。
答案 3 :(得分:0)
好的,我明白了。假设我知道列数(10)和行数(10)我可以使用以下代码得到我想要的内容:
data a;
w=1;
infile "C:\sas\file.txt" n=10;
input #w x1-x10;
array x(*) x1-x10;
array t(10) _temporary_;
do i=1 to 10;
if(x(i)^=.) then t(i)=x(i);
else leave;
end;
do j=1 to i-1;
w=t(j);
input #w x1-x10;
output;
end;
stop;
run;
剩下的就是在不知道行数和列数的情况下做同样的事情。这样我只读取我感兴趣的行,而不是读取所有行,只输出我需要的行。
答案 4 :(得分:0)
如果您只是将整个矩阵读入数据集然后使用行号来选择所需的数据,那么维护程序可能要容易得多。您的文件可能需要在节省的时间内保存数十万个观察值,以避免阅读完整文件。
这是使用SET语句的POINT =选项选择行的一种方法。
options parmcards=tempdata ;
filename tempdata temp;
parmcards;
2 4 6
2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5
6 6 6 6 6 6 6 6 6
;
data rows;
infile tempdata obs=1 ;
input row @@;
row=row-1;
run;
proc import datafile="%sysfunc(pathname(tempdata))" dbms=dlm out=full replace;
getnames=no;
delimiter=' ';
datarow=2;
run;
data want ;
set rows ;
pointer=row ;
set full point=pointer ;
run;
proc print; run;