I have a table with 100 variables (I copied here only 8 for the example), and I want to convert it into a macro in which I can only insert the first variable number (1) and the last one (100) and run this table with only one or two rows inside it (instead of 100).
Does anyone know how to do that?
CTABLES
/VLABELS VARIABLES=Loop1_a_01 var1 DISPLAY=DEFAULT
/TABLE var1 [C][ROWPCT.COUNT F40.0] +
var2 [C][ROWPCT.COUNT F40.0] +
var3 [C][ROWPCT.COUNT F40.0] +
var4 [C][ROWPCT.COUNT F40.0] +
var5 [C][ROWPCT.COUNT F40.0] +
var6 [C][ROWPCT.COUNT F40.0] +
var7 [C][ROWPCT.COUNT F40.0] +
var8 [C][ROWPCT.COUNT F40.0] BY Loop1_a_01
/CATEGORIES VARIABLES=Loop1_a_01 EMPTY=INCLUDE
/CATEGORIES VARIABLES=var5 ORDER=A KEY=VALUE
EMPTY=INCLUDE
/TITLES TITLE= 'TV'
.
Since you are using the same statistics for all the variables, you can simplify the ctables code by factoring out the repeated statistics, e.g.,
/TABLE (var1+var2+...)[ROWPCT.COUNT F40.0] BY ...
Now, if you want to do something like including all the variables in a dataset whose names look like varnn, you can automate this by using the SPSSINC SELECT VARIABLES extension command to generate a macro. For example
SPSSINC SELECT VARIABLES MACRONAME="!myvars"
/PROPERTIES PATTERN = "var\d+"
/OPTIONS SEPARATOR="+".
CTABLES
/TABLE (!myvars)[....
It is possible to write a more complex macro to generate !myvars, but if you need to impose extra logic, generating it with Python programmability would be much easier.
Related
Write two statements to read in values for my_city followed by my_state. Do not provide a
prompt. Assign log_entry with current_time, my_city, and my_state. Values should be separated
by a space. Sample output for given program if my_city is Houston and my_state is Texas:
2014-07-26 02:12:18: Houston Texas
Note: Do not write a prompt for the input values.
current_time = '2014-07-26 02:12:18:'
my_city = ''
my_state = ''
log_entry =
''' Your solution goes here '''
print(log_entry)
I've tried several solutions and it is only printing out the date and time. Since the date and
time is given, I figured to concatenate the city and state strings then add them under log
entry however it still only prints out the date. I can't enter the actual city and state
because there is a back end test where Zybooks add a different city and state. Here is what I
have tried so far.
concatenated_string = my_city + ' ' + my_state
log_entry = current_time + concatenated_string
Actually figured it out.
my_city = input("")
my_state = input("")
log_entry = (current_time + ' ' + my_city + ' ' + my_state)
I'm having some trouble referencing a global macro variable outside of the macro to create a new data set. The global variable was created to run a loop for creating several yearly data sets using a vector of specified years, as you can see in the code below:
%macro loopyear;
%global year;
%do year = 2004 %to 2017;
proc import datafile = "C:\Filepath\blah.txt"
dbms = dlm out = blah&year.; /*Creates a dataset for each year, e.g. blah2004, blah2005, etc.) */
delimiter = " ";
getnames = no;
run;
data blah&year.;
set blah&year.;
year = &year.;
run;
proc sql;
create table blah&year._rail as
select year, var1, var2, var3, var4
from blah&year.
where var2= "rail";
quit;
%end;
%mend loopyear;
%loopyear;
/*Merge all year datasets into one master set*/
data blah_total;
set blah&year._rail;
run;
When I try to create the master data set outside of the macro, however, I get the following error:
data blah;
set blah&year._rail;
run;
ERROR: File work.blah2018_rail.data does not exist
This is frustrating because I'm only trying to create the master set based on 2004-2017 data, as referenced in the macro variable. Can someone help me pinpoint my error -- is it in the way I defined the global variable, or am I missing a step somewhere? Any help is appreciated.
Thanks!
This is an interesting quirk of both macro and data step do-loops in SAS - the loop counter is incremented before the exit condition is checked, so after your loop has run it will be one increment past your stop value, e.g.:
%macro example;
%do i = 1 %to 3;
%put i = &i;
%end;
%put i = &i;
%mend;
%example;
Output:
i = 1
i = 2
i = 3
i = 4
For your final step you probably want the set statement to look like this:
set blah2004_rail ... blah2017_rail;
You could write a macro loop to generate the list and move the data step inside your macro, e.g.
set %do year = 2004 %to 2017; blah&year._rail %end;;
The second semi-colon is important! You need one to close the %end and one to terminate the set statement.
Change your naming structure. Have a common prefix and put the year at the end, then you can use the semi colon to short reference all the datasets at once.
%macro loopyear;
%global year;
%do year = 2004 %to 2017;
proc import datafile = "C:\Filepath\blah.txt"
dbms = dlm out = blah&year.; /*Creates a dataset for each year, e.g. blah2004, blah2005, etc.) */
delimiter = " ";
getnames = no;
run;
data blah&year.;
set blah&year.;
year = &year.;
run;
proc sql;
create table blah_rail_&year. as
select year, var1, var2, var3, var4
from blah&year.
where var2= "rail";
quit;
%end;
%mend loopyear;
%loopyear;
/*Merge all year datasets into one master set*/
data blah_total;
set blah_rail: ;
run;
I have a .scores file with two delimiters space and comma. I need to import it sas and not able to do it with regular import command. The format is as follows
832783_9399 973299,03200 238003
Thanks!
you can use multiple delimiters in dlm as show below
data want;
infile datalines dlm=' ,' ;
informat var1 var2 var3 var4 $60.;
input var1 $ var2 $ var3 $ var4 $;
datalines;
832783_9399 973299,03200 238003
;
I have a table which has 120 columns and some of them is including Turkish characters (for example "ç","ğ","ı","ö"). So i want to replace this Turkish characters with English characters (for example "c","g","i","o"). When i use "TRANWRD Function" it could be really hard because i should write the function 120 times and sometimes hte column names could be change so always i have to check the code one by one because of that.
Is there a simple macro which replaces this characters in all columns .
EDIT
In retrospect, this is an overly complicated solution... The translate() function should be used, as pointed by another user. It could be integrated in a SAS function defined with PROC FCMP when used repeatedly.
A combination of regular expressions and a DO loop can achieve that.
Step 1: Build a conversion table in the following manner
Accentuated letters that resolve to the same replacement character are put on a single line, separated by the | symbol.
data conversions;
infile datalines dsd;
input orig $ repl $;
datalines;
ç,c
ğ,g
ı,l
ö|ò|ó,o
ë|è,e
;
Step 2: Store original and replacement strings in macro variables
proc sql noprint;
select orig, repl, count(*)
into :orig separated by ";",
:repl separated by ";",
:nrepl
from conversions;
quit;
Step 3: Do the actual conversion
Just to show how it works, let's deal with just one column.
data convert(drop=i re);
myString = "ç ğı òö ë, è";
do i = 1 to &nrepl;
re = prxparse("s/" || scan("&orig",i,";") || "/" || scan("&repl",i,";") || "/");
myString = prxchange(re,-1,myString);
end;
run;
Resulting myString: "c gl oo e, e"
To process all character columns, we use an array
Say your table is named mySource and you want all character variables to be processed; we'll create a vector called cols for that.
data convert(drop=i re);
set mySource;
array cols(*) _character_;
do c = 1 to dim(cols);
do i = 1 to &nrepl;
re = prxparse("s/" || scan("&orig",i,";") || "/" || scan("&repl",i,";") || "/");
cols(c) = prxchange(re,-1,cols(c));
end;
end;
run;
When changing single characters TRANSLATE is the proper function, it will be one line of code.
translated = translate(string,"cgio","çğıö");
First get all your columns from dictionary, and then replace the values of all of them in a macro do loop.
You can try a program like this (Replace MYTABLE with your table name):
proc sql;
select name , count(*) into :columns separated by ' ', :count
from dictionary.columns
where memname = 'MYTABLE';
quit;
%macro m;
data mytable;
set mytable;
%do i=1 %to &count;
%scan(&columns ,&i) = tranwrd(%scan(&columns ,&i),"ç","c");
%scan(&columns ,&i) = tranwrd(%scan(&columns ,&i),"ğ","g");
...
%end;
%mend;
%m;
I have a table is SAS say t looking like this
A B C D
--------------------------------------------------------------
VOLUME 172631922966528 IMPLIED 2012-10-04
VOLUME 173731441803264 IMPLIED 2012-10-04
PRIX_VOLUME 189124634214400 IMPLIED 2012-10-04
PRIX_VOLUME 123153895784448 IMPLIED 2012-10-04
VOLUME 266090408574976 IMPLIED 2012-10-04
VOLUME 119855364243456 IMPLIED 2012-10-04
The column D is a Date (format yymmdd10) colume and I have a macrovarible date0 that is worth 2012-10-04 I am trying to do a trivial data-step
data test;
set t (where=(A eq "VOLUME" and D eq &date0.));
run;
but this is not working
Can you help fix it ?
That is because when the macro variable is processed, you get:
data test;
set t (where=(A eq "VOLUME" and D eq 2012-10-04));
run;
Which SAS will resolve as:
data test;
set t (where=(A eq "VOLUME" and D eq 1998));
run;
Because it sees math instead of a date.
You need to make clear to SAS that:
1. it is not algebra.
2. it should read it as a date.
To make it read it as a string, add quotes. To make clear that the string represents a date, append a d after the quotes:
data test;
set t (where=(A eq "VOLUME" and D eq "&date0."d));
run;
That should do the trick.