*! version 3.2.3 23aug2001 program define ksmapprox, sort version 7 syntax varlist(min=2 max=2 numeric) [if] [in] [, /* */ NUMpnts(int 0) /* */ Line Weight noGraph GENerate(string) BWidth(real 0) /* */ BY(varlist) LOWess LOgit T1title(string) /* */ Symbol(string) Sort Connect(string) * ] local gen "`generate'" local generat if "`gen'"~="" { confirm new var `gen' } local tmpwgt "`weight'" local weight marksample touse local weight "`tmpwgt'" local tmpwgt if "`lowess'"!="" { local weight "weight" local line "line" } local sort "sort" /* Force -sort- */ tokenize `varlist' local Y `1' local X `2' tempvar grp if "`by'"~="" { sort `touse' `by' qui by `touse' `by': gen long `grp'=1 if _n==1 & `touse' qui replace `grp'=sum(`grp') if `touse' local n = `grp'[_N] /* check more than one groups */ if `n'<2 { di in red "by() variable takes on only one value" exit 198 } } else { local n=1 qui gen `grp'=1 } /* Set up complete. */ local bw = `bwidth' if `bw' <= 0 | `bw' >= 1 { local bw .8 } local smlist local lsymbol local lconnect local i=1 while `i'<=`n' { tempvar subuse qui gen byte `subuse'=`touse' & `grp'==`i' tempvar Y1 X1 smooth`i' quietly { gen `Y1'=`Y' if `subuse' gen `X1'=`X' if `subuse' summ `X1' local cnt = r(N) if `cnt'<3 { noisily error 2001 } if r(max)-r(min)<1e-30 { di in red "Range of `2' is too small" exit 499 } _crcslbl `Y1' `1' _crcslbl `X1' `2' /* smopt=0 (unwtd mean), 1(unwtd line), 2(wtd mean), 3(wtd line). */ local smopt = ("`line'"=="line") /* */ + cond("`weight'"=="weight",2,0) local estpnts = `numpnts' if (`estpnts' <= 0 | `estpnts' >= `cnt') /* */ { local estpnts `cnt' } Ksmapprox `Y1' `X1' `cnt' `bw' `smooth`i'' `smopt' `subuse' `estpnts' if "`logit'" == "logit" { local adj = 1/`cnt' local small = 0.0001 replace `smooth`i'' = `adj' if `smooth`i'' /* */ <`small' & `touse' replace `smooth`i'' = 1-`adj' /* */ if `smooth`i''>(1-`small') & `touse' replace `smooth`i'' = ln(`smooth`i''/(1- /* */ `smooth`i'')) if `touse' } } local smlist `smlist' `smooth`i'' local lsymbol "`lsymbol'i" local lconnect "`lconnect'l" capture drop `subuse' `Y1' `X1' local i=`i'+1 } /* Graph (if required) */ if "`graph'" == "" { if `"`t1title'"' ==""{ if "`lowess'"!="" { local t1title "Lowess smoother" } else if "`line'" == "line" { local t1title "Running line smoother" } else local t1title "Running mean smoother" local t1title `"`t1title', bandwidth = `bw'"' } if "`logit'"=="" { tempvar sm qui egen `sm'=rmax(`smlist') if "`by'"~="" {sort `by'} local symbol = cond("`symbol'"=="", /* */ "oi", "`symbol'") local connect = cond("`connect'"=="", /* */ ".l", "`connect'") gr `Y' `sm' `X' if `touse', `options' /* */ t1(`"`t1title'"') s(`symbol') /* */ c(`connect') `sort' by(`by') } else { tempvar sm qui egen `sm'=rmax(`smlist') if "`by'"~="" {sort `by'} local symbol = cond("`symbol'"=="", /* */ "i", "`symbol'") local connect = cond("`connect'"=="", /* */ "l", "`connect'") gr `sm' `X' if `touse', `options' /* */ t1(`"`t1title'"') s(`symbol') /* */ c(`connect') `sort' by(`by') } } if "`gen'"~="" { qui egen `gen'=rmax(`smlist') } end program define Ksmapprox args Y X count bwidth Ys smopt touse estpnts tempvar W capture drop `Ys' /* Args: 1=Y, 2=X, 3=count, 4=bandwidth, 5=smoothed Y, 6=0 (unwtd mean), 1(unwtd line), 2(wtd mean), 3(wtd line). NOTE: bandwidth is expressed as a fraction of the sample size, not a number of sample values. 7=number of estimation points */ tempvar revuse gen byte `revuse' = cond(`touse',1,2) sort `revuse' `X' drop `revuse' /* touse sample is now 1/`count' */ /* Using symmetric neighbourhoods. `k' is half-bandwidth. Initialise using points 1,...,k+1. Delta is distance between current Y and furthest neighbour in the interval. `W' is tricube weight function within the interval. */ gen `W' = 1 in 1/`count' gen `Ys' = . local wtd = (`smopt'>1) local mean = (`smopt'==0 | `smopt'==2) local k = int((`bwidth'*`count'-0.5)/2) local i 0 local j 0 while `j'<`estpnts' { local j = `j' + 1 local i = round(`count'*`j'/(`estpnts'+1),1) local x0 = `X'[`i'] local imk = max(1, `i'-`k') local ipk = min(`i'+`k', `count') if `wtd' { local delta = 1.0001* /* */ max(`X'[`ipk']-`x0', `x0'-`X'[`imk']) replace `W' = cond(`delta'>1e-30, /* */ (1-(abs(`X'-`x0')/`delta')^3)^3 , 1) /* */ in `imk'/`ipk' } if `mean' { summ `Y' [aw=`W'] in `imk'/`ipk' replace `Ys' = r(mean) in `i' } else { reg `Y' `X' [aw=`W'] in `imk'/`ipk' replace `Ys' = _b[_cons]+_b[`X']*`x0' in `i' } } end