我需要将多个原始文本文件读入SAS数据集。每个文件包含几个成分,如下面的示例文件所示。每个文件(一个菜)列出一行中的所有成分,用逗号分隔。成分的量是可变的。一些示例文件(菜肴):
示例文件1(dish1.csv):
Tomate,Cheese,Ham,Bread
示例文件2(dish2.csv):
Sugar,Apple
示例文件3(dish3.csv):
牛奶,糖,可可
因为我有大约250个文件(菜肴),所以我创建了一个宏程序来读取这些文件。这样我就可以在另一个宏中执行这个宏来读取我需要的所有菜肴。该计划如下:
%readDish (dishNumber);
data newDish;
* Find and read the csv-file;
infile "my_file_location/dish&dishNumber..csv" dlm=";" missover;
* Read up to 25 ingredients;
input ingredient1-ingredient25 : $25.;
* Put all ingredients in an array;
array ingredients{25} ingredient1-ingredient25;
* Loop thrue all the ingredients and output;
do i=1 to dim(ingredients);
dishNumber = &dishNumber;
ingredient = ingredients{i};
output;
end;
run;
%mend;
是否有可能创建一个能够读取所有菜肴的SAS(宏)程序,无论我有多少成分? SAS表应如下所示:
1 Tomate
1 Cheese
1 Ham
1 Bread
答案 0 :(得分:1)
对我来说似乎很简单:垂直读取数据,然后如果需要水平,则在之后添加转置步骤。您不必一步一步地读取整行 - @@
运算符告诉SAS将行指针保留在该行上,因此您只需读取该行。
data dishes;
length _file $1024
ingredient $128;
infile "c:\temp\dish*.csv" dlm=',' filename=_file lrecl=32767; *or whatever your LRECL needs to be;
input ingredient $ @@;
dishnumber = input(compress(scan(_file,-2,'\.'),,'kd'),12.);
output;
run;
在这里,我使用通配符将它们全部读入 - 当然,如果需要,我们可以使用类似代码的宏,尽管通配符或连接文件名可能更容易。我获取dishnumber
的方式可能并不总是有效,具体取决于文件名构造,但某些形式的应该是可用的。
扩展其工作原理:datastep在SAS中的工作方式是它是一个循环,循环遍历代码,直到遇到“结束条件”。结束条件最常见的是stop
关键字,然后是从SET或INFILE读取的任何尝试都不可能进一步读取(即,您读取100行SAS数据集,并尝试读取第101行) in,失败,所以结束数据步骤)。但是,除此之外,它将继续执行相同的代码,直到它到达那里。它只是在“运行”点进行一些清理,以确保它不是无限循环。
在从infiles输入的情况下,通常SAS读取一行,然后在RUN中,它将跳转到下一个EOL(行尾,通常是回车和Windows中的换行),如果它还没有在一个行。有时这很有用 - 通常也许。但是,在某些情况下,你宁愿让SAS继续读同一行。
来自@@
运算符。 @@
说“即使你打RUN也不要进入EOL”。 (@
说“除非你按下RUN,否则不要前进到EOL” - 通常输入本身会导致SAS读取直到EOL。)因此,当你执行下一个数据步骤迭代时,输入指针将在同一个你离开它的确切位置 - 就在你读到的前一个字段之后。
这在60年代和70年代非常有用,当时标签卡是时髦的新东西,你会经常输入输入线而不考虑任何线条组织 - 特别是,如果你每行只输入一个变量,那么8每个输入变量的列,你不会从一个穿孔卡中浪费72个块 - 所以,你输入的就像你的成分一样:输入上每行有很多数据,然后想要在每行中转换成一行数据记忆。虽然现在以这种方式存储数据并不常见,但这肯定是可能的 - 正如您的数据所示。