我已经(并将在未来收到)许多CSV文件,这些文件使用分号作为分隔符,逗号作为小数分隔符。 到目前为止,我无法找到如何使用proc导入将这些文件导入SAS - 或以任何其他自动方式导入,而无需手动处理变量名称。
创建一些示例数据:
%let filename = %sysfunc(pathname(work))\sap.csv;
data _null_;
file "&filename";
put 'a;b';
put '12345,11;67890,66';
run;
导入代码:
proc import out = sap01
datafile= "&filename"
dbms = dlm;
delimiter = ";";
GETNAMES = YES;
run;
导入变量的值" AMOUNT"例如350,58(相当于美国格式的350.58)在SAS中看起来像35,058(意思是三十万......)(再次出口到德国EXCEL后,它看起来像35.058,00)。 一个简单但肮脏的解决方法如下:
data sap02; set sap01;
AMOUNT = AMOUNT/100;
format AMOUNT best15.2;
run;
我想知道是否有一种简单的方法来定义CVS-import的小数分隔符(类似于分隔符的规范)。 ..或任何其他"清洁剂"解决方案与我的解决方案相比。 非常感谢提前!
答案 0 :(得分:6)
从技术上讲,您应该使用dbms=dlm
而不是dbms=csv
,尽管它确实可以解决问题。 CSV表示“逗号分隔值”,而DLM表示“分隔”,这在此是正确的。
我认为没有直接的方法可以通过PROC IMPORT
使用逗号读取SAS。在读取数据时,您需要告诉SAS使用NUMXw.d信息,我没有办法在SAS中强制设置该设置。 (输出的选项带有逗号NLDECSEPARATOR
,但我认为这不起作用。)
最好的办法是自己编写数据步骤代码,或者运行PROC IMPORT
,转到日志,然后将读入的代码复制/粘贴到程序中;然后为每个读入记录添加:NUMX10.
或任何适当的字段最大宽度。它最终会看起来像这样:
data want;
infile "whatever.txt" dlm=';' lrecl=32767 missover;
input
firstnumvar :NUMX10.
secondnumvar :NUMX10.
thirdnumvar :NUMX10.
fourthnumvar :NUMX10.
charvar :$15.
charvar2 :$15.
;
run;
它还会生成大量的信息和格式代码;您可以将信息转换为NUMX10.
而不是BEST.
,而不是将信息添加到读入中。您也可以删除信息,除非您有日期字段。
data want;
infile "whatever.txt" dlm=';' lrecl=32767 missover;
informat firstnumvar secondnumvar thirdnumvar fourthnumvar NUMX10.;
informat charvar $15.;
format firstnumvar secondnumvar thirdnumvar fourthnumvar BEST12.;
format charvar $15.;
input
firstnumvar
secondnumvar
thirdnumvar
fourthnumvar
charvar $
;
run;
答案 1 :(得分:0)
您最好的选择是自己编写数据步骤代码,还是运行 PROC IMPORT,转到日志,并将读入的代码复制/粘贴到 你的程序
这有一个缺点。如果csv文件的结构发生更改(例如更改的列顺序),则必须更改SAS程序中的代码。
因此更改输入更安全,在数字字段中用逗号替换逗号并将SAS修改为输入。
第一个想法是为此使用perl程序,然后在SAS中使用带管道的文件名来读取修改后的输入。
遗憾的是,proc导入中存在SAS限制:IMPORT过程不支持FILENAME语句的设备类型或访问方法,DISK除外。
因此,必须使用调整后的输入在磁盘上创建工作文件。
我使用CVS_PP包来读取csv文件 testdata.csv 包含要读取的csv数据 substitute_commasep.perl 是perl程序的名称
perl代码:
# use lib "/........"; # specifiy, if Text::CSV_PP is locally installed. Otherwise error message: Can't locate Text/CSV_PP.pm in ....;
use Text::CSV_PP;
use strict;
my $csv = Text::CSV_PP->new({ binary => 1
,sep_char => ';'
}) or die "Error creating CSV object: ".Text::CSV_PP->error_diag ();
open my $fhi, "<", "$ARGV[0]" or die "Error reading CSV file: $!";
while ( my $colref = $csv->getline( $fhi) ) {
foreach (@$colref) { # analyze each column value
s/,/\./ if /^\s*[\d,]*\s*$/; # substitute, if the field contains only numbers and ,
}
$csv->print(\*STDOUT, $colref);
print "\n";
}
$csv->eof or $csv->error_diag();
close $fhi;
SAS代码:
filename readcsv pipe "perl substitute_commasep.perl testdata.csv";
filename dummy "dummy.csv";
data _null_;
infile readcsv;
file dummy;
input;
put _infile_;
run;
proc import datafile=dummy
out=data1
dbms=dlm
replace;
delimiter=';';
getnames=yes;
guessingrows=32767;
run;