#input #sas #txt
#ввод #sas #txt
Вопрос:
У меня есть следующий текстовый файл .txt:
Mark1[Country1]
type1=1 type2=5
type1=1.50 EUR type2=21.00 EUR
Mark2[Country2]
type1=2 type2=1 type3=1
type1=197.50 EUR type2=201.00 EUR type3= 312.50 EUR
....
Я пытаюсь ввести его в свою программу SAS, чтобы он выглядел примерно так:
Mark Country Type Count Price
1 Mark1 Country1 type1 1 1.50
2 Mark1 Country1 type2 5 21.00
3 Mark1 Country1 type3 NA NA
4 Mark2 Country2 type1 2 197.50
5 Mark2 Country2 type2 2 201.00
6 Mark2 Country2 type3 1 312.50
Или, может быть, что-то еще, но мне нужно, чтобы можно было печатать двухсторонний отчет
Country1 Country2
Type1 ... ...
Type2 ... ...
Type3 ... ...
Но вопрос в том, как прочитать такой текстовый файл:
- прочитайте и разделите Mark1 [Country1] на два столбца Mark и Country;
- сохраните метку и страну и прочитайте информацию для каждого типа ( каким-то образом игнорируя type1=, возможно, используя форматы) и введите его в таблицу. Возможно, есть способ использовать какие-то шаблоны ввода для выполнения этих или настроенных запросов.
Комментарии:
1. Поэтому иногда после знака равенства стоит одно слово (
type1=1
), а чего-то больше (type1=1.50 EUR
) . Есть ли какая-либо закономерность, когда у вас есть один тип строки, а когда у вас есть другой? У вас всегда есть три строки на группу?2. @Tom Да, это ровно три строки на группу. Первая строка с меткой и страной, вторая с количеством для каждого типа и третья строка с ценами.
Ответ №1:
У вас есть 3 пары имя / значение, но пары разделены между двумя строками. Необычный текстовый файл, требующий творческого ввода. INPUT
Оператор имеет функцию управления строкой #
для чтения относительных будущих строк в неявном цикле шага данных.
Пример (ОТЧЕТ о ПРОЦЕДУРАХ)
Считайте mark
и country
из текущей строки (относительная строка #1), count
s из относительной строки #2, используя #2
и price
из относительной строки #3
. После ввода имени / значения для заданного mark
country
выполните сводку на основе массива, транспонируя две переменные ( count
и price
) одновременно в категориальную ( type
) форму данных.
ОТЧЕТ Proc создает «двусторонний» список. На самом деле список представляет собой сводный отчет (ячейки в графе количество и цена являются совокупной суммой по умолчанию), но каждая ячейка имеет только одно значение, поэтому СУММА является исходным индивидуальным значением.
data have(keep=Mark Country Type Count Price);
attrib mark country length=$10;
infile cards delimiter='[ ]' missover;
input mark country;
input #2 @'type1=' count_1 @'type2=' count_2 @'type3=' count_3;
input #3 @'type1=' price_1 @'type2=' price_2 @'type3=' price_3;
array counts count_:;
array prices price_:;
do _i_ = 1 to dim(counts);
Type = cats('type',_i_);
Count = counts(_i_);
Price = prices(_i_);
output;
end;
datalines;
Mark1[Country1]
type1=1 type2=5
type1=1.50 EUR type2=21.00 EUR
Mark2[Country2]
type1=2 type2=1 type3=1
type1=197.50 EUR type2=201.00 EUR type3= 312.50 EUR
;
ods html file='twoway.html';
proc report data=have;
column type country,(count price);
define type / group;
define country / ' ' across;
run;
ods html close;
Выходное изображение
Комбинированная агрегация
proc means nway data=have noprint;
class type country;
var count price;
output out=stats max(price)=price_max sum(count)=count_sum;
run;
data cells;
set stats;
if not missing(price_max) then
cell = cats(price_max,'(',count_sum,')');
run;
proc transpose data=cells out=twoway(drop=_name_);
by type;
id country;
var cell;
run;
proc print noobs data=twoway;
run;
Ответ №2:
Вы можете указать имя переменной с помощью параметра DLM= в инструкции INFILE. Таким образом, вы можете изменить разделитель в зависимости от типа считываемой строки.
Похоже, у вас есть три строки на группу. Первые имеют значения МЕТКИ и СТРАНЫ. Второй содержит список значений количества, а третий — список значений ЦЕНЫ. Так что что-то вроде этого должно сработать.
data want ;
length dlm $2 ;
length Mark $8 Country $20 rectype $8 recno 8 type $10 value1 8 value2 $8 ;
infile cards dlm=dlm truncover ;
dlm='[]';
input mark country ;
dlm='= ';
do rectype='Count','Price';
do recno=1 by 1 until(type=' ');
input type value1 @;
if rectype='Price' then input value2 @;
if type ne ' ' then output;
end;
input;
end;
cards;
Mark1[Country1]
type1=1 type2=5
type1=1.50 EUR type2=21.00 EUR
Mark2[Country2]
type1=2 type2=1 type3=1
type1=197.50 EUR type2=201.00 EUR type3= 312.50 EUR
;
Результаты:
Obs Mark Country rectype recno type value1 value2
1 Mark1 Country1 Count 1 type1 1.0
2 Mark1 Country1 Count 2 type2 5.0
3 Mark1 Country1 Price 1 type1 1.5 EUR
4 Mark1 Country1 Price 2 type2 21.0 EUR
5 Mark2 Country2 Count 1 type1 2.0
6 Mark2 Country2 Count 2 type2 1.0
7 Mark2 Country2 Count 3 type3 1.0
8 Mark2 Country2 Price 1 type1 197.5 EUR
9 Mark2 Country2 Price 2 type2 201.0 EUR
10 Mark2 Country2 Price 3 type3 312.5 EUR