简体   繁体   中英

SAS Proc Import CSV and missing data

So, I'm trying to import some datasets in SAS and join them, the only problem is that I get this error after joining them -

    proc import datafile='filepath/datasetA.csv'
    out = dataA
    dbms= csv
    replace;
    run;


    proc import datafile='filepath\datasetB.csv'
    out = dataB
    dbms= csv
    replace;
    run;



    /* combine them all into one dataset*/


    data DataC;
    set &dataA. &dataB;

    run;



    ERROR: Variable column_k has been defined as both character and numeric

The column in question looks something like this in both of the data sets that I'm trying to join -

+----------+
| column_k |
+----------+
| 0        |
| 1        |
| 5        |
| 4        |
| NA       |
| NA       |
| 4        |
| 3        |
| NA       |
+----------+

Basically, I would like to import the NA data in that column as 'missing', if that's possible? I need the entire column to remain numeric as I'm planning on doing some mathematical stuff with the data in that column further down the line.

Thanks for your help!

If you wish to continue using Proc IMPORT then you will need to ensure the columns are like-typed. In your case you know column_k should be numeric, so a DATA step can convert the character values to numeric using the INPUT function.

proc import … out = dataA;
proc import … out = dataB;

data dataA;
  set dataA;
  _num = input(column_k, best12.);
  drop column_k;
  rename _num = column_k;
run;

data dataB;
  set dataB;
  _num = input(column_k, best12.);
  drop column_k;
  rename _num = column_k;
run;

data want;
  set dataA dataB;
run;

In a larger scope mismatched data types for a column name can occur in a scenario such as dealing with multi-year imports.

Suppose the older data can't be re-read and the newer data has different column type.

For the case of wanting numeric values, one approach is to have macro that writes source code that converts, if necessary, specified variables from character to numeric.

Example:

%enforce_num (perm.loans2015, age amount remaining, out=work.loans2015)
%enforce_num (perm.loans2016, age amount remaining, out=work.loans2016)
%enforce_num (perm.loans2017, age amount remaining, out=work.loans2017)

data loans_3yrs; 
  set work.loans2015-loans2017;
run;

Going back to your simpler case:

proc import … out = dataA;
proc import … out = dataB;

%enforce_num(dataA, column_k)
%enforce_num(dataB, column_k)

data want;
  set dataA dataB;
run;

What would the macro enforce_num look like? It would have to:

  • scan the input data set meta data
  • determine if a variable is one of those specified and is character type
    • write source code to convert the variable to numeric
    • maintain original variable order
%macro enforce_num(data, vars, out=&data);

  /*
   * Arguments:
   *   data - name of input data set
   *   vars - space separated list of variables that must be numeric, convert type if necessary
   *   out  - name of output data set, default same as input data set
   *
   * Output:
   *   - Unchanged data set if data and out are the same and no conversion needed
   *   - Changed data set if some columns in data need conversion to numeric
   *     - replaces data if out is same as data
   *     - replaces out if out is different then data
   *     - the column order of the changed data set will be the same as the original data set
   */

  %local dsid index index2 vars varname vartype varnames debug;

  %let index2 = 0;  %* number of variables determined to be requiring conversion;
  %let debug = 0;

  %if &debug %then %put NOTE: &SYSMACRONAME: data=%superq(data);

  %let dsid = %sysfunc(open(&data));
  %if &dsid %then %do;
    %do index = 1 %to %sysfunc(attrn(&dsid, nvars));
      %let varname = %sysfunc(varname(&dsid, &index));

      %let varnames = &varnames &varname;

      %if %sysfunc(indexw(&varname, &vars)) %then %do;
        %if C = %sysfunc(vartype(&dsid, &index)) %then %do;
          %* Data contains character variable requiring enforcement;
          %let index2 = %eval(&index2+1);
          %local convert&index2;
          %let convert&index2 = &varname;

          %let varnames = &varnames ___&index2 ;   %* Variables that will be converted will be named __<#> during conversion;
        %end;
      %end;
    %end;
    %let dsid = %sysfunc(close(&dsid));
  %end;
  %else
    %put %sysfunc(sysmsg());

  %*put NOTE: &=vars;
  %*put NOTE: &=varnames;

  %if &index2 = 0 %then %do;
    %* No columns need to be converted to numeric, copy to out if necessary;
    %if &data ne &out %then %do;
      data &out;
        set &data;
      run;
    %end;
    %return;
  %end;

  %* Some columns need to be converted to numeric;
  %* Ensure the converted column is at the same position (varnum) as in the original data set;

  data &out;
    retain &varnames;

    set &data;

    %do index = 1 %to &index2;
      ___&index = input(&&convert&index,?? best12.);
    %end;

    drop
      %do index = 1 %to &index2;
        &&convert&index
      %end;
    ;

    rename
      %do index = 1 %to &index2;
        ___&index = &&convert&index
      %end;
    ;
  run;

  %put NOTE: ------------------------------------------------;
  %put NOTE: &data has been subjected to numeric enforcement.;
  %put NOTE: ------------------------------------------------;
%mend enforce_num;

proc import is a guessing procedure and works by examining a few rows of data.This is a problem because Excel data cells have no data type whatsoever. A column can have text, date, datetime and numeric values in different cells.

So, better to use infile statement with specified variable types:

filename input 'filepath/datasetA.csv';

data dataA;
   infile input truncover firstobs=2/*reads from the second line*/;
   input column_k;/*here you should specify input variables. If you want to read column_k as character, use : "input column_k $100." with specified length*/
run;

filename input clear;

Input(csv file):

+----------+
| column_k |
+----------+
| 0        |
| 1        |
| 5        |
| 4        |
| NA       |
| NA       |
| 4        |
| 3        |
| NA       |
+----------+

Output (sas dataset dataA):

+----------+
| column_k |
+----------+
|        0 |
|        1 |
|        5 |
|        4 |
|        . |
|        . |
|        4 |
|        3 |
|        . |
+----------+

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM