Is there an equivalent of the Oracle NVL function in SAS?
For example, if I have a where clause in SAS that says:
where myVar > -2;
it is not going to include any rows that have myVar = .
If I want to treat missing values as zero, i have to say:
where myVar > -2 or missing( myVar )
I'd like to be able to do something like:
where NVL( myVar, 0 ) > -2 // or some SAS equivalent
Is there something like this in SAS?
The coalesce function should do the job.
where coalesce(myVar,0) > -2
I'm not sure if the function became available in SAS 9, so if you have a really old SAS version this might not work.
Using the coalesce function is the right way to do this.
But if you have an old version of SAS where coalesce isn't implemented, you can use this trick:
where sum(myVar,0) > -2
If you use the sum function in SAS for adding, any non-missing number in the summation will force the result to be non-missing.
Thus adding 0 with the sum function will transform a missing value to 0, and non-missing values will remain unaltered.
One thing that y can do is
like
array varlistname var1 var2 var3 varn;
if array <>. then output;
It will ouput data sets having non missing values
Related
I'm running SAS code on a data set that is thousands of rows (typical). I need to create 2 new variables in a data step that includes the sum of each row (categories by either X or Z in the title for each observation of y based on the Variable Name. Obviously I cannot write out each variable I need the sum of because it will be impossible in my actual data set. I think the answer is a Loop of sorts, but not having any luck finding a solution online where I don't need to list all of the variables.
A much smaller example data set is listed below of what I need the data to look like at the end.
So far I tried doing something like this but I KNOW this is so far off, I just am really stuck on how to get it to recognize the variables name and stop when it hits the last X or last Z.
DATA sample1 (drop = i);
set data;
do i = i to 10;
answer = sum(i);
end;
run
You can use a variable short cut references with the :.
of X: means sum everything that starts with the variable X.
data want;
set have;
sumx = sum(of X:);
sumZ = sum(of Z:);
*if you know the end of the series;
sumx = sum(of X1-X4);
sumZ = sum(of Z1-Z5);
run;
Different ways of specifying the variable list is illustrated here
I am trying to use the SAS XIRR function on a dataset. The syntax is:
finance('XIRR',value1, value2, value3...valuen,date1,date2,date3...daten);
My problem is that the data has different numbers of values/dates on each row. There could be up to 122 values/dates per row.
Where there are missing values the XIRR function fails, so I set all missing values to 0. Now the function fails as the 'missing' dates are now Jan1960. Anyone got any ideas?
in the code below cf1-cf122 are the cash flow values and ed1-ed122 are the dates.
/* remove blanks */
data irrtable3;
set irrtable2;
array change _numeric_;
do over change;
if change=. then change=0;
end;
run;
/* create irr */
data irrtable4;
set irrtable3;
IRR=finance('XIRR',OF CF1-CF122,OF ED1-ED122);
run;```
You can use codegen to construct a dynamic FINANCE(..) call, with a variable number of arguments, that is resolved by the macro system at DATA step run-time.
Using RESOLVE to compute the result in macro environment for many, many rows will likely have a noticeable slowness compared to plain DATA step.
Example:
data have;
v1=−10000; d1=mdy(1, 1, 2008);
v2=2750; d2=mdy(3, 1, 2008);
v3=4250; d3=mdy(10, 30, 2008);
v4=3250; d4=mdy(2, 15, 2009);
v5=2750; d5=mdy(4, 1, 2009);
output;
call missing(v5,d5); output;
call missing(v4,d4); output;
call missing(v3,d3); output;
call missing(v2,d2); output;
run;
options missing=' ';
data want;
set have;
args = catx(',', of v1-v5, of d1-d5);
result = resolve( cats (
'%sysfunc(FINANCE(XIRR,', args, '))'
));
run;
options missing='.';
From what I can tell (And I don't work with Finance functions, so I'm not an expert), if you have all of the 'filled' arguments prior to the 'unfilled', you are okay to just set everything to zero that's missing (both on the 'value' and 'date' side). Using the example Richard provides (which is the one from the SAS documentation):
data want2;
set have;
array v v1-v5;
array d d1-d5;
do _i_ = 1 to dim(v);
if missing(v[_i_]) then do;
v[_i_]=0; d[_i_]=0;
end;
end;
args = catx(',', of v1-v5, of d1-d5);
result =FINANCE('XIRR',of v1-v5, of d1-d5);
run;
That works and gets the same result as Richard's, and is probably faster.
This does require the 0s to all be at the end - if they're interspersed, and you can't use CALL SORTN to get them put all on one end - and your data is too big to use with RESOLVE, then I would construct this entirely in the macro language. You could do a few things, all of which are too long for this answer, but the simplest is probably to create code for every line, and put them behind if _n_ = 5 then do; &row5code.; end; for each row. This would be very long, certainly, but should be faster than the resolve (just a lot less maintainable). You could also do a CALL EXECUTE for each line, also slow but a possibility, or even DOSUBL.
I will present the simplified version of what I want to do. I know how to do it easily in SAS but not in Stata.
Let's say I am trying to create a "poor" binary variable = 1 if an observation is classified as poor and 0 otherwise. I want to have two classifications, one is based on real income, and another based on real consumption (these are variables in the dataset).
The SAS macro would be
%MACRO poverty_bin(type=, measure=)
DATA dataset;
SET dataset;
IF &measure. <= poverty_line THEN poor&type. = 1 ELSE poor&type. = 0;
RUN;
%MEND
%poverty_bin(type=con, measure=real_consumption);
%poverty_bin(type=inc, measure=real_income);
which should create two binary variables poor_con and poor_inc.
I have no idea how to do this in Stata. I tried doing something like this just to see if nested foreach is what I'm looking for:
foreach x of newlist con inc {
foreach y of newlist real_income real_consumption{
display "`x' and `y'"
}
}
But it gives an error message saying "variable real_income already defined"
The error message you cite implies that earlier code you do not show us created a variable real_income.
I do not know SAS but I can tell you that given a numeric variable x
gen y = x <= 42
will create a variable y with value 1 if x <= 42 and 0 otherwise.
For another such variable, use another similar statement. In Stata and perhaps any other language, setting up a nested loop or defining a program instead of making two statements directly seems overkill. For a number of new variables much larger than 2, that might not be true.
foreach v in x y {
gen new`v' = `v' <= 42
}
For completely arbitrary existing names, new names and thresholds it is likely to be easier to write out statements individually.
This is documented. See for example 13.2.2 in [U] or this FAQ.
I am trying to create a new variable that is the sum of other variables. Should be simple enough, however if one of the variables that is being used in the calculation of the new variable has a missing value, then the new variable has a missing value as well, when I want it to just sum across the remaining non-missing variables. For example, the data may look like:
a b c d e
1 . 3 2 6
The new variable is calculated as
newvar=a+b+c+d+e
For the above row, SAS returns a missing value for newvar because b is missing, when I would like it to return
newvar=a+c+d+e
as the answer. Is there a simple way to get SAS to do this?
Sure thing: just use the SUM function:
data _null_;
a=1;
b=.;
c=3;
d=2;
e=6;
newvar = sum(a,b,c,d,e);
put newvar=;
run;
I have a set of data like below:
A B C D
1 2 3 4
2 3 4 5
They are aggregated data which ABCD constitutes a 2x2 table, and I need to do Fisher exact test on each row, and add a new column for the p-value of the Fisher exact test for that row.
I can use fisher.exact and loop to do it in R, but I can't find a command in Stata for Fisher exact test.
You are thinking in R terms, and that is often fruitless in Stata (just as it is impossible for a Stata guy to figure out how to do by ... : regress in R; every package has its own paradigm and its own strengths).
There are no objects to add columns to. May be you could say a little bit more as to what you need to do, eventually, with your p-values, so as to find an appropriate solution that your Stata collaborators would sympathize with.
If you really want to add a new column (generate a new variable, speaking Stata), then you might want to look at tabulate and its returned values:
clear
input x y f1 f2
0 0 5 10
0 1 7 12
1 0 3 8
1 1 9 5
end
I assume that your A B C D stand for two binary variables, and the numbers are frequencies in the data. You have to clear the memory, as Stata thinks about one data set at a time.
Then you could tabulate the results and generate new variables containing p-values, although that would be a major waste of memory to create variables that contain a constant value:
tabulate x y [fw=f1], exact
return list
generate p1 = r(p_exact)
tabulate x y [fw=f2], exact
generate p2 = r(p_exact)
Here, [fw=variable] is a way to specify frequency weights; I typed return list to find out what kind of information Stata stores as the result of the procedure. THAT'S the object-like thing Stata works with. R would return the test results in the fisher.test()$p.value component, and Stata creates returned values, r(component) for simple commands and e(component) for estimation commands.
If you want a loop solution (if you have many sets), you can do this:
forvalues k=1/2 {
tabulate x y [fw=f`k'], exact
generate p`k' = r(p_exact)
}
That's the scripting capacity in which Stata, IMHO, is way stronger than R (although it can be argued that this is an extremely dirty programming trick). The local macro k takes values from 1 to 2, and this macro is substituted as ``k'` everywhere in the curly bracketed piece of code.
Alternatively, you can keep the results in Stata short term memory as scalars:
tabulate x y [fw=f1], exact
scalar p1 = r(p_exact)
tabulate x y [fw=f2], exact
scalar p2 = r(p_exact)
However, the scalars are not associated with the data set, so you cannot save them with the
data.
The immediate commands like cci suggested here would also have returned values that you can similarly retrieve.
HTH, Stas
Have a look the cci command with the exact option:
cci 10 15 30 10, exact
It is part of the so-called "immediate" commands. They allow you to do computations directly from the arguments rather than from data stored in memory. Have a look at help immediate
Each observation in the poster's original question apparently consisted of the four counts in one traditional 2 x 2 table. Stas's code applied to data of individual observations. Nick pointed out that -cci- can analyze a b c d data. Here's code that applies -cci to each table and, like Stas's code, adds the p-values to the data set. The forvalues i = 1/`=_N' statement tells Stata to run the loop from the first to the last observation. a[`i'] refers to the the value of the variable `a' in the i-th observation.
clear
input a b c d
10 2 8 4
5 8 2 1
end
gen exactp1 = .
gen exactp2 =.
label var exactp1 "1-sided exact p"
label var exactp2 "2-sided exact p"
forvalues i = 1/`=_N'{
local a = a[`i']
local b = b[`i']
local c = c[`i']
local d = d[`i']
qui cci `a' `b' `c' `d', exact
replace exactp1 = r(p1_exact) in `i'
replace exactp2 = r(p_exact) in `i'
}
list
Note that there is no problem in giving a local macro the same name as a variable.