*! abuxton 20Jun2022, 27sep2020 pwexp -piecewise exponential- *! pwexp varlist [if] [in], TIMe(numlist) Gen(string) [SURvival(numlist) Hazard(numlist) Ftype(string) RHR(real 1) ] *20jun2022 v3 add option hazard(); required survival() or hazard() *27sep2020 v2 check rhr >=0 & subtaskA(...st_matrix()...); 13sep2020 v1 version 16.1 mata: mata set matastrict on mata: //subtask subtaskA void subtaskA(string scalar xv, string scalar yv, real scalar rhr , string scalar tp, real colvector nrowi, real colvector tmpts, real colvector svpts, string scalar iptype ) { real scalar i, j, k, cA, cB, cumhazard real scalar Jnrow, nrow, answerflag, npw, npw1, newvarnum, minuslambda, sstar real matrix tbl real colvector xcol, ycol, S, T, H st_view(xcol, ., tokens(xv)) st_view(ycol, ., tokens(yv)) tbl = ( svpts , tmpts ) nrow = rows(xcol) npw = rows(tbl) npw1= rows(tbl)-1 if (iptype == "h") { /* add the hazards calculate S */ H = J(npw,1,.) for (k=1; k<=npw; k++) { if (k==1) { H[k] = svpts[k]*(tmpts[k]-0) } else { H[k]=H[k-1]+svpts[k]*(tmpts[k]-tmpts[k-1]) } } /*k loop*/ S = exp(-H) tbl = ( S , tmpts , svpts , H ) /* note col3 is h */ } S = tbl[(1::npw),1] :^ rhr /* S either way s or h */ T = tbl[(1::npw),2] /* T time */ if ( tp == "pdf" ) { for(i=1; i<=nrow; i++) { cumhazard = 0 answerflag = 0 for(j=1; j<=npw1; j++) { cA = (xcol[i] <= T[j+1]) cB = (xcol[i] >= T[j]) if (cA & cB & answerflag == 0) { minuslambda=log(S[j+1] / S[j]) / (T[j+1] - T[j]) cumhazard = -log(S[j]) + -minuslambda*(xcol[i]-T[j]) /*H*/ ycol[i] = exp(-cumhazard) answerflag = 1 } } /*j loop*/ } /*i loop*/ } if ( tp == "cdf" ) { for(i=1; i<=nrow; i++) { cumhazard = 0 answerflag = 0 for(j=1; j<=npw1; j++) { cA = (xcol[i] <= T[j+1]) cB = (xcol[i] >= T[j]) if (cA & cB & answerflag == 0) { minuslambda=log(S[j+1] / S[j]) / (T[j+1] - T[j]) cumhazard = -log(S[j]) + -minuslambda*(xcol[i]-T[j]) /*H*/ ycol[i] = 1 - exp(-cumhazard) answerflag = 1 } } /*j loop*/ } /*i loop*/ } else if ( tp == "inv" ) { for(i=1; i<=nrow; i++) { answerflag = 0 for(j=1; j<=npw1; j++) { cA = (xcol[i] <= S[j]) cB = (xcol[i] > S[j+1]) if (cA & cB & answerflag == 0) { minuslambda=log(S[j+1] / S[j]) / (T[j+1] - T[j]) sstar = (xcol[i] / S[j]) ycol[i] = T[j] + log(sstar)/minuslambda answerflag = 1 } } /*j loop*/ } /*i loop*/ } else if ( tp == "lmd" ) { for(i=1; i<=nrow; i++) { cumhazard = 0 answerflag = 0 for(j=1; j<=npw1; j++) { cA = (xcol[i] <= T[j+1]) cB = (xcol[i] >= T[j]) if (cA & cB & answerflag == 0) { if (xcol[i]>0) { minuslambda=log(S[j+1] / S[j]) / (T[j+1] - T[j]) } else { minuslambda=0 } ycol[i] = -minuslambda answerflag = 1 } } /*j loop*/ } /*i loop*/ } } end program define pwexp , rclass version 16.1 syntax varlist(numeric min=1 max=1) [if] [in] , TIMepoints(numlist) Generate(string) [SURvivalpoints(numlist) Hazardpionts(numlist) Ftype(string) RHR(real 1) replace] marksample touse qui count if `touse' if r(N) == 0 error 2000 tokenize `varlist' args xvar tokenize `generate' args yvar garbage if "`garbage'" != "" { di as err "at most one name should be given in generate()" exit 198 } if "`survivalpoints'" != "" & "`hazardpionts'" != "" { di as err "required: please choose only one, survival() or hazard()" exit 198 } else if "`survivalpoints'" != "" { local iptype = "s" } else if "`hazardpionts'" != "" { local iptype = "h" } else { di as err "required: please choose one, survival() or hazard()" exit 198 } tokenize `ftype' args ftp garbage if "`garbage'" != "" { di as err "at most one name should be given in ftype( {pdf , cdf , inv , lmd} )" exit 198 } if `"`replace'"' == `""' { confirm new variable `yvar' qui gen double `yvar' = . } else if `"`replace'"' == `"replace"' { cap confirm new variable `yvar' if !_rc { qui gen double `yvar' = . } else { cap confirm numeric variable `yvar' qui replace `yvar' = . } } if `"`ftp'"'==`"pdf"' | `"`ftp'"'==`""' { local type `"pdf"' } else if `"`ftp'"'==`"cdf"' { local type `"cdf"' } else if `"`ftp'"'==`"inv"' { local type `"inv"' } else if `"`ftp'"'==`"lmd"' | `"`ftp'"'==`"lambda"'{ local type `"lmd"' } else { di as err "one name in ftype( {pdf , cdf , inv , lmd or lambda} )" exit 198 } qui { if `rhr' < 0 { di as err "option rhr(), relative hazard ratio, must be >=0" exit 198 } local tlst = `"`timepoints'"' cap numlist "`tlst'" , min(2) range(>=0) ascending if _rc != 0 { di as err "time() values, n=2+, must be ascending with no repeated values & >=0" exit 198 } local timepointlst = r(numlist) local Ntlst = 0 foreach z in numlist `timepointlst' { local Ntlst = `Ntlst'+1 } local Ntlst = `Ntlst'-1 local timepointA =subinstr("`timepointlst'"," ","\",.) if "`iptype'" == "s" { local slst = `"`survivalpoints'"' cap numlist "`slst'" , min(2) range(>=0 <=1) if _rc != 0 { di as err "survival() values, n=2+, must be >=0 & <=1" exit 198 } local survpointlst = r(numlist) local Nslst = 0 foreach z in numlist `survpointlst' { local Nslst = `Nslst'+1 } local Nslst = `Nslst'-1 local survpointA =subinstr("`survpointlst'"," ","\",.) if `Ntlst' != `Nslst' { di as err "time() (n=`Ntlst') and survival() (n=`Nslst') require an equal number of values" exit 198 } } else if "`iptype'" == "h" { local slst = `"`hazardpionts'"' cap numlist "`slst'" , min(2) range(>=0) if _rc != 0 { di as err "hazard() values, n=2+, must be >=0" exit 198 } local hazardpointlst = r(numlist) local Nslst = 0 foreach z in numlist `hazardpointlst' { local Nslst = `Nslst'+1 } local Nslst = `Nslst'-1 local hazardpointA =subinstr("`hazardpointlst'"," ","\",.) if `Ntlst' != `Nslst' { di as err "time() (n=`Ntlst') and hazard() (n=`Nslst') require an equal number of values" exit 198 } } numlist "1/`Nslst'" local rowindex = r(numlist) local rowindexA =subinstr("`rowindex'"," ","\",.) tempname a b c d matrix input `a' = (`rowindexA') matrix input `b' = (`timepointA') if "`iptype'" == "s" { matrix input `c' = (`survpointA') mata : st_matrix("`b'", sort(st_matrix("`b'"), 1)) mata : st_matrix("`c'", sort(st_matrix("`c'"),-1)) matrix `d' = (`a',`b',`c') matrix colnames `d' = irow time survival } else if "`iptype'" == "h" { matrix input `c' = (`hazardpointA') mata : st_matrix("`b'", sort(st_matrix("`b'"), 1)) matrix `d' = (`a',`b',`c') matrix colnames `d' = irow time hazard } return matrix itimeS = `d' } mata subtaskA("`xvar'", "`yvar'" , `rhr' , "`type'" , st_matrix("`a'") , st_matrix("`b'") , st_matrix("`c'") , "`iptype'") qui replace `yvar' = . if cond(`touse',0,1) end