【问题标题】:How to divide a variable with delimiter into several rows in SAS如何在SAS中将带分隔符的变量分成几行
【发布时间】:2017-05-24 06:54:35
【问题描述】:

我有以下数据:

Name Scores 
A    93/90/100
B    70/90/80
C    80/20/40/30
D    60/60
E    100/100/0/60/80
F    0/20/40/50

这里唯一的规则是“>=60:通过”、“

但是,如果有的话,我想保留“失败”的记录。因此结果应该是:

A    Pass
B    Pass
C    Pass/Fail
D    Pass
E    Pass/Fail
F    Fail

我唯一的想法是将分数分成几行:

Name Scores 
A    93
A    90
A    100
B    70
B    90
B    80
C    ...

然后,将它们转移到

data Score;
    set Score;
    if Scores>=60 then indicator = 'Pass';
    if Scores<60 then indicator = 'Fail';
run;

Name Scores 
A    Pass
A    Pass
A    Pass
B    Pass
B    Pass
B    Pass
C    ...

然后删除重复的,做与第一步相反的操作。

A    Pass
B    Pass
C    Pass/Fail
D    Pass
E    Pass/Fail
F    Fail

但我仍然不知道 SAS/SQL 是否可以做到这一点......

【问题讨论】:

  • 永远不要将数据存储为破折号分隔的项目。只会给你带来很多麻烦。
  • 您提出的每个步骤都非常简单。在寻求帮助之前,您应该自己尝试这样做,并在这样做时发布您的代码。
  • @user667489,我只输入了我能输入的代码。我发现一个communities.sas.com/t5/SAS-Procedures/… 也在做类似的事情。我不知道如何将此应用于列中的所有元素。 (对不起,我不知道如何在SAS中使用数组)
  • 不应该'E'有'Pass'作为指标,因为没有一个值是

标签: sql sas delimiter divide


【解决方案1】:

这是执行此操作的一种方法:

data have;
infile cards truncover;
input Name $ Scores $50.;
cards;
A    93/90/100
B    70/90/80
C    80/20/40/30
D    60/60
E    100/100/0/60/80
F    0/20/40/50
;
run;

data want;
  set have;
  do i = 1 to count(scores,'/') + 1;
    score = input(scan(scores,i,'/'),3.);
    if score >= 60 then pass = 1;
                   else fail = 1;
  end;
  length result $9;
  if pass and not(fail) then result = 'Pass';
  else if fail and not(pass) then result = 'Fail';
  else result = 'Pass/Fail';
  keep name scores result;
run;

【讨论】:

  • 如果我有 600 个间隔(而不是 2 个通过或失败)在你的情况下怎么办...?
  • 阅读数组文档并了解如何使用它们。然后,如有必要,发布另一个问题。
【解决方案2】:

这里是解决方案。解释是在查询的每一步之前的 cmets。我已将 'E' 的 60 更改为 50 以符合您想要的输出。

/*********Input sample dataset***********/
data have;
  input Name $ Scores $20.;
datalines;
A    93/90/100
B    70/90/80
C    80/20/40/30
D    60/60
E    100/100/0/60/50
F    0/20/40/50
;

run;

/*******Getting number of required column for each row*******/
data have1;
set have;
no_of_col=countw(scores);
run;

/***Getting maximun number of required columns and storing them in a macro****/
proc sql noprint;
Select max(no_of_col) into: max_col
from
have1;
quit;

%LET MAX_COL = &MAX_COL;

/*****Using array to divide score in columns and then creating pass/fail column for each value of score columns*/
Data have2;
set have1;
array indicator $20. indicator1-indicator&max_col;
array temp  score1-score&max_col;
do i=1 to dim(TEMP);
        temp[i]=scan(scores,i,'/');
        IF temp[i]>=60 then indicator[i]= 'Pass';
        IF temp[i]<60 and temp[i]<> . then indicator[i] = 'Fail';
end;
DROP I NO_OF_COL scores score1-score&max_col;
run;

/***************Transposing to get indicators as column values for names**************/
proc transpose data=have2 out=outdata(drop=_name_);
by Name notsorted;
var indicator:;
run;
/***********Getting distinct values of pass/fail for a Name**********/
proc sql;
Create table have3 as
Select distinct a.* from
outdata a
where col1 not=" ";
quit;

/*********transpose pass/Fail column back as column values*/
proc transpose data=have3 out=outdata2;
by name notsorted;
var col1;
run;

/*******Getting indicator using 'CATS(to concatenate)'***********/
Data want (Keep=Name indicator);
set outdata2;
format indicator $20.;
indicator=" ";
array col $20. col1-col2;
do i=1 to dim(col);
indicator=compress(cats(col[i],"/",indicator));
end;
if substr(indicator,1,1)="/" then indicator=substr(indicator,2,length(indicator)-2);
else indicator=substr(indicator,1,length(indicator)-1);
drop i;
run;

My Output:-

Name    indicator
A        Pass
B        Pass
C        Pass/Fail
D        Pass
E        Pass/Fail
F        Fail

如果您有任何问题,请告诉我

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-04
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多