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).

It's time to register for SAS Innovate! Join your SAS user peers in Las Vegas on April 16-19 2024.
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-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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
  • 20075 views
  • 5 likes
  • 8 in conversation