Sas 输入变量中的数字行

Sas 输入变量中的数字行,sas,Sas,我有一个数组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; 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

我有一个数组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;
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
当然,此解决方案(firstobs)仅在列数为常量时有效。如何使用数组(也从同一文件读取,即从第一行读取)执行此操作

例如,如果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;
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

如果您的文件是结构化的(即相同的分隔符/一行连续的输入数据),那么下面的方法应该有效。我相信您可以调整以提高效率,但我在其中添加了一些注释来解释每个部分的功能。我还建议阅读文档,了解
\u infle\u
自动变量和其他操作输入数据缓冲区的方法的说明。此外,如果您的输入数据文件本身需要拆分为单独的行,那么您需要对此进行调整

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;
输入 输出
希望这能有所帮助。

听起来第一行包含要保留的行列表。从一个单独的文件中读取可能会更容易,但您可以使用单个文件。您没有提到如何知道数据的列数或第一行中的最大行号数。现在让我们假设您可以在宏变量中设置这些数字

让我们将示例数据放入一个文件:

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;

这里有一个类似于Tom的答案,但它不会尝试读取非路径数据。对于跳过的行中的数据格式与路径数据格式不同的情况,这可能更适合。它使用Tom的Parmcard和结构,因此您可以更容易地看到差异

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。

好的,我已经解决了。假设我知道列数(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;

剩下的就是在不知道行数和列数的情况下执行相同的操作。通过这种方式,我只读取我感兴趣的行,而不是读取所有行并只输出我需要的行。

如果您只是将整个矩阵读取到数据集中,然后使用行号选择所需的数据,那么程序维护可能会容易得多。您的文件可能需要有数十万次的观察才能节省时间,从而值得编程来避免读取完整的文件

下面是使用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;

您的意思是文件的第一行包含行号,而您只想读取第一条记录中的行号所引用的文件中的记录吗?如果这不是你想要的,那么试着用一些相应的输出数据显示一些示例输入数据,并扩展你对所需内容的解释。我不认为OPs实际数据只包含行号。似乎OP希望读取第2、4、6行,而不仅仅是在该行中放置2。只需将实际输入语句移动到IF语句之后就更容易了<代码>输入@;如果whichn(_n_,行数(*));输入x1-x&ncol;产出我认为上面的速度会稍微快一点,因为我不必每次都查询
whichn
。好的,但这里您读取所有行,只输出第一行中的行。我不想那样做。我想避免读取其他行。无法避免读取顺序文件的所有行。您可以避免尝试将行中的文本转换为变量,但仍然需要读取文件。如果“只读取我感兴趣的行”,则不会保存任何内容。需要时间的是将文件中的行读取到内存中。操作系统将以块的形式读取行。像本例这样小的文件可以放在一个磁盘I/O操作中。是的,如果我在sas集中有它,我就可以这样做。我很想做‘point=’所做的事情,但是当从.txt文件中读取时,不可能从文本文件中读取point=。您可能可以从具有固定长度记录的文件中删除它,但现在没有人真正使用这些记录了。