Need Clarification in NEGPARENw.d - sas

The NEGPARENw.d reads the values -2000 as (20,00) based on the w.d
is there anyway to do the same in SAS 9.1?
I read a value 00005000- as character value and then converted to numeric value
-5000
TEMP=000005000-
Temp= COMPRESS(TEMP,'-')
TEMP=-(INPUT(TEMP,16.2)) format NEGPARENw.d its not working
PRoc report;
.....
define temp /display format = NEGPAREN16.2
Run;
Thanks

NEGPARENw.d format exists in 9.1.3, so there's no particular reason it wouldn't work the same in 9.1.3 as it would in later versions.

Related

Add zero before decimal place in SAS

Hello I need to add a zero for only results and ranges are in a .2, .3 etc format but not tall values are like this. What would be the most efficient way to do this?.
I've only tried to format it using a w.d but the issue is that not all values are the same and all I want to do is add a zero for where they are applicable without messing the format of the other values.
format lborres lbornlo lbornhi z7.2.;
If your variable is numeric you can apply a standard format and that would add the leading zero.
ie
format yourVariable 8.1;
If your variable is character then you can test if the first character is a period and add a 0 or you can convert it to a number and store it that way instead. Option 2 is illustrated first as the first option overwrites the variable so to avoid any issues with that it's shown after.
data want;
set yourInputDataSet;
*Option 2;
new_numeric_variable = input(yourVariable, 8.);
format new_numeric_variable 8.1;
*Option 1;
if yourVariable =: '.' then yourVariable = catt('0', yourVariable);
run;
And as always, if your variable is incorrectly formatted this way, I would check my data import step and see if I can fix it there instead of after the fact. This is especially true if you used PROC IMPORT on a text file, where you can easily control the variable format and types as they're read in.
Are you value all less than 1? eg.
.3
.002
.752
.056
If not you would have to create picture format for each unit (thousands, hundreds, tens etc)
If they are all less than 1, z5.3 I believe will give you - 5 being the total length and 3 the number of decimal points.
data test;
format A z5.3;
a=.3; output; /* 0.300 */
a=.002; output; /* 0.002 */
a=.752; output; /* 0.752 */
a=.056; output; /* 0.056 */
run;

Why can't I use length function inside input function in SAS?

I have a code that converts a character to numeric using the informat and I'm using length function as the value of informat.
However, I'm having error with this approach.
Background of this problem is that the informat before was fixed value. I want to enhance the code for the informat to be flexible and remove the fixed value.
Before code:
data work.test;
emp_input = '168643123'
emp_value = input(emp_input, 6.);
run;
My current testcode:
data work.test;
emp_input = '168643123'
emp_value = input(emp_input, length(emp_input).);
run;
I expect the result that character '168643123' would be converted to numeric 168643123.
Using before code the output for this would be: numeric 168643.
That is not valid syntax. You have to use inputn an and then generate an string for the format.
data work.test;
emp_input = '168643123';
emp_value = inputn(emp_input, cats(put(length(emp_input),3.),'.'));
run;
But better use Use BEST32. for all generic numbers of up 32 chars length.
data work.test;
emp_input = '168643123';
emp_value = input(emp_input, BEST32.);
run;
INPUT requires a text value for the second parameter.
INPUTN() or INPUTC() can take the second parameter as a string/character/variable and use that to apply the format. You do have to convert it to a string first.
Why? The INPUT function is happy to adjust when the width of the informat is larger than the length of the string you are reading. Just use the maximum width that the informat allows.
emp_value = input(emp_input,32.);
If you did want to limit the number of characters read (perhaps there are letters after the digits?) then you can use the INPUTN() function (or INPUTC() function for character results). Let's test by appending some X's to the end of the string and using an informat whose width stops before the X's.
emp_value = inputn(cats(emp_input,'XXX'),cats(length(emp_input),'.'));
This code worked for me. This is based on all your answers. Thank you very much!
data work.test;
emp_input = '168643123'
emp_value = inputn(emp_input, cats(length(emp_input),'.'));
run;

Convert Number with Format into a String

How do you convert a number or currency variable into a character string that keeps the format as part of the string?
For instance, the below code has a character variable, MSRP_to_text, and currency variable, MSRP. When I set MSRP_to_text equal to MSRP, it takes the unformatted number and converts it to a string, so the dollar sign and the comma are gone.
DATA want;
SET SASHELP.CARS(KEEP=MSRP);
ATTRIB MSRP_to_text FORMAT=$8.;
MSRP_to_text = MSRP;
RUN;
In other words, the code is currently converting $36,945 -> "36945", but what I really want is $36,945 -> "$36,945".
Is there a way to keep the dollar sign and comma in the string?
VVALUE function will retrieve the formatted value of a variable.
MSRP_as_text = VVALUE(MSRP);
VVALUEX goes one step further for the case of the variable name being dynamic; such as being stored in a different variable, or is computed from some name patterning algorithm.
name = 'MSRP';
formatted_value = VVALUEX(name);
Instead of ATTRIB statement, Use the PUT function to convert number to Character. and it will keep the text value with format. Since the original Format of MSRP is DOLLAR8. , so using same format in put statement will suffice the purpose
DATA want;
SET SASHELP.CARS(KEEP=MSRP);
MSRP_to_text = put(MSRP, DOLLAR8.);
RUN;
proc contents data=want; run;

How to use proc format with the number of lines?

I have a table like this :
|Num | Label
-----------------------
1|1 | a thing
2|2 | another thing
3|3 | something else
4|4 | whatever
I want to replace my values of my label column by something more generic for example the first two lines : label One, the two next ones label Two ...
|Num | Label
-----------------------
1|1 | label One
2|2 | label One
3|3 | label Two
4|4 | label Two
How can I do that using proc format procedure ? I was wondering if I can use either the number of lines or another column like Num.
I need to do something like this :
proc format;
value label_f
low-2 = "label One"
3-high = "label Two"
;
run;
But I want to specify the number of the line or the value of the Num column.
You could do what you are describing using the words format. You could swap out num for _N_ in the ceil function below in order to use the observation number instead of the value of num (if they are not always equal):
data have;
length num 8 label $20;
infile datalines dlm='|';
input num label $;
datalines;
1|a thing
2|another thing
3|something else
4|whatever
5|whatever else
6|so many things
;
run;
data want;
set have;
label=catx(' ','label',propcase(put(ceil(num/2),words.)));
run;
Although this answer is probably a bit too specific to your example and it may not apply in your actual context.
Gatsby:
It sounds like you want to format NUM instead of LABEL.
Where you want the use the 'generic' representation defined by your format simply place a FORMAT statement in the Proc being used:
PROC PRINT data=have;
format num label_f.;
RUN;
If you want both num and generic, you will need to add a new column to the data for use during processing. This can be done with a view:
data have_view / view=have_view;
set have;
num_replicate1 = num;
attrib num_replicate1 format=label_f. label='Generic';
num_replacement = put (num,label_f.);
attrib num_replacement label='Generic'; %* no format because the value is the formatted value of the original num;
run;
PROC PRINT data=have_view;
var num num_replicate1 num_replacement;
RUN;
If you want a the 'generic' representation of the NUM column to be used in by-processing as a grouping variable, you have several scenarios:
know apriori the generic representation is by-group clustered
use a view and process with BY or BY ... NOTSORTED if clusters are not in sort order
force ordering for use with by-group processing
use an ordered SQL view containing the replicate and process with BY
add a replicate variable to the data set, sort by the formatted value and process with BY
A direct backmap from label to num to generic is possible only if the label is known to be unique, or you know apriori the transformation backmap-num + num-map is unique.
Proc FORMAT also has a special value construct [format] that can be used to map different ranges of values according to different formatting rules. The other range can also map to a different format that itself has an other range that maps to yet another different format. The SAS format engine will log an error if you happen to define a recursive loop using this advanced kind of format mapping.
propaedeutics
One of my favorite Dorfman words.
Format does not replace underlying values. Format is a map from the underlying data value to a rendered representation. The map can be 1:1, many:1. The MultiLabel Format (MLF) feature of the format system can even perform 1:many and many:many mappings in procedures many MLF enabled procedures (which is most of them)
To replace an underlying value with it's formatted version you need to use the PUT, PUTC or PUTN functions. The PUT functions always outputs a character value.
character ⇒ PUT ⇒ character [ FILE / PUT ]
numeric ⇒ PUT ⇒ character [ FILE / PUT ]
There is no guarantee a mapped value will mapped to the same value, it depends on the format.
INFORMATs are similar to FORMATs, however the target value depend on the in format type
character ⇒ INPUT ⇒ character [ INFILE / INPUT ]
numeric ⇒ INPUT ⇒ character
character ⇒ INPUT ⇒ numeric [ INFILE / INPUT ]
numeric ⇒ INPUT ⇒ numeric
Custom formats are created with Proc FORMAT. The construction of a format is specified by either the VALUE statement, or the CNTLIN= option. CNTLIN lets you create formats directly from data and avoids really large VALUE statements that are hand-entered or code-generated (via say macro)
Data-centric 'formatting' performs the mapping through a left-join. This is prevalent in SQL data bases. Left-joins in SAS can be done through SQL, DATA Step MERGE BY and FORMAT application. 1:1 left-joins can also be done via Hash object SET POINT=

how to set missing values to NULL in SAS

I am trying to set missing values to NULL in SAS dataset for a numerical variable,
how can I do this?
as missing is null in sas?
If you're asking how to have the period not display for a missing value, you can use:
options missing=' ';
That however doesn't actually change them to null, but rather to space. SAS must have some character to display for missing, it won't allow no character. You could also pick another character, like:
options missing=%sysfunc(byte(255));
or even
options missing="%sysfunc(byte(0))";
I don't recommend the latter, because it causes some problems when SAS tries to display it.
You can then trim out the space (using trimn() which allows zero length strings) if you are concatenating it somewhere.
Taking the question very literally, and assuming that you want to display the string NULL for any missing values - one approach is to define a custom format and use that:
proc format;
value nnull
.a-.z = 'NULL'
. = 'NULL'
._ = 'NULL'
;
run;
data _null_;
do i = .a,., ._, 1,1.11;
put i nnull.;
end;
run;
You can set values to missing within a data step, when it is numeric :
age=.;
to check for missing numeric values use :
if numvar=. then do;
or use MISSING function :
if missing(var) then do;
IS NULL and IS MISSING are used in the WHERE clause.
Look at : http://www.sascommunity.org/wiki/Tips:Use_IS_MISSING_and_IS_NULL_with_Numeric_or_Character_Variables