*! version 1.5.9 13FEB2022 * Added various options + use mata for orthogonalisation * Based on an original program by Chris Nelson * Chris Nelson 24/APR/2006 * Paul Lambert 28/AUG/2008 * Mark Rutherford 05/DEC/2008 * Patrick royston 16/OCT2009 - allow numlist for knots to be in non-ascending order * Therese Andersson 01/FEB/2010 - add an option to calculate the spline variables backwards, to use for cure estimation in stpm2 * Paul Lambert 13/APR/2011 - added scalar option. (fixed for cure models 24/6/2011 & 28/6/2011). * Therese Andersson 17Jan2012, adding options for relaxing the constraints of continuous first * * and second derivative at the first knot (last if reversed splines) * Paul Lambert 8/4/2013 - correct incorrect error message when using df(1) * Mark Rutherford 25/July/2014 - allow a center option & make percentiles code more efficient * Patrick Royston 31/7/2014 - return macros for rcslist varlists * Paul Lambert 25/6/2015 - when using percentiles, r(knots) were not in numerical order * Sarwar Mozumder 18/10/2021 - added Harrell's knot positions (from RMS book, table 2.3) * Paul Lambert 18/10/2021 - rmsknots fix program define rcsgen, rclass version 10.0 syntax [varlist(default=none)] [if] [in] /// , [Gen(string) DGen(string) Knots(numlist) BKnots(numlist max=2) Orthog Percentiles(numlist ascending) RMATrix(name) /// DF(int 0) IF2(string) FW(varname) REVerse SCAlar(string) NOSecondder NOFirstder CENTer(string) RMSKnots(string) ] marksample touse // sort knots if "`knots'" != "" { numlist "`knots'", sort local knots `r(numlist)' } /* Error checks */ if "`scalar'" != "" { if "`varlist'" != "" { display as error "You can't specify both a varname and the scalar option" exit 198 } if "`df'" != "0" { display as error "You can't specify the df option with the scalar option" exit 198 } if "`percentiles'" != "" { display as error "You can't specify the percentiles option with the scalar option" exit 198 } if "`rmsknots'" != "" { display as error "You can't specify the rmsknots option with the scalar option" exit 198 } if "`orthog'" != "" { display as error "You can't specify the orthog option with the scalar option" exit 198 } if "`fw'" != "" { display as error "You can't specify the fw option with the scalar option" exit 198 } } if "`rmsknots'" != "" { if (`rmsknots' < 3 | `rmsknots' > 7) { display as err "Can only specify k = 3, ..., 7 knots as detailed in Table 2.3 in Regression Modeling Strategies by F. Harrell." exit 198 } } if "`knots'" != "" & "`rmsknots'" != "" { display as err "Only one of the knots, df, percentiles and rmsknots options can be used" exit 198 } if "`percentiles'" != "" & "`rmsknots'" != "" { display as err "Only one of the knots, df, percentiles and rmsknots options can be used" exit 198 } if "`df'" != "0" & "`rmsknots'" != "" { display as err "Only one of the knots, df, percentiles and rmsknots options can be used" exit 198 } if "`knots'" != "" & "`percentiles'" != "" { display as err "Only one of the knots, df and percentiles options can be used" exit 198 } if "`knots'" != "" & "`df'" != "0" { display as err "Only one of the knots, df and percentiles options can be used" exit 198 } if "`df'" != "0" & "`percentiles'" != "" { display as err "Only one of the knots, df and percentiles options can be used" exit 198 } if "`bknots'" != "" & "`df'" == "0" { display as err "Boundary knots can only be defined with the degrees of freedom option" exit 198 } if "`orthog'" != "" & "`rmatrix'" != "" { display as error "Only one of the orthog and rmatrix options can be specified" exit 198 } if "`center'" != "" & "`reverse'" != "" { display as error "The center option cannot be used when using the reverse option" exit 198 } if "`nofirstder'" != "" & "`nosecondder'" != "" { display as error "Only one of the nofirstder and nosecondder can be specified" exit 198 } if "`gen'" == "" { di in red "Must specify name for cubic splines basis" exit 198 } /* Determine knot locations if rmsknots is used */ // (from RMS book, table 2.3) if "`rmsknots'" != "" { if `rmsknots' == 3 { local percentiles 10 50 90 } if `rmsknots' == 4 { local percentiles 5 35 65 95 } if `rmsknots' == 5 { local percentiles 5 27.5 50 72.5 95 } if `rmsknots' == 6 { local percentiles 5 23 41 59 77 95 } if `rmsknots' == 7 { local percentiles 2.5 18.33 34.17 50 65.83 81.67 97.5 } } /* percentiles option */ if "`percentiles'" != "" { if "`fw'" != "" { local fw [fw=`fw'] } if "`if2'" != "" { local aif & `if2' } local knots local percentilesm foreach ptile in `percentiles' { summ `varlist' if `touse' `aif', meanonly if `ptile' == 0 { local knots `r(min)' } else if `ptile' == 100 { local knots `knots' `r(max)' } else { local percentilesm `percentilesm' `ptile' } } local dfp: word count `percentilesm' _pctile `varlist' if `touse' `aif' `fw', p(`percentilesm') forvalues i= 1/`dfp' { local knots `knots' `r(r`i')' } local knots : list sort knots } /* Find knot locations if df option is used */ if "`df'" > "1" { if "`fw'" != "" { local fw [fw=`fw'] } if "`if2'" != "" { local aif & `if2' } if "`bknots'"!="" { local lowerknot: word 1 of `bknots' local upperknot: word 2 of `bknots' } else { quietly summ `varlist' if `touse' `aif', meanonly local lowerknot `r(min)' local upperknot `r(max)' } local dfm1=`df'-1 forvalues y= 1/`dfm1' { local centile=(100/`df')*`y' local centilelist `centilelist' `centile' } local intknots _pctile `varlist' if `touse' `aif' `fw', p(`centilelist') forvalues i= 1/`dfm1' { local intknots `intknots' `r(r`i')' } if real(word("`intknots'",1))<=`lowerknot' { display as err "Lowest internal knot is not greater than lower boundary knot" exit 198 } if real(word("`intknots'",`dfm1'))>=`upperknot' { display as err "Highest internal knot is not greater than upper boundary knot" exit 198 } local knots local knots `lowerknot' `intknots' `upperknot' } /*Derive the spline variables in the default way (not backwards)*/ if "`reverse'" == "" & "`nosecondder'" == "" & "`nofirstder'" == "" { /* Start to derive spline variables */ if "`scalar'" == "" { quietly gen double `gen'1 = `varlist' if `touse' } else { scalar `gen'1 = `scalar' } if "`center'"!= "" { tempname center1 scalar `center1' = `center' } /* generate first derivative if dgen option is specified */ if "`dgen'" != "" { if "`scalar'" == "" { quietly gen double `dgen'1 = 1 if `touse' } else { scalar `dgen'1 = 1 } } local rcslist `gen'1 local drcslist `dgen'1 local nk : word count `knots' if "`knots'" == "" { local interior = 0 } else { local interior = `nk' - 2 } local nparams = `interior' + 1 if "`knots'" != "" { local i = 1 tokenize "`knots'" while "``i''" != "" { local k`i' ``i'' local i = `i' + 1 } local kmin = `k1' local kmax = `k`nk'' forvalues j=2/`nparams' { local lambda = (`kmax' - `k`j'')/(`kmax' - `kmin') if "`scalar'" == "" { quietly gen double `gen'`j' = ((`varlist'-`k`j'')^3)*(`varlist'>`k`j'') - /// `lambda'*((`varlist'-`kmin')^3)*(`varlist'>`kmin') - /// (1-`lambda')*((`varlist'-`kmax')^3)*(`varlist'>`kmax') if `touse' } else { scalar `gen'`j' = ((`scalar'-`k`j'')^3)*(`scalar'>`k`j'') - /// `lambda'*((`scalar'-`kmin')^3)*(`scalar'>`kmin') - /// (1-`lambda')*((`scalar'-`kmax')^3)*(`scalar'>`kmax') } if "`center'"!= "" { tempname center`j' scalar `center`j'' = ((`center'-`k`j'')^3)*(`center'>`k`j'') - /// `lambda'*((`center'-`kmin')^3)*(`center'>`kmin') - /// (1-`lambda')*((`center'-`kmax')^3)*(`center'>`kmax') } local rcslist `rcslist' `gen'`j' /* calculate derivatives */ if "`dgen'"!="" { if "`scalar'" == "" { quietly gen double `dgen'`j' = (3*(`varlist'- `k`j'')^2)*(`varlist'>`k`j'') - /// `lambda'*(3*(`varlist'-`kmin')^2)*(`varlist'>`kmin') - /// (1-`lambda')*(3*(`varlist'-`kmax')^2)*(`varlist'>`kmax') } else { scalar `dgen'`j' = (3*(`scalar'- `k`j'')^2)*(`scalar'>`k`j'') - /// `lambda'*(3*(`scalar'-`kmin')^2)*(`scalar'>`kmin') - /// (1-`lambda')*(3*(`scalar'-`kmax')^2)*(`scalar'>`kmax') } local drcslist `drcslist' `dgen'`j' } } } } /*Derive the spline variables in reversed order */ /*ADDED: 2010-02-02 by Therese Andersson*/ else if "`reverse'" != "" & "`nosecondder'" == "" & "`nofirstder'" == "" { local rcslist local drcslist local nk : word count `knots' if "`knots'" == "" { local interior = 0 } else { local interior = `nk' - 2 } local nparams = `interior' + 1 if "`knots'" != "" { local i = 1 tokenize "`knots'" while "``i''" != "" { local k`i' ``i'' local i = `i' + 1 } local kmin = `k1' local kmax = `k`nk'' forvalues j=1/`interior' { local h = `nk'-`j' local lambda = (`k`h''-`kmin')/(`kmax' - `kmin') if "`scalar'" == "" { quietly gen double `gen'`j' = ((`k`h''-`varlist')^3)*(`k`h''>`varlist') - /// `lambda'*((`kmax'-`varlist')^3)*(`kmax'>`varlist') - /// (1-`lambda')*((`kmin'-`varlist')^3)*(`kmin'>`varlist') if `touse' } else { scalar `gen'`j' = ((`k`h''-`scalar')^3)*(`k`h''>`scalar') - /// `lambda'*((`kmax'-`scalar')^3)*(`kmax'>`scalar') - /// (1-`lambda')*((`kmin'-`scalar')^3)*(`kmin'>`scalar') } local rcslist `rcslist' `gen'`j' /* calculate derivatives */ if "`dgen'"!="" { if "`scalar'" == "" { quietly gen double `dgen'`j' = (-3*(`k`h''-`varlist')^2)*(`k`h''>`varlist') - /// `lambda'*(-3*(`kmax'-`varlist')^2)*(`kmax'>`varlist') - /// (1-`lambda')*(-3*(`kmin'-`varlist')^2)*(`kmin'>`varlist') if `touse' } else { scalar `dgen'`j' = (-3*(`k`h''-`scalar')^2)*(`k`h''>`scalar') - /// `lambda'*(-3*(`kmax'-`scalar')^2)*(`kmax'>`scalar') - /// (1-`lambda')*(-3*(`kmin'-`scalar')^2)*(`kmin'>`scalar') } local drcslist `drcslist' `dgen'`j' } } /* Derive last spline variable */ if "`scalar'" == "" { quietly gen double `gen'`nparams' = `varlist' if `touse' } else { scalar `gen'`nparams' = `scalar' } local rcslist `rcslist' `gen'`nparams' /* generate first derivative if dgen option is specified */ if "`dgen'" != "" { if "`scalar'" == "" { quietly gen double `dgen'`nparams' = 1 if `touse' } else { scalar `dgen'`nparams' = 1 } local drcslist `drcslist' `dgen'`nparams' } } } // no second derivative else if "`nosecondder'" != "" & "`reverse'" == "" & "`nofirstder'" == "" { /* Start to derive spline variables */ if "`scalar'" == "" { quietly gen double `gen'1 = `varlist' if `touse' } else { scalar `gen'1 = `scalar' } if "`center'"!= "" { tempname center1 scalar `center1' = `center' } /* generate first derivative if dgen option is specified */ if "`dgen'" != "" { if "`scalar'" == "" { quietly gen double `dgen'1 = 1 if `touse' } else { scalar `dgen'1 = 1 } } local rcslist `gen'1 local drcslist `dgen'1 local nk : word count `knots' if "`knots'" == "" { local interior = 0 } else { local interior = `nk' - 2 } local nparams = `interior' + 2 local npar = `interior' + 1 if "`knots'" != "" { local i = 1 tokenize "`knots'" while "``i''" != "" { local k`i' ``i'' local i = `i' + 1 } local kmin = `k1' local kmax = `k`nk'' forvalues j=2/`npar' { local lambda = (`kmax' - `k`j'')/(`kmax' - `kmin') if "`scalar'" == "" { quietly gen double `gen'`j' = ((`varlist'-`k`j'')^3)*(`varlist'>`k`j'') - /// `lambda'*((`varlist'-`kmin')^3)*(`varlist'>`kmin') - /// (1-`lambda')*((`varlist'-`kmax')^3)*(`varlist'>`kmax') if `touse' } else { scalar `gen'`j' = ((`scalar'-`k`j'')^3)*(`scalar'>`k`j'') - /// `lambda'*((`scalar'-`kmin')^3)*(`scalar'>`kmin') - /// (1-`lambda')*((`scalar'-`kmax')^3)*(`scalar'>`kmax') } if "`center'"!= "" { tempname center`j' scalar `center`j'' = ((`center'-`k`j'')^3)*(`center'>`k`j'') - /// `lambda'*((`center'-`kmin')^3)*(`center'>`kmin') - /// (1-`lambda')*((`center'-`kmax')^3)*(`center'>`kmax') } local rcslist `rcslist' `gen'`j' /* calculate derivatives */ if "`dgen'"!="" { if "`scalar'" == "" { quietly gen double `dgen'`j' = (3*(`varlist'- `k`j'')^2)*(`varlist'>`k`j'') - /// `lambda'*(3*(`varlist'-`kmin')^2)*(`varlist'>`kmin') - /// (1-`lambda')*(3*(`varlist'-`kmax')^2)*(`varlist'>`kmax') } else { scalar `dgen'`j' = (3*(`scalar'- `k`j'')^2)*(`scalar'>`k`j'') - /// `lambda'*(3*(`scalar'-`kmin')^2)*(`scalar'>`kmin') - /// (1-`lambda')*(3*(`scalar'-`kmax')^2)*(`scalar'> `kmax') } local drcslist `drcslist' `dgen'`j' } } /* Derive last spline variable */ local c=(1/(3*(`kmax' - `kmin'))) if "`scalar'" == "" { quietly gen double `gen'`nparams' = (`varlist'-`kmin')^2*(`varlist'>`kmin') - /// `c'*((`varlist'-`kmin')^3)*(`varlist'>`kmin') + /// `c'*((`varlist'-`kmax')^3)*(`varlist'>`kmax') if `touse' } else { scalar `gen'`nparams' = (`scalar'-`kmin')^2*(`scalar'>`kmin') - /// `c'*((`scalar'-`kmin')^3)*(`scalar'>`kmin') + /// `c'*((`scalar'-`kmax')^3)*(`scalar'>`kmax') } if "`center'"!= "" { tempname center`nparams' scalar `center`nparams'' = (`center'-`kmin')^2*(`center'>`kmin') - /// `c'*((`center'-`kmin')^3)*(`center'>`kmin') + /// `c'*((`center'-`kmax')^3)*(`center'>`kmax') } local rcslist `rcslist' `gen'`nparams' /* generate first derivative if dgen option is specified */ if "`dgen'" != "" { if "`scalar'" == "" { quietly gen double `dgen'`nparams' = 2*(`varlist'-`kmin')*(`varlist'>`kmin') - /// 3*`c'*((`varlist'-`kmin')^2)*(`varlist'>`kmin') + /// 3*`c'*((`varlist'-`kmax')^2)*(`varlist'>`kmax') if `touse' } else { scalar `dgen'`nparams' = 2*(`scalar'-`kmin')*(`scalar'>`kmin') - /// 3*`c'*((`scalar'-`kmin')^2)*(`scalar'>`kmin') + /// 3*`c'*((`scalar'-`kmax')^2)*(`scalar'>`kmax') } local drcslist `drcslist' `dgen'`nparams' } } } ****************************!!!********************* else if "`nosecondder'" != "" & "`reverse'" != "" & "`nofirstder'" == ""{ local nk : word count `knots' if "`knots'" == "" { local interior = 0 } else { local interior = `nk' - 2 } local nparams = `interior' + 2 local npar = `interior' + 1 if "`knots'" != "" { local i = 1 tokenize "`knots'" while "``i''" != "" { local k`i' ``i'' local i = `i' + 1 } local kmin = `k1' local kmax = `k`nk'' /* Derive first spline variable */ local c=(1/(3*(`kmax' - `kmin'))) if "`scalar'" == "" { quietly gen double `gen'1 = (`kmax'-`varlist')^2*(`kmax'>`varlist') - /// `c'*((`kmax'-`varlist')^3)*(`kmax'>`varlist') + /// `c'*((`kmin'-`varlist')^3)*(`kmin'>`varlist') if `touse' } else { scalar `gen'1 = (`kmax'-`scalar')^2*(`kmax'>`scalar') - /// `c'*((`kmax'-`scalar')^3)*(`kmax'>`scalar') + /// `c'*((`kmin'-`scalar')^3)*(`kmin'>`scalar') } local rcslist `gen'1 /* generate first derivative if dgen option is specified */ if "`dgen'" != "" { if "`scalar'" == "" { quietly gen double `dgen'1 = -2*(`kmax'-`varlist')*(`kmax'>`varlist') - /// (-3)*`c'*((`kmax'-`varlist')^2)*(`kmax'>`varlist') + /// (-3)*`c'*((`kmin'-`varlist')^2)*(`kmin'>`varlist') if `touse' } else { scalar `dgen'1 = -2*(`kmax'-`scalar')*(`kmax'>`scalar') - /// (-3)*`c'*((`kmax'-`scalar')^2)*(`kmax'>`scalar') + /// (-3)*`c'*((`kmin'-`scalar')^2)*(`kmin'>`scalar') } local drcslist `dgen'1 } forvalues j=2/`npar' { local h = `nk'-(`j'-1) local lambda = (`k`h''-`kmin')/(`kmax' - `kmin') if "`scalar'" == "" { quietly gen double `gen'`j' = ((`k`h''-`varlist')^3)*(`k`h''>`varlist') - /// `lambda'*((`kmax'-`varlist')^3)*(`kmax'>`varlist') - /// (1-`lambda')*((`kmin'-`varlist')^3)*(`kmin'>`varlist') if `touse' } else { scalar `gen'`j' = ((`k`h''-`scalar')^3)*(`k`h''>`scalar') - /// `lambda'*((`kmax'-`scalar')^3)*(`kmax'>`scalar') - /// (1-`lambda')*((`kmin'-`scalar')^3)*(`kmin'>`scalar') } local rcslist `rcslist' `gen'`j' /* calculate derivatives */ if "`dgen'"!="" { if "`scalar'" == "" { quietly gen double `dgen'`j' = (-3*(`k`h''-`varlist')^2)*(`k`h''>`varlist') - /// `lambda'*(-3*(`kmax'-`varlist')^2)*(`kmax'>`varlist') - /// (1-`lambda')*(-3*(`kmin'-`varlist')^2)*(`kmin'>`varlist') if `touse' } else { scalar `dgen'`j' = (-3*(`k`h''-`scalar')^2)*(`k`h''>`scalar') - /// `lambda'*(-3*(`kmax'-`scalar')^2)*(`kmax'>`scalar') - /// (1-`lambda')*(-3*(`kmin'-`scalar')^2)*(`kmin'>` scalar') } local drcslist `drcslist' `dgen'`j' } } /* Derive last spline variable */ if "`scalar'" == "" { quietly gen double `gen'`nparams' = `varlist' if `touse' } else { scalar `gen'`nparams' = `scalar' } local rcslist `rcslist' `gen'`nparams' /* generate first derivative if dgen option is specified */ if "`dgen'" != "" { if "`scalar'" == "" { quietly gen double `dgen'`nparams' = 1 if `touse' } else { scalar `dgen'`nparams' = 1 } local drcslist `drcslist' `dgen'`nparams' } } } **************************** !!!! ************************************ ******** ADDED 2012-01-10 Relax assumption of continuous first and second derivative at the first knot (or the last knot if reverse option is used) ****************************!!!********************* else if "`nosecondder'" == "" & "`reverse'" == "" & "`nofirstder'" != "" { /* Start to derive spline variables */ if "`scalar'" == "" { quietly gen double `gen'1 = `varlist' if `touse' } else { scalar `gen'1 = `scalar' } if "`center'"!= "" { tempname center1 scalar `center1' = `center' } /* generate first derivative if dgen option is specified */ if "`dgen'" != "" { if "`scalar'" == "" { quietly gen double `dgen'1 = 1 if `touse' } else { scalar `dgen'1 = 1 } } local rcslist `gen'1 local drcslist `dgen'1 local nk : word count `knots' if "`knots'" == "" { local interior = 0 } else { local interior = `nk' - 2 } local nparams = `interior' + 3 local npar = `interior' + 1 local par = `interior' + 2 if "`knots'" != "" { local i = 1 tokenize "`knots'" while "``i''" != "" { local k`i' ``i'' local i = `i' + 1 } local kmin = `k1' local kmax = `k`nk'' forvalues j=2/`npar' { local lambda = (`kmax' - `k`j'')/(`kmax' - `kmin') if "`scalar'" == "" { quietly gen double `gen'`j' = ((`varlist'-`k`j'')^3)*(`varlist'>`k`j'') - /// `lambda'*((`varlist'-`kmin')^3)*(`varlist'>`kmin') - /// (1-`lambda')*((`varlist'-`kmax')^3)*(`varlist'>`kmax') if `touse' } else { scalar `gen'`j' = ((`scalar'-`k`j'')^3)*(`scalar'>`k`j'') - /// `lambda'*((`scalar'-`kmin')^3)*(`scalar'>`kmin') - /// (1-`lambda')*((`scalar'-`kmax')^3)*(`scalar'>`kmax') } if "`center'"!= "" { tempname center`j' scalar `center`j'' = ((`center'-`k`j'')^3)*(`center'>`k`j'') - /// `lambda'*((`center'-`kmin')^3)*(`center'>`kmin') - /// (1-`lambda')*((`center'-`kmax')^3)*(`center'>`kmax') } local rcslist `rcslist' `gen'`j' /* calculate derivatives */ if "`dgen'"!="" { if "`scalar'" == "" { quietly gen double `dgen'`j' = (3*(`varlist'- `k`j'')^2)*(`varlist'>`k`j'') - /// `lambda'*(3*(`varlist'-`kmin')^2)*(`varlist'>`kmin') - /// (1-`lambda')*(3*(`varlist'-`kmax')^2)*(`varlist'>`kmax') } else { scalar `dgen'`j' = (3*(`scalar'- `k`j'')^2)*(`scalar'>`k`j'') - /// `lambda'*(3*(`scalar'-`kmin')^2)*(`scalar'>`kmin') - /// (1-`lambda')*(3*(`scalar'-`kmax')^2)*(`scalar'> `kmax') } local drcslist `drcslist' `dgen'`j' } } /* Derive the first extra spline variable */ local c=(1/(3*(`kmax' - `kmin'))) if "`scalar'" == "" { quietly gen double `gen'`par' = (`varlist'-`kmin')^2*(`varlist'>`kmin') - /// `c'*((`varlist'-`kmin')^3)*(`varlist'>`kmin') + /// `c'*((`varlist'-`kmax')^3)*(`varlist'>`kmax') if `touse' } else { scalar `gen'`par' = (`scalar'-`kmin')^2*(`scalar'>`kmin') - /// `c'*((`scalar'-`kmin')^3)*(`scalar'>`kmin') + /// `c'*((`scalar'-`kmax')^3)*(`scalar'>`kmax') } if "`center'"!= "" { scalar center`par' = (`center'-`kmin')^2*(`center'>`kmin') - /// `c'*((`center'-`kmin')^3)*(`center'>`kmin') + /// `c'*((`center'-`kmax')^3)*(`center'>`kmax') } local rcslist `rcslist' `gen'`par' /* generate first derivative if dgen option is specified */ if "`dgen'" != "" { if "`scalar'" == "" { quietly gen double `dgen'`par' = 2*(`varlist'-`kmin')*(`varlist'>`kmin') - /// 3*`c'*((`varlist'-`kmin')^2)*(`varlist'>`kmin') + /// 3*`c'*((`varlist'-`kmax')^2)*(`varlist'>`kmax') if `touse' } else { scalar `dgen'`par' = 2*(`scalar'-`kmin')*(`scalar'>`kmin') - /// 3*`c'*((`scalar'-`kmin')^2)*(`scalar'>`kmin') + /// 3*`c'*((`scalar'-`kmax')^2)*(`scalar'>`kmax') } local drcslist `drcslist' `dgen'`par' } /* Derive the last spline variable */ if "`scalar'" == "" { quietly gen double `gen'`nparams' = (`varlist'-`kmin')*(`varlist'>`kmin') if `touse' } else { scalar `gen'`nparams' = (`scalar'-`kmin')*(`scalar'>`kmin') } if "`center'"!= "" { tempname center`nparams' scalar center`nparams' = (`center'-`kmin')*(`center'>`kmin') } local rcslist `rcslist' `gen'`nparams' /* generate first derivative if dgen option is specified */ if "`dgen'" != "" { if "`scalar'" == "" { quietly gen double `dgen'`nparams' = 1*(`varlist'>`kmin') if `touse' } else { scalar `dgen'`nparams' = 1*(`scalar'>`kmin') } local drcslist `drcslist' `dgen'`nparams' } } } ****************************!!!********************* else if "`nosecondder'" == "" & "`reverse'" != "" & "`nofirstder'" != ""{ local nk : word count `knots' if "`knots'" == "" { local interior = 0 } else { local interior = `nk' - 2 } local nparams = `interior' + 3 local npar = `interior' + 1 local par = `interior' + 2 if "`knots'" != "" { local i = 1 tokenize "`knots'" while "``i''" != "" { local k`i' ``i'' local i = `i' + 1 } local kmin = `k1' local kmax = `k`nk'' /* Derive first spline variable */ if "`scalar'" == "" { quietly gen double `gen'1 = (`kmax'-`varlist')*(`kmax'>`varlist') if `touse' } else { scalar `gen'1 = (`kmax'-`scalar')*(`kmax'>`scalar') } if "`center'"!= "" { tempname center1 scalar `center1' = (`kmax'-`center')*(`kmax'>`center') } local rcslist `gen'1 /* generate first derivative if dgen option is specified */ if "`dgen'" != "" { if "`scalar'" == "" { quietly gen double `dgen'1 = -1*(`kmax'>`varlist') if `touse' } else { scalar `dgen'1 = -1 } local drcslist `dgen'1 } /* Derive second spline variable */ local c=(1/(3*(`kmax' - `kmin'))) if "`scalar'" == "" { quietly gen double `gen'2 = (`kmax'-`varlist')^2*(`kmax'>`varlist') - /// `c'*((`kmax'-`varlist')^3)*(`kmax'>`varlist') + /// `c'*((`kmin'-`varlist')^3)*(`kmin'>`varlist') if `touse' } else { scalar `gen'2 = (`kmax'-`scalar')^2*(`kmax'>`scalar') - /// `c'*((`kmax'-`scalar')^3)*(`kmax'>`scalar') + /// `c'*((`kmin'-`scalar')^3)*(`kmin'>`scalar') } if "`center'"!= "" { scalar center2 = (`kmax'-`center')^2*(`kmax'>`center') - /// `c'*((`kmax'-`center')^3)*(`kmax'>`center') + /// `c'*((`kmin'-`center')^3)*(`kmin'>`center') } local rcslist `rcslist' `gen'2 /* generate first derivative if dgen option is specified */ if "`dgen'" != "" { if "`scalar'" == "" { quietly gen double `dgen'2 = -2*(`kmax'-`varlist')*(`kmax'>`varlist') - /// (-3)*`c'*((`kmax'-`varlist')^2)*(`kmax'>`varlist') + /// (-3)*`c'*((`kmin'-`varlist')^2)*(`kmin'>`varlist') if `touse' } else { scalar `dgen'2 = -2*(`kmax'-`scalar')*(`kmax'>`scalar') - /// (-3)*`c'*((`kmax'-`scalar')^2)*(`kmax'>`scalar') + /// (-3)*`c'*((`kmin'-`scalar')^2)*(`kmin'>`scalar') } local drcslist `drcslist' `dgen'2 } forvalues j=3/`par' { local h = `nk'-(`j'-2) local lambda = (`k`h''-`kmin')/(`kmax' - `kmin') if "`scalar'" == "" { quietly gen double `gen'`j' = ((`k`h''-`varlist')^3)*(`k`h''>`varlist') - /// `lambda'*((`kmax'-`varlist')^3)*(`kmax'>`varlist') - /// (1-`lambda')*((`kmin'-`varlist')^3)*(`kmin'>`varlist') if `touse' } else { scalar `gen'`j' = ((`k`h''-`scalar')^3)*(`k`h''>`scalar') - /// `lambda'*((`kmax'-`scalar')^3)*(`kmax'>`scalar') - /// (1-`lambda')*((`kmin'-`scalar')^3)*(`kmin'>`scalar') } if "`center'"!= "" { tempname center`j' scalar `center`j'' = ((`k`h''-`center')^3)*(`k`h''>`center') - /// `lambda'*((`kmax'-`center')^3)*(`kmax'>`center') - /// (1-`lambda')*((`kmin'-`center')^3)*(`kmin'>`center') } local rcslist `rcslist' `gen'`j' /* calculate derivatives */ if "`dgen'"!="" { if "`scalar'" == "" { quietly gen double `dgen'`j' = (-3*(`k`h''-`varlist')^2)*(`k`h''>`varlist') - /// `lambda'*(-3*(`kmax'-`varlist')^2)*(`kmax'>`varlist') - /// (1-`lambda')*(-3*(`kmin'-`varlist')^2)*(`kmin'>`varlist') if `touse' } else { scalar `dgen'`j' = (-3*(`k`h''-`scalar')^2)*(`k`h''>`scalar') - /// `lambda'*(-3*(`kmax'-`scalar')^2)*(`kmax'>`scalar') - /// (1-`lambda')*(-3*(`kmin'-`scalar')^2)*(`kmin'>` scalar') } local drcslist `drcslist' `dgen'`j' } } /* Derive last spline variable */ if "`scalar'" == "" { quietly gen double `gen'`nparams' = `varlist' if `touse' } else { scalar `gen'`nparams' = `scalar' } if "`center'"!= "" { tempname center`nparams' scalar `center`nparams'' = `center' } local rcslist `rcslist' `gen'`nparams' /* generate first derivative if dgen option is specified */ if "`dgen'" != "" { if "`scalar'" == "" { quietly gen double `dgen'`nparams' = 1 if `touse' } else { scalar `dgen'`nparams' = 1 } local drcslist `drcslist' `dgen'`nparams' } } } **************************** !!!! ************************************ /* orthogonlise */ if "`orthog'" != "" { tempname R Rinv cons mata: orthgs("`rcslist'","`touse'") matrix `Rinv' = inv(`R') if "`dgen'" != "" { gen `cons' = 1 if `touse' mata st_store(.,tokens(st_local("drcslist")), /// "`touse'",st_data(.,tokens(st_local("drcslist")), /// "`touse'")*st_matrix("`Rinv'")[1..`nparams',1..`nparams']) } } else if "`rmatrix'" != "" { tempname Rinv cons matrix `Rinv' = inv(`rmatrix') if "`scalar'" == "" { gen `cons' = 1 if `touse' mata st_store(.,tokens(st_local("rcslist")), /// "`touse'",(st_data(., tokens(st_local("rcslist") + " `cons'"), /// "`touse'"))*st_matrix("`Rinv'")[,1..`nparams']) if "`dgen'" != "" { mata st_store(.,tokens(st_local("drcslist")), /// "`touse'",st_data(.,tokens(st_local("drcslist")), /// "`touse'")*st_matrix("`Rinv'")[1..`nparams',1..`nparams']) } } else { tempname scalarmatrix matrix `scalarmatrix' = `gen'1 forvalues i = 2/`nparams'{ matrix `scalarmatrix' = `scalarmatrix',`gen'`i' } matrix `scalarmatrix' = `scalarmatrix',1 mata st_matrix("`scalarmatrix'",st_matrix("`scalarmatrix'")*st_matrix("`Rinv'")[,1..`nparams']) forvalues i = 1/`nparams'{ scalar `gen'`i' = el(`scalarmatrix',1,`i') } if "`dgen'" != "" { tempname dscalarmatrix matrix `dscalarmatrix' = `dgen'1 forvalues i = 2/`nparams'{ matrix `dscalarmatrix' = `dscalarmatrix',`dgen'`i' } mata st_matrix("`dscalarmatrix'",st_matrix("`dscalarmatrix'")*st_matrix("`Rinv'")[1..`nparams',1..`nparams']) forvalues i = 1/`nparams'{ scalar `dgen'`i' = el(`dscalarmatrix',1,`i') } } } } /*subtract the value at the last knot, so that there is an interpretable baseline*/ /*ADDED: 2010-04-14 by Therese Andersson*/ if ("`orthog'" != "" | "`rmatrix'" != "") & "`reverse'" != "" { /*2010-04-28 TA, also make this work with rmatrix*/ tempname rcsvaluevector local rcsvaluelist if "`knots'" != "" { local i = 1 tokenize "`knots'" while "``i''" != "" { local k`i' ``i'' local i = `i' + 1 } local kmin = `k1' local kmax = `k`nk'' if "`nosecondder'" == "" & "`nofirstder'" == "" { forvalues j=1/`interior' { local h = `nk'-`j' local lambda = (`k`h''-`kmin')/(`kmax' - `kmin') local rcsvalue`j' = ((`k`h''-`kmax')^3)*(`k`h''>`kmax') - /// `lambda'*((`kmax'-`kmax')^3)*(`kmax'>`kmax') - /// (1-`lambda')*((`kmin'-`kmax')^3)*(`kmin'>`kmax') local rcsvaluelist `rcsvaluelist' `rcsvalue`j'' } } if "`nosecondder'" != "" & "`nofirstder'" == "" { local c=(1/(3*(`kmax' - `kmin'))) local rcsvalue1 = (`kmax'-`kmax')^2*(`kmax'>`kmax') - /// `c'*((`kmax'-`kmax')^3)*(`kmax'>`kmax') + /// `c'*((`kmin'-`kmax')^3)*(`kmin'>`kmax') local rcsvaluelist `rcsvalue1' forvalues j=2/`npar' { local h = `nk'-(`j'-1) local lambda = (`k`h''-`kmin')/(`kmax' - `kmin') local rcsvalue`j' = ((`k`h''-`kmax')^3)*(`k`h''>`kmax') - /// `lambda'*((`kmax'-`kmax')^3)*(`kmax'>`kmax') - /// (1-`lambda')*((`kmin'-`kmax')^3)*(`kmin'>`kmax') local rcsvaluelist `rcsvaluelist' `rcsvalue`j'' } } if "`nosecondder'" == "" & "`nofirstder'" != "" { local rcsvalue1 = (`kmax'-`kmax')*(`kmax'>`kmax') local rcsvaluelist `rcsvalue1' local c=(1/(3*(`kmax' - `kmin'))) local rcsvalue2 = (`kmax'-`kmax')^2*(`kmax'>`kmax') - /// `c'*((`kmax'-`kmax')^3)*(`kmax'>`kmax') + /// `c'*((`kmin'-`kmax')^3)*(`kmin'>`kmax') local rcsvaluelist `rcsvaluelist' `rcsvalue2' forvalues j=3/`par' { local h = `nk'-(`j'-2) local lambda = (`k`h''-`kmin')/(`kmax' - `kmin') local rcsvalue`j' = ((`k`h''-`kmax')^3)*(`k`h''>`kmax') - /// `lambda'*((`kmax'-`kmax')^3)*(`kmax'>`kmax') - /// (1-`lambda')*((`kmin'-`kmax')^3)*(`kmin'>`kmax') local rcsvaluelist `rcsvaluelist' `rcsvalue`j'' } } } /* Derive last spline variable */ local rcsvaluelist `rcsvaluelist' `kmax' matrix input rcsvaluevector=(`rcsvaluelist' 1) matrix rcsvalueorthog=rcsvaluevector*`Rinv' if "`scalar'" == "" { forvalues j=1/`nparams' { qui replace `gen'`j' = `gen'`j' - rcsvalueorthog[1,`j'] } } else { forvalues j=1/`nparams' { scalar `gen'`j' = `gen'`j' - rcsvalueorthog[1,`j'] } } } ***Orthogonalise the centred scalars** if ("`orthog'" != "" | "`rmatrix'"!= "") & "`center'"!="" { tempname centermatrix matrix `centermatrix' = `=`center1'' forvalues i = 2/`nparams'{ matrix `centermatrix' = `centermatrix',`=`center`i''' } matrix `centermatrix' = `centermatrix',1 mata st_matrix("`centermatrix'",st_matrix("`centermatrix'")*st_matrix("`Rinv'")[,1..`nparams']) forvalues i = 1/`nparams'{ scalar `center`i'' = el(`centermatrix',1,`i') } } **Centre the spline variables if center specified*** if "`center'"!= "" { if "`scalar'" == "" { forvalues j=1/`nparams' { qui replace `gen'`j' = `gen'`j' - `=`center`j''' } } else { forvalues j=1/`nparams' { scalar `gen'`j' = `gen'`j' - `=`center`j''' } } } /* report new variables created */ if "`scalar'" != "" { local type Scalars } else { local type Variables } if "`dgen'"!="" { di in green "`type' `gen'1 to `gen'`nparams' and `dgen'1 to `dgen'`nparams' were created" } else { di in green "`type' `gen'1 to `gen'`nparams' were created" } if "`knots'" == "" { di in green "Warning: Only `gen'1 has been created as you did not specify any the knots, df, percentile or rmsknots options" } if "`orthog'" != "" { return matrix R = `R' } return local knots `knots' return local rcslist `rcslist' if "`dgen'" != "" return local drcslist `drcslist' end /* Gram-Schmidt orthogonalization in Mata */ mata: void orthgs(string scalar varlist, |string scalar touse) { x = st_data(.,tokens(varlist),touse) meanx = mean(x) v = x :- meanx ,J(rows(x),1,1) q = J(rows(v),0,.) R = J(cols(v),cols(v),0) R[cols(v),] = (meanx,1) for (i=1;i<=cols(x);i++){ r = norm(v[,i])/sqrt(rows(v)) q = q, (v[,i]:/ r) R[i,i] = r for (j = i + 1; j<=cols(x); j++){ r = (q[,i]' * v[,j])/rows(v) v[,j] = v[,j] - r*q[,i] R[i,j] = r } } st_store(.,tokens(varlist),touse,q) st_local("R",Rname=st_tempname()) st_matrix(Rname,R) } end