How specify GBP currency in proc tabulate format - sas

What is the format for GBP currency?
I would like to have the variable 'rent' to be displayed as £X in the below tabulate. What format should I put in the 'format' statement?
An example would be the equivalent of 'format=dollar12' that gives the USD currency. What would it be for GBP?
proc tabulate format=?;
var rent;
class bedrooms city;
table bedrooms, (city=' ' all='Total')*rent=' '*mean=' ' / box='Average Rent';
run;

Apply a format to the mean statistic using * f= NLMNLGBP.
From https://communities.sas.com/t5/General-SAS-Programming/How-do-I-specify-a-currency-format-and-a-comma-format-in-a-DATA/td-p/80230
applied NLMNLGBP. to the currency field, which formatted it as £1,672,349
Sample code
data have;
bedrooms=2; city='London'; rent=4500;
label rent = 'Rent';
format rent NLMNLGBP.;
run;
proc tabulate data=have;
class bedrooms city;
var rent;
table
bedrooms
,
(city=' ' all='Total')
* rent=' '
* mean=' ' * f=NLMNLGBP. %* <----- Happy brexiting ;
/
box='Average Rent'
;
run;

Related

Deleting and adding specific row/ column in SAS output

I have the following data
DATA HAVE;
input year dz $8. area;
cards;
2000 stroke 08
2000 stroke 06
2000 stroke 06
;
run;
After using proc freq
proc freq data=have;
table area*dz/ list nocum ;
run;
I get the below output
In this output
I want to delete the 'dz', what can I do to delete this column?
I want a row in the end that gives 'total', what can I do to get a 'total' row?
Thank you!
There must be a better way of doing this, but the following code creates the desired table:
data have;
input year dz $8. area;
cards;
2000 stroke 08
2000 stroke 06
2000 stroke 06
;
run;
ods output List=list;
proc freq data=have;
table area*dz / list;
run;
data stage1;
set list(keep= area frequency percent CumFrequency CumPercent) end=eof;
area_char = put(area,best.-l); /* Convert it to char to add the Total row */
if eof then do;
call symputx("cumFreq", cumfrequency);
call symputx("cumPerc", cumpercent);
end;
drop area;
run;
data want;
retain area frequency percent; /* Put the variables in the desired order */
set stage1(rename=(area_char=area) drop=cumfrequency cumpercent) end=eof;
output;
if eof then do; /* Manually create the Total row */
area = "Total";
Frequency = &cumfreq.;
Percent = &cumperc.;
output;
end;
run;
Output (want table):
You should subset your data with a where clause and use a title statement if a important partitioning variable is to be removed from output. If you didn't subset how would your audience know if a count contained say episodes of stroke and ministroke if ministroke was also in the data.
Compute the frequencies with freq and use a reporting procedure (print, report, tababulate) that summarizes to show a total line.
Example:
data have;
input year dz $ area;
cards;
2000 stroke 08
2000 stroke 06
2000 stroke 06
;
proc freq noprint data=have;
where dz = 'stroke';
table area / out=freqs;
run;
title 'Stroke dz';
title2 'print';
proc print data=freqs noobs label;
var area;
sum count percent;
run;
title2 'report';
proc report data=freqs;
columns area count percent;
define area / display;
define count / analysis;
rbreak after / summarize;
run;
title2 'tabulate';
proc tabulate data=freqs;
class area;
var count percent;
table area all, count percent;
run;
Thank you all for your valuable responses. The following code gives me the desired output in a concise way
proc freq data=HAVE;
tables area / list nocum out=a;
run;
proc sql;
create table b as
select * from a
union
select
'Total' as area,
sum(count) as count,
sum(percent) as percent
FROM a
;
quit;
proc print data=b; run;

How to create nested rows in SAS?

I am a beginner so my knowledge is lacking. I have a data set consisting of the following columns:
Subject
Age
Height
Weight
I wish to create a table such that for every 1 person i have three rows called Age, Height, Weight.
I have tried to use Proc Tabulate :
proc tabulate data=new;
class person;
var NEWCOLUMN;
table person,NEWCOLUMN;
run;
However i am getting an error because the new column is not the correct type.
You can pivot the data per person and REPORT or TABULATE the cell values.
Example:
proc transpose data=sashelp.class out=pivoted;
by name;
var age height weight;
where name <= 'C';
run;
ods html file='output.html' style=plateau;
options nodate nonumber nocenter;
title; footnote;
proc report data=pivoted;
column name _name_ col1;
define name / ' ' order order=data;
define _name_ / ' ';
define col1 / ' ';
run;
proc tabulate data=pivoted;
class name _name_ / order=data;
var col1;
table name*_name_='', col1=''*min='' / nocellmerge;
run;
ods html close;
Output

how to vertically sum a range of dynamic variables in sas?

I have a dataset in SAS in which the months would be dynamically updated each month. I need to calculate the sum vertically each month and paste the sum below, as shown in the image.
Proc means/ proc summary and proc print are not doing the trick for me.
I was given the following code before:
`%let month = month name;
%put &month.;
data new_totals;
set Final_&month. end=end;
&month._sum + &month._final;
/*feb_sum + &month._final;*/
output;
if end then do;
measure = 'Total';
&month._final = &month._sum;
/*Feb_final = feb_sum;*/
output;
end;
drop &month._sum;
run; `
The problem is this has all the months hardcoded, which i don't want. I am not too familiar with loops or arrays, so need a solution for this, please.
enter image description here
It may be better to use a reporting procedure such as PRINT or REPORT to produce the desired output.
data have;
length group $20;
do group = 'A', 'B', 'C';
array month_totals jan2020 jan2019 feb2020 feb2019 mar2019 apr2019 may2019 jun2019 jul2019 aug2019 sep2019 oct2019 oct2019 nov2019 dec2019;
do over month_totals;
month_totals = 10 + floor(rand('uniform', 60));
end;
output;
end;
run;
ods excel file='data_with_total_row.xlsx';
proc print noobs data=have;
var group ;
sum jan2020--dec2019;
run;
proc report data=have;
columns group jan2020--dec2019;
define group / width=20;
rbreak after / summarize;
compute after;
group = 'Total';
endcomp;
run;
ods excel close;
Data structure
The data sets you are working with are 'difficult' because the date aspect of the data is actually in the metadata, i.e. the column name. An even better approach, in SAS, is too have a categorical data with columns
group (categorical role)
month (categorical role)
total (continuous role)
Such data can be easily filtered with a where clause, and reporting procedures such as REPORT and TABULATE can use the month variable in a class statement.
Example:
data have;
length group $20;
do group = 'A', 'B', 'C';
do _n_ = 0 by 1 until (month >= '01feb2020'd);
month = intnx('month', '01jan2018'd, _n_);
total = 10 + floor(rand('uniform', 60));
output;
end;
end;
format month monyy5.;
run;
proc tabulate data=have;
class group month;
var total;
table
group all='Total'
,
month='' * total='' * sum=''*f=comma9.
;
where intck('month', month, '01feb2020'd) between 0 and 13;
run;
proc report data=have;
column group (month,total);
define group / group;
define month / '' across order=data ;
define total / '' ;
where intck('month', month, '01feb2020'd) between 0 and 13;
run;
Here is a basic way. Borrowed sample data from Richard.
data have;
length group $20;
do group = 'A', 'B';
array months jan2020 jan2019 feb2020 feb2019 mar2019 apr2019 may2019 jun2019 jul2019 aug2019 sep2019 oct2019 oct2019 nov2019 dec2019;
do over months;
months = 10 + floor(rand('uniform', 60, 1));
end;
output;
end;
run;
proc summary data=have;
var _numeric_;
output out=temp(drop=_:) sum=;
run;
data want;
set have temp (in=t);
if t then group='Total';
run;

Report using data _Null_

I'm looking for report using SAS data step :
I have a data set:
Name Company Date
X A 199802
X A 199705
X D 199901
y B 200405
y F 200309
Z C 200503
Z C 200408
Z C 200404
Z C 200309
Z C 200210
Z M 200109
W G 200010
Report I'm looking for:
Name Company From To
X A 1997/05 1998/02
D 1998/02 1999/01
Y B 2003/09 2004/05
F 2003/09 2003/09
Z C 2002/10 2005/03
M 2001/09 2001/09
W G 2000/10 2000/10
THANK you,
Tried using proc print but it is not accurate. So looking for a data null solution.
data _null_;
set salesdata;
by name company date;
array x(*) from;
From=lag(date);
if first.name then count=1;
do i=count to dim(x);
x(i)=.;
end;
count+1;
If first.company then do;
from_date1=date;
end;
if last.company then To_date=date;
if from_date1 ="" and to_date="" then delete;
run;
data _null_;
set yourEvents;
by Name Company notsorted;
file print;
If _N_ EQ 1 then put
#01 'Name'
#06 'Company'
#14 'From'
#22 'To'
;
if first.Name then put
#01 Name
#; ** This instructs sas to not start a new line for the next put instruction **;
retain From To;
if first.company then do;
From = 1E9;
To = 0;
end;
if Date LT From then From = Date;
if Date GT To then To = Date;
if last.Company then put
#06 Company
#14 From yymm7.
#22 To yymm7.
;
run;
I have done data step to calculate From_date and To_date
and then proc report to print the report by group.
proc sort data=have ;
by Name Company Date;
run;
data want(drop=prev_date date);
set have;
by Name Company date;
attrib From_Date To_date format=yymms10.;
retain prev_date;
if first.Company then prev_date=date;
if last.Company then do;
To_date=Date;
From_Date=prev_date;
end;
if not(last.company) then delete;
run;
proc sort data=want;
by descending name ;
run;
proc report data=want;
define Name/order order=data;
run;
IMHO, the simplest way is exploiting proc report and its analysis column type as the code below. Note that name and company columns are automatically sorted in alphabetical order (as most of the summary functions or procedures do).
/* your data */
data have;
infile datalines;
input Name $ Company $ Date $;
cards;
X A 199802
X A 199705
X D 199901
y B 200405
y F 200309
Z C 200503
Z C 200408
Z C 200404
Z C 200309
Z C 200210
Z M 200109
W G 200010
;
run;
/* convert YYYYMM to date */
data have2(keep=name company date);
set have(rename=(date=date_txt));
name = upcase(name);
y = input(substr(date_txt, 1, 4), 4.);
m = input(substr(date_txt, 5, 2), 2.);
date = mdy(m,1,y);
format date yymms7.;
run;
/****** 1. proc report ******/
proc report data=have2;
columns name company date=date_from date=date_to;
define name / 'Name' group;
define company / 'Company' group;
define date_from / 'From' analysis min;
define date_to / 'To' analysis max;
run;
The html output:
(tested on SAS 9.4 win7 x64)
============================ OFFTOPIC ==============================
One may also consider using proc means or proc tabulate. The basic code forms are shown below. However, you can also see that further adjustments in output formats are required.
/***** 2. proc tabulate *****/
proc tabulate data=have2;
class name company;
var date;
table name*company, date=' '*(min='From' max='To')*format=yymms7.;
run;
proc tabulate output:
/***** 3. proc means (not quite there) *****/
* proc means + ODS -> cannot recognize date formats;
proc means data=have2 nonobs min max;
class name company;
format date yymms7.; * in vain;
var date;
run;
proc means output (cannot output date format, dunno why):
You may leave comments on improving these alternative ways.

Calculating correlation and covariance for a event window in SAS

I have to calculate the correlation and covariance for my daily sales values for an event window. The event window is of 45 day period and my data looks like -
store_id date sales
5927 12-Jan-07 3,714.00
5927 12-Jan-07 3,259.00
5927 14-Jan-07 3,787.00
5927 14-Jan-07 3,480.00
5927 17-Jan-07 3,646.00
5927 17-Jan-07 3,316.00
4978 18-Jan-07 3,530.00
4978 18-Jan-07 3,103.00
4978 18-Jan-07 3,026.00
4978 21-Jan-07 3,448.00
Now, for every store_id, date combination, I need to go back 45 days (there is more data for each combination in my original data set) calculate the correlation between sales and lag(sales) i.e. autocorrelation of degree one. As you can see, the date column is not continuous. So something like (date - 45) is not going to work.
I have gotten till this part -
data ds1;
set ds;
by store_id;
LAG_SALE = lag(sales);
IF FIRST.store_idTHEN DO;
LAG_SALE = .;
END;
run;
For calculating correlation and covariances -
proc corr data=ds1 outp=Corr
by store_id date;
cov; /** include covariances **/
var sales lag_sale;
run;
But how do I insert the event window for each date, store_id combination? My final output should look something like this -
id date corr cov
5927 12-Jan-07 ... ...
5927 14-Jan-07 ... ...
Here is what I've come up with:
First I convert the date to a SAS date, which is the number of days since Jan. 1 1960:
data ds;
set ds (rename=(date=old_date));
date = input(old_date, date11.);
drop old_date;
run;
Then compute lag_sale (I am using the same calculation you used in the question, but make sure this is what you want to do. For some observations the lag sale is the previous recorded date, but for some it is the same store_id and date, just a different observation.):
proc sort data=ds; by store_id; run;
data ds;
set ds;
by store_id;
lag_sale = lag(sales);
if first.store_id then lag_sale = .;
run;
Then set up the final data set:
data final;
length store_id 8 date 8 cov 8 corr 8;
if _n_ = 0;
run;
Then create a macro which takes a store_id and date and runs proc corr. The first part of the macro selects only the data with that store_id and within the past 45 days of the date. Then it runs proc corr. Then it formats proc corr how you want it and appends the results to the "final" data set.
%macro corr(store_id, date);
data ds2;
set ds;
where store_id = &store_id and %eval(&date-45) <= date <=&date
and lag_sale ne .;
run;
proc corr noprint data=ds2 cov outp=corr;
by store_id;
var sales lag_sale;
run;
data corr2;
set corr;
where _type_ in ('CORR', 'COV') and _name_ = 'sales';
retain cov;
date = &date;
if _type_ = 'COV' then cov = lag_sale;
else do;
corr = lag_sale;
output;
end;
keep store_id date corr cov;
run;
proc append base=final data=corr2 force; run;
%mend corr;
Finally run the macro for each store_id/date combination.
proc sort data=ds out=ds3 nodupkey;
by store_id date;
run;
data _null_;
set ds3;
call execute('%corr('||store_id||','||date||');');
run;
proc sort data=final;
by store_id date;
run;