BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Jade_SAS
Pyrite | Level 9

Hi All,

 

    I want to establish that we can run R or Python in SAS, I googled on line and found that I need to run "proc options option=rlang;run;" to check whether R language option is enabled. I have two questions below:

    1) In order to run R in SAS, Is the "Rlang" option a necessary criteria?

     2) In order to Run Python, are there any necessary options in SAS needs to be enabled? I did not find any information about this part.

 

Thank you!

 

Jade

1 ACCEPTED SOLUTION

Accepted Solutions
AndreasMenrath
Pyrite | Level 9

The documentation says that this option is necessary to execute R code, see SAS/IML documentation at http://support.sas.com/documentation/cdl/en/imlug/64248/HTML/default/viewer.htm#imlug_r_sect003.htm

View solution in original post

14 REPLIES 14
AndreasMenrath
Pyrite | Level 9

In order to execute your R code in SAS as you described, you need a license for SAS/IML and execute that R code in

the IML environment. There is no such way to execute python code.

 

So you might want to take a look at the approach described here: https://github.com/sassoftware/enlighten-integration

Jade_SAS
Pyrite | Level 9
Thank you @AndreasMenrath !
I do have SAS/IML license. Do I still need R language option is enabled if there is SAS/IML license already?
AndreasMenrath
Pyrite | Level 9

The documentation says that this option is necessary to execute R code, see SAS/IML documentation at http://support.sas.com/documentation/cdl/en/imlug/64248/HTML/default/viewer.htm#imlug_r_sect003.htm

ChrisHemedinger
Community Manager

Some more information resources about running R in SAS/IML:

 

Twelve advantages to calling R from the SAS/IML language (blog by @Rick_SAS)

Learning SAS programming for R users (free course and materials, which also describes the setup in the course notes).

Register for SAS Innovate 2025!! The premier event for SAS users, May 6-9 in Orlando FL. Sign up now for the best deals!
Rick_SAS
SAS Super FREQ

Or if you prefer learning by watching a short video, see

 

Jade_SAS
Pyrite | Level 9

Thank you all!

 

Jade

rogerjdeangelis
Barite | Level 11

 

I run Python, R and Perl within and between  SAS datasteps. I am able to create SAS datasets from R dataframes, without IML.

 How I execute other languages within SAS

 You can find more information in SAS-L

  Relatively easy with command pipes

  %utl_submit_py64('..');  Python
  %utl_submit_r64('..');   R
  %utl_submit_pl64('..');  Perl

  options validvarname=upcase;
  data "d:/sd1/class.sas7bdat";
     set sashelp.class(where=(sex='M');
  run;quit;

  * input SAS dataset and output SAS dataset;
  %utl_submit_r64('
       library(haven);
       class<-read_sas("d:/sd1/class.sas7bdat");
       class$BMI <- 703 * class$WEIGHT / (class$HEIGHT * class$WEIGHT);
       class
       endsubmit;
       import r=class data=work.class;
       run;quit;
  ');

  proc print data=work.class;
  run;quit;

      NAME   SEX   AGE HEIGHT WEIGHT       BMI

1   Alfred     M    14   69.0  112.5 10.188406
2    Alice     F    13   56.5   84.0 12.442478
3  Barbara     F    13   65.3   98.0 10.765697
4    Carol     F    14   62.8  102.5 11.194268
5    Henry     M    14   63.5  102.5 11.070866
6    James     M    12   57.3   83.0 12.268761
7     Jane     F    12   59.8   84.5 11.755853
8    Janet     F    15   62.5  112.5 11.248000
9  Jeffrey     M    13   62.5   84.0 11.248000
10    John     M    12   59.0   99.5 11.915254
11   Joyce     F    11   51.3   50.5 13.703704
12    Judy     F    14   64.3   90.0 10.933126
13  Louise     F    12   56.3   77.0 12.486679
14    Mary     F    15   66.5  112.0 10.571429
15  Philip     M    16   72.0  150.0  9.763889
16  Robert     M    12   64.8  128.0 10.848765
17  Ronald     M    15   67.0  133.0 10.492537
18  Thomas     M    11   57.5   85.0 12.226087
19 William     M    15   66.5  112.0 10.571429



rogerjdeangelis
Barite | Level 11
/* T1002110 Code to interface with Perl, Python, R32, R64, MS_r64 and WPS from SAS


%utl_submit_pl64     PERL
%utl_submit_py64     PYTHON
%utl_submit_r64      R 64
%utl_submit_r32      R 32
%utl_submit_msr64    Microsoft muti-threaded mathpack R
%utl_submit_wps64    WPS 64


*____           _
|  _ \ ___ _ __| |
| |_) / _ \ '__| |
|  __/  __/ |  | |
|_|   \___|_|  |_|

;

*Running a perl program (macro below);

* create a spreadsheet;
libname xel "d:/xls/simple.xlsx";
data xel.simple;
  set sashelp.class;
run;quit;
libname xel clear;

* print cells A1 and A2 from an excel worksheet;
%utl_submit_pl64("
#!/usr/bin/perl
use strict;
use warnings;
use 5.14.0;
use Spreadsheet::Read qw(ReadData);
my $book = ReadData ('d:/xls/simple.xlsx');
say 'A1: ' . $book->[1]{A1};
say 'A2: ' . $book->[1]{A2};
");

* in output window;
A1: NAME
A2: Alfred

*____        _   _
|  _ \ _   _| |_| |__   ___  _ __
| |_) | | | | __| '_ \ / _ \| '_ \
|  __/| |_| | |_| | | | (_) | | | |
|_|    \__, |\__|_| |_|\___/|_| |_|
       |___/
;

options validvarname=upcase;
libname sd1 "d:/sd1";
data sd1.class;
  set sashelp.class;
run;quit;

%utl_submit_py64('
import numpy as np;
import pandas as pd;
from sas7bdat import SAS7BDAT;
with SAS7BDAT("d:/sd1/class.sas7bdat") as m:;
.   mdata = m.to_data_frame();
print(mdata);
');

       NAME SEX   AGE  HEIGHT  WEIGHT
0    Alfred   M  14.0    69.0   112.5
1     Alice   F  13.0    56.5    84.0
2   Barbara   F  13.0    65.3    98.0
3     Carol   F  14.0    62.8   102.5
4     Henry   M  14.0    63.5   102.5
5     James   M  12.0    57.3    83.0
6      Jane   F  12.0    59.8    84.5
7     Janet   F  15.0    62.5   112.5
8   Jeffrey   M  13.0    62.5    84.0
9      John   M  12.0    59.0    99.5
10    Joyce   F  11.0    51.3    50.5
11     Judy   F  14.0    64.3    90.0
12   Louise   F  12.0    56.3    77.0
13     Mary   F  15.0    66.5   112.0
14   Philip   M  16.0    72.0   150.0
15   Robert   M  12.0    64.8   128.0
16   Ronald   M  15.0    67.0   133.0
17   Thomas   M  11.0    57.5    85.0
18  William   M  15.0    66.5   112.0


*____
|  _ \
| |_) |
|  _ <
|_| \_\

;

%utl_submit_r64('
library(haven);
class<-read_sas("d:/sd1/class.sas7bdat");
class;
');

# A tibble: 19 × 5
      NAME   SEX   AGE HEIGHT WEIGHT
     <chr> <chr> <dbl>  <dbl>  <dbl>
1   Alfred     M    14   69.0  112.5
2    Alice     F    13   56.5   84.0
3  Barbara     F    13   65.3   98.0
4    Carol     F    14   62.8  102.5
5    Henry     M    14   63.5  102.5
6    James     M    12   57.3   83.0
7     Jane     F    12   59.8   84.5
8    Janet     F    15   62.5  112.5
9  Jeffrey     M    13   62.5   84.0
10    John     M    12   59.0   99.5
11   Joyce     F    11   51.3   50.5
12    Judy     F    14   64.3   90.0
13  Louise     F    12   56.3   77.0
14    Mary     F    15   66.5  112.0
15  Philip     M    16   72.0  150.0
16  Robert     M    12   64.8  128.0
17  Ronald     M    15   67.0  133.0
18  Thomas     M    11   57.5   85.0
19 William     M    15   66.5  112.0


*_        ______  ____     __   _  _
\ \      / /  _ \/ ___|   / /_ | || |
 \ \ /\ / /| |_) \___ \  | '_ \| || |_
  \ V  V / |  __/ ___) | | (_) |__   _|
   \_/\_/  |_|   |____/   \___/   |_|

;

* WPS express does not limit the number of rows returned to SAS;
* if you have one data set in work WOS will return a SAS dataset not a WPD dataset;
%utl_submit_wps64('
libname sd1 "d:/sd1";
options set=R_HOME "C:/Program Files/R/R-3.3.2";
libname wrk "%sysfunc(pathname(work))";
proc r;
submit;
source("C:/Program Files/R/R-3.3.2/etc/Rprofile.site", echo=T);
library(haven);
class<-read_sas("d:/sd1/class.sas7bdat");
class<-class[class$SEX=="M",];
class;
endsubmit;
import r=class  data=wrk.classwps;
run;quit;
');

INSIDE R
# A tibble: 10 × 5
      NAME   SEX   AGE HEIGHT WEIGHT
     <chr> <chr> <dbl>  <dbl>  <dbl>
1   Alfred     M    14   69.0  112.5
2    Henry     M    14   63.5  102.5
3    James     M    12   57.3   83.0
4  Jeffrey     M    13   62.5   84.0
5     John     M    12   59.0   99.5
6   Philip     M    16   72.0  150.0
7   Robert     M    12   64.8  128.0
8   Ronald     M    15   67.0  133.0
9   Thomas     M    11   57.5   85.0
10 William     M    15   66.5  112.0

proc print data=classwps;
run;quit;

Returned to SAS;

Obs    NAME       SEX    AGE    HEIGHT    WEIGHT

  1    Alfred      M      14     69.0      112.5
  2    Henry       M      14     63.5      102.5
  3    James       M      12     57.3       83.0
  4    Jeffrey     M      13     62.5       84.0
  5    John        M      12     59.0       99.5
  6    Philip      M      16     72.0      150.0
  7    Robert      M      12     64.8      128.0
  8    Ronald      M      15     67.0      133.0
  9    Thomas      M      11     57.5       85.0
 10    William     M      15     66.5      112.0





*____  _____ ____  _
|  _ \| ____|  _ \| |
| |_) |  _| | |_) | |
|  __/| |___|  _ <| |___
|_|   |_____|_| \_\_____|

;

* create a spreadsheet;
libname xel "d:/xls/simple.xlsx";
data xel.simple;
  set sashelp.class;
run;quit;
libname xel clear;

* read the sheet in PERL and output to SAS output window;
%macro utl_submit_pl64(pgm)/des="Semi colon separated set of py commands";
  * write the program to a temporary file;
  filename py_pgm "%sysfunc(pathname(work))/py_pgm.py" lrecl=32766 recfm=v;
  data _null_;
    length pgm  $32755 cmd $255;
    file py_pgm ;
    pgm=&pgm;
    semi=countc(pgm,';');
      do idx=1 to semi;
        cmd=cats(scan(pgm,idx,';'),';');
        put cmd $char96.;
        putlog cmd $char96.;
      end;
  run;
  run;quit;
  %let _loc=%sysfunc(pathname(py_pgm));
  %put &_loc;
  filename rut  pipe "perl -w &_loc > __log.txt";
  data _null_;
    file print;
    infile rut;
    input;
    put _infile_;
  run;quit;
  filename rut clear;
  filename py_pgm clear;
  data _null_;
    infile "__log.txt";
    input;
    put _infile_;
  run;quit;
%mend utl_submit_pl64;


%utl_submit_pl64("
#!/usr/bin/perl
use strict;
use warnings;
use 5.14.0;
use Spreadsheet::Read qw(ReadData);
my $book = ReadData ('d:/xls/simple.xlsx');
say 'A1: ' . $book->[1]{A1};
say 'A2: ' . $book->[1]{A2};
");

A1: NAME
A2: Alfred


*____        _   _
|  _ \ _   _| |_| |__   ___  _ __
| |_) | | | | __| '_ \ / _ \| '_ \
|  __/| |_| | |_| | | | (_) | | | |
|_|    \__, |\__|_| |_|\___/|_| |_|
       |___/
;

%macro utl_submit_py64(pgm)/des="Semi colon separated set of py commands";
  * write the program to a temporary file;
  filename py_pgm "%sysfunc(pathname(work))/py_pgm.py" lrecl=32766 recfm=v;
  data _null_;
    length pgm  $32755 cmd $255;
    file py_pgm ;
    pgm=&pgm;
    semi=countc(pgm,';');
      do idx=1 to semi;
        cmd=cats(scan(pgm,idx,';'));
        if cmd=:'.' then cmd=substr(cmd,2);
        put cmd $char96.;
        putlog cmd $char96.;
      end;
  run;

  run;quit;
  %let _loc=%sysfunc(pathname(py_pgm));
  %put &_loc;
  filename rut pipe  "C:\Python_27_64bit/python.exe &_loc";
  data _null_;
    file print;
    infile rut;
    input;
    put _infile_;
  run;
  filename rut clear;
  filename py_pgm clear;
%mend utl_submit_py64;

*____   __   _  _
|  _ \ / /_ | || |
| |_) | '_ \| || |_
|  _ <| (_) |__   _|
|_| \_\\___/   |_|

;

%macro utl_submit_R64(pgmx)/des="Semi colon separated set of R commands";
  * write the program to a temporary file;
  filename r_pgm temp lrecl=32766 recfm=v;
  data _null_;
    file r_pgm;
    pgm=&pgmx;
    put pgm;
    putlog pgm;
  run;
  %let __loc=%sysfunc(pathname(r_pgm));
  * pipe file through R;
  filename rut pipe "c:\Progra~1\R\R-3.3.2\bin\x64\R.exe --vanilla --quiet --no-save < &__loc";
  data _null_;
    file print;
    infile rut;
    input;
    put _infile_;
    putlog _infile_;
  run;
  filename rut clear;
  filename r_pgm clear;
%mend utl_submit_r64;


*____    _________
|  _ \  |___ /___ \
| |_) |   |_ \ __) |
|  _ <   ___) / __/
|_| \_\ |____/_____|

;

%macro utl_submit_R32(pgmx)/des="Semi colon separated set of R commands";
  * write the program to a temporary file;
  filename r_pgm temp lrecl=32766 recfm=v;
  data _null_;
    file r_pgm;
    pgm=&pgmx;
    put pgm;
    putlog pgm;
  run;
  %let __loc=%sysfunc(pathname(r_pgm));
  * pipe file through R;
  filename rut pipe "c:\Progra~1\R\R-3.3.2\bin\i386\R.exe --vanilla --quiet --no-save < &__loc";
  data _null_;
    file print;
    infile rut;
    input;
    put _infile_;
    putlog _infile_;
  run;
  filename rut clear;
  filename r_pgm clear;
%mend utl_submit_r32;

*__  __ ____    ____     __   _  _
|  \/  / ___|  |  _ \   / /_ | || |
| |\/| \___ \  | |_) | | '_ \| || |_
| |  | |___) | |  _ <  | (_) |__   _|
|_|  |_|____/  |_| \_\  \___/   |_|

;

%macro utl_submit_msr64(pgmx)/des="Semi colon separated set of R commands";
  * write the program to a temporary file;
  filename r_pgm temp lrecl=32766 recfm=v;
  data _null_;
    file r_pgm;
    pgm=&pgmx;
    put pgm;
    putlog pgm;
  run;
  %let __loc=%sysfunc(pathname(r_pgm));
  * pipe file through R;
  filename rut pipe "D:\exe\Microsoft\MRO-3.3.1\bin\x64\r.exe --vanilla --quiet --no-save < &__loc";
  data _null_;
    file print;
    infile rut;
    input;
    put _infile_;
    putlog _infile_;
  run;
  filename rut clear;
  filename r_pgm clear;
%mend utl_submit_msr64;

*_        ______  ____     __   _  _
\ \      / /  _ \/ ___|   / /_ | || |
 \ \ /\ / /| |_) \___ \  | '_ \| || |_
  \ V  V / |  __/ ___) | | (_) |__   _|
   \_/\_/  |_|   |____/   \___/   |_|

;

 %macro utl_submit_wps64(pgmx,resolve=Y)/des="submiit a single quoted sas program to wps";
  * write the program to a temporary file;

  %utlfkil(%sysfunc(pathname(work))/wps_pgmtmp.wps);
  %utlfkil(%sysfunc(pathname(work))/wps_pgm.wps);


  filename wps_pgm "%sysfunc(pathname(work))/wps_pgmtmp.wps" lrecl=32756 recfm=v;
  data _null_;
    length pgm  $32756 cmd $32756;
    file wps_pgm ;
    %if %upcase(%substr(&resolve,1,1))=Y %then %do;
       pgm=resolve(&pgmx);
    %end;
    %else %do;
      pgm=&pgmx;
    %end;
    semi=countc(pgm,';');
      do idx=1 to semi;
        cmd=cats(scan(pgm,idx,';'),';');
        len=length(strip(cmd));
        put cmd $varying32756. len;
        putlog cmd $varying32756. len;
      end;
  run;
  filename wps_fin "%sysfunc(pathname(work))/wps_pgm.wps" lrecl=255 recfm=v ;
  data _null_ ;
    length textin $ 32767 textout $ 255 ;
    * file "%sysfunc(pathname(work))/wps_pgmtmp.wps" lrecl=255 recfm=v ;
    file wps_fin;
    infile "%sysfunc(pathname(work))/wps_pgmtmp.wps" lrecl=32767 truncover;
    format textin $char32767.;
    input textin $char32767.;
    if lengthn( textin ) <= 255 then put textin ;
    else do while( lengthn( textin ) > 255 ) ;
       textout = reverse( substr( textin, 1, 255 )) ;
       ndx = index( textout, ' ' ) ;
       if ndx then do ;
          textout = reverse( substr( textout, ndx + 1 )) ;
          put textout $char255. ;
          textin = substr( textin, 255 - ndx + 1 ) ;
    end ;
    else do;
      textout = substr(textin,1,255);
      put textout $char255. ;
      textin = substr(textin,255+1);
    end;
    if lengthn( textin ) le 255 then put textin $char255. ;
    end ;
  run ;
  %let _loc=%sysfunc(pathname(wps_fin));
  %let _w=%sysfunc(compbl(C:/Progra~1/worldp~1/bin/wps.exe -autoexec c:\oto\Tut_Otowps.sas -config c:\cfg\wps.cfg));
  %put &_loc;
  filename rut pipe "&_w -sysin &_loc";
  data _null_;
    file print;
    infile rut;
    input;
    put _infile_;
  run;
  filename rut clear;
  filename wps_pgm clear;
  data _null_;
    infile "wps_pgm.lst";
    input;
    putlog _infile_;
  run;quit;
%mend utl_submit_wps64;
Jade_SAS
Pyrite | Level 9

Thank you! @rogerjdeangelis                    

 

Where did you get the following macro?

 

%utl_submit_pl64     PERL
%utl_submit_py64     PYTHON
%utl_submit_r64      R 64
%utl_submit_r32      R 32
%utl_submit_msr64 Microsoft muti-threaded mathpack R
%utl_submit_wps64    WPS 64

rogerjdeangelis
Barite | Level 11

All the macros are in previous post:

 

A knowledge of quoting is needed not

 

%utl_submit('

%utl_submit("

If pure macro code

%utl_submit(

%utl_submit(%nrbquote(

 

Scoping in child process(dosubl) is somewhat of a mystery as is

the dosubl macro symbol table

 

You canset up a 'common block of storage between parent and child for shared address.

My want to see posts ob SAS-L

 

data _null_;
  %commonc(stop_flag $2,action=INIT);
  set have1 end=dne;
  call symputx('age',put(age,2.));
     rc=dosubl('
        proc sql;
           select age, count(*)
           into :age separated by "", :cnt separated by ""
           from have2 where age=&age group by age
        ;quit;
        data _null_;
        stop_flag="&cnt";
        put stop_flag;
        %commonc(stop_flag $2,action=PUT);
        run;quit;
     ');
     if stop_flag="0" then stop;
run;quit;


%macro commonc(var,action=INIT);
 * dosubl sets sysindex to 1;
 * we are in dosubl if sysindex=1;
 * increment sysindex so it is not 1 next time macro called;
 %local varcut varlen;
 %let varcut=%scan(&var,1);
 %let varlen=%scan(&var,2);
 %if %upcase(&action) = INIT %then %do;
    length &var;
    retain &varcut " ";
    call symputx("varadr",put(addrlong(&varcut.),hex16.),"G");
 %end;
 %if "%upcase(&action)" = "PUT" %then %do;
    length &var;
    retain &varcut;
    call pokelong(&varcut.,"&varadr."x, &varlen.);
 %end;
 %else %if "%upcase(&action)" = "GET" %then %do;
    retain &varcut " ";
    &varcut = peekclong("&varadr."x,&varlen.);
    %end;

%mend commonc;

 

 

Bluesgu
SAS Employee

cool, it is fantastic

Tom
Super User Tom
Super User

@Jade_SAS wrote:

Thank you! @rogerjdeangelis                    

 

Where did you get the following macro?

 

%utl_submit_pl64     PERL
%utl_submit_py64     PYTHON
%utl_submit_r64      R 64
%utl_submit_r32      R 32
%utl_submit_msr64 Microsoft muti-threaded mathpack R
%utl_submit_wps64    WPS 64


A quick search found Roger's GITHUB account:

 

https://github.com/rogerjdeangelis?utf8=%E2%9C%93&tab=repositories&q=utl_submit_&type=&language=

 

bpowell
Obsidian | Level 7

Genius!

Bluesgu
SAS Employee

There is no output when I use the code. my python version is 3.7, and the error is that stderr output: The system could not find the specified path.

sas-innovate-wordmark-2025-midnight.png

Register Today!

Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.


Register now!

How to connect to databases in SAS Viya

Need to connect to databases in SAS Viya? SAS’ David Ghan shows you two methods – via SAS/ACCESS LIBNAME and SAS Data Connector SASLIBS – in this video.

Find more tutorials on the SAS Users YouTube channel.

Discussion stats
  • 14 replies
  • 22052 views
  • 5 likes
  • 8 in conversation