Hi all,
I have a specific question that is not easy to google. Most certainly someone has already asked it, so apologies for asking it twice.
I have a dataset that looks like this:
Client Code
1 A
1 B
2 A
3 A
3 C
3 D
4 A
5 A
5 B
...
For every Client number I have the code A, so I want to make my dataset a little smaller and easier to handle by creating indicators if a client also has the codes B, C and/or D.
So, my final dataset (after removing the redundant rows) looks like this:
Client Code ind_B ind_C ind_D
1 A 1 0 0
2 A 0 0 0
3 A 0 1 1
4 A 0 0 0
5 A 1 0 0
...
I succeeded to do this by creating 2 datasets and joining them, but that is not time and memory efficient. I prefer not to loop over all clients and I'm convinced there is a better way to do this, I just cannot come up with it.
Can anyone help me?
data have;
input client code $;
cards;
1 A
1 B
2 A
3 A
3 C
3 D
4 A
5 A
5 B
;
run;
proc sql;
select client,'A' as code,
sum(code='B') as B,sum(code='C') as C,sum(code='D') as D
from have
group by client;
quit;
TBH I would strongly suspect that your want dataset here would be larger than the have dataset. In the have dataset you are only capturing data where it appears, in the want data you are creating empty data items where there is no data. For example:
Client 1 has two datapoints, a and b, but in the want dataset the same client has 3 datapoints, b, c, and d two of which are redundant. Unless there is a very good reason (and I can't see one) to have that want structure, I would stick with your first, and filter out where code="A" if they all have it, as that is not needed at all. This would effecively shrink your have to 4*2 fields which is far smaller than your want of 5*5.
You are right in my example.
I did not mention though that each row contains much more columns with client information.
These columns are independent of the code, so the dataset contains a lot of duplicative information.
Therefore it is more efficient to create an indicator such that I can remove the rows that have not code A.
Sorry, you going to have to clarify, test data/required output etc. This:
"I can remove the rows that have not code A"
To me resolves as:
proc sql; create table want as
select *
from have where client not in (select distinct client from have where code="A"); quit;
Ie create a copy of the data with only clients who have an "A" record.
See this:
data have;
input client code $;
cards;
1 A
1 B
2 A
3 A
3 C
3 D
4 A
5 A
5 B
;
run;
data int;
set have (where=(code ne 'A')) ;
val = 1;
run;
proc transpose
data=int
out=codes (drop=_name_)
prefix=ind_
;
by client;
id code;
var val;
run;
data want;
merge
have (
in=a
where=(code = 'A')
)
codes
;
by client;
if a;
run;
proc print data=want noobs;
run;
data have;
input client code $;
cards;
1 A
1 B
2 A
3 A
3 C
3 D
4 A
5 A
5 B
;
run;
proc sql;
select client,'A' as code,
sum(code='B') as B,sum(code='C') as C,sum(code='D') as D
from have
group by client;
quit;
Seems like a method works without knowing the values of CODE would be useful.
data have;
input client code :$1. @@;
cards;
1 A 1 B 2 A 3 A 3 C 3 D 4 A 5 A 5 B
;;;;
run;
proc transreg data=have design;
id client;
model class(code/zero=none CPREFIX=0);
output out=design(drop=Int: _:);
run;
proc print;
run;
proc means noprint nway;
class client;
output out=want(drop=_:) sum=;
run;
proc print;
run;
John King,
Long time no see.
Sure . That would be easy.
1) PROC FREQ to get all these levels.
2)CALL EXECUTE() to make it happen .
Don't miss out on SAS Innovate - Register now for the FREE Livestream!
Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.