BookmarkSubscribeRSS Feed
WorkingMan
Calcite | Level 5

Hi everyone. This is a lil bit tricky for me and I am seeking for advice online. I am currently reading from a xlsx file and then want to transpose the data from wide to long. Here is the trick, have a look at the table structure:

Country    A_Sept17  A_Oct17  B_Sept17  B_Oct17
Denmark  100           99             3                5
Japan       700           350           7                9

And i want it to look like this:

Country   Period   ColA   ColB
Denmark Sept17  100     3
Denmark Oct17    99       5
Japan      Sept17  700     7
Japan      Oct17    350     9

As you all can see, It looks like kinda straightforward transpose. However, when i use PROC Transpose, i do not get the desire result. Here is my code:

proc transpose data=test out=transposed;
by country;

var 
a_sept17
a_oct17
b_factor_sept17
b_factor_oct17;
run;

The result that i got from my code:

Country   Period      Col1
Denmark a_sept17      100
Denmark a_oct17       99
Denmark b_sept17      3 
Denmark b_sept17 5
Japan a_sept17 700
Japan a_oct17 350
Japan b_sept17 7
Japan b_oct17 9

What could be wrong here?

3 REPLIES 3
Kurt_Bremser
Super User

You need 2 transposes, and a little manipulation in-between:

data have;
input country :$10. a_sept17 a_oct17 b_sept17 b_oct17;
cards;
Denmark 100 99 3 5
Japan 700 350 7 9
;
run;

proc transpose data=have out=trans;
by country;
var a_: b_:;
run;

data trans1;
set trans;
name = scan(_name_,1,'_');
period = scan(_name_,2,'_');
drop _name_;
run;

proc sort data=trans1;
by country period;
run;

proc transpose
  data=trans1
  out=want (drop=_name_)
  prefix=col
;
by country period;
var col1;
id name;
run;

proc print data=want noobs;
run;

Result:

country    period    cola    colb

Denmark    oct17       99      5 
Denmark    sept17     100      3 
Japan      oct17      350      9 
Japan      sept17     700      7 

If you want to have really nice SAS date values, expand the manipulation step:

data trans1;
set trans;
name = scan(_name_,1,'_');
_period = scan(_name_,2,'_');
period = input('01' !! substr(_period,1,3) !! substr(_period,length(_period) - 1),date7.);
drop _name_ _period;
format period yymmn6.;
run;
singhsahab
Lapis Lazuli | Level 10

Hello,

 

here you can go ...

 

data test;
input Country $ A_Sept17  A_Oct17  B_Sept17  B_Oct17;
datalines;
Denmark 100 99 3 5
Japan 700 350 7 9
;
run;

proc transpose data=test out=want name=name1 prefix=cola;
by country notsorted;
var a_:;
run;

proc transpose data=test out=want1 name=name1 prefix=colb;
by country notsorted;
var b_:;
run;

proc sort data=want;
by country ;
run;
proc sort data=want1;
by country ;
run;

data final (drop=name1);
merge want(in=a) want1(in=b);
by country ;
if a and b;
Period=substr(name1,3);
run;

Thanks,

RW9
Diamond | Level 26 RW9
Diamond | Level 26

Assuming those variables appear in month/year order and there is always 2 of them, its easier with arrays:

data want (keep=country month a b);
  set have;
  array x{2} a_:;
  array y{2} b_:;
  do i=1 to 2;
    month=scan(vname(x{i}),2,"_");
    a=x{i};
    b=x{i};
    output;
  end;
run;

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 3 replies
  • 736 views
  • 0 likes
  • 4 in conversation