Einführung in effizientes Programmieren mit PROC IML am Beispiel einer Simulation Biljana Gigic 1, Andreas Deckert 2 1 Deutsches Krebsforschungszentrum / Nationales Centrum für Tumorerkrankungen (Heidelberg) 2 Institute of Public Health / Institut für Medizinische Biometrie und Informatik (Heidelberg) 15. Konferenz der SAS Anwender in Forschung und Entwicklung (KSFE) "Voneinander lernen" an der Ruprecht Karls Universität Heidelberg
Überblick SAS IML Software Einführung in SAS IML Programmierung Syntax Einführungsbeispiel Spezifizierung einer Matrix Generierung einer Matrix Modifizierung einer Matrix Operatoren in SAS IML Simulation ToxCrit Hintergrund und Fragestellung Ein und Ausgabeparameter Effektivität der IML Programmierung Fazit und Diskussion
SAS IML Software Interactive Matrix Language Eigenständige Programmiersprache innerhalb von SAS Matrizenorientiert Interaktion mit SAS Datensätzen Hohe Performance Geeignet für Matrizenoperationen Programmierung statistischer Verfahren, die nicht in SAS implementiert sind aufwendige Simulationen
Syntax Aufruf von SAS IML: proc iml;...; < IML-Statements >...; quit; Mit quit wird die Session beendet.
Einführungsbeispiele Spezifizierung einer Matrix proc iml; reset print; a = {1 2 3 4}; /*Zeilenvektor der Dimension 1 x 4*/ b = {1,2,3,4}; /*Spaltenvektor der Dimension 4 x 1*/ c = {1 2 3 4,5 6 7 8}; /*Zweidimensionale Matrix der Dimension 2 x 4*/ d = 10; /*Skalar der Dimension 1 x 1*/
Einführungsbeispiele Spezifizierung einer Matrix proc iml; reset print; a = {1 2 3 4}; /*Zeilenvektor der Dimension 1 x 4*/ b = {1,2,3,4}; /*Spaltenvektor der Dimension 4 x 1*/ c = {1 2 3 4,5 6 7 8}; /*Zweidimensionale Matrix der Dimension 2 x 4*/ d = 10; /*Skalar der Dimension 1 x 1*/ Output:
Einführungsbeispiele Spezifizierung einer Matrix proc iml; reset print; a = {1 2 3 4}; /*Zeilenvektor der Dimension 1 x 4*/ b = {1,2,3,4}; /*Spaltenvektor der Dimension 4 x 1*/ c = {1 2 3 4,5 6 7 8}; /*Zweidimensionale Matrix der Dimension 2 x 4*/ d = 10; /*Skalar der Dimension 1 x 1*/ Output:
Einführungsbeispiele Spezifizierung einer Matrix proc iml; reset print; a = {1 2 3 4}; /*Zeilenvektor der Dimension 1 x 4*/ b = {1,2,3,4}; /*Spaltenvektor der Dimension 4 x 1*/ c = {1 2 3 4,5 6 7 8}; /*Zweidimensionale Matrix der Dimension 2 x 4*/ d = 10; /*Skalar der Dimension 1 x 1*/ Output:
Einführungsbeispiele Spezifizierung einer Matrix proc iml; reset print; a = {1 2 3 4}; /*Zeilenvektor der Dimension 1 x 4*/ b = {1,2,3,4}; /*Spaltenvektor der Dimension 4 x 1*/ c = {1 2 3 4,5 6 7 8}; /*Zweidimensionale Matrix der Dimension 2 x 4*/ d = 10; /*Skalar der Dimension 1 x 1*/ Output:
Einführungsbeispiele Generierung einer Matrix
Einführungsbeispiele Generierung einer Matrix Vielfaches eines Ausgangselements:
Einführungsbeispiele Generierung einer Matrix Vielfaches eines Ausgangselements: d = j(2,3,0);
Einführungsbeispiele Generierung einer Matrix Vielfaches eines Ausgangselements: d = j(2,3,0);
Einführungsbeispiele Generierung einer Matrix Vielfaches eines Ausgangselements: d = j(2,3,0); Wiederholtes Eintragen verschiedener Elemente:
Einführungsbeispiele Generierung einer Matrix Vielfaches eines Ausgangselements: d = j(2,3,0); Wiederholtes Eintragen verschiedener Elemente: e = shape({1 2 3 4},2,3);
Einführungsbeispiele Generierung einer Matrix Vielfaches eines Ausgangselements: d = j(2,3,0); Wiederholtes Eintragen verschiedener Elemente: e = shape({1 2 3 4},2,3);
Einführungsbeispiele Generierung einer Matrix Vielfaches eines Ausgangselements: d = j(2,3,0); Wiederholtes Eintragen verschiedener Elemente: e = shape({1 2 3 4},2,3); Vielfaches einer Matrix:
Einführungsbeispiele Generierung einer Matrix Vielfaches eines Ausgangselements: d = j(2,3,0); Wiederholtes Eintragen verschiedener Elemente: e = shape({1 2 3 4},2,3); Vielfaches einer Matrix: f = repeat(e,2,1);
Einführungsbeispiele Generierung einer Matrix Vielfaches eines Ausgangselements: d = j(2,3,0); Wiederholtes Eintragen verschiedener Elemente: e = shape({1 2 3 4},2,3); Vielfaches einer Matrix: f = repeat(e,2,1);
Einführungsbeispiele Generierung einer Matrix Vielfaches eines Ausgangselements: d = j(2,3,0); Wiederholtes Eintragen verschiedener Elemente: e = shape({1 2 3 4},2,3); Vielfaches einer Matrix: f = repeat(e,2,1); Indexvektor:
Einführungsbeispiele Generierung einer Matrix Vielfaches eines Ausgangselements: d = j(2,3,0); Wiederholtes Eintragen verschiedener Elemente: e = shape({1 2 3 4},2,3); Vielfaches einer Matrix: f = repeat(e,2,1); Indexvektor: g = do(-8,2,2);
Einführungsbeispiele Generierung einer Matrix Vielfaches eines Ausgangselements: d = j(2,3,0); Wiederholtes Eintragen verschiedener Elemente: e = shape({1 2 3 4},2,3); Vielfaches einer Matrix: f = repeat(e,2,1); Indexvektor: g = do(-8,2,2);
Einführungsbeispiele Modifizierung einer Matrix
Einführungsbeispiele Modifizierung einer Matrix
Einführungsbeispiele Modifizierung einer Matrix Die ersten drei Elemente der zweiten Zeile um 3 erhöhen:
Einführungsbeispiele Modifizierung einer Matrix Die ersten drei Elemente der zweiten Zeile um 3 erhöhen: do i = 1 to 3; c[2,i] = c[2,i]+3;
Einführungsbeispiele Modifizierung einer Matrix Die ersten drei Elemente der zweiten Zeile um 3 erhöhen: do i = 1 to 3; c[2,i] = c[2,i]+3;
Einführungsbeispiele Modifizierung einer Matrix Die ersten drei Elemente der zweiten Zeile um 3 erhöhen: do i = 1 to 3; c[2,i] = c[2,i]+3; Alle Elemente der zweiten Zeile um 3 erhöhen:
Einführungsbeispiele Modifizierung einer Matrix Die ersten drei Elemente der zweiten Zeile um 3 erhöhen: do i = 1 to 3; c[2,i] = c[2,i]+3; Alle Elemente der zweiten Zeile um 3 erhöhen: c[2,] = c[2,]+3;
Einführungsbeispiele Modifizierung einer Matrix Die ersten drei Elemente der zweiten Zeile um 3 erhöhen: do i = 1 to 3; c[2,i] = c[2,i]+3; Alle Elemente der zweiten Zeile um 3 erhöhen: c[2,] = c[2,]+3;
Einführungsbeispiele Syntax einer Funktion innerhalb PROC IML proc iml; start Indexvektor(Startwert, Endwert, Inkrement); Vektor = do(startwert, Endwert, Inkrement); return(vektor); finish Indexvektor; reset print; Ausgabe = Indexvektor(-8,2,2); Output:
Operatoren in SAS IML Transponieren einer Matrix ' Matrixmultiplikation * Potenzierung quadratischer Matrizen ** Elementweise Multiplikation # Elementweise Potenzierung ## Elementweise Division / Horizontale Konkatination Vertikale Konkatination // Arithmetisches Mittel :
Simulation ToxCrit 1 Hintergrund und Fragestellung Toxische Reaktionen von Patienten auf Therapie in frühen Phasen onkologischer Studien Primärer Endpunkt früher klinischer Phasen: Toxizität Sicherheit Wirksamkeit Studienabbruch oder Dosisreduktion aufgrund von Toxizität Schätzung des Studienabbruchrisikos Monte Carlo Simulation Entscheidungsgrundlage für Studiendurchführung und ethische Gesichtspunkte Darstellung des Abbruchrisikos 1 H. Aamot et al.: Continuous monitoring of toxicity in clinical trials simulating the risk of stopping prematurely ; Int J Clin Pharmacol Ther, 48(7):476 7, Jul. 2010
Simulation ToxCrit Ein und Ausgabeparameter
Simulation ToxCrit Ein und Ausgabeparameter Eingabeparameter für die Simulation npat Anzahl Studienteilnehmer ptoxcrit kritische Toxizitätsrate pabbruch Wahrscheinlichkeitsgrenze für inakzeptable Toxizität ptox angenommene Wahrscheinlichkeit für Toxizität bei einem Patienten nsim Anzahl der Simulationsläufe seed Zufallsanker für die Reproduzierbarkeit der Simulation
Simulation ToxCrit Ein und Ausgabeparameter Eingabeparameter für die Simulation npat Anzahl Studienteilnehmer ptoxcrit kritische Toxizitätsrate pabbruch Wahrscheinlichkeitsgrenze für inakzeptable Toxizität ptox angenommene Wahrscheinlichkeit für Toxizität bei einem Patienten nsim Anzahl der Simulationsläufe seed Zufallsanker für die Reproduzierbarkeit der Simulation Ausgabe Anzahl Toxizitätsfälle, bei denen die Studie abgebrochen wird Abbruchrisiko der Studie
Simulation ToxCrit Anzahl Toxizitäten Studienabbruch %macro toxcrit(npat=,ptoxcrit=,pabbruch=,nsim=,ptox=,seed=); proc iml; start Pat_Array(npat,pabbruch,ptoxcrit); crit = j(npat,1,npat+1); do u = 1 to npat; do l = 0 to u; wk = betainv((1-pabbruch),1+l,1+u-l); if (wk>ptoxcrit) then do; crit[u,1] = l; goto exit; exit: return (crit); finish Pat_Array;
Simulation ToxCrit Anzahl Toxizitäten Studienabbruch %macro toxcrit(npat=,ptoxcrit=,pabbruch=,nsim=,ptox=,seed=); proc iml; start Pat_Array(npat,pabbruch,ptoxcrit); Funktionsaufruf crit = j(npat,1,npat+1); do u = 1 to npat; do l = 0 to u; wk = betainv((1-pabbruch),1+l,1+u-l); if (wk>ptoxcrit) then do; crit[u,1] = l; goto exit; exit: return (crit); finish Pat_Array; Funktionsende
Simulation ToxCrit Anzahl Toxizitäten Studienabbruch %macro toxcrit(npat=,ptoxcrit=,pabbruch=,nsim=,ptox=,seed=); proc iml; start Pat_Array(npat,pabbruch,ptoxcrit); crit = j(npat,1,npat+1); do u = 1 to npat; do l = 0 to u; wk = betainv((1-pabbruch),1+l,1+u-l); Initialisierung des Vektors crit if (wk>ptoxcrit) then do; crit[u,1] = l; goto exit; exit: return (crit); finish Pat_Array;
Simulation ToxCrit Anzahl Toxizitäten Studienabbruch %macro toxcrit(npat=,ptoxcrit=,pabbruch=,nsim=,ptox=,seed=); proc iml; start Pat_Array(npat,pabbruch,ptoxcrit); crit = j(npat,1,npat+1); do u = 1 to npat; do l = 0 to u; wk = betainv((1-pabbruch),1+l,1+u-l); if (wk>ptoxcrit) then do; crit[u,1] = l; goto exit; exit: return (crit); finish Pat_Array; Wie im macro, jedoch nicht im Data Step
Simulation ToxCrit Anzahl Toxizitäten Studienabbruch %macro toxcrit(npat=,ptoxcrit=,pabbruch=,nsim=,ptox=,seed=); proc iml; start Pat_Array(npat,pabbruch,ptoxcrit); crit = j(npat,1,npat+1); do u = 1 to npat; do l = 0 to u; wk = betainv((1-pabbruch),1+l,1+u-l); if (wk>ptoxcrit) then do; crit[u,1] = l; goto exit; exit: return (crit); finish Pat_Array; Rückgabe des Ergebnisses; Vektor wird übergeben
Simulation ToxCrit Anzahl Toxizitäten Studienabbruch %macro toxcrit(npat=,ptoxcrit=,pabbruch=,nsim=,ptox=,seed=); proc iml; start Pat_Array(npat,pabbruch,ptoxcrit); crit = j(npat,1,npat+1); do u = 1 to npat; do l = 0 to u; wk = betainv((1-pabbruch),1+l,1+u-l); if (wk>ptoxcrit) then do; crit[u,1] = l; goto exit; exit: return (crit); finish Pat_Array; Steuerbefehle und Parameter innerhalb einer IML Funktion benötigen kein %
Simulation ToxCrit Anzahl der abgebrochenen Studien start sim(npat,nsim,ptox,crit,seed); call streaminit(seed); stop = j(npat,1,0); do i = 1 to nsim; total = j(npat,1,0); do z = 1 to npat; tox = RAND('BINOMIAL',ptox,1); if (z=1) then total[z,1] = tox; else total[z,1] = total[z-1,1]+tox; if (total[z,1]>=crit[z,1]) then do; stop[z,1] = stop[z,1]+1; goto exit; exit: return (stop); finish sim;
Simulation ToxCrit Anzahl der abgebrochenen Studien start sim(npat,nsim,ptox,crit,seed); call streaminit(seed); stop = j(npat,1,0); do i = 1 to nsim; total = j(npat,1,0); do z = 1 to npat; tox = RAND('BINOMIAL',ptox,1); if (z=1) then total[z,1] = tox; else total[z,1] = total[z-1,1]+tox; if (total[z,1]>=crit[z,1]) then do; stop[z,1] = stop[z,1]+1; goto exit; exit: return (stop); finish sim; Zugriff auf Vor und Nachfolgewerte im Vektor; Im Data Step innerhalb von Do Schleifen mit lag Funktion nicht möglich; Arrays nötig jedoch nicht trivial
Simulation ToxCrit _wkm=j(&npat,1,0); _Pat=j(&npat,1,0); _wkmkum=j(&npat,1,0); Abbruchrisiko einer Studie _crit = Pat_Array(&npat,&pabbruch,&ptoxcrit); _stop = sim(&npat,&nsim,&ptox,_crit,&seed); _wkm = 100*_stop/≁ do i = 1 to &npat; _Pat[i,1]=i; do i = 1 to &npat; if i = 1 then do; _wkmkum[i,1] = _wkm[i,1]; else _wkmkum[i,1] = _wkmkum[i-1,1]+_wkm[i,1];
Simulation ToxCrit Abbruchrisiko einer Studie _wkm=j(&npat,1,0); _Pat=j(&npat,1,0); _wkmkum=j(&npat,1,0); _crit = Pat_Array(&npat,&pabbruch,&ptoxcrit); _stop = sim(&npat,&nsim,&ptox,_crit,&seed); Aufruf der Funktion Pat_Array der return Wert (gesamte Vektor) crit wird an _crit übergeben _wkm = 100*_stop/≁ do i = 1 to &npat; _Pat[i,1]=i; do i = 1 to &npat; if i = 1 then do; _wkmkum[i,1] = _wkm[i,1]; else _wkmkum[i,1] = _wkmkum[i-1,1]+_wkm[i,1];
Simulation ToxCrit _wkm=j(&npat,1,0); _Pat=j(&npat,1,0); _wkmkum=j(&npat,1,0); Abbruchrisiko einer Studie _crit = Pat_Array(&npat,&pabbruch,&ptoxcrit); _stop = sim(&npat,&nsim,&ptox,_crit,&seed); _wkm = 100*_stop/≁ do i = 1 to &npat; _Pat[i,1]=i; do i = 1 to &npat; if i = 1 then do; _wkmkum[i,1] = _wkm[i,1]; else _wkmkum[i,1] = _wkmkum[i-1,1]+_wkm[i,1]; Aufruf der Funktion sim seed wird gesetzt, da hier der Zufallsgenerator implementiert wurde
Simulation ToxCrit _wkm=j(&npat,1,0); _Pat=j(&npat,1,0); _wkmkum=j(&npat,1,0); Abbruchrisiko einer Studie _crit = Pat_Array(&npat,&pabbruch,&ptoxcrit); _stop = sim(&npat,&nsim,&ptox,_crit,&seed); _wkm = 100*_stop/≁ do i = 1 to &npat; _Pat[i,1]=i; do i = 1 to &npat; if i = 1 then do; _wkmkum[i,1] = _wkm[i,1]; else _wkmkum[i,1] = _wkmkum[i-1,1]+_wkm[i,1]; Kein %sysevalf für Operation nötig
Simulation ToxCrit Output und Data Set print _Pat _crit _wkmkum; _toxcrit = _Pat _crit _wkmkum; varnames = {PatientNo ToxPatients InterruptionProb}; create toxcrit from _toxcrit [colname=varnames]; append from _toxcrit; close toxcrit; quit; %mend toxcrit;
Simulation ToxCrit Output und Data Set print _Pat _crit _wkmkum; Ausgabe in Output _toxcrit = _Pat _crit _wkmkum; varnames = {PatientNo ToxPatients InterruptionProb}; create toxcrit from _toxcrit [colname=varnames]; append from _toxcrit; close toxcrit; quit; %mend toxcrit;
Simulation ToxCrit Output und Data Set print _Pat _crit _wkmkum; _toxcrit = _Pat _crit _wkmkum; varnames = {PatientNo ToxPatients InterruptionProb}; create toxcrit from _toxcrit [colname=varnames]; append from _toxcrit; close toxcrit; Horizontale Konkatenation quit; %mend toxcrit;
Simulation ToxCrit Output und Data Set print _Pat _crit _wkmkum; _toxcrit = _Pat _crit _wkmkum; varnames = {PatientNo ToxPatients InterruptionProb}; create toxcrit from _toxcrit [colname=varnames]; append from _toxcrit; close toxcrit; Variblennamen quit; %mend toxcrit;
Simulation ToxCrit Output und Data Set print _Pat _crit _wkmkum; _toxcrit = _Pat _crit _wkmkum; varnames = {PatientNo ToxPatients InterruptionProb}; create toxcrit from _toxcrit [colname=varnames]; append from _toxcrit; close toxcrit; Matrix _toxcrit wird in Datensatz geschrieben quit; %mend toxcrit;
Simulation ToxCrit %toxcrit(npat=20,ptoxcrit=0.1,pabbruch=0.95,nsim=1000000,ptox=0.08,seed=123456);
Simulation ToxCrit Simulationszeiten im Vergleich zu R und Java Sim.-Läufe
quit;