3
votes

I am a SAS programmer, and have built an opioid morphine milligram equivalent (MME) calculator using Base/SAS. Deploying any kind of SAS distributable is difficult because the end-user would have to have a SAS license, which is very expensive. I do have the option of SAS/Connect, which is a client/server setting, but I want my end-users to keep their data on their systems, and not upload to a SAS server in the cloud. The reason is, the data privacy is very important with medical claims. So. The code is not terribly complicated, but I don't know where to start to convert it to a self-contained executable with a user interface so that the end-user can browse a file on their system, then run the program to calculate the MME per patient. The deliverable back to the end user would be summary file(s) of the patient's daily opioid MME dose, and other reports the end-user may want. I can do all of this in SAS but SAS does not make it is to distribute code. Maybe if I share the code and explain what it does, someone could help me? It would be a paying job $$.

Here is the SAS code using Hash Tables.

The second method of calculating a patient’s daily opioid MME dose involves SAS Hash Tables. I have relied on several SAS papers describing how to use hash tables, please see the references section at the end of this article. Assume dataset CLAIMS has the following columns: PATIENT_ID, RX_FILL_DATE, NDC_CODE, DAYS_SUPPLY, QTY_DISPENSED, DAILY_MME_DOSE, STRENGTH_PER_UNIT, MME_CF (MME conversion factor), and that the DAILY_MME_DOSE column has already been calculated using the formula below: DAILY_MME_DOSE = STRENGTH_PER_UNIT*(QTY_DISPENSED/DAYS_SUPPLY)*MME_CF

Create a DATA _NULL_ step, which will loop through the dataset CLAIMS, and add the patient’s daily MME doses across multiple opioid prescriptions and multiple prescribers, if there are any.

DATA _NULL_;
    FORMAT DATE DATE9.;
        /* define the hash table PATIENT_MMES, it starts out empty */
DECLARE HASH PATIENT_MMES();    
/* define the two-part key for the hash table: PATIENT_ID and DATE */
RC=PATIENT_MMES.DEFINEKEY('PATIENT_ID','DATE');
/* define the data to be included in the PATIENT_MMES hash table, adding the TOTAL_MMES column, which we will be adding to as we iterate through the dataset CLAIMS */
    RC=PATIENT_MMES.DEFINEDATA('PATIENT_ID','DATE','TOTAL_MMES');
    RC=PATIENT_MMES.DEFINEDONE();

/* iterate through the CLAIMS dataset until the end-of-file (EOF) is reached */
    DO UNTIL (EOF);
      SET CLAIMS END=EOF;
      /* initialize TOTAL_MMES to missing */
      TOTAL_MMES = .; 

      /* iterate through the entire days supply of each opioid script: */
        DO I = 0 TO (DAYS_SUPPLY-1);

           /* define DATE as a dynamic date counter, it will loop through             every day in the drug’s days supply */
         DATE = RX_FILL_DATE + I;

         /* define DAY as the day number of the DAYS_SUPPLY */
         DAY = I+1;

         /* initialize TOTAL_MMES to the first DAILY_MME_DOSE */
         TOTAL_MMES = DAILY_MME_DOSE;  

/* use the Find function to look up the patient_id and the date.          If the combination is not found, then add the patient_id, date, and TOTAL_MMES to the hash table PATIENT_MMES */

           RC=PATIENT_MMES.FIND();   
         /* RC is 0 if the patient_id, date combination was found 
              RC is not 0 if the patient_id, date combination was not found
            If not found, then add to the hash table */

             IF RC NE 0 THEN PATIENT_MMES.ADD();
         /* If the patient-date combination is found, because we already
 added it, then increment the TOTAL_MMES by the DAILY_MME_DOSE */

         IF RC=0 THEN 
         DO;
            TOTAL_MMES = TOTAL_MMES + DAILY_MME_DOSE;
            /* if the combination was found, then replace the
  TOTAL_MMES with its new, incremented value */
            RC=PATIENT_MMES.REPLACE();
         END;

    END;
    /* when the end-of-file is reached, output to the dataset     
       PATIENT_DATE_SUMMARY */
    IF EOF THEN PATIENT_MMES.OUTPUT(dataset: 'PATIENT_DATE_SUMMARY’);
    STOP;
  RUN;
4
"can browse a file on their system, then run the program to calculate the MME". Are the files in a standard format ? CSV, XML, Excel, Access, Other ?Richard
Looks like this would be an excellent opportunity to learn how dictionary work in python. Key is to start thinking in algorithms instead of specific language.Lee
@Lee that's harder from SAS to other languages. R/Python have more in similarity but the SAS methods are different enough.Reeza
Are you looking to help open source this for other people to use or just to pass it on to others? Is it intended to work on a patient input data set of opioids rx? Can you show some examples of what the full implementation may look like? this is probably not quite a SO question but there are ways to do this.Reeza
You can contact me here and I would be happy to discuss this with you. I know both SAS, R and Python and work in the medical field as well and could use a small contract over xmas. statgeeks.wordpress.com/aboutReeza

4 Answers

2
votes

There is no tool that takes a SAS program or step and compiles it into a separate .exe or .dll.

If you are working at a company that has a SAS Server installed you can published your code as a stored process, and other users can run the stored process through a browser when they are logged into the SAS Server.

You can create a .dll or (.exe) that protects the computation method and makes it available to non SAS environs. The .dll would require all the data for the computation be passed into it, or some data retrieval parameters if the .dll is supposed to retrieve the data itself (2 examples: (1) a data filename, or (2) an odbc connection string and query).

SAS has several interfacing methods and call routines that allow a SAS session to execute a method in a dynamic load library (.dll) or run an external program.

DLL:

  • module call routine
  • modulen function
  • modulec function

EXE:

  • X statement
  • %SYSEXEC statement

If you are looking to make a whole bunch of data reporting features available to a wide audience of non-SAS users you will have to implement that functionality in a non-SAS system that is widely and freely distributable, some examples:

  • separate exe you compile and distribute that users can run
    • might require other (non-SAS) 3rd party library licensing to get the output charts you want
  • web server endpoint
    • output be generated by technology such as R, PHP, Perl, ASP, etc...
  • program source code for different system (such a R)
    • Users would install R and run the source code themselves

The requirement to protect the health data means the most likely scenario is you MME computation is performed and delivered through some sort of web server. This also provides you the greatest control over 'versions' of the computation that users will be using.

1
votes

You probably still want to use "a statistics-oriented language," and one possibility that occurs to me is the open-source language "R."

https://en.wikipedia.org/wiki/R_(programming_language)

Now, this is not a direct "answer" to your question but it might be a pointer in a viable direction. "R" is specifically oriented towards statistics work, and, unlike SAS (which consists of macro-calls except in the DATA steps), it is entirely a procedural programming language. Hope this helps ...

(Both SAS and SPSS today include interfaces to "R," because it is a powerful adjunct to both of these tools and somewhat "fills a hole" in their traditional approaches.)

Another open-source programming language that is often used in statistics work, in conjunction with "R," is Python:

https://en.wikipedia.org/wiki/Python_(programming_language)

It is particularly well-suited to working with lists, and I see these two products being successfully used together in projects where SAS or SPSS might otherwise be used. Both have a vibrant and active user community and are well-supported.

1
votes

For SAS developers who consider doing this, the thought is to work with a statistics oriented language. That is fine but a lot of the stats I see are not statistically bound but more of a thought flow vs a particular proc. Statistics leads to a polynomial and that is then implemented. YMMV. Look at the SAS code above and it does not use any stat proc that I see.

I would strongly say don't use R. It is an aging language and Python seems to have taken its usefulness.

For exes, I would also say that it is best to not go that route. Why? They are hard to distribute and can be reverse-engineered.

The world I am working on, right now, is the suggested path which is server-side Blazor (aka, C#/.NET). Cross-platform, secure code base (no IP loss), works almost as seamlessly as a Windows app but distributed over the web. Behind the scenes, you can use whatever language to determine the formula but deliver it via the web using something else.

1
votes

If you want to let them keep their data in their system then you probably need to convert the logic to SQL. You might look into using windowing functions that most modern implementations of SQL support (unlike SAS's PROC SQL). But if performance is an issue you might end up needing custom code for each different database engine you want to support as each SQL implementation will have its own idiosyncrasies.

For example your algorithm could easily be implemented in Teradata's SQL by joining your input data to the SYS_CALENDAR.CALENDAR view on CALENDAR_DATE between RX_FILLED_DATE and RX_FILLED_DATE+DAYS_SUPPLY. Then just generate the sum of DAILY_MME_DOSE grouped by the PATIENT_ID and CALENDAR_DATE. In some other database you might need to build your own calendar table or view.