Чтение текстового файла с разделителями пространства в SAS

#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    ...        ...  
  

Но вопрос в том, как прочитать такой текстовый файл:

  1. прочитайте и разделите Mark1 [Country1] на два столбца Mark и Country;
  2. сохраните метку и страну и прочитайте информацию для каждого типа ( каким-то образом игнорируя 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