【问题标题】:Split SAS datasets by column with primary key使用主键按列拆分 SAS 数据集
【发布时间】:2019-07-28 15:11:30
【问题描述】:

所以我有一个带有一个主键的数据集:unique_id 和 1200 个变量。此数据集是从宏生成的,因此列数不会固定。我需要将此数据集拆分为 4 个或更多数据集,每个数据集包含 250 个变量,每个较小的数据集都应包含主键,以便稍后将它们合并回来。有人可以用 sas 函数或宏来帮助我解决这个问题吗? 提前致谢。

【问题讨论】:

  • 嗨!到目前为止,您尝试过什么?
  • 我创建了一个父数据集的列名数组。我的困惑是 a) 运行数据步骤的次数,因为列数不固定,b) 修复主键。
  • 将行切成 250 列的目的是什么?是否有任何带有数字后缀的变量“排列”?你想把排列的变量放在一起吗?对于您的“更少的列”处理,您可以使用依赖keep 语句或keep= 选项的视图 吗?将原始数据集切碎后会发生什么?您是否删除它以节省磁盘空间?

标签: arrays loops sas sas-macro


【解决方案1】:

按照您的要求拆分数据集的一种简单方法是使用具有多个输出数据集的单个数据步骤,其中每个输出数据集都有一个 KEEP= dataset 选项列出要保留的变量。例如:

data split1(keep=Name Age Height) split2(keep=Name Sex Weight);
  set sashelp.class;
run;

因此,您需要获取变量列表,然后将其分组为 250 个或更少的集合。然后你可以使用这些分组来生成类似上面的代码。这是一种使用 PROC CONTENTS 获取变量列表并使用 CALL EXECUTE() 生成代码的方法。

我将使用宏变量来保存输入数据集的名称、每个数据集需要保留的关键变量以及每个数据集中要保留的最大变量数。

因此对于上面的示例,这些宏变量值将是:

%let ds=sashelp.class;
%let key=name;
%let nvars=2;

所以使用PROC CONTENTS来获取变量名列表:

proc contents data=&ds noprint out=contents; run;

现在运行一个数据步骤将它们分成组并生成一个成员名称以用于新的拆分数据集。计数时,请确保不要将 KEY 变量包含在变量列表中。

data groups;
  length group 8 memname $41 varnum 8 name $32 ;
  group +1;
  memname=cats('split',group);
  do varnum=1 to &nvars while (not eof);
    set contents(keep=name where=(upcase(name) ne %upcase("&key"))) end=eof;
    output;
  end;
run;

现在您可以使用该数据集来驱动代码的生成:

data _null_;
  set groups end=eof;
  by group;
  if _n_=1 then call execute('data ');
  if first.group then call execute(cats(memname,'(keep=&key'));
  call execute(' '||trim(name));
  if last.group then call execute(') ');
  if eof then call execute(';set &ds;run;');
run;

以下是 SAS 日志的结果:

NOTE: CALL EXECUTE generated line.
1    + data
2    + split1(keep=name
3    +  Age
4    +  Height
5    + )
6    + split2(keep=name
7    +  Sex
8    +  Weight
9    + )
10   + ;set sashelp.class;run;

NOTE: There were 19 observations read from the data set SASHELP.CLASS.
NOTE: The data set WORK.SPLIT1 has 19 observations and 3 variables.
NOTE: The data set WORK.SPLIT2 has 19 observations and 3 variables.

【讨论】:

  • 哇!让我试一试..我会回复你的:)
【解决方案2】:

使用宏变量的另一种方式:

/* Number of columns you want in each chunk */

%let vars_per_part = 250;

/* Get all the column names into a dataset */

proc contents data = have out=cols noprint;
run;

%macro split(part);

  /* Split the columns into 250 chunks for each part and put it into a macro variable */

  %let fobs = %eval((&part - 1)* &vars_per_part + 1);
  %let obs  = %eval(&part * &vars_per_part);
  proc sql noprint;
    select name into :cols separated by " " from cols (firstobs =  &fobs obs = &obs) where name ~= "uniq_id";
    quit;

  /* Chunk up the data only keeping those varaibles and the uniq_id */
  data want_part∂
    set have (keep = &cols uniq_id);
  run;

%mend;

/* Run this from 1 to whatever the increment required to cover all the columnns */

%split(1);
%split(2);
%split(3);

【讨论】:

    【解决方案3】:

    这不是一个完整的解决方案,但可以帮助您从另一个角度了解如何解决这个问题。以前的解决方案很大程度上依赖于 proc 内容和数据步骤,但我会使用 proc sqldictionary.columns 来解决这个问题。我会创建一个宏,将原始文件分成所需的多个部分,每个部分 250 列。大致步骤:

    proc sql; create table as _colstemp as select * from dictionary.columns where library='your library' and memname = 'your table' and name ne 'your primary key'; quit;
    

    计算某处需要的文件数量:

    proc sql; 
        select ceil(count(*)/249) into :num_of_datasets from _colstemp; 
        select count(*) into :num_of_cols from _colstemp; 
    quit;
    

    然后像这样循环原始数据集:

    %do &_i = 1 %to &num_of_datasets
    
    proc sql; 
        select name into :vars separated by ',' 
        from _colstemp(firstobs=%eval((&_i. - 1)*249 + 1) obs = %eval(min(249,&num_of_cols. - &_i. * 249)) ;
    quit;
    
    proc sql; 
        create table split_&_i. as
        select YOUR_PRIMARY_KEY, &vars from YOUR_ORIGINAL_TABLE;
    quit;
    %end;
    

    希望这能给你另一个想法。该解决方案未经测试,并且可能包含一些伪代码元素,因为它是根据我的做事记忆编写的。这也没有宏声明,并且可以做很多参数化。这将使解决方案更加通用(例如,参数化每个数据集的变量数量、主键名称和数据集名称。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-21
      • 2015-12-23
      • 2021-03-28
      • 2016-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多