I have a sas macro which if certain conditions are met creates a user defined format which is used later in the macro. However this user format is not always created. So when sas validates the syntax when the macro is called it errors as the user defined format is not known when the condition is not met. The statement to use the user defined format is wrapped in an if condition which has not been met but the macro still errors.
Any advice to overcome this problem greatly received.
One good way to deal with this is to create a dummy format that doesn't actually do anything, before the conditional creation. That way, you have something to prevent the error.
%macro fizz_buzz(format=0);
*Format that does nothing;
proc format;
value FIZZBUZZF
other=[best.]
;
quit;
*Conditionally created same format;
%if &format=1 %then %do;
proc format;
value FIZZBUZZF
3,6,9,12='FIZZ'
5,10='BUZZ'
15='FIZZBUZZ'
other=[2.]
;
quit;
%end;
data _null_;
do _i = 1 to 15;
put _i fizzbuzzf.;
end;
run;
%mend fizz_buzz;
%fizz_buzz(format=0);
What do you mean by IF condition? SAS will check the syntax of a DATA step before it starts executing. So cannot prevent the reference to format in the data step by using an IF or similar execution time code. So this code will generate an error even though the condition in the IF statement can never be true.
data bad;
if 0=1 then format x $1XYZ.;
run;
If you use a macro %IF statement so that the reference to format is never generated in the SAS code that the macro creates then you should not have any error. So if you had a similar data step being generated by a macro and used a %IF to prevent the macro from generating the invalid format name then the code will run without error.
data good;
%if (0=1) %then %do;
format x $1XYZ.;
%end;
run;
Most likely you just want to use a macro variable to hold the format name and set it empty if the format is not created.
data good;
format x &format_name ;
run;
Related
I am new to SAS and have been using R most of the time. I am stuck with a simple and frustrating issue. All I want to do is to create a simple 3 X 3 matrix in SAS. But it throws an error. I need some help in understanding what's going on. The SAS documentation is not very helpful.
data matrixTest;
input Y $ X;
cards;
4 0
3 1
1 1
;
run;
/*Convert X to a categorical variable*/
data matrixTest;
set matrixTest;
if X = 0 then X = "0";
else X = "1";
run;
/*Get design matrix from the regression model*/
proc transreg data=matrixTest design;
model class(X/ zero=last);
output out=input_mcmc(drop=_: Int:);
run;
mX = {5 4 3, 4 0 4, 7 10 3};
And I get the following error when creating the matrix mX:
ERROR 180-322: Statement is not valid or it is used out of proper order.
Your error is that SAS is not a matrix language. SAS is more like a database language; the unit of operation is the dataset, analogous to a SQL table or a dataframe in R or Python.
SAS does have a matrix language built into the system, SAS/IML (interactive matrix language), but it's not part of base SAS and isn't really what you use in the context you're showing. The way you enter data as part of your program is how you did it in the first data step, with datalines.
Side note: You're also showing some R tendencies in the second data step; you cannot convert a variable's type that way. SAS has only 'numeric' and 'character', so you don't have 'categorical' data type anyway; just leave it as is.
Do not use the same data set name in the SET and DATA statements. This makes it hard to debug because you've destroyed your initial data set.
You cannot change types on the fly in SAS. If a variables i character it stays character.
If a variable is numeric, you assign values without quotes, quotes are used for character variables.
Your attempt to create a categorical variable doesn't make sense given the fact that it's already 0/1. Make sure your test data is reflective of your actual situation.
I'm not familiar with PROC TRANSREG so I cannot comment on that portion but those are the issues you're facing now.
As someone else mentioned, SAS is not a matrix language, it processes data line by line instead which means it can handle really, really large data sets because it doesn't have to load it into memory.
Your data set, matrixTest is essentially a data set and ready to go. You don't need to convert it to a matrix or 'initialize' it.
If you want a data set with those values then create that as a data set:
data mx;
input var1-var3;
cards;
5 4 3
4 0 4
7 10 3
;
run;
I have a program which is counting the biggest number from 3 numbers. I need to modify the program as the result to be write in text file maxim.out (PASCAL)
You can write the value (assuming it is an integer and it has the name, say, yourValue) with:
var
maximFile: Text;
...
Assign(maximFile, 'maxim.out'); // link the name to the Text variable
Rewrite(maximFile); // open it for writing
Writeln(maximFile, yourValue); // write the value as a line of its own
Close(maximFile); // close the file
You can then read back the value later on with:
Assign(maximFile, 'maxim.out');
Reset(maximFile);
Readln(maximFile, yourValue);
Close(maximFile);
I did not add any error handling (e.g. if the file can't be found, or if it is readonly, or empty, or ...). Depending on settings, that is either done with exceptions or with IOResult values. Read the documentation on how to do that. There should be examples in the docs.
You should read about "file management in pascal". Anyway, declare a variable of type textfile:
var
outputfile : TextFile;
then assignfile() to it your name of choice (maxim.out), rewrite() the file, use writeln() to write into it, and finally closefile() it.
You can find a complete example program here: http://wiki.freepascal.org/File_Handling_In_Pascal
I'm doing a check in my syntax to see if all of the string fields have values. This looks something like this:
IF(STRING ~= "").
Now, instead of filtering or computing a variable, I would like to force an error if there are fields with no values. I'm running a lot of these scripts and I don't want to keep checking the datasets manually. Instead, I just want to receive an error and stop execution.
Is this possible in SPSS Syntax?
First, you can efficiently count the blanks in your string variables with COUNT:
COUNT blanks = A B C(" ").
where you list the string variables to be checked. So if the sum of blanks is > 0, you want the error to be raised. First aggregate to a new dataset and activate it:
DATASET DECLARE sum.
AGGREGATE /OUTFILE=sum /count=sum(blanks).
The hard part is getting the job to stop when the blank count is greater than 0. You can put the job in a syntax file and run it using INSERT with ERROR=STOP, or you can run it as a production job via Utilities or via the -production flag on the command line of an spj (production facility) job.
Here is how to generate an error on a condition.
DATASET ACTIVATE sum.
begin program.
import spssdata
curs = spssdata.Spssdata()
count = curs.fetchone()
curs.CClose()
if count[0] > 0:
spss.Submit("blank values exist")
end program.
DATASET CLOSE sum.
This code reads the aggregate file and if the blank count is positive issues an invalid command causing an error, which stops the job.
My SAS session details are:-
ENCODING=LATIN1
LOCALE=EN_US
I am reading encrypted customer names, decrypting them using a java code that has
been implemented in the sas code using javaobj.
data outlib.X1 ( ENCODING = 'asciiany' );
set inlib.INP1 (ENCODING = 'asciiany' ) end=eof;
length decryptedvalue $100;
declare javaobj jObj("<jarname>");
jObj.callstringmethod("<method>", FIRST_NAME , decryptedvalue);
run;
The jObj.callstringmethod returns the decrypted first_name value in the string decryptedvalue. I do a proc export at the end of my SAS code and store all the decrypted names as csv files.
In the last run some of the names have special characters e.g. RÉAL.
This is causing SAS execution to fail with following error :-
ERROR: Transcoding failure at line 30 column 2.
ERROR: DATA STEP Component Object failure. Aborted during the EXECUTION phase.
Is there some way to make SAS session (LATIN1) accept these unicode characters? Can i set
the encoding of the decryptedvalue variable? I dont want to run my entire SAS session in unicode using sas_u8. I only want to accept these characters
Even reading these problematic values as blank is ok.
I have already tried following things :-
Set inencoding= utf8 for the libname
Make ENCODING = 'asciiany' for the input dataset.
Any inputs would be useful.
Thanks in advance!
SAS Tech support suggested this :-
Adding export EASYSOFT_UNICODE=YES in the sasenv_local file .
We are now able to run the entire SAS code (including SQL queries) in the sas u8 session.
Thanks to all for your support.
I just started using SPSS, there is a option of Select cases that I was trying in SPSS, and later on finding frequency based on that filter.
For Eg:
Suppose Q1 has 12 parts, Q1_1 Q1_2 Q1_3 Q1_4 Q1_5 Q1_6 Q1_7 Q1_8 Q1_9 Q1_10 Q1_11 Q1_12
I want to see data in these variables based on a condition that I used in select cases. Now when I try to see frequencies of these variables based on the filter, only 4 out of 12 satisfy has data.
Now my question is can I hide rest 8 and show only 4 with data on my output window.
It's not entirely clear what you are trying to describe however reading between the lines, I'm guessing you are trying to delete tables generated from FREQUENCIES which may happen to be empty (likely due to a filter applied but perhaps not necessarily either)
You could do this with SPSS Scripting but avoiding that, you may want to explore using CTABLES, which though may not be in the exact same format as FREQUENCY table output it will still none the less retrieve the same information.
Solution below. Assumes Python Integration with SPSS SELECT VARIABLES installed and of course the CTABLE add-on module.
/****** Simulate example data ******/.
input program.
loop #j = 1 to 100.
compute ID=#j.
vector Q(12).
loop #i = 1 to 12.
do if #j<51 and #i<9.
compute Q(#i) = $sysmis.
else.
compute Q(#i) = trunc(rv.uniform(1,5)).
end if.
end loop.
end case.
end loop.
end file.
end input program.
execute.
/************************************/.
/* frequencies without filtering applied */.
freq q1 to q12.
/* frequencies WITH filtering applied */.
/* Empty table here shoult be removed */.
temp.
select if (ID<51).
freq q1 to q12.
spssinc select variables macroname="!Qp" /properties pattern = "^Q\d+$"/options separator="+" order=file.
spssinc select variables macroname="!Qs" /properties pattern = "^Q\d+$"/options separator=" " order=file.
temp.
select if (ID<51).
ctables /table (!Qp)[c][count colpct]
/categories variables=!Qs empty=exclude.
Note if you had assess empty variables at a total level then there is a function in spssaux2 (spssaux2.FindEmptyVars) which could help you find the empty variables and then you could build the syntax to exclude these and so contain the variables with only valid responses and then run FREQUENCIES. But I don't think spssaux2.FindEmptyVars will honor any filtering.