smcfcs/0000755000176200001440000000000014062674212011534 5ustar liggesuserssmcfcs/NAMESPACE0000644000176200001440000000036214062657540012761 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method(plot,smcfcs) export(smcfcs) export(smcfcs.casecohort) export(smcfcs.dtsam) export(smcfcs.nestedcc) export(smcfcs.parallel) import(stats) importFrom(rlang,.data) importFrom(survival,Surv) smcfcs/README.md0000644000176200001440000000067113757721034013024 0ustar liggesusers[![](http://cranlogs.r-pkg.org/badges/grand-total/smcfcs)](https://cran.r-project.org/package=smcfcs) smcfcs is an R package implementing Substantive Model Compatibly Fully Conditional Specification Multiple Imputation. Examples and further details are given in the package documentation and vignette. To install the latest GitHub development version, run: ```r install.packages("devtools") devtools::install_github("jwb133/smcfcs") ``` smcfcs/data/0000755000176200001440000000000014002404030012424 5ustar liggesuserssmcfcs/data/ex_cc.rda0000644000176200001440000010601314002404026014203 0ustar liggesusersBZh91AY&SYYզSfZ^xDJ R,QUD钄TPM:RRᄉwv\V鎣"{B{wZvwh]4kmVvΪՕQux^_t4ٕݮm Uֵ׉ܦ-5=knܺVm.ʔQu{V{CsZl:uG;c%^'zӺzU?A&Fɦɚ&&L& f& F22`dщ!`44& L1B*`ɄѣSab0hx 0ƀ& &#i&MS0CFMh2hS4 LL0iL4 `i022hdCC&2dM)iƔ"L4hm#L L2hz4i2bdiFcM2M  eO b MML14i OD @L12`*~h LiL S dH 2hi0 2`4426bbL #LLDA#$HM0)d=l ]3DF'^Kttڕ}^wl+W"^ik(BYz'CD;0_\HnGZY?fBެ 6[b`_HALx,tKorW|mk7"v|>$D5Fjջ)S'9iLeC+ >A"iV]PVT{r׹[^ bŋf^ҚLՆEq;#:Kn HS3d]Õ&y`Nh9@Tqu`m{(ތ~n{b=09m`5SK~Oz2SI.:ܶ/œ}QE[j_$Nrm~VD#! l0D@6" #I D0B4l׻pOмѡ.""&T8F`ql*qRsFhDf@Б얲\Ɲ71Zr?$z(iSC4t UbzP8?4E13YDrFeHhq0X# yJ43Zh "fk| C$\IR&R.?,4s9;g&JvL>>\az!!jaǛATrGhX:$,dQ D &"l9~&C_cWC<ur8Aw N<SdB}!wK$ !8B `._ A;{?#o I#Q=Ex:&4=z zO9/ƙ$vr#xMrCr8ӑ$9?3Q6d"OCKLvȢOHY4) ii5z;QG{1Ip Ir\0$˞HfH~D~-g&}G4ij-F/Ξx jK 5c wIi=Bhٖ^ J^KYj) )`:a9c6[Oe,;%^kΩ <[ RP`J`:ЛJ-l'NAS^nL/d6##$8OnH\o_ x&ɳZaoϰ7b0:dNq<'%MF?EȢ7"{ż7gI.l @30 30k rN _q)HR ~#Qz)Nq)H1tKIi7&$1G轗1?g{;oNx7;R8ĝ3E9f$ߙq͉.D?qߏӛPǔ'4;%A>K|l(OYcA<ӀiɑiM! kN9-儦&N [!K#Y#Dz=<k-)a8gcGA$ a h~9F0Dt(K!?S7f<E 9唲o 3q 3 Fq R%J."q ܔF8d~'8xr>& !BF| N.G?cp1( @H3~ds(˙B=Mp& Bd"M$?$A?kΙ8'ȢL9LcȢP|7D` "$"1"'%@}shVgGYs UUq B(sH@Q#?'lh;$>@UMo rd$*j)Āhf~(ڦ %7λ¼Fg6ؠ1o C G#GXPq鷗+T_LU%ߒ'CA#U`֠zz$vHuBH. axY*?擛`Cf Tqh6n1G`Y*zH,qa;4ի΍__?nG6@78d~AהwKg@N"KPH6 @r B3[__Gwa;Q{ܢ+(v*d< qjASѹjAV?Q[ }{PD(ʨFD@6(\&]٥pg:*_Ka)P2ȁӓa嘢 ړB00RG;j~~D /ʂOVY5BDΒ#\C-,"@q|lKq.If_gFm0C89( s`h*67z\kѩqԌj=;aoLN(PH [ƽ R驩~* "a=nVBS]YFzr:UjڞKpև 5@ O %lĴaN>&ӇLK  Q~&3z ➍ߩDΩ@[ &m¢ YHuy0?t65*^LuWH` )14IhNPCz`nkfUftm41B1Cc*4ެ^d-ݐe`;LN3EuBڅZ A`ڪ WoϕtwJW* 6D cO1 [g. A80~ ǃaȃ"rU*cΩ2~ߓx" E,~s`F]{ۖ~B2[MtqPrk0dR}$QS'wSi؂B QHg+4imw :G`s^Oؠ? C^tJx9%`ğ:5qUByQmWZ*_pD?K܉U"TXޚrBgĤ{wr`9eo% > +Oo^  ؠ?5I>2m$EqDU:,/&<4wKº;tG#㶭G B84}}H?k]Suq/ﭣʡoëcs jCx]OSGLQ7 z-6_U#{ DZ eѸn3J|y۱Li:bN&yʢ|̎+88BFD́#w3$ #k HFHV\f\V'Ms .Q #Ce$Do=GϩAq]}&xn3A _@h-/)hGw<)94 sҠҞjLݫZ~k"lVCw[gpx|h<$H\T)yrn2wLra\|mu!trjxGKҙiCin#igӕs -e6!ԡ,J yzEaʟ1њ8Y7##2OE@7Ghg գhPMGLP/ y37]ѽEx{.]@0*'_A1;1URwcEa1+b9]J{vvlcʦjh.DeZ33E}ݏhH|gRx2yb$",93 5elA[Ov[u|4&`=Su|׶)TpQ0L\9D㒜& 3QݘbcQљר|Gt .ՙ75j&vx(84"@&4Ne2~E$@KKߜw%19YǐݓPB*Db1朘YD xr,a6)lC*DyTD>%njhS#]_亯Ɔ=ٱ߼Y;{~Jd;}9zOtIB Y`Tgi RTv(OY24 ^[共в0%.ݤI-wfCP(j>lO%ٱ.SnV5m@5ityLԴQ;pmEY]H@cq]WԋX?4ۉ^q3҃ʝ;>qX`, d~]ޛŦLcНl~Cn6ܷ=aSgmlh.VN `>|h75ΦPSmUa@HyD&'taw9˟>jw"uO*W:Zٚ6n=ɱ)>E?L9iNOu"Ȩ>pqat\:g-;aL.Vk̥z BIJ. 2Мɗ"@ʕc2=" $3S"Â@d$'j FwyIחzd!V"ަ. ">%b풕{cwSA }kg>"H=gNl%<Drs?"mh(DN欈,-r<u.^/_?n}3 *bX&_ޅZp y "gh'63K4kiPX,-{8өy }GYԩ y! :6h30?|NՁ)b!ASRMC58B)0u{YBV:|dPHt1lK ʛ }-L;9lQ(aBmO9 oaEa"f0nQT"mAhH LE;h1Q>N<[7=f/ãui%+շ5^i8+EGR_Y@S_Ȅ@ (|r=h0DM .b$ :] .% (ԙDtxP\Hsv߭a2&$d_Mg6`H,Ep.l+(j+Tц6C`4A겚o$sImjFɿ5I:QHy~, ]2)m쉙p e@/v Wum&J広ƿ\a]“*.)[n/ q+bҰh CN>AGƪR>4pqW-^&U`ՔHZ: ͟YZ!ʏ<%͆@=][cnXSJ}Pâ N7mh`h.Tbxij+ܠ⾋P! @,hxu^0}.eTr,d=/Niar3F%FSАkGh&bV[Mߦ=C _UGKZÕ`}jzT0ūX; &ri_;CX=kAZ#( v)0jD4.J4Qv{Cs:?Q仰mp;KW}^<#Rc]hYA1v2F|<'tr70ͦEp. U{Ssa,`M>}Ñd&KבO5eP(I%vl^{Wi7NrRzOAƨ6ە4bgs81[s ohT)yZs<2VN~W:BKwh"P&d{+!κ>(&C0> ?plb'_EhEOSo vyKUɢC)+WdtNLM)SQ9}v7*7dqLE)/Jߖ*SI$>$O/Ԏ3mP)FKԝoc3#XJwiE y.?V- o6y( L-Ar ?F9bH,uVW5PEݻcSwo @OΛc8?4駘TLvav.V$ޘw4X OXIM;3=3mb l{/gnHG#'e$#~F@I~ߛP` nz+ Csc X%HԺ#99VFC ,XW^ĢdVׇ-E )Jui vަ} $,[dվSUB ;6,9a֗[=̓B8z@?y >MM"(Tg?آ-ck)̨"|faK|{zѻ=~[]:I;MJ76Ui.,VIʶ@H,#H1eַ6ÜquO8ۢekb{O~= }Пf4 Oe>rW d$PRV^/rN܉V(?Z/}ɮQDjcjgVL#t?(_*٥B!y>@PʾycO&heu҂0e#Ń:R8kRWYRl\̒A+B؉.Әp=Z_j19_G@;todɗ3?](m?=ςB7ϊu' V AԹW\%Q,rvUBeJe7[{Z2PR4ywg jޛT*4Uñi?-?|,9& ~W$JRUrX=dߐ5icoeٿj O5w.TeS)BOcfdq3p.0l*B *}c %w l&SC鉈 ͵ط: ]}:I6~Ţ\<_m4+[>ӫwP:;Rr%cX5= &^^gW:RJSBS#f\>#lKS@}`^b8I,_X;` 9M5*5ʮT$V)mQ{m˳+ZL$l+ʚ toPg hjuRWsSd0)~ɦs:["ҼWjs r$֩=dSq b}~LK e  /;}$y>g2A Q' ~?ЎɞqGܡ$+NjxAA #~^у2@XyawH [f 2!zIrO 9o]a[ >Z<ӳEgkշ%Ϝn2#A?3mqn'9ҒC!f"_'۫sV֭xKӝ٭6` p RnoOS u^>oCSdf^Kl_+&vq) x7Tƙ^%  |wmT]0ퟒPt'Xuu[mvtĿ$cQNs&UMv`~4bڻʲĺը4*F JǵEqݱS̄k@t,`YP_duۗn!R:!V`r9x`GE[~MKsgUztjgэ+t1/(O$.YIڰp~(ƫgvȓϹ99/RqYb/Wes5}NJbxa onNNxm0㸝 iȹaqֵ5|_ s2|O!b3/\ ئMԤ&&cRRV>27EzZ9 wxKոoWA\a!Xg/'p&ݬ ʥiWy}qѯP bq(F'.Y?[ ^<S!("f+^ D|^̊!R*0Z_J3;.сHsE޸HD!C GT6glz~ѪldD!Qr$2|'4xK6SRqRNNSvWCٺH_(jEO"h0 S(MԤWWi\獎?ψcG8n2&ʙnymh$c(3,e}T7cNVѝ "K[>1"1 (^İ7$ңLYq`'|ֈxxGP oЖu鑮'J9Рґ t92:M2di9"G32/^4Oxf~vd/7"GŘ⹲;C&?t$*zNAK,˃.[@1D^v\ٸ̫(^vrq<Ҡo-LLWImTʵ]#}*?bfY"Dפ7o#Y4 8Ǩ-& ŗ"AZryaё>,IJW4ۇk;DQgAZ 'PDDT@XAib0 P8XAHaRB 2R$:P*PaD`P,RP-Z@@CJ* ,B DF ,.PHX *XK !`Bb4XT<],qPQ JU (QU@yK(CIuXƔ  @%$P AD @5Z UP!P8T15X `("҅! @BZQQFa$5ab" B#KWc (I 1AiuPUkQBI!WUb8",R!ҍ@I|I$ B#Q_5CZD`$ `x$Q,*(F!` @\Db0" (P1 (@qI`R # F D-FBUP iPXH!@!$,GQ@yuPRP\D*VT@X$(PXˆ*>T I!ŒiI ATF(],BUuQUƢ8UKQI *B(G:B:@^DTwVx@(ciR ZZ  + E Bj X],E(KRRDW$q,$[#âXv']]⽀^38(͇LGkzFgftg=@cɑTl?p1UUDyCM ėVVwy`6ߑwaQ,)669d~^atLF )>s8ge)5~M;9&̍Ev.-v!cEsxEJO+Ez^5zUh7)zeQ .0J S:KcR31i];Qũ">_7Μ*!`i0 vݳ''7!m0) aA`L08n3?CቑpvQHbDeU=R֌G]_kc5SLQ%u9o!0D3Oc8'-2/D:]]pRtj饔PqHrHÁ-Vly{7jZDPA'w8BN'$&OW#`m-O|J^Rd+7T3>@7Z g`%n.63eF9ѝLUqwHS\. ‚VѼJ8x,ի?WօhP48pk~ pˬ~>j0[kSg*\iX3aW ɚU*+QAR.=_0|\3wX9IMŷ2-vψJEC = 2X."$QZ>E1vc7JV@(B8”)zsvӗ{v:?`iLpvQߖQccBӝz'(ˇ)+ /?vQu]kjLgoIyӑyf*c,=`m0K>T߸ ^iX)z>Kf/x+Q0ھ!RXzP夗0-σT|2 #Q&Lį`ݑJ|Cd a` m:(k*soK`ƪQhznbTÇ{eY*ʷ ReL>#BbVy$Bv%?K?zTБ9+Xm)E짽,RV_ziފ-: ].>:2G2UKI]~"? YJ6 rYmA[*n_,"u+n #w {։$7F._7>i TiN7G=m[EX*/.e\Jǝ{{!9Ql0j>[3wf/祺ÈO)k+ӵ`SU2\~ǀEJT~juVʗLUM*Z9`Hs:MH6:|^WQzTۮ4lsiN^$7<>bLj,mU9"d:~k^->0Y_܆],G#ve1Pne8z: -il' 2 'Z %\.S30 'kJ\jL R$t^Ys2맗3aߞ;0; hHbCyG6ZG] ڎFj2Ї?9Ǿc.Q}rSh;jOl3DuJgJ%@&pA0:߰],E ?[_-ff CL|7غ(;9|+DvZOC'c ` N+wOqu-~t 9^i 3@!mSVpM"60)N̾dlzgؤw]b&d``}vDHېl~n/Jcj9.S{y""yo\i',Ծod$5z[ GZRXv(NR %aT捓~4&x^\H Naunr} qy͵*˖Y  _i/pW\.6~fc|^JOCH͓e1*]F{n(! ZyES=r?e-8dN|l}%[WuQ^ vj!rjd,c%S$j0?Xa@.lyυh19}1j|QijcO7t?{t3Ww&?hD${/cJf5.eԸo3 dVu>+_ml!"QlHlؓIPo:Ws;@EFk4T"lCNkX0yO=z6Eߧ!hE{yƬ~2>sse<;iňB\ۑ绿3f]!10̷}V=RnvH1T6ݣk܇=y cQtf1rvQdw-)[m{^"gE^U4`<D&wba -LU\(|"}МW[Pha^s_%3؎h LRFtHfX cڰ,1v)U\2j~AΛ9D#obZդ̒ ^}ySXK:.7aiG(#D\ ;z,RQV8J(Q@QMXǚh0hR7W U"PL\fkxsGJZ똮 YJ-Ko?'!_ ;a8* Pә]nt!z+W:Xj:k7 ږ=7&f۾&] n*?!-DzkHt'? +s y4A1hɗ~)l7D<%"F(@WP-!Օth'zqyn~mWG(GAlT|(Sq M Ph ER)6Nt7`4՟T*ܐ!xr"ZY"YYdθ1ֽqjH;;qM-Bܫ2H?OuSqGo>5$M,3E46f B]YvCUS_vy.8z-v=ׅSA7|H'$-A5KՆlR2*\PZ[$Tk&-ƅPZaBǕ6Ap/Caqn??QS[F}^$U 1NNl|VdtNݖR73~!EBNo$Hl!x+w*.c'#V8rE;GskM Ǐ9e/6KM=c^GoL;M=wxIpzumu z"^mĄׄ  ޾Ez&^'қxjɕCIzd^24q+M2=\⛛3vZ/zS Vi{QÆ[0\Gڭ8QL1T40S1Mē E͆Yۯi`̕Kbk١O ʹq5Y5Ay#CNDwoE V}]t^wDZ#$݆{i?Zy'kN;D¸ni@ @N?E9,3ܭhdUe5k]cܽzg;;><VRVw!~&_~Z^}6?V}kBTKw󛛇IG=Jbt⺮64wl֑IR4}͸/(;8`Z))cw- % (1J} e 6ыFG$U4&G0ۍgZ /!tfpgW-#Dh{?z/wc<_iL\n-ݸ2~Y9K9r},-:Wߺ:g}0mD̕Y?uBxxBN;l/1uNW7()J{]_ )X"{d-Nڋ.4Xmd@p88J%5(G+Fѷz.~^f+>  ޽:l5p\r4NW~p1*[x[<)Cb@Ԉ'{uvsþմwעȦ98m)!V 6,B)G% ӕdb`LuKة hF q#C(U]O{u/X]J6R*wh{I^d+kQ"TӉ #3}3:l4^ZpsyBtf<7J" Q)x@eC574m f|w21g=̉FчGOm`Il \G^ o碕^`wt"%Z}A7 /xt٨Dޖ*Oq7ך?GݣF:^KfLùsIG~vhpEN3t{g;*yS` "e :/1EU8ai/s-M:V%Ƀ/YOU&kk7n?iZe°k{ןmۢ SlEϮcΗ|Up$͘ɖk`1q}r9a\u NZGY6{J rCOBa*̀Wlʣ;ntLuU9X1| S=NZ`3ޕ41ZEF6- k?! Eh*@ KTDou0/sbrb2JҪR*AI#|yHOxsрP9^ y-j?q&0^{XYy9scٕwb/_" @By"mo~sUԪKdڟr`;`Ɓk#l+>.a!i4raRPmF:լk1{.p^nO?#~;(? JPmhk޲ )+ۏ^G |J<$} ,f| o8O*5г&Vyl13JjHDSc0="IɔAhPI7zfQ.o->Z;xTRF, R6krsCU^[LR^޿oTmf.6R qZ&u3cYt%sb_Po |.-A;"$Ѝe4QŰ4uw'{]YgoOdZ 6hԥx d]V.!|^ *j(Fh*b m4e9%kT<0Z{uT)' ыԮmGqJ(3*+h焑(:]̷?T*6豠^ct}\_[f Gjp{%mJ"mÃgkXXF$kC|Or8 ;<PE@Ҫ%A+JH aLG<_idw'LWDDD*"} 5JXG53?_UMڀ]5v$뭟)D]M"*ێT$}QwK7NSQb׬٨l7VoCQ"Y5WK1F-Ul~S)'Ӵ+]lWZ&$aIKc*391hngwW w7JCo곓n qEZCw֍\| z/ςA2>8"p13*+ØP$g]ěIan\rMsߋ%;J钚8vxrɰ7&$&jW-U @,S {9ŏQx5e47SIDVxQ0ǽYU>S.JU%d:Tν|+1$ c=X6ot ُX~N>yew~[:mcg[4O-{mJXnk-1%wu;r^%({Tk6OSuX0>f524''mO)o|x{>zB]MLԹ|@ؕnjo|RWʅoqj`OL `x ͯ맂FxB5!L߂>A.L/ q_Ky2jӤ%ޖwg4!lf cFy_Ffx;+N4Dtw/ |1srM1|iF,8UGZ*|8Enai| -5cŪLJ랬xdMm\hI)T:5 3NRW*2Mtfv{X/A-Y~HsFem|&~Qcv_13 JnVXO+͛hmI tgc_w~2I2Vg$#Y#f)e!\\N-w…;f]F,SQ}M6j2=kȃ*:9H>i-Ҕr 6Y,^֚AA9eR^Hk⑫֮e- vD8[ws=͝z:\v(4灻m-g6silE B 5x;CȨk6(]YP+4lԕ0)W='8Ga HQ0iƁaa4^hacV:h%t+bƓIճ52vJ.8JD)aHlMGOo-ضpa*8cAL~D(hڟ4c"2Ao}5ѐ*dXp%0Wz" ;)êX[\HUT}+zYE =Kͩ,V !̩bsإ,^xzvqɉUHAd֖峦<2đ{O4.5"D&3Oi8+:: )P/tUH|;BFZgS8 <'滾T\y9A+%o_4p; xlzVƐ]JdaD'G`v6+}سL^hs6`j4E1S&4HecsSt6iʒ"}9HBZοx a5R˩nZ%ϖ\H 쪮M;@7}|t ҏ| R]hLZ'dd2 w ǂPwn`P| .`{v}/!:Q.Il-L}*|}A'›wZ]D7l`ÜR SC77x^ ư3<߯PЕ5-Na:@Ch9TG6OSi}N!GkJ\9ezvDNad+@1emB݇4bgor+>O†r!:0] " b|=Gbe=-qX qugFLVӱ>Z;F^dc؀bSrI~;Î)Qzи߼e8 +v6Ng8~]G K(9Bu'֯"򇒁'%vvQ,&qMBNO'*=`48A^×wgF":uo&3IBdR:Rˏ=F+M/G?(;Q9ie ss}+iöW7Hi`~fr>v{!Ң&X2M+~J-fxz:M?QC^zf MMd}~6VM[﷫?3\rIt> hC/T)ǫUޣu'aQC$V3f -{ֿ_ GhBH/Ql>A[lHOۤmײHϹQUYNmH,~ _n{Yy@{?ݰ}݊ӡicrfx PmD \hږ=k˵Wf Q.$ YROoA& {iҌG=?T5y5z0$\Pة%GmRpi 2PB]X} a*eGAvq Ã0~/=̐>M7d@jyWt*/RxߦX9P^9/npOp?Z D%PF;cb(|!ѤU./ofZCa1̄cI OFI71A4yQJ"RPz Pݚ#m>-5PBUc9yH!?[n:܂yy͓GoYqg\kZ-Bi]MRhh-\ݱl2| Ʒ]歈Q&t!j&l4)c<_dpPH$"`=w=h9V]dSge0VTa>M&ah2w؃uzfAcKk)6B] w:B(j&iTÛ0 e7af[2p3 -훽^XsvkU"u!O6lmk: p \'GDI+q|Ƹܙ8+" H/B GPLzV/錠D,W) mQ3-Zo0Ds7e;M; Obtg#7-꿈`/­dIt0eI =wT=d^YH4O:lV5/9aǑB>F(_^627/+7El '_n͑^0 7",wPW,l+rn^o>]+{S9x9:'TJp~F*giFXHZƀ,?n*84G9ZBv?cy0~Tb˭~p9Bj.F.շrVAH5V2FXg?Se Q o`LP(5glHӖs;ᤶFA#EM #YqKW. Q_oPDGxMG3{@_IHC?yN4UX-zMwQNM>,#d#0.*Dp튡P}@ȿgD[rQ <ç]yKde e})1/TzU /s}-؄to5*20zq& I>~b k{1hN0F+MYGR5x83AEn'?;Pގ&`)t!DՆQC@2&UvϬa8 ` .xNe{h5R5-Kg4ɹQh}3$4FL =E(,aaK;w͊?Bk%"oܝCè[vn.M< 5(qDFp&6v1K @41}ɹ-!O#22=pu~Ѭ3rɧ4JmӎNWP4c6Sީ9A>劋LƋ1#tцh?:ƅM]GTxf6d`_}k0FCQ#:naQ{An|Wk}r\eapu_g{n9 "<fdEX `,w1v1vJ*OCCqmUYuw-:Ig'{x@ZI8\rrB k=ܛCZqKVu3͞oS$j?Q"u x rMONƼk/J 1`@凝?[ylqJAmwO,}n[J4W/Ctpq"yA"#*J}apG#T6bkg},<# [-Ld!$5;K!«;N1t85>ط" {d/l;͟&.r iB |F#aP.g*60E<^tW 2.cOlmdhH&4!)c8}6Q+EPL+:Z譏LAB,`];z/-gk=2Zt_|g޼q]Q:477 =_ǵJ@]E:[H4P @hY=Ù:"L s:$y7و@F<2*c@]7!5=bz0]X6>AȪٴq,C"vxhI.»TLwg myZsLQH@Uqf)% ,Da R %nBXgl1$PBzFġ2@_H%9[f>_4@:T*,Y.Ȉ"#v4cuEf  }wMXsd lH7 |@kr*9Ȥ xB0cE0.$$"1; lW^{c!VKP,B0tO.^O^;"xP9Ny^+S 2 h!1aZ|W=ux؀Yq㬫)Ӽ׹@cA g*Hh3!^Bx >EK뢴>֠Gd^SJ[q;u͞AE_K̐}%??p>4{N$u^4[< 39,)>̨DNܥqsmZd+W}f23:/)YMP~%0(D~s[(u#K03Kk#`z HI>h"2Z(mejy3@4lzQ ~&,Rޡ6 jќqOY!GHM\,/ /SkG=l/HՆ+"11pwN~4c6LQ4&33}T5!zH8[ 0"ۓK~[qV,NC}XT r̻od85y˭ j5uѱZYBhWyS&Gm9Hq7v 4A\ b =vɬj#Y쯭tP0iH@9wȿZ:|8n3mU "Q 4f3V玢)engsKQ@Xnk3u# S} U5&Wj0d Q-)[VvwiƐSq|!]<"Ue!%eNgly|C5 JFe%j; [Sѽ ȭZPM-nѻJI 05}>쳱?FmβG],;ڭ<=8׋ߊ HͰy=m͘EQLroXP˥Wk!FA.EU|~V;pzkʎ]<2Df98끯5 =f?τh񪸪`}X.5yu^d=Ivj , U [Fn1Kf܅<Ұp'":V}ރv*e|:H'n7|ׅ|"f-/fؿgsqh9HOo__"i) .!j,]n|e{sZ1w .O3/dusB]N*Wm0F$|53_Esou޶!>D@D` {& 11Vb8i5#̆C[zetD b YnMO19^StU9F'jjוӟ5VME[+jr"+%وt\g 4Qϒ:?|S/Jb/ӐJtm$/%jQ H4P{iÚ0-1me=51ڎ;w@r$GZjգcd[t?ʆL z0f 4C’Gt9 2!!Qp Gu1(;z'L6C*wHl$_6[dMVbO^1r?Ļ3z|c2͠Lّ8bY3b(ª;w%VzHweC7Un;+E m ^Fy.y[j[YK^p$B +ԕE7zs L\bM?_,O7\!A `i kEd)vBiE` Kjج4aO_7žUG铪p'~s5|vAt^ʆX f~_%&ԗOЍg;.l#o-ϣ1bFHWW`F,ё‹vߢFh"EI(EЂr]wϞ"ta.wK8R7ͩoS˞S*aHbY4UYR5-s#,ҏV7UN=:BhRydhY1tEsSbZF}}{Agy!qqefn"chM4g=<*Zو!OP1ScM1:>}!Mv^i+P]c-Yٿ7yE:<=~. seAn6[;jC]*9F `pE0`h*$#H~zFFY3A/$x VMwXJ8(#, Q}dYdkHPˢ<6T9X1cZKsjIUL݉ѷbzS^&+Mӫ?bU'_ʜ5~"%&Xi\GD"C_)xI!5,u¦6#$/b]4i!p(>=̇/{>/8h4'!Ќ,AG @|NPM" Y|*'PM2QѥOL$9h`R_iCq_ZJmCHWwO)TAQ/ZCk,4u/k${;L| ۼ?J[b.uIhJrllSM lKw{fdbr:F"8}&<>V𛩉eaM.DԻXH"<c?D\mxkk)?LZ t́;? D" +tckI`S)1XzHHtNJZQi<:HA8ͻ 2UH|$7S+B&2u3Du0_1z[Waݶ;b N>A%鎵 ѣ@ ُjD$A.C 8NLD(.K$\K5mR\Y֬}'}"d07dҐ7`Ixa+&`QlY# :RHOVyD1H K:smcfcs/data/ex_linquad.rda0000644000176200001440000007743714002404026015274 0ustar liggesusersBZh91AY&SYfI!S_(k:>8Xﻻ^u즘ۛkumz{똏n3m<7nמ;u_^z^6{ms{.m\=ڜwݽs׶=ylπ}u>Ƹ;{'m:O^};6n+vvomVk{v۵s-]uZEGx=z@(P0 ɀ12i0 &12a4zi40 4?!4 j2`LLM0Lhd0&FLL0hhMi3& M4:jbbjiLfjy2jzaO4hɁ0aFF2Mjz0zMMLT0M&FMHeT =1db4= 4ddL0M'0h0LL5OɀM4dOɠjC*~LM&h4Ƅd`#?L# l&LSb4` F&4i=2b`E?F#a2Bfi!@M jc&M4Ѧ! 4@hmO@ hhe'>$  B  " @@"D@ D@@ @ @A A@@ @ @$ A$!A!@BA! CpDm^I2DHBa5p_Ĩ_A_)A;]Bez_PLKLB7$`gY=ŷQ[ $ک3/\tj94ySz4`:).V(ϰ-Ԙޚ؜w<~ ϩFM-KwIpWm,AsǓFnn.7).>FhlHjeMeFE nol#"t8ťx/o-njI" 8$4/SbS#^l_ABwpk~`x lE?^%}O!f$EKc: CΑ%m(/OK%a}dgoV!S$ίw{V؉vd * D뛡~\$5%NvmX/;,q*?\ϙrbod} ]rFR5 xf]Eb'g'4H Qcnf 7Z^|(q_}׆a7 4^{Yo\-MS7`U;DL?U@\Ӳv:t"`0Fd 5$%'Y[ιF31uZq mX=Mp4* d+kk$۬' ̟@jP$eJVChx]*0i0sdME SVYo92U,~ҧk'ngj U'M/W22R0͐ h]KES \f0(Ei×O,@3䥰tK@Ϩ 0A}{ )h>EC0D|d X\|&fI7=ԉ6^Q>[vgx]˽d, K )]d'4E֤gי>.Eqa b#֔h}0k.Sn /QUdZ&]32$xVGpṆ^ w=+hH8<TE ZsoI!XL%s4>9'BQtwni|Mq7*+0 cvmݢ,* pr]%UV-N}aoAq@F 毤SWztic!2OzY{jṲ_yoͽy<K@]m5HyinƗ+<8RrTC [}ɵ5V]:ˢ]@: %}bG!VȝHK}Q($ISEhXAW^ C;Mb(8)c^NKmoկx`eAWD>>{jO9X,9n!᣽M"IYM:o9lr`ـjfE$9qT]F@H83_,죒E MdM5StVMMr<"Mz$ /3<jM/ٙp( E-ogֺKAKm݂YÁZ]ˮtOb nv9$7@O04csG_XHnÕ|ZG7xjXM/nRHQG_O>UQknv{%aҞU/YN4a?AY Ëw+'ji:^5I{zccF=7h|$Ύ~Ύ`DSG  Ajҝ@nJzlW^z㧕gd{ۈjCXuGSnO:&AC>F[rJ⏋אEI(yao]Uܻ_T{MO LUo1VXc;+wŻ `r Ikb]#d)QWp\)C1ȣy溱9{Y)v'"IįݷOwIUAju=UܩFy6%mxɟtj$GN!441{,'5}5@bS{ۘL.F-;yQ[i-~凞CCʁP%t5ȗNGB?9X{XV%1\ a\|ت.\Mz눌|t{˨HHν.OpQS\vz/Kn.ˠS"H6:GL"XF(-`(3_z#[(˚jU;| ;L$/v+4&23s j) 2&L1]cד%:Ǐ"Ֆ_6&{il ޳> g0VR 4†O G,DN^ kxZ[EfS V7dᥕF-0x(Wڋ15Oh^doQlY LKpN,.%%=X߼A@_^M6ܬ;dutlr3\^uD5JQ_CΤ.m~'7[.y3ۑD%,s8 Le=izEq^ci__;P/Kl@H'`/&o#o@Yⷻ!~ۺAsHa-vgvm7Ϋt`|T|23P$rQ& H,, ;8KX\zTfLORbBEM $.΁CT ;m6`F(}ϗv "WAՅ96,:zۤ)Jޔ˥wV@qjn%> FO&X*,y"+Ce*|3vNKALe"t}B- r-L&*ZWPQ+XzQ*Ixve)\&Voi+2ob-ig$K\zSq IA<"$Cax+t) >Nf=IpMZJï7t*(wQ16/IGsyzT:VXc\҆,fa{.yZ׿5>PV (T^{GH @e>`) `hѶ6de+%I"Q,>JS4N:2f`5(Sg59Aŏ<7gu]I9 UGȰt*Au ?9 T6Ѵ`eQvtӛZܱIҡJ`9jæ2U?JOslGF*49!1J4s}t1MJBGqBߟ޳{jNfSu{2 ٪x_c9-l ],V'\tJcvћBpVeQ8P0?BFXy]ǏlchtF D+0f$h⇣&?`q!'FH.\ob橖yeXʜT$_wfڤwd,ʎz/0nWYekin9g%-P\ʚq(Q߫ &Zv',m7'3׍SWF +ׄ M$/PJCRuJ$]xB~E/k[V9kg bzc*2XA0 1P3ŔzqzJ* aǦHZz̍Ғ6Un5=݃`2?zTM٩^2g;&,zŖ@=)!b= -X:fcLDL5=ە6$Q&)nJT.#K 4O* G#zKN8UW{f/_sWAX*8KY~%?%=mZυuO]P+l̾3릓9 Y#s&jGMӯXnGT8l S7LVN}㮍/j"Hfp0{@xwPcI{*4O^\p ~ja@hKCJ FQшT-A #1 7r;PWOtE;;}pRZqꘀ..B{$ݑ?:; 2%I a7R 5;0pq/Cϝ3t\nPR8}m y$w'v?ٲ:3 '~?G,\8[}jKZE$8@gP+iDrg5͂\kҿQnU":|<= dX%/1zcu_, gFx&p{tM-AÎ&;f^֜@WAX `)PmqNs ubU)i(VRgheBwNS6XO|'b"[=7ϫㄽMHP T4 /H.g@ ƒ6>,$nqk84Ζv#%S4U9ew6:\[4<)F:63y?RPL?(8Oצ\ވ6.|%{"^4R+u|Q PYm'@Q;k& 8%j3C_JeGùtk@?+Eȣb|u͠ݲ/ܭz B)azė >\;M0K|I\4NYv`PQ>ݛϱVA ˢ xVb6=ehՁ;Ue'w~ВJP`zYnJCy܂%ey0$gӼqw!q vrs/ !Z8J3" o@&ժ@Wwd`ɛ72/4]FrQm:+JLKC4!^lb/ZLamܲY/wO |vbĎҟ {x%ӓT~4EoK̯[e ; p)D `)< @ddl䚯ߠ95BL`d ~-A[]4LMM݅y~u DƉSU u(8RL]˶W`0w?ahB’KAe5M!E;f>c]8e%vI[mdx)0Kx:^A$gO\W%O.1N& R_R _BSFWGv`1ߩe 4x9Rl27.Uv@ts{p HT6ʌL9- ".3(fxMw C QDxV C^?DʦƖQ$h@A &ܻBBIrf3Q;CڠD<(P!6aqEDE4Iq`Z@p54[xWڧ5Il$Wb ,KNRQT+s26^ U}68 R|ewDqvWQo_r,CaeHj:`n]DnZ0`!vdY!oQ%0lI6RgglN[<0Hp@g "nL$ɼᇙ-o5gnf~Z$)!(؏0qb#.rxr`'<>UiphY0C,W_Sб |B>@ Ap9+\k3dbI]Qn5~XybT? ^h-^QvM^4)%5eb@NI)x9]/ <1.s$ c(NoJUy8vZEBcD|f a $%?~z]jpɒߪI;gRW Ao/-aÊxu&hShS|/?yo:f`U٠5AX 3D !Ve[W w9%:LtHơ\Z&OT7#A_̭`*;dܒ"YsNMankJ̧N miBu02ٖ+ Ī.IX⾉KD؎gA.9i דeO8& WN{N?{hEN.T{,q6"(_PXQԻ&a@kt~ħ#rLW]Raf'n9AGkOtRsQ}3ae_2 Pgrڜ%P|0MhfsT+lVͣonFf~({M\&BnCvk qT]4L5;X\Ffpf"^xG)Cm(jۖt(=YI YWy{^N?"'g]LZ72-&a;@Fi'Jj/l:ܩ'iD.L-SU72j!V7KpWc[9+Ȑ簉-zۺ֜ӷXHgi}h%;m /xf8%|_t#?!Q 1QũEcdOlsF1  #4aLUgGpBVc9xǪƜ$̈́Ye@o<'tAd=? Xv3j"ovk('r6Y >Pϙ),D@4&cjNBr .ļdK.^4MȒM?4KL*uj9c.`-\DƸÞa1^)2k MR.å'>qсw\FK]"nvỵ7k5?69gvbdtO~zW19fYPQNaʖa\X/9dR(^9p/h>TzۭL)@~::Œ5m5aoոCAϣپch!FV.h02{m ϔw!9HŻNX $MS7#CSV`! #ߍt_JRJ)[,'z  QIΛ6?qJ=7r0^ΌZE :|qO{HP:Z/A?S5`_spovO+x+`G3}_?y2Uv3si]~XW}<#T3ƸUw)a;Z~jUrX(G̰˱9ېl>i=l) _kJR;i"VڏE G]7?CMȺdd_ND~wn}șrQA}4 H"6+#!נ| z/ۖlky[!=e<e2=3: MPhl +9xuZp$^xc+7:!{zo6"2=~/e{!2xpifxHVdGyqVJT|F'>>9rA+ Ӓ Qyru{ۧ2 e i*޵i/ #TW%`5YS*Yx,pKLսGQ\ky~G֩*|Zȶ۟Ū}rÁ8*t iwr9 UfQǔ&u4,JǤq,T@k~K]GI!Ю̠Ͱ#}ātM(jSfPX)֭ڥ%? p$~*vV*DQdA GMB'^'%3;g\Hk#~Mr(T',;/6pthN e[~X"LS2{b$!TS,ta.;!{}j̾ǎ &6DNNbւP5cf{6lRΤ#_[{kIL\ؽ%f~l \o ,BN_!ظ!J4PrEX (טnJub"GBmvqf[mk+V3/exj#l/B/Qah`-R+Nح\Y%eV^r^3kV9RviTa5:Bo7m~m9㺖 P4:bSl`|qs70kqxJ%؆J ^P?VL!7#\Alݲ(j`cg| 7y[R:yu3FpHIygCj[.׸^'>w1o1qݜʁyl2S%oV ؕ1QN1K{/6|5u=>8F'=S/aN3){_V}T#H_Bvscjvro\Bՙ줟Ѷu x-Sõ SzEV ;dU6l%ңG#^P9.QSf3VyxeyUW5gPAb]pl7Mjr~wcB^?UwC@],+2.56;s⌗ғ{ 9H [+:3:fYZ(op;!F< ݃U.S\ۙ:WXVR[g+?,!IPfJjk$N\P,NԵ?g@,`x邴Ζ16t qo~M;s;.`7Zpśԯ3 JJiZ7'];W6H8D?*RJ.Ԓry ktmjдmfڋ_yqɿCߗ-䡴oqxG?+Ntǹs0%"QOy§VG)&N/2Y1mҳ_1yL@D]V[#Jw<[ UZ2r'/B<\kOkS#9r wOFC1\+9qkʇd y ߠH3 tk9c?ΪnjmGNOTġh(C}wc: vg<3.(hbx~zȞ\Xz#- }ܝ<2=y OPW+*#&f׈.љnFDdGzt,{kP:*MЃ=<;u HbA#|p' o ~{gҀicX !Nzt;-V*8NyBAEAdHp*:7V@TD"ݞ,AΜm3j_m|Hg\p[0eM4F=4"zO2p1eȬ^+!{fja!Rl4G߭+ƦsM51JI>ӾeS"λ1"c}>OgVuSҥ~{키ITb?ȟtsNlEU$L &݁Xx+W'x*HphJ/D?̍lpP6 V%#Ve8ֱ#$ySI"k =Sq7Wʬ]q,e PQa2 P2+St/?P2薺ȸm~~GI&b)DZLm@]MfqQ,jЁ,R=LG,zE@YºƝW}\/s XyRrdߧDиYHm֧=U9u$~DtZ_ I^Y->i^wz8o-0"[\I 9[ *Cot2xzaAPSyU[聡wuر>+V;|"J |E|Lۦ  AĂ,PleJ3u*|ikmSÊ[ qUq$RkU2 iȻ.d7iw\ʐS^o %RUauhA&li "xk=(ETY_oUyIu_3j0b:ml)%EsAP(EZ HPV4?(b#y2ի).o5R9|eD%a Hd;zQG`ԑa%wZB{c(H-F\#JKdR_[ER vD{Fc:^ؔmt)E`LPVL䣚\L*KU4Z(4Dô+Ls#3ѯ!| GsMCQv譏oT턩0YtY!]-=l{B$wN=N3JNYJhoDP-ϫ6r4(*XǿkOA2VZAS "tov'.ད.={/=<͹6Whp&0-ɘ7yo*Y}rfS/jR~E!fCkT[nljT'0@шWƒR%Ds_Aoe~+)Lϟم平N@gO]zI}qIeT ]ZuEK:?~A2 &A4ts$=5FN{rkhGnզa`WTDrݶTuR[zxCخ/qs;F2/#x՛}}G*= sĵGWu[M ][V#h0dDU w.N1ⲪYxֽXOjS$_=4:iޥ78+ߺCI|yyv=G&d1 $`tΤΉJif̟\YYuN'QQuSYGJC v!cAX"]g;CY@XT cӵ'1  {.)Eyϩ^%Kt@]a5q鏫M?+-Tu1|an_H>ƬwrKWk6F'u%tV!v(w*Ѯ_55,i_w~Y#qC[aacoJj/$Obr+ i"aǹxcOVlߠdWq›EsX$M߀/тux<{VSqc>97G`.cn4T3z㐦'J͝-y:Ki?V]4yy3CtId>T8/۬ذ UV{WX6tWs,|jyRm"3wXzG+ƲK/ mGm1k{ADm3- Rn1Ujjc vfFlO syښV>ޡRa~4)sTcip RnUxӭS*/vy{#jUޠsUEw Q:ׁv iPSws߿nϵ>vGR;WȻO⊾Z}+;j$)KL Lijof2 ,UܼgחD2q Kd|=2L3Us{DZ;7<Mf+-cȯLTTK*]quu{aGZ!rY-O/42VdLfH~dշIߪZzF$C]dfdʅ=ɊM1[Ujȴ9kf*mNHbqYy^r #5ǟJ-xO=.adj>?x|$%M`[ϼ¼ XЎ180+bQ\:TA9bj'`əlyz3? D"A<]"O3~/MRGZUAO4?!kHYkj߈{.JRBqanDƺ'sK4VPؤ%9sqj"TGBw$=O߼kG-;=gB͛uY(>K .JЬv_>&7 " #ط-[}&M/r?fqFn9~X)o}02VeDl99 l¯¨\15hN_t/\ajLBqg b;x3]C_]~_/]O}ڞO$A3g3F;cb%M[6m{fm b>E`o!S:c^Q5#ϟb%ZtU:+N&Yq&F>6VirF0j(. GG|c/59ww&>L a*]'Z 7+Jw^7π!~UDVy\x㈅VN*EL(dRH(1l2@dj4].>CډOKr'-|T}jL2Ç%Wu Knr ؕJ?X#_GoI|IZz Cʠv)Vܢz\2a绪aJ3Ē։ i %lO-D%Bpi\ƣ1;r|쉼yYA!B% W@.GpBE$ a*eVɓ{VgG\4eϧDHB P ""TnN,syWfx$l +"F#AlHX$eIɴ_}MWE_:/i5ڭC,ȴ8}a!2=~51P(_֔(|L݈,k$ÙwMwbLAIMT$%j'c87vfc7{'^`Szj?r QΝBس^ָ %Ru#]I2<d9M]7#zGjNc(4Y~sL6Lz0X6 Dj!ySY @VJ50e& , Sq;` ;2]}ӦC1a?nJo]Bp+8UH?q7E::EA4g4})g} |J3y&{Jx߹@>} 'ބkLwoj,38-irGl*a6)(u\HVyza15W;Œ\9?Rw3/ӺNϽ <؎?eIZBDy^܉;_\!&lIpr bᾰx*[8cw dPyP+ާ<bU"!n!(b:90o0Sݨٗ)6~d|~h3?hy Bu>$?>l= njا$}푸syQē&!ϑ?D~"xka=N) 'n6qw't @3a[PBЛyPp/%{`c@ n䢭FQuFKa,_3;iͥKyJ, `bqQ;xNc7b5Zd7DlyV]vAPڣ[ٺ'm ,T7\UAx>)$c eߔ;z!X>hiQG^eS Ѹʻve]ф{}y㗶K)|څdvx5H(nENPXE4zaF>0j)8<>STMq 90&)EX}>5ugOEAp7ti2,c̫)&Pn@⚫K(fiBl3gA5XsّJs{ Ԗ,w 90[.0~`6j]r(k,3Xt7O]xjK@8R>0\O@2Klhx_o+p揄/+3'f=w ;ܘxM7T(س( yL>M pq뜹`7vً/n f:5A`ŝp! ;T(Z t9ag sm Wt_- Ms{^ {K`!(+ufvv=AG}~<"Gһd6yFGfE[< Bh[_zIGH+R;ʢ+wFX؟!?W)+zR F'{u8iBFM5a^M=,nҁ@7'5:DwyPߺ{zo5 ^%⣈ = S#m2aۡ<1Ʈ$-۱3\ɦ ڌ~(6i[hNPHT~QTh2PLk -"b@~:- :i;]WU]lkkm`%Gl5} F>h> $Si{O!I8 u%j>EOޝ"kb] w6V+H洄Ϧ'2e'QVcqwԝ2v,A&eF^3Z[|J u,o[5* .76X: QEΣݨ3967NӺ^Qf yYdsߎ1| 2.јx>k_ W8sW𝺬BT^j†XJ?;zkD/7@"Hx<Ȭ2L`f M@PImҧ~ȴ: ~qmŭj2>\/C<q⽾Q iׁa`Yi) 9&{UAv,'Ԟ.[s}pU 9~f<ﯢXϾjU[4yd̓@V{?-eXQNyDYZƓ #>}5$.`31Ty)vUF&1ںEOU2I;l$7_9O:"00ITY7vh"9>ӷ)%qJP#b_@ИWBj+`B21a7w[87Χ Sgz(BT;ZKgr铢x=7Э_c`c4K۫V^@~nOMSX1 rimqxHRQ>K.=v/]}x[&<,ԭ >9Dx7.nmp1uE]L[X\L1=ѧ ɮ0#:8r/hfš"3= )}j",Ȑul!Gz(o=}m sJ/i8vzH}6As=^sbjiQ"slf^VױcˣXv)(5_SzWZfn b}uT!`h 0#zSO<6i-XѰ}6GiZD GTb,sHp\L`:)[+>K\2ub7⠍ rF!)EHf\c6oѥGX!Ei> ݷLNMg-!,s$W@'#q~g*wפ}ˬ̽@v{+ 'BjDpI9Zb .j<߮C3+8~!`NlZnJ?k@iDθcurbq!)Vrwʽ'3\$oJW&vw@"Sk tD?i P8C#A`?瀝Jn@Yf JleWr7 sz)v%ǡ9#}9nP9& qxz5hf6G)?01GI.hN#G]K+] 4@0MDkέP%¹w9הőP÷DBNa]Y͕pl iFH/-2^5a.>5qO xGO]um@?2t2K88 M .ʴj4xY_ߪ-; G"Ax1n?i[.ڭ fZQBÀX V/mv1=欽.܆\RfE*%ㅧ 6Xy $}R#*Vh5!)|Jm4V `uVj[W;͈`?|ȏ} `^ 0z Ah`KkYm{~9JWEyW?+߇3{bQF $Jh>p-˜ P0 mX6bjQ.m$1G!Զ:bMjH9B} &r, `V9IW]oi!Qiک]V;qm]7I\+P'܈">.k}/gKEmHgMgns>iwCқh~ʜ'5(wc,t%:ܳ`+)S&Mz8?,_ݘ(=w+ܰ+?8jd?~tmLo06 =m G[yEm]g)껥Y0yXeThqú e3&-/co4yLqoNQ5pPmIcz.VD`&pDAc2EnBU ,0{I9s$t k??6\igd5:LHB9[,h?tfHƞZu5Ag`ԙ p!"9FN{upVQ<ȸ%^aD0bf Pi&l *5p iP"YJnaNMQ Ys!zmcdþmL9L$*ڣ5kXM0"_yzP%WdW>E0d`jZ0QE3us?*w)|@ 8W{φr/>vmyʃH̹ryWK "cPZ|lFطv"Z^ A9\(٧Ů>`d3@0c=>Ɓx.ZҜC蜜H%R&9`u MWS<$27f ۱CI. _ `t}4Б _t1NDaۯBW?ge:}b׽:&v?=|.̣`|/yh!Vf0* Ajc,o϶}U3U60sG* )P0c j8|{McF+sޚrˀK z|{cɥwm[|H}wn<=D :y̛ښ`' ,FTX^RV/wR=gdJr%X +G/!je 0 [QAU筛1 ) `&iwC)x\_4ɛ]^q9/~,@8IQ) қ`>l2 s+7]۸SRܩC#4e05q/tRyc^@lJs}>s~sɚKdί<5a96J0 ~5K@+=!7eRK#gaZԸҙY4 X-Z]̈"`ȸ*RJ&[\{͋+1u`4;4A X_E1W:)BVu"kEuS<,,7%`C@>׃ ^[CyvSmiƤnHP! ;:$Y3l,B9;*NfX[ƘqR 8u!" KȂnQQC>4,ue۝Gl #MNx[eBŮK)K??8EDLH0bu:߱|}#0KzAV%(ə>(B p 1ј;xlq? m22ύL'ӛA25 = 2s@A,_ֺG <p0$)0 PhRv{<\HuC0ӃN[oי'252ӆjѝ8'oN,}\/J(Ķalh`{> a~;>vkF:|Vr Õ3*`}V]Y);ӬFY-oURToe}Ysڸ+ ro'~&"q|}X7b`Mn>*Hlۙ{5lidy=1tUPqO3[R#Qt90>!iЫ=29$wnf%j8O3jo'p|3)b4Ƚn){?J.涒 ) Jѓ'cH1ǀ޻w_Lѝ8c,:E1=VsMwF= ᚔ4ǔ npo~b!' 1pCaȂ& tYc$DZveBOaw%6._ixNßmvkp-toqIaKTT2*/۱KQQ7`DA4? ;974.2FcIէf өh[!,XF|Yv ll9ć20Tbnv u=& z5s#@,QZnc|w5!rWKo_ɹP}- B4HgCC3{cf3FgYd@I8i6=l/ٴzoOE3Dԛj7vdrS=v( asN v+; 0#H& l+#;گSugm{.GݱidЁd΍s QJiIFP I@klGV큽eڬv;zo^! >] uĮ^2c 4ܪF>Xj 3Pm_#.!vUfKelօJ!姉^clFo@65LU19㿶kᛗ dy#jP A+5!DLM[&TZ7]⧪4뛍-z9FxZPO劸1T/ NrU%ū#6>IJ,!nEe17l1н[lp67o Cyy%w!-3QJ6y{\cȺAKEBrJx*N!Tt] aͪ(k8 ohMc7j[ɫK w{ 'YXCN8&}e\(?VgBK L`P0~ÝlSU}V,?CaoqFqcB0oSx+\`/RE6 XII)ӟo籬jLPk iۄN<Plz2D!B XEA)+wc,Pf }ҒrwʓK*W]WO*0,]Q)!?CW&?0!vRl!-CyeV\w{\Znbuq4 D.# iŪmd*˚R 8"0 OGV"h;hTR5/x@YR`z`$$LGJeGe{$/2l> Ѐ\L#j|WS) <Q/eczKa7%c/jɽ `qE'. 0q7L%{ٔz=vk>^ⰹ  #=3p[&HSU]ɥecl!5=fp"EO*눍LPe6;F|`{0{!O~j.$1vFuX$c|2Y~| =h>?F٢f3Jnb{]}MэnMS#Љp /y8dkF߁kJ%{3Jmgq:.(yH=~;:CKW--[\OPh,t_y8N@W5A1KhmxS$})==m}UfП4ƈyhe^ߧ;aZfJYOnGjDq(Kd"w+Y%s`њ' 5X7ᆝi_/ em6$%Kyaت bL[p<@qI%o.N ؘ *'gĿ탧^ʃ5^6xlQw糏u';Bm\7'hmQxem)HZ׷~X7I2deSS+SjoCywwmPvQTJsG ښ<򟊶Z}xi9)THFcaF8mna`wÜcA~ҟ&: obv21~$!B YYUTrbZh]ģqB$߹uh9\Wt ] k 6_OuNs7޺@N?9[OnjU:xɞβ\Ed_$:oV3k3:r  ܁|s&ϸo1ZԈJԿb^|G6&eC00ɸ 7B-rXDA(wQ9wɜJm)[E@3#CoX63Atvd"m^ӽ0@R8CVi 4Z*XI>]Zw߳]dYָzmz]RT?Ej8>RKNT]>|g̟y.Q Mk]efT*{,#UW:jVv~U/~|{^U}AH=l9 nґ]cY#*,3!зkyK3}Llփoha6x1qbesmU*\)%ܭ^uG ri.PA+Hv4MLg\HHݹ/UkIG!Me5r`Tm;oع6d9Z]Y{T.-H훖 p :#RS5lg)Z.dYo`&~ J:fY_{~s`9?A'Df!H5X4b|I6aZqL .^еFM ŋEU  6{,e:4Dە2EI]*tM|)b5ZV >;uAyn|6׾kuѢgݜ3ۗ\sH , smcfcs/data/ex_coxquad.rda0000644000176200001440000010032114002404026015256 0ustar liggesusersBZh91AY&SY}A(FU_=﻾vnӻSmZn׺yݵ`gn^]znٷ}m^uU7+]ͻwVNꛮ]Zۮ{vcl0 D4С Im݈RUV*: h рL&L&& LL2040<d10 SiL M0dɣLh&bcS SɦLF&&&4`@M4h&&iO2zMM4L #@ &T 02iS 5<44h 4@j44'ɓSL`dѩѦiFUOM=!ރMLh&D2d &FOFIfLMdi0 &2b`L* Mh &F)h40L&M`5F@h FDdi@ #!d1?C#FM"!4& =&4i0L`Td&d0` 4 2L4a @!(JJ!BI $P B@$% $ ! I$ A$! H @(@$AH$I$I! BP(A(I$@ @QDB""!"( q"2wP"" d(<ZjgšP= K{p-@ њ#NqS_P>PTD@D "BZr@Fo> -S mw>f#]^o ZP&NWgݓeŚL(0oŷb> 12[-2?]3m-W1l'S Cofm_?7R-LY`R U؄ [K{a(;*KNT5!W]D'9uG>^}P] _Nc>ݏ ٫\g NN^{8A#<|ޚOKk) W'3ϺͼqJ>}O85nW#֪0Pe1@'j  [-=LuxL [|!73T꥽!8iT-MnAe]Fks8Y$8Ii - wɲhюѷxZ[ 8 # V?s O&^ZMTDӡx=cʴFbP&v/ PUȡN g+aTf$݈t%\a*# 2%OGnDBPڒO>ܑc_^9FL3gJ+m 8-g铜Gk^co7U8BwI9Yyq0:cm XGf4,u4[6Yk/NӈN ATI6@+eb\iAbAPszͯ&95Q @;EܭQqҟ*xÝ0є3R̿U[c0jK$YtIa7\<= U×11uZB‰D6p9.E7"%HEVݑ{Qk'ȟNzf0.s> `_f&I`8MFyA8B)WraNja~}SA<+ 'ufнw'ٳ%>t^br<_r r$UF'k#74O}shO^Q='el,a>HP䈶˔{bՐZOL]Byﺍ򤃭jAR~M^Ј8>&J.YE#:j  +㋬n:@/1蕶Yf꜅*eo'u)xÊk'z;XӄSbZ$[y۞ebF鏑fzEB#U48zbDOMC,sA$MlaQc+p>YAL[PZW%EOXn)bV>qRźx>$4#M #2 PPKqRc:Fʼ*emvK8@UrT"vkъ-I- qf]/ E>z嚏ד~]J H\; #"ߑr \RO ,čVtR\ ue+'gFTQGsB/&[?i#jfϩaķČ f`$eW#gCְ!^l~1%fG'ZIwL;RGR.$w*Â5K27I\`Y!V>v:;ӹD;߅7T+ stbpS.]"&n; F˫kIM-q86K%DuR*ݡ[5ٴ)ge*Kwˀs2ZDԥH\jcYi,oZKCۇc3e>!'f8_l+kKf>q J#g6|mre}QNKesb.M-Qf:-kt8t֢ڗnLbӰ2SCiwt~eApљl.N~vdi8dW*ܐfWK:_oV׏1=`3*s\Op Py+p煷=PHDhrb@6^nim֡vKP-( P<]7[Zxͭ\򶟾>@_#D6a:DHe=PI}(sю!Ju5*L6+"`r)J),%ruckzv%+*ߜ>t*zJi$hr8qW%?W%rp[]^*έ)[!|s"*qǣ\ Dگ5ǩkGU/:9TTxg)fe+%ON)NUm v",׃;XʆX_mW&~J3>hZH bjwP5dF`_E{IY~P?(uI.1%{aнl-ڨ`D*c0IDz?gyuuVd^jF- Jj[^ұL%,Fcm.ϺWM$z7_`׺M#"@{8tؔǩ/4xP2cGTNYMIҿ&TSĒ = '[n;<[㩺kJQLy? }@0v;>Q֌V~E~얒_ۗ:mVE>Y <QVs;q}@._ski AJYcC=cZ/Gg?_,{J߈ʓ%#`1/Jx\,$Ӗ^pYb„ۆ8u;iJg-\FވΚkG2/` KD5i euP# mmozP'/'O]` g?e&l23[g1>Qp9eV:7Kz& Y~W7R+ڞ b*"i'HCSsOqVǗWϑ<]i}[)+LG1\C˜8dwcj:b覄{KR}SoQG1[a 0b;~]#p!-%{ -MSៜF~PT|Oְ1q@n,VPAyngrl"J)iy%*S{N+o~Pْ'Wn7t?| !Dx?.7{z[iWqGky,ԜElF`fR:இΣ)] 'h5&H|3>Ec`s5l0OV0*^{K߄bS%c0S 5 ;RABD6a +'d8 Iô bp;cMm_ D/ +-37M׮KWn=yN'ka"jIz/Ъu/]<}}6h;߻4t#\/1Qa~$Nyո\Ɔ]ġ~uP愕ziI82Dkz ^ILM?X)ih['kEuNrB] ?M/5D664d ,JJmVcKMwhޏ'4z9P/~^/×H R#8mWDj0ɫlPe CM!MLLa< Taq;*&tTq$RE}FSLbglRqw{JmG4_u5bV dџDgu3#?8VN\a>0f2?K7!P6o7e|6L,[AnKZNBTjhY "ְO YͲSL>[ǹB).[)$1 2tp 2EkRح]p8@GS`u70`#3Jȟ`KQ3_-g[m2 GVqd-.w`kZLUۮ%"CyLEbʎ)'v7K[qr1\NtkΩTG?)o-*qc y)G3sZZÇ0}`9m~I?vcnl?3vO\|);^z˘ )m"e4/,'(Hq0aܐi]9W`f$CdZH65kBX"qwVST{Xyr;MǜaiBͣT\ Ho;y\odTK~Y;{ζR/=>“BF\xnР"4yoL@|~4|c'J &Mŧ~*|řƂB*E]JNEMuo1q^nd(ţ9KD<O6:E _oLfx#ƞşZ?\eaC],IXgvK?AgMTb\hyZcx;蝦$gfo 8,uJ=p]J7f؞-x-)!R L/kha5 4 jT;1r-Y%/}CXgǗ#P9]8 ko߼Wٮ6j9 ;rw#sA A {#g Ɓ7TEb*D3(P'u:~5rUهH2RP_3aS4 ]Y'O*6m3}0Bf/Vn~Joc \smv[qKvRV )ّt岯1SBHrBCS#9Ƥtdgn(m*J.OKE3]vAle|}*mEps%~cf,ΞsΌ׮/g;쏅`u/#o;⾾寻*T`wm_qr]X+ SwMoC8S+ IT7;-[e)pw0ur$9]3ⰕAwcx;FìdJCKCdIQ.!8/sADƨ(4wsmg^RhBn>j3 K X¿D~'leF UD瑤.]t#Pg_?vxpZzwWERw k佖ʫepϽd8 4>lSTOscW^P D}!U| Qf:-Q5DO;;פVc_'usx fO2T#sdmRm`+*lJ5"ps.oZ)VRVGX՞'B{Yqp>7 /j )M5YhAK͈=Ԟ?|~ʤ䢳;[p>x؝SHP9@G1KwJ(?52f:xH%Ί# Pci.rd|eJw93U[vfD)`P ֤Ai}4oK<+ZŞƔBn$&`Uڊ \`6JG2z-SQZV~7C9ʉi y13YcJh0 N9o oAc9;Dv,Q+BՕ\mt!͂>a`( *}R=t m}k{~&f}]ڄ3u@jt@Cd1 CT! ȟF?l H M$tA ArN:u=ue&?a+ɹX4Pr3P&oJITZQ&I򏐛4@k鉍4n+uTdGThh"ob&!z,'z4:j %#獛nE=unckIq{]oz6G1gŧqK7ϱ𤢹Mo"1_EU4 s#Yo 3 1|/`" gW$s3DN9 DK"$]$Uۀ TUQtѮ2ۄu R5'E~VRz$ J:MƲ')R9᪹׺Z.L#+oFȀpa7 ݳ:deW&,oO)\%_|j^AC>5'B9!/DHǙ~PTMj=DpM@ c+]ZN##;*݀Uަo]O7Qg ˑ6PC%x>byɴ)O[WLX)e7(ls=)*ïgRqt7HYRil/@^>(dBI4h ٩\qh ڪv7E\/|>E{&e&>_M%#q{3~!}'wGsvHcbUti>f1.XN'nBCWCyqQBRE  ˴Z Q Ơ)%r(A--`PIID(P1 I% BI$J) cb*J#H BCKUBQJ$$XBK )EU CI(Q(AiJ ѼTh Z  )@A !B Ry5A$U,$JA$UR TKJI H$P BP)`*B( UEB*Qǘ4|a]ob$)w P`8fM ݲ1ݲ]Im +OcA4:X`zDmgզxCe ڜZǭXP4)]] Y饋ΪoBЕ,T —7 9y֦9}[>VÓ! "B?E<1X)+dj*%-tP^LRz O 0y4&=cq>  b G.Ϗ9͗2+a/3fszg^ GQ(6JaOVa+} 2{^=p7 T1 ǗMKd;z{TJSqVMË;ン.<@c`IM"4)f\./@#C.5n_fGY }|b):V'_TI۱w.0ZڨeuzH؅X\9GR z 7-|$q! 4SmĻT ~3 , ISϵim^fz}ߍm1pfQͫ#t%̟% [;2S) nkhOzc-`B?41 r j`[R~ן[ak \QyeBs5a\|9vf]1#*?nMQML7BmU!6ߧNNƛS5:9ldPd r%y?&ddkilT%@wK+Kc8/E: I#P"[)N78>[!״3i~5#RrqB8X:k; yv{djU/2!̀R&D~ <؅oN%62Ǡ)̢PY'57w?iF':]W(PX6o4 cL*^K9gK |.-F1Q+m{8YCj{?AgN(xd";j8oNgD-[';+D{ź}P0c@媢{կD/ЙZJn7\NuM9g-[ʨև[N#:dZg.qr;3^ԟݳbCI@ZR0A5<#HBŧqSC\d^^_|NvrV\ ;/6c O+{%%VvRr'Zvl47I,0k~Em|zteyx3د#)RYՁ7(VnFoBbNXyD)B(D򯀙'xkYê #;3U/jYY2x1be S!JaYl`8NGKt/\A>\ vGPKϞWm㐃}_-Ӗc-4}Vg4zw+L-Q֨8t&[M({~OsV,Uw8r-'s\Um p:T}kAs[:,btֹb0c l"4[[0 \vdӝe߁KC M}zVz;qdހjQ=G?T9_!>q~GRҹU|!3 W4JR,J+Mjc[kA8"CgM%,+ D:d}Ad[1r[iJ{غ9jn8JCέscYu{UI읖U!v-}:w,(gᅦ~E*4NbxI|-e{0[,-=ۭ|b]=z?h4oI}S<nG7[&IJ\-58Tdo,KU_K y_ S6V )j/Ĥ0]'EݲU-/t%A5rm6vJ5#R.*lH́wU[x55Fscܛ4P«Uk z|#q팟~zeZ@㜊_WN[Kas(fl" 9 /h#*ʺzETY#9jSgnjU׍ͭA,?FY]Z sb6^7ՙGb8~TL, L0MQ2O0A GX=YJoe >4 ll"͠Adˠ.sG[tNlCH/n(v]XI>WS\w $@J|#֪> i ׵='AXNrdݲqjIbe9~-IQ]\a}k;Nbƕݖ"@PXpĕ Qc`k7&8)]\t=T4~hg #7G8.c0Nd[4'ZobtOv7J*Ut5Gي4ě`D.YBq|V'%. Kߋ-OPSpZt@<1n$ζΣ8w=ZDھay}d\H _'" "XftN -`a 6~in~3n U끫.65`9r_9t+z;1iZVӏ-Ճ 䀛Y/IV*j˞9h$sKneѓY #/\M:Ru-]V1?D^o!v1XBG^B_{Y|)-Q8i xAG8p)^ad64y~6 5ֹLT.C>+>;>ɶҕA16t^e=7a1(]6Fҙg].r1![Do7.h*Q HL((E}+zJ%u؊DL9=%Sqn0^;$ց{=?pꍌ"' \k15x,B8-.` Y-AӔf̪V;oLO^W>:;%@ҊP\iyWŸ[eտCkx"k_Dbֲrܛs^Dc:VUz*%k5j}Wo6)a˫EWR /l4J;֣LNN^3IPYMI8{;J3p=F<|AL ğuyC|cuk/G܄Yc$T!h?Q/[ue)ۗ'{b)׺S|? Ԡ'Iпj;2W˅Ta#+tڥU_¼@A:q9WmO$v+~Itb / Տmڜi|6\0a2۔QR;'Cqe5.q%m.Q.ODA{0p^}#Gw/C*K{TTf8FE~;e;EoÉ\(2)aM\*%E;ćs8?>w\A(CzEa ߚH>&- Aɏ: Cn&wsP* o{  4I4Y7e ^-t|vإmKTCaCfP =H `*,6 {.nV>]JU6J涤8Aw[ZT*Y?2J2YtQdl#q3L[7W6+RHfP C9b XTgx#v mSF8^!#zTpLHXz\<r 9xV H.5ӻoWK߯({w9p>ڂN=x/Lx6hф6n5%VH |mq ?vԏ){^-q/ć]ORY>&s?7R!lcto[)8 k5Gu,%O7Yz> j񈯾'Xdy0۾ 2X=wK6:ʐ/o'y3flGnIą>JI,y0w/RL:ڔت"j$dWx|[|Aó)AxM+r3M5lȲ\*,Xyg@ 6ב}I|ҤB5GUҀ47{&46S]I#hOEUe s#%4Ƥ5iҬ"G+n;\*bs.!Y7D a^a;g3Ί4ːëu~vF dz#N+Lm1E~hwud@8t|jϣ[\*,c=dBPpmBn p ֔RŰoXύG Oغ*TR?,^?_x5y{:}6nEԑ"o@tW#twЧ@2TK}޷@ӏ)=V ~;(&y-!9 x(9EPNz5YZ G\d쿚iϖ4NK];9^KNgפ2;|g$b  5!RR*O~:/=bu??;fJ;6EtS~(,8;$$tWP!nHu}u֤YNsQ\"|p|b8Y{H9[P6akݏ%Ov~;:/$J}4x܊Oإ(W9o~6z{ س/¶h-eq:g 3Tgw`(=Sy9s49i:{^5WFD*F-pq5gͲw3:G>xy4bkj+2 ZMlTw븲QY"MG<ޡ`)m[L9{Z{b$Av{q:$EGj@g0&Pf8j4wUcú5Yc`Ǫvʙ2GNwmY8zŀX4b9`8n!7 -wi Z=~7 y[o[Fs rc~|'4s9p!@W-J ( Vf^b{߹tiBvm #'Nnv[,E0 R_S!=鹚 C~"mneҦ7\cޱ76zo^/+Zŋ"FA"~k  ,ߥ]"TY F nVR_$uخ[_ <`Ͻ#JPHV[E r̝BC<*DB[{= j_g  !vwq0BOp^鎹N Ɖ|j 4ʪ 溺ddu]5Q7{s&UQ 74e)./ ^*|U},u p !hWv#OXZLA=;վ,kiaJ`GX-{ZԲLz80KFE>ޜl"y&RKJsa2H'RA̅(˿R  %[)YqNmYHϯ-5۷ -t<4uh<2QgQN*<.VƳoCq] e|3%E(9ϨS,=jET4W*}1OL۬ܯEJ BJ58-$]d tRқ1Tv~?wjyyin4e:sC"-Wsq%?IOTErV,v5<9j=$s ֖3}0/oz @;(YL#Ds!!Ϥ'@i2#S&EWSܐl$a6\q=bݰ@anߢ}x7GC͟\v^B*9ZͷCQtx=a5ʍim~#.zλ^kEi 7m`,{NeΤw}pcՍ9Ш/74V5Nա^j}IvWgjnx#ccXn9p?'G&UEӿ; "ǢؗW3F6 noZaB|3On@m+KQ=Q]QP&8ƬT?r+i ʎ!,N(><0DM䧜t [1{j+DzErlp O_.== z|n: vT' ku.\/gqLfïl)żKøctgt#)i|'Lk+*h=쯯Q5'6%UT󕨤L+9CN|߮BjS$DO\ 03.ȃwZϥ\9Ϡ_IZfM o{r/O)NoS-ĩ^ŤvBD!쵱5kxN4"}TP(EAm?G[ mgLC$W t~ "_r}yOKvkĨu #$f&g-cщ~QSϭў/< _n<{$2WCۛ=5 |:\XV5:w;;OWo~ˊ-[pVE*}lbMj}L51R ]*D RO7eaO#~T@39b/ܧx6iS($2 Cۦz (PLyoy;c+&7s~ G~c=G:OQ"=J5EE.P: Mك%F7 h? \}ʴ@1R#Tm?yxa[x]{@ :gq_<&aE}\ dsvDP@?ϼ궥dcLA6ܫ#CCF37zX DvUK᱅"v}.sB>_N  4 zl Douۊ.S+q7jZCCL%#"%ܬ (٣Nz?h-?%՜URwaJ tlE0S\eO8ŏPуWf`U9j"$6(ˆGqQA"Q( @B(GM6tZŃI&50v:?"zP @Uڲ3d"`b@b Z Ϫ@=rv^ _pm56єw9Ӓ<Z?“CD2" oTS/!`g_yx]i 5EuN:Q/?K{gI89GrP[-m3=)xV`7{G1b  g6Zآ v+C }E>:UOwL([ƈ}t;k4V#A}eHsy$".`jp@c+ibYbS'R:Wy߲@0z҆YsuB~7Mb(,|H8uY0W"ޠu6FՔpNH2Z gJlT!Z/)X&Y_`K(-aJs}_ЊFmOyvن!]6 Ԡڙ`,c,5')Ci/:<[KUdՠI<w~w 6a J ~Ա <n#.$?%&)B1P1;e޳꺺3ҎŞPiA )iSMY4B5!+[6{wO Ho/A,WtW6FFKۆAmKڇ1HHZ_1 s)Qe5#7ph㌵}b[ T6 POzdDG̼6o^1.KDhv˯|KÖN[g:'aL37erl)2%_OL6uש,>V=_2y@:IN~ېy,{Gf҃HƤDw8@;Zq\0Q@Jp]nXL]'ȲuBl,[] ;$s B2byJ ~VtbZ?=lt~a^b~VrV>8|A=4K]E0(D0'v'J ?,,A}Cdw;$74<:klXါ07Br8>0?"hlIA繑Erd|qrFyi-Bޅ{,BQjQa /MR؁>xs#\0 B@ljn ֊$L@ )碐{ȶ)a7jaf|8*sòbXTZ; =έCG&fN *߱U6\NӇ~[Jߒ/N\8^H%W}k4Eo9{ l WT;id3M;g京eo>%ZoJZ5!$ӿ@.F#ϜPErG4dźf!ԗ~-$-F멡U&% L~qJP;~@k;&v>z\.'/0v~">U1e@G=tjSH_ض'- 4UZUL͓pѓ=B6h`j9b$cvJ)>:0}4v:jo5dYk (?4*<{ohɹ $\ $Lw`K97 =vxͰT7W[^}d@5Sߩkf NJDAdۘMXQ2t[ waU5'姘GZ(Fk@+tlEgL&?2OZlP #񍮀_Xrv18@\LV魕k̋m_D'S/P=25n& }R)^J:@T*4t_O#PBb@"FA R=uX𨎫1Z,E<"10BB0[L2j8jE`Oa$G€:ɟ7߰=в4z>;GjTVV0Y`L/~mbN]d  W MY4E+֊]e'zڀFf݋pG+O-"hsmIN(҃M'E#թ7nZ=e/`gS۹qZg|E-z\Li6:s3ٻVqr'S[ñI8o$1Z 9CK^Fo&=W5Wu*v~7~1,v\g\oy>NMuo'mlhG)1ݙٯ9ˠyX|a]m Sh'fy*Q@KǕ' ҩlntЫ@cȃs߱%YtPf;4k-5sF ,Y>!G,  {6 @qoph 7IM؆a5N,K&9~8**9d sAx"xѣۑ?%mG熨?5wMZr?C+ C`OjjZ/ţR&$o*mn.rW|~#]¢(hRtA?t)x=tZ(ڑS ?m2퐴!*MVg{ >(jTڔHBqGpZEN%t .).DcCnjc7eKq7)Pi4ۭ/~ٮ=0{Hz)p{gقk%t];kN*$ȷKc_'1m\ڝ܀pZH%eDJ/'z%)V-Ź}ɭ`se,SZhEwQYw6`sUZ}.44 VAckA6N Iѷ dbx39:S{; ]J`렮s!H3wMVH`#LfЃX_~6~F%0-tqh/(\DOVeٔp;O'|tG1oQy pD L٥,~*F\Qo%=XȗZ'Eeˣpt08d MCKͣ۟1 ]OZ)g KK}|_Q WĈ뱘fF <{zO2QymCY4٨m~`Eۜ $/SVI#`l~L*ɳ9*5J[LhV1/P].#w]'tfͶ:ҹDz)UB%ɷGe ?X(:nq,0:>XBH7;cۓdKJPZu@E @qqǮ6W=f2.MxhDIrGm!zX4n *4CIJxR{lsf8!V&x+ߟ1~/0Ԏz_xp4BI k I\8` |jU&=1g!Peٙ\4>h̃RPޖGoMjC%*E[ šjy^cu5nx%ho{㽁0?"w*%_ct}3YIzuNO~V mg73`X.$bPzԺfXE-H)dۙp]lahf䨢[N^89I]Vj^ٞcʩ~rjSydjgQ(f&BZrytto 萞lBh@Bj@"9l;8Ii'C|%JIg9@Udy)n1!ٴ#r6vߤU+ P9\vhT0[儓̅UFbO"i98Ft$U˷࿍lIhQH`@ Dr v8SW'槎ߪPu&Ag%][1BGAvZ&~>8-c9[;(Sʬ?Y0uTrI.9?O1-##$^O!c[-.Ąnq]do'O\GI/ >`MiE]v*5mȂ@@6.h}uÆ0^`dy cK!3C^8l ^>Bx]=9$U7ė)9NLmFeQkۣD^>5X7Gfp{ʱDNMDpム_4GJK-^>Bo kIo }F٦p0rvCo2 waɺF`UQT>+sMY5k3Ls ›>yo?H)pX&*Z sK{i 5Ӌ{ꡦ*d5Xae]=S.귮plčE6\2GA%DHaٰ_* R;CM?_GvhU47M|,h["T~}0jFqz_ӹFwB|U;k#91]Jo:٠*+]5Iȧa&1'jRc+5u*O\]u8 #Azt>]D I`^Õ$) P*ue˻ {39|4 ژۑbZ`xv%0? KCVFF{ja3g`?L#Oo@<-e  VajYYBp m 1Y>=7aF/wDqV,?IlDNA [ƺiw~likbʋ_8hq#NM ?4 Vd Y '2:p vȊΈ'FU3l0ç!i,9 u&x@yWwM3{ 2$'0C&%hgu4gٍ$|TgmLxF۝tUd`>"DZV&@6](xW.B2wf44D-5o &bV "*k0m#k/eOxQ?$\3tK;Tl 1^i<1SqQRX3'%ڨ+%QU˭WZYb!fx(H.SBfv~ϱ9 H*" ~)>.R)Mcpn}t3t>Vv$CS)0UqXqOP5@Pws@?^c8pƔ6wo\y v툛%݋PPsghhbȵD;\} 鳑As7{OV 96O=u=~bd3?tn rP4Hz LSBs3./$-HRi:g~;-F;뚄s.+C| h6(p[)m!]'nL. ﲺ%/,;#h\qOc@[Bv2KM֥lS"{.W][|á:s*ə3~7 Ʌ ~Wv%@Z6tu3IDK LO5ّ֬Wy\~bG&^MY$s5pހ!d.vAO:RJ O-|3H2:l5!ԫo8 ܬF(f@,#,/C S"t{oWlax=j!?P'>;etx^/E[2h ^POGϨ@^R$Ry49-1-E1?Oԉ;;2sݓ/;o[w v)rFo\awiB4YL}!b _˯{ P}PN,E?\I,/MIOX/hew){sIl2D|}bNSzRU2G1གjҶ:CF C 9lEYZL>'Ch4\;_R_SU? tyc!5oyEKܹoW-rf޲'E4SZM}{7ԭ:XP*k!{ Es;Oiw̛P3{^Y4xbSɖМwc爿و l;?HhxBk5qk0J=`f_qP W. 0H!$A pk曉8p#c%nQi}NU3mͼs&,XߧFee}03gׯUW:^wiІFEr¶mlK7|ki=(zd̻u'mGD2=N&׵)Q*{fl)0C ew<@moS(A?}nT 2(<:2*/֎ u +"twS*kOmAUlz?@EhBM(r1ߢA2kȻf~"- UѾEӽ?R>q{=:iz,benF^9$A+ %`4A/d] X+saA*mR5랖'̻՞.)hFR*z&fȣD ]Kިv>;E_Ϯu ZOT3mTkSTx$<3l(MBʭ  W+2C*c<Ԣ\M)"y/{h_3VyX8k 6cUH2v67nc D($3r> 4rYL75h~ 蠯޺4ZD=QxOȍv1wB?6[Ccd8>C^'7̿i|4mhb~Ų6xULC\d抶xNq0n*Cxٕic1tĆw>)$ ^d>z&M8Q_8jT; 㢯sc 8{7gRC(˱b̛ 9K13\ұ@Lv5Z1h?WTӾAF 3E < z$q]Ax=at:i[sM$ôI(;T׎•UA=}r%rMKpgA72R6sMJgG-Gw~8Q r/0 gTpSLeǥu3r\}H7ٗOKns_W{n麱ϺYEHEwte܍WAvdk>Y+%.[qxH=j8 7xN(cm.ÄsiuQ(M0=<>>mO̴nb;~ M ԭmv1gَ >?߄&t6^xї*|C u˙C+nkR!v=l<FâcQm q7+{5+׺'c%8wACx9rd.1V*<ջ,Ø[tl"DF"?B aBPG̝)lOl6Fm0yy6|89Y,uM2uvFԬ,|8|քI+-;-5{J:6U,$;Ը-~̛4lX^ݯB씽9ԛt;E2QW:kvf!2k3ܪ0obyWuF.0|B<5}ԝI!5g/c<ږ"rcX_ͻ渎γjNfn@+ 䫍PR> '3^n vz57OEoݽ[GxcAb3cǧ#h| ,>/HrUӿ^mb ׅŽ=V<[*_#X۳!R^A-4[ofV3M:wQ>hrDr}Qe\ϔWOS v&Q|қZVi=7Շ˔uq*wJDro5j55If.Wgg{,FTj 1A*luj;<䖍{sw|Q7KQ׌X]0%S| _UcX.iZEh$0n2MDžn?TQvQ%rY*d #FEfKo}g5XXg8|yZw[;ME-)UpcU,+I mܠ($X Sr 8+8 $͎^ΚީQ j8n.sjݽֿk j Gdʔb[|(>%agȌ^T$fk3ddd`""8*q>i(xr#mY > ae+Uʺz>o<;Ãv JxgN`?&(;. \9R~G,ePSB&~P+_g% Bkk$ZTڑ@\I2l6wH%[oбuF}$n.`N#ٞ h,:zgw|zCoR NyQ"F^nN?;ϗ.Z N鏺|?SJ0 %\h[HΈ@LE%Xfgy9S_Tݠ]V_.5>܎`·RxVƋ@r#&(^v ji8=6Fw{6ju5GhHC}"U__6}يZκD[ВI;Y䫹.^~eNTXY@cwm1 9 F}9:R*NqY;ꊽ==,[!ټmwY/8dl =,W{5SGr} kfI- ]F1yŇ˝cE!NMaZcԏrq`'gf"8TA LIJfuفn diş꓁ xIN S4v:ClO e2x’UNQ%,)hHHC@7ͮvƖp`; %:l3 02pBN H˨0/;TFi;lU>a@Ioɤ󻿿͢(Q{C Q0 9"1(Zy qI{ $YΣ!t"6:ޭ%oqVfގ)/W6X*x^6& 0'8hwzTa[0 q^0)P`ӏEE"ĸfWBZpc+g8kswru4I<.S8m|Qmt^/S=?qgVY֞5CqHPfB *AE&^' K1bW*jF)Z[c?Yqv|VLN 3 d> #m}R1p7,2ŭkPF`zT0$ `~f⠃PnP /NmJ n֌K@93_,&:D?qT`fjAN hQ4=UIlp2Y=5, ԪtKHnP\6O% aH~J _!$sT֏r1wjiGhUCw?p\Վ(+p_@ђAj0*jdp rd/J^ nlwlgmy*ހ5)2L(>g4G'$~AVxI+`݌9-!r"[u LV1GR;'M-at+dzu7I_m$(pa5Kg?U3Yl 0FΑPl~jpt1ӊ4~6'3][s:{ W) +;!\dDnC~ lCqDyY;u azIk6:&zJ;h 2pqT+:qI*qzËuSzFmGE4Q1{ 5<3n1Bd-ժ؅@: yCwMJsxlGQMݤKe٥,݌10RDHN{t{.lʹLZc{Ǧ-ĠPT=!Y9'hZ{0V|Em|DX бcv!z3>AW)F3fD4 |^G[zWxi'Lk \YX3&30s]ae: [ t;PٓMr hȯw<.LT\iN+u~N٤ 'c),ƵB2R‘fY\fhgKj$շs59CZ_Ӫwajݝ7/.Ƞq\@qTIIku;u)tnJ{ ?G5ObZi!cƭ^a"WO:7d&…}-ZjpJ\ isD@Kz-kmgAi,Kʎm,:/oq ؎׷yݮĊ3j_;vY.8rotڔ,2īxcY_7Ŗnbm9~X i4Za G";}BKT&K]h F"MȮz(+FjWzo&-5Wv:/iګ D<$6xYL[):[JlTwaO@q6nc,gfp1kYIwS?Rz!uZR'5B4/W'= 李"PÆp2Tp ?>k&P gp! S ҳAgf%Ɏ[+őۏXcgoEDRbwj5 v}E_L)h!؃ AN7:)>ޡB㍝V0ߢӍqwU Ⱦ5Mq ŝ۸?8#\KJdxN&woG6M6EoS 5٧Lx,ỻ6{_{~SKPټ~soQ;-|d?q\wcNo[7b,_kPj$ɹ,xl^UA18k ~yt%a¸FV@{UD]Rul4[2;TΦ6%JȖSYTSTRRZU9mUduK.()ZNdUZ1*(QSIL`!MZ*%rT+Qə`jSL[}6mmMRV.lm#1 jkf 3v%duf֨eѬ,bM&nt!m0! i=|FPxR%JE4:k5ڃ7\Q$WŘ=tM&#y@?Ovx3ǘc~_WK5ݡF/j1‘&.RS+k(2WO,VJXr3UCM2˔Uutk?=mb65lgf@A񖎭-+ -A3G0'ŨqذϋrEQMQ$fSȂ~nvj5;Ʀ(Z~n<;cgMevE.A̹ͥBlL udS~ _Z9W(28Ng{tH+zڔV2~[#u o\f^g;Z%=K8y^~/p2c#ڈJ2.mtl>>T@V,0 LFgn\-«7:UZY`u-~ zN0ma+MYerYwTGT:he'#"}̭ +K73f7^3rYEGciS4da:Cfhˍ}DGb p(j?  sK=}+\pB7,E1>ȳArE%gM|,~EP?|(y`-i`[BBE֗ʊ7":Jn ݁y{ljNNM#HnEW`dT\j?K&/dpүy\ZFk~ mG洐o2z:gy~ƵT OGcPM!nyfpFvw?${ywUe㑟}b~_T:aX.3<>#"^dDHl.4rƯv^洭P-u}J \"dDZWby//tN>qhS_PB5u|>GQ#<#waao(ѱ1 Ò5wÊN6 #^^bm^P*B]_{rdHf!t"BxXلGK%a÷H9NUxn<ഭ]DML6^Wux|к ) E%Ɩ5΅a9KAf0i~<8B<@0`HfPZ CJ ,S~/S|źh$OƂOt,f<.VM\~ݙx26Lݰ}ȔaSZ牒$?U}Bn[:NL:)*R[C`Z*$g:B u>[P:~k֊ʬͤv:}(UO0QcP+.C4uOv İJR UuA&̶àAxŋd2]3ueؓ+ͩ IX8 `I%Ct`Ɓ<X(<1 va COxm;q| o!u{aԐWUDzfK?)!oq a{-?8}j Ea\yS`mO'{Uɠ bu oLBB2@ZU (^򇿻//gC<]D Pe3EA{QݴИAsmyɼt)! t`<xpЇx6'52h1rM\!cCH+Q!㙇t$!Lt`-Yˮ@3/I*ˠ/ (0orfݎ87\؛{je賫cm)w{ֵjW1veA],14T.:ձί0`w `hmf9X4aNE@Ymx[QXʥ| < gDhwO~ wz~c??wԧbF*;a%BkA≹{@+n;dǭkl\(n0vN_<<\}*4SV)hrCKM,8-)&PAn8ʋ^ K/(I5n_O A/ AL_YӸ5ݢW9x3HK>$a(5NY+x Af\N0aWNѶcp,,{d@׀,6 QB4>9[9J>:d!|tkަ1+u5We.le%djE~r a(0K2 i$ڡj.%W( !ltMLrr.C?+kFNN!66ƖJd?AX%)1}ܐER? PTĂ۔)Fnao RʅFDYr[sPcX맂$3='Mr-ɷGD ـq(F_r|Ul! $b bM,L]Y^z,uz-mcz̓LO3HQ,Θb{#L$˄oN-z\V{ Q@-5)y΁gg2:?8A'%BD G2[ QizFRDTJi)JPHGC;΀pw~,6=)P~@ (VwjLf%cM',`1UZ#. 5ްZ1`B-b 8@] F*f9TՍ@DϊKS:g~:6GcY  aRP+^oU~qz ޱ^B61j%d3s:REm *|k:#1 Q1Z؉5߽}f|z,aD?aߙAFNz :7~v S8T*H-Fiږ l9[$U\ُ]ڷRIgmPk sϗvF% qPc驪@؛Ys='E=JCR ܭiP@{ўmTT\߭9:n<-Dyi=J%c [*)Ω~|BDǜmEo[ɩONW׹;PqRĵ;:ONfu#Uݚdk坺!#(ʼl/Rb%|;}|;'uGMФ5ϯP֙[$R,4MSMqD B^U垽^㊿4n9Sl>+ϺyeNwk4}3뽥:N"w{Ozywp/tgNO+|WmC}#DOv#&>^㳦; #,L!g kO$S)j7)_ʹ'9-wyyP&."!d)>C|#b 0>r0bsK_]T((یEҵZuYjдJfc妚#S2z6XKR\ȉ*9ofs$v-ul)EFcmlud,C)QQ-m+FZmmof 8"-(lqA26F(Īif%6Q)@ /sQ/& c DžM7V߻GǑߌ7=WSV6ܲ]H"חHȗa w1G)Dtr4%ysh>zg͗9{՞vrA>OXqqqQsdlMXlW 78&ܤ'N]=Ӭ(k'%49IXX+ ַ,-؛<97+V[yQ%`ɠZjUKsGbqƗUW+Ru%?l;Vtfv,4*yX[§dcD:7MݬVc9zrOEr!bv]J+v輚dkgqTv^7/ C.{(r.*hs<ɑP9KXNjϐ},6rW)0+d_{3릿5*櫹*nw+\j10w[8'X?&Z N>N& lsU2$sK5~v4R(sz!cV\u)wۨUxc_7$ƖR#p G=,UhbS#Cَ|#mZI- 58pЧ[bCį&N,K <1cM誴3$҉h15UMVpʽwFFT=z(ϒ|NK?G=m)PfvѮxyT90G4r+nۉe({/7w(w81^ͦo9O)u:6nG^ j}RIrߋy}_3Yl뻶|H6'E3)0D^)1jQ2:L˵7CeDvJ?ұDoQ2/x*q< M/ 7Kn3k-olͲ _YͅM$'w] Aҧf׵,Nc9t^>islm}wʏ4O8b]iz/%z0N͗O"9!Bcw4zq-:bJ%4xvs tb<=| 3{>ĢtÆV[͝q:^!uN\IFG~7"^yUW}r.ʞC\釠O\hj_bFQ`qD0WvW@'aur|/oMPd=pwL2me\~pQ~9=e#^1U${@flJ3hif٭z$O5Qf!#EgMG wg3U-wȠM6GHo tIBRQ0 xA{׿@S͸sp3H z|[R"mrپL/ ą,BΥSQAB)Hp FȐ$'n+P?_7MCm cnerY޲(Xzz\+]^~x[ܽZnM@p9>!Ivγ8,/ޝpYeρf]{bW9M_*fݵ!%1k/8iȓ ^%w/(ݐQuqO[o9x>=:O{[}e뒗r`Vҏ q^W<Mhr;eeJCV L܌X IQ7T{g?1JFQ=Ԭ3 joi?9 sN|bDRؙp66'[pUTgg V9gm=gVV+>b)E52DZ?(9R!u)pU. 6Yjd]0~5[p@̘D[?nرBɠLCcV%X\oZz qs4VyaS]AQ28sq2fXⵂ>:@^_m{>4S3=% , %k¬CmO5%oXP4C:r +jJѣ{(,YwRIϿ(Y8IV;uC>Y>.OxߤNs?+G64T[ UBYŀD%]5E{C"Ech[QLAkg_ į`7_.LOVRG38uXPvW_xW|\FmIf5V$Ow{w*{R qV-L,sBty7z~cJ%}~t(0JY&jPHϸ6jlu vq{ĭyZYƯSn:Z?q'10݌ד&8R$)ڮ_1li |HoX&!WaM9Bf#[n֬^ɉat7cYt>Ԕn,{aM9Rܹ(wj_vS?7[e]m6;:.moK~ܗj|zsU']Fqvc=aaH>yto)|G-YB@'xS F9f~4=numĊݗy5q-Vn9Z^!'aG{\m׋m}QVgDgIIpoL͝|[!-(w'D 6cH`g%j7/5F2 Vǁ.Xv:V Un&R4%@yY@D,uY_NDm bh$"'oع?VOmx3]D֪c vQ=A? R fgMfh]s%E,G!%#ץ ;i\հCYX])N E /:–g4ewZM#e|6#H9NQwͲJ<;aNtZ_'}qCdJ;vh SvFx +ZbEM 0?hVNќV.Bx?a+WYZKXD37CGΙm" *lę^d\-E:BYlT0orsbFhfZW,-4hņ՚=~}t64"1}"%x3WIm2KV.,zz4x4EgSexg*|4X[M_WJj?XNy%O_$roK׎4TH);ig)xp[n 'R B=Wsf ?c\Ct-"X0F,MKh8໤_8[$*0dphfi"1SB )1t;aYx]K]K>tzհ8C|I Y 2WEa^*2yʂy^2a <.5)R,N&aӜ|`g)kotX#ӠъLV1CuSk5ۺgo1ԋWrSFP.]adhg_KhAћIJƱm|$͋ C^J4{/ @2I$cQ-\Ӭ4{d$Tu.5_/&D!HG).W0B5HRĢ""430Q7Fhhy4F$5Hb^ 7M*Z-Q& j%hN0WAI{z5ZrV~si|'=_5t;^|N?}9-s^/{മ0{JZ^ (̒iRBX+32X2g*B9kqW2L=fw a,I0 Ndv&4e:kw:vwDD mHSd?UV.ʹ6XjyIH2ܱ[:I7v%7w` :Ҿ7+ =x>!4wm'wЗNM*dTlM&:;\6LZZkؽw$D?h/s+I:XX F־ITdzxZRTo$hzTjxZ!奸_¾] `yr19\q84[_UWz 6yl)VUߝ0r mK e \Dn(`!Wn n`5?Az]Z.al7$"wpx(oAZꜲm2Utq|!1!un0;Zݮ S <{ɲTu8-f@CKP48^UsQE}A ˁf䍍t7)Ȇk$e,}_B{9o)„lsmcfcs/data/ex_logisticquad.rda0000644000176200001440000006047214002404026016316 0ustar liggesusersBZh91AY&SY<"@>zwn|r:9uw-珯OA-|N׾UݺήmݷuqֻݻEnscWM}K{fW;f[_Jޝ;{^k]׮v@fBIRU((JO@ hɆ=L)&b2dɈ`hhL@j`j~F@O@Cd<1 h46d&S`h= 1&iLM=#L`4ѓOJT*x&&hbzM6&2L& j`&4i h&&jjz`}ѐ@ O"BC EBHҀ"~[+eAH7Ȟ_`_Ծ#ָ92=P1 A`w$BL gޠT9W{hּ^^)R\>cܼD!(1:Kv^&jy]T"" CA5ze2 F~AAzd^@τĿݑ=sD1p\ #O:=t!`#|Mw|@wVS;T~_X  0% Y9QD٭jU[6N@2+0s.p؀[GhffU4[×NQIUkD^R Fb_*x@d0h/`&JQ5¥lBƹcivL3޳zkcPޅzaզtO <AN qB8w6w`1ER)Zq5+k1MS/黏K}Ü:mWjgxZJc)b ib[椈=:o _?<b"3.45˔/~}+;6{Nn mK0)w?-_hݧ{}oBK>O1?{*k^( yGT;4@ 9HCl i|gYe;P|“#p\!(X>)atvQts8>=F[FB~3m"-b6dI@[YZA}D).UY:*HTx`%32i3_K|K.>!qn (8+mʧ$ty1tDp)_wM*Mn߿=c"H ' M:n3Uml(mu1#}5D~%,v*r񦋰 T!p?I*;A TQF9WTzko Gj{ǚ% \_ ;4_OT`L4gJG9n }Q`n%1;{bn oטgDb6jww,R5/Fd_a0%m I^9$mY7: ?eb،;Wſkh戛B04-8dQolF9󓛬gBP< `ʚ$䇦jwALk `cT:6 2$Ξ$)HAˏц&ԦP-{Nx*Ic(v,楃J=scqp۝VnK\:ƑW*Kp//] q1괱1?Y7n~,VXvդE.ՕV2Vz'^ELijAq ,/=ÒdW45b7bO?nM)D_;&j;XYe}(Hro牵:?RXy4 U'ɟݺys2_usK= >lW49j#Q;Աo]uYʠJLX*<3( +H~P9-"HOY ⰖD%mg6|hb9>uGo${/F,ؕS|!ڬi^j|Hxwgޟ:ÿGH!RАぐ!vIT{h:_׬ V08j.&d:)ZuQʸȼ>q"X,װNE=FcXnt&EKyyy L꙽8$$֙0B$ 4cPkZ=\P$^WrbvMa7!6ӯsxw^xJU]ޞ2ޑr"gQV锭۹2LSlrߩӡWϣh]}1M):p!{7K}7&;2[(Ϸh܆}m Q{=sTs3h@5a%7܊Pt!txV7Hp7)v⋻<'g>eg` 7SɺH L3V:ݮ,G=uKh h)&\ԮjD [=y34;eQγe~riX}|ٟu$\V [_z5v˻~܅`{><1r9K>! RH|V!(-lӄ5Du9eN+@xz2E_9? }8g`z,`Մ?b9Pא(>ČA(qH{U5xJdkfU-1$CʠqOtYr՘W1!ME&+>ib?U⒥@$.]`'";M5 jfGU*qV_$[)D=vd3_7> D1,3]9΄ߴ/v2/0Gv1 I CP;!S̽3hQ>N[yS!o%20(Lnӑ#2ݖ'4JS3 q<ٽق)zw!Ƚ ֤wcj^3d35<: c7 _pU3ʐwqa(KSOu+@?Lyڏ^A㙵^W_5d _o }g{ҝagE8c`%WTװx K:ab=\Aef>b"H=A4<'0Fma7ìkRhqy uLX6*f}R(p :5&z ޞfvv_l/<-.&2RA:}jW 6 ]Kȅc¸u$@0H`(4|+m6J`/R-M♡k83#MVnIq'6d'tikc4Uǹ> 5{Lz߳ug> Nr[\Q_q5C6-";"K?5 saf"H0PP3fG'QnA Ť+rdꂼ^6Mv}6R԰6f~6 yײ.6zkK9O<oK0p)}}Åa%?@dJ)J0Ĉ?!kG  3Yv#_AG=\iqTE{L`rz$5w H8kY'z[?T%# ʴznʴ^?l%ž^}A [l7/|[i|u&*kT)8E g@ _яh68/&,o]6ħs+5LUѢ\H;Le1q"(W݋4BmF;xe;D6j8ǦqiIU3}vU0ܝV{PJ9\~ HSrm%^ZѠ$dj\ߡ|hջ' fW.z`sQ <A\urd? vϨ`&ـFVa9d(X ^Pۚr-IeJ߮.k(8aa3NAg?0V tq釪Did~<T1 塐){;(G5ݭn.El ^ȸ2g5בcuGq@Ftj\R]݂?95[O\א=< Ve;eAJ%Zؕ%2j˺Ki2\gT\KV`4OKnjn(_}QbP I TUeE )% H%e (B*@%JԨR $G EA* %J RHqF iG(BUR BJ A!T*)B$UPQY P)TReUU*B!)UR*@J)URI$% U(bX$9C" V@X!JX, H(ԕbP9H ARC*(Z&kn3ɍ^{F~B+S;'*[˜V_ -I~ێvgl|~ML#29~•yL \lMe/d(t:>mܘxL(PXK="APCOᆧ 0ECq#@ [;~:,2gWJz_`,k|z= }!#l7ϣfjYQq1ү@aOhG4(DuKhN!:l\Ћ(l^ln~4kRBS&ZTsk๹O9+Ó?s)y%to.I06e(Ӎ]sw:qosL(j d8$ Lߪd[*I:U.Wf8&tmN6 n nγgՇ ļT|V]KJu~v#=Jۋ8$oH1:9gv[z\>$ImHnM[L%U'tWW&no6rL=qs* ,1`R!g~XdS3p%<7rd~Ɖ}@6X먷X5i^4赞>GK5!̸.(l|:4]eTGi*749@mnͪoHK{vLܖM*xc35D\ݼҷ0 )݋1B.OO)py"W▏O!%!'+y@Ρ@m؍asލhs6lP~Å\JMQ~-OqU.i~BGs@r[o,9ғC?̂AT:5"TR&M7,6r8Q5CY^ET: 4:I3J7c& 9Ro>f&,/u0$1)qxha(8ZX̼]Nusԇ©g}) ЬeKݥ q}6u8IMlb'fXYSȇᓄ+b}~i?(;=Ӂ.νU7{бDB|7i)~cĠR%&@d[D߲gfU؍ckcmIg I:Opq;xD=9>Uk5?:fӃ5 Olpw𒔑2]VMyUӂ56_"ӳacOC'*t3AAњ!@_ M~B_̓f OŤu znʻ{|\:4q4亯pAaqe\;=ZRc_I#ɾ[+{.6ts Ay *_R^9 3B k>o]I].Ug Ktg6BJ ,IA: 8 _piVP3ډQ's 'V=-6db; Iy41w=A6I}3v,r4Q@N~T_YFGPNiQP&,LZ7FE2ҧQޗ6LO}w3GY^.#psW>+&N`LLk. < O]CTLtؿŭ-!ӶMN`UCi@/bn[ΜaW$̿N m!.]<8E^n7^%=}n`W )u (FBANҭ&#M+^_{)<ޒn1j&1^*^ %3Є"oY㗧Tl e+*W[RW6v8eU)0ŭ%A[JK1>猧'r6k":~\ щ`3LЉ~Dp޾Q}W `5±z1ɷ\0Փx ZrmNL#Of% }QH.޶Aqt(syruvffN^jMGl}ʶ"?͒KZ<}YnfoyW'J~pvQ@kpH* TwζպI%{r߼'%-D^;f^zi;%xVRkj>'bw=-2eO~%?茬 wE;4pOLC4&9MlNXC$%e3j#y %p,*[rs H{,Wdx^Գ̀|gbf%y-fNI/LkZpsWSptoP2WV'*; 3 |r*K'WV-(o i!7G/g=e^3<)t\:/a.-z glKw"IL{^tS z\fjf?zOxji#}*>?3Q7W X̔*02k$yf Dv:>>;C^RASHOϼk mSJe7rO- ~2 1e,uWsE۱zGء_"G##Xj78]/2Fy%|@ZqZH>Pa.󎙐ɚ: Wi[_NGo&~3%x)sɆxO\7kaK<*:ffzj:l\ /nJe|xCԯ$V{֤-e:dC? 5]CQw'K[~Ai kH>e# ,Bg(Ƽ #-(D|:;JF&}FBLҠd8F#3?GƬ- x.]wޣW8*$ᷢswwTH;TeA{K6VϪ16| 1ψp+Lm$JPW+iV-6A>Zp KƬq4IF7*߻n r~ Cb>/z)@7Z5?T2M!klSb6.ޟ9ۯL D~^]5ǐEV-F2 gN˗^Xm"oz\'ggvuG%us67+O2ds aA wut˽:S^peJ*A|`N ޾۞N%{O,W~*@`=au}-xScN튛fkzcm|,!}q\FT^Ɗ\wf.v/Tq:JEN7zAafl*R:;!{ F Pt=/.S7e9(]F=k2?SL]sʼJ+lTHm=b䡨L{ 0%ܑC(e>wm֤hUeSOWn(?{"¸RDESSfak(d#FRsQCa2{uV}&4@qLJßIz|F)DWG}ý2~Z+D3UKXUn1"z1GH9ן㹯y'\ݻׂ~@1EZTPlμJsn=:Q)8*'N}QxY:;ΟGamYVsU*'ugoMVw)1{ָNQAz6 F^9;c䞲l85?KN:~M1vjTp&Hߚl,*ra(Mv43\c/eh(&FV9\L,Vgf:PJR yCKꔿ& ʮ_"[+G簔+B!|ӆ zKFݩ[$}hs4M3Onaw}M&e]Ǟ"zm|&ɫT(o3aD=|]qnrѳUOUVMd-,?%IT8 ˰` s=% /Kf\*UB|4L$PwyBD(Fmvm>wcQCuvҶ4GU5&5gNM0E"n1u;\ gl/AO+uXAYm 34:or{멗k;Q) !<_y-kF,RYzon愾4<d_g=>zMN \^*nz ԟZc煦Y҅dK!Уg½M(.ݑ_rIlqEo[d\@Q5(})hUngvTdh z7ZpNݷeJɪњWqb>oz .*.# J_+a g }U[BkM9ekgCr-!9UB.Yſc;g,55K?PmF&w.X\N^'+V Q}k.&a4D劌lki˶V,wƾ.ebk -V:UjU}b+ Z&& 5e{ <]ߡ+c7J3Jߛ"*R)_RGVC=@Jgn!x@{TFiQ 3t$+?C;tRF OܔmsՂ>re@_y0<S ߤXx$ Բ$vt!7>R"Pa]ߨўiO~T5)(۳m'ip2)/`O\R*bcmmL!K7>G77wT\=PM hjဠ?0uxo~*jݶvcS,PQz`79Fe:!O3Ԃ6!)PACMm>Uf.H:#{wb2yK% td f _Ã)"jE# 4iMpi$O"OvrǪu$EfC@ڳql ZW xTSv?KLwO07 sF$!:mGEnꐵ",%U;oo0{9c#jꊔX&wtێ}khcHKL@XD O. 톢N!,nޥ"6C^UpuPN1 fazXU+oi0? 23ŇQ:%e$CW?p0z8E?è*|OG@pkmd?r3WnVDhFo K'V) HɅ}kQY̖?8Utt+Xe E5guu0j1}Iҝq!PER8t|`Q']hu=a+&Ֆ:7E`1oLDcXa \?Kdߕ'0A$&%]ZA[Ȫ]Y;]6< /oK;nC++N`PL6;02d$L"qIx7!Pw(Q>~+4 O3CCDDPID"eJy6}*gMSHnK^MA v<8"̔ؗY`}ې~*8u^!8a[nNۍۊ,ž綔n=)Ӌlu@NbqVKu{y6o<jxSed umg@%1-唢jXT0.?$!!$mk櫾xMp^ReS0kYϹ.JF7j{Rj>j]v$ y"ݕ0%$K׷SH+^t8]Ph6O5@j^qk_k\v 0HdͪHX;~ǟwABcu+,Âw_QB%O{%ˉNzr*93x۾ރHy1`4MwUQ۫N"c3= 2?%VQ[.܉jj ؁JY$d𯕨|ތ'fjC{34@hֻrm a5lgau&Y~ Pa60Oۼh_6R`n6 ?)ڱ7JLI Az\ }g{VpLo^PR]fdf4it{3=53DƎk qj6IyTvTFCkSfe$|F[.ܴZ7{Q@F.w fedॼXje4=7G|7McfYXZ51.UK˕ւy?`ס1(#N5JM78ߦ\/̽ӚQdP؆?yDGbUX)Eeu;ksq' Z1WI8a6&g -`ԦӾ`?5 N6~ m(P|7,9|"Q>2>"~JLX]X:4"yaS4}ސHLKo (T'cWGVF8ڜ3fUQKYA>a6{HrhU`-KB|S$"X m&ޮ)s8=k;tͫm%e ?كdH{btTh"wwdꟘdd&_H{ncڞ4^gȈ~ҟ+lk?l;I]7rZ:ʈ:tگz ~1@D#+_uqx:6(Ր@];HmX-$lrܐG%ܣd5fw֯r}/*cX6jyn:^ ][a,'+?m`~Huw5@TG@O)nN7[7d]v+20a{h5D4n{{73WI?tKuf|;ɽFjwV@N3<͕d/}|A'q)KV_:>amo WK1dC];F#NfHNu X裿}id.f/λ7`d0&&0g|\ʦW"-=T}0؉Q1=FzGJjOr??*rOp.2$W1^c>6Ҁ>( [F -%]Ӌum>HwM>Aa0kW6:aDiό=Zim!kiZ $J\?ٮꂋP!#O2OSi»~{Ta/rɐˆ7!x+dKvhf-z [v p8!`U4K1z1L[uaKtl?G,~۶(:wQ%j]IIqLd\>ZpO tvIo-"O3c>"YDc7P%^%j FNˠ'4B<sdgQm ?<H:R.6%Ђn٣~jn1&r$Q:W!JuS_ ߡJʵtNoT[ƙ`(IhX/pRYZY =;3;9N/TBAޡçOS>@qAR6 >Bmhg2ǝ'?4ERDCj; :>R|AJ7nĎ|zcvPAitQV\%_" ˴L^WL<<9Y8n*eCU3J4M&ۛ! v`.x}m[ u'|Nzq{Y()FjvTdGUkx75vE)3Rl<([߻7NgX[I\d<``Cנ5ojO \O~ݎ@ # 0IM4zdEG"uǡ'BdyMN t݁/rLo\ #~%P ASѼ\$;]ΏCuDXYZ%yVGfu֮3})Vp|4dcn\FL$Sk}!XkTLI/kLvR UKҒH:O$wپv-}._c؉@G#+xS(DkHlCP㫍,/M@GDv뼏#<ֳn}_,Q*XS{r/sh.|/zm.< g9''djIN]ykoטuqHn34B K@d2_+C+Au艻PxSJ]ݠJ- H{+Ϙ-([Pm :aDڹ7iZ;!r;mP5dCVH@)^Q5Ds<HN=GB@PLT㱔aS4ILXXn'd|b@gH٨t#M"u5Z;Pgx< 9f)>Kɘ~_UYߗNM9S旈$2TO)C~gQXR0e y0 ]JbZjyZ5!apdz}DwzNuXh񖯳K]Q1pޚ 4 kW 0ʇŇ-zFF=A`-0@0,e2ucSJZ #ܨ drwao }b!Rqऋ4"7{@׮Jtql~.xBk#wDMlx ̓&_`k~yuo$$@ٳ(yظy J),FtׄvS13pq35͇hÎS|:tqi0AmM3Ŷk|ncyCm:>q}Y|_"k/uĝ>"B~1FmL ڊn^R8K29K ށ&.^^[/W786YTX0=8 a2e-yh7 wÏNF#FP| C8 $Qb2}8G:>6B~sx 7Ĵ"^+k2!u1+ĚX0ַO ñnY9X:ߥz<ًL[w *%A (Yzb,m<-CpZBصM^>?e6JJC|&6! >JDk&7/*y$b&q24SK=0GkW$xIx%jRד mD(/Ft=tnu0No [bް>)]i^exX,isT3V4U}Hxڤ5:3^|Jn\3p,b ~$=F#&l72 r(>^"bnK4^15 MPkf^ Q%)( 2Mt$# n^RO6/ =_<5 Kw:f}E_H&mwW<[BW z c#%Amej KQ;7Go$x{E1:/}WY/@mhb_՜m)$ȹxS4w%).QfGZ@ QXU3im !nlnp^cԨ ,ή #\^;oMTEUHNYgK֭fS4#\K‡Pget~M+Y@~Mn'duZ}JA %q\yN H<CJ>k#V' 4rބ_ zX~Χ8tY|>x^ ,fƼ}Kw_ @Rޟq/鰧{F]]b #' kOݬ:-i1kX ٥yJ.y\.=oWس:9vljEA;oE673 *N jKj0>zT7Nz`2T{S}Ӝ 1H% 8$Um\oہ?f*Mntnu;c`sϯʞӾ/g7=}N/\O>Mrt@ڝF.@ Q psTkK<މÝ)O[4WDS sxv^`eEeuF6Ek2F.]. çZ씀5=p>ww ވOSlCw1\J~'3v;^LH~:of0ҥ"?|l~ż؛;_/=q! Ϫe( A*3yξsWWaj%u 7>;<^_;8AK[)鯬 =8ŦS;7 /3ރh}7OSr: ~va\ġ?[viKԾU2&Ye1y|TdlQtIWG߀Hlx*YM8u/k]4'ޓJv}h_тG[y} 2жŴ{kO[FñC쌞G{FrD)t`8WZFgl{3]Orمع5Rk:x^v[ zt9 ITa8:2جYנ^49ؽ:GQ&u"Zf#;Vi9gەZᣳLac=qd2Mp6UZ,*:SWNHޞ6?8{lW .r} 3,K~/qϿ/ۘie/ϋě~{KpcWaCN`uHd~Fz!+^t۸q]l,K]%dy4 &Q6(0ysim2oٳ~)7beJ&yY3㒑a8]ޟ=z֣u#f"Y}xӌAC ^>.7  HuG5vL[qXֈ}6zs7d3a/~!<|i7mF*5kُ AO.o[ģJvy-|/}n;>? 걨`tSx8]ۼ/uO.3ܓra~h 41vܲJQ/Xw U'Ca# 1F><1dXmfiޠAZveB߬-D5VfAk$̐= } K9)$Q:  -xݙ Ӈ.@lw5. 6ݝp9J.}`By,I~KU-҄z[& B=2GGx -tUڿUZ)xheK 3*@B_:WK!x0Lz;WHg #])" {^i6kZ^cheETF*D ۥy|+i`Y]vz '@UFj6Fװ|j'֗*5G 2im+#XʨaQn VsKLwWlj|t0lw"(HTePsmcfcs/data/ex_poisson.rda0000644000176200001440000001520014002404026015305 0ustar liggesusersBZh91AY&SY0gk\; u%zyy{{@N:yIyz!hCf3MAL&ޔSƞH6iS4P02S=5=6IFh64FF!jd&&S򚞧0M=2)Q#TWv:Hɜ:.xo/rL0*н >m!:SmX\ C7Ŷ8民8:8i+hP;wsA_CQ1Hֆ'瑝_ 織Xԏ:\۸*$0m0ڭI31"'2 r\Ԫp#%pbٽPHfk!@U(

bL48dž]>|Ͱ~ߌow{^&3JG]/zP8Z~Q=N5S 1":CsiD7l@# 1!D]_GV[<};,Pf(o qn@\@hUh|L62Hڤ 21k)XXя6K7z(gD;WV]&9UĝϒBrN#iY]Ҳj"(?yɤ&-ik(6=ko*U)#emU7+sߟL&-10e "0PRJB.p1%n6%2*TR* K#X•UTARKrJ)>Qb!UЉ#%rD+AtHS)Q]YKDy%HU$r( !Ct!I"re"1PuQE: 2{3g#t 6D8j MBBfs l8-lؘt.tj7T<QE2Gj V[Y^"XL7d6<,DI4br09{&a¡(k\;TvnwsT-l"@ѠZ/=o$O聯HkPJӺ\!|Ux]&:N'X),{{\:>iF;_VAVWIߝζ7sɴ0Z+i_ǜN\R!?jWM-O+~,nF-yjrQ ۡ6DGm>75L\!]`:rI1k$RpLԢ܃y/ܢX~Ԕh'47,N?KMqQ] (=[h+pm[s"HL?1OӤGp1s$G wv\&('ҕ[u9m20^|֟G-ףg %'wuyYj!lum~RMnJ_(zeuYo q cyoy$鐬nˆIKOF%4#8sDCFOhckUn{ 6OSG<+C^*pH-Ȁ#{;=}yڗU]?&Ԥ/2"_Vrj?&b*L]f|$ V5 fR$T1K4׃G0ۈ́=RA.3ӗ-4vbG$OsJLUE1ץx:29#_g Юԣgvr^d~U%%/-iBK5;:ÁP\enu섑^ MNID {,O%j їna+j2B"4t/:l 5#'IDk)8 t4lU/oX;ȚH\ XupƇ+hnH65e'!5?.oĪJ…0DkfV9Kp:ԗn̾c2)JEk;oqtWAȒHӺ$ *@5LeA{e@VQ,\|No ]+%46/&4<<C}&8̌mrbM't\;"/X6"dt9,Ih#qYس$mal4Us9rfgea;p7!A _{ vh)ڮw)v@9gjUy!Wks\wG!xC˲(ǰUK&a3g\YRDzn7qRC~ΝPw} Kؓd)~mĎEJ1":l~KS0;Ie^\9kϗ`A/o]C?g6X#*IR9Fܼ*8N8IA\?6œ<0 qZ-CRۉgŦwII]PqN^+E,m&T 96gINX7 ~KGE|=s56+G2RlUOdS=\Ew _ꟆcRCM^saNpu@zJɳ6øO6l&}.NAAJSK@]bs0 *LTsa趌m 'I&5:TAF*6J]px Acgs_SK[FZ| rl= % yV!?dqԡZ|9ǥnncPxNV(|O]nһյ\^ 9FC~EjUZpϖ-}[e$ XGAzy3t[UtM[Q9UQJ`f3"§ܴa0T-IF.P$|'Ök6Oc] #}|@!@|Aq10]&#HEî/ݰUV4^YTo%J 4YV f8 Ӛb `A*:˨xֻ]Ϯ :uZϰzzw^̶fVkւݵWeV_iBA<5Ysdp,$F!ɋYdǶcxFSJ1Lho?GDk=?L̇:y2]Z`1Mo+`Y&$ c@j,n*'s$Z'Kf5^xzwTKg@1 ]'uh,,YDOv7(x\YK 5v>i"1camP"+\4\gSL %5ሸ qx=~Ԏ,_9&M'EIC-=,~s+KcdV!׮na%qyRɶ&/eb`w POZ^9;9mSuj29\/f &el>b:]ˣ<@J$ "΁3ژ !!ZM#e"qƼ3 OuU3C4n]JE([+KUq()Y~S#sjkpW'}P^1!,.\{F|ݙJ9X 9z ]ϛc$ql 9}:PdFoUA^̙aR~vSoyٺ@y{TXIus{l#mc$8!].=|+ ٔ?!PҬ^IwA#{A Qk*WpHA"8];] e[7-w%*&Ȃ!j۫gL[A;*9;~)= +Ԛdrѐ>hҎѪg 3{Lj_ _@vbh~fdUWgÀBj G1B 0g` ie'x`Z 鴘A]2,pgniv "v*Β@%w.:ǸQ۲LkIk\1`s~͸>7"(HOEsmcfcs/data/ex_ncc.rda0000644000176200001440000003610414002404030014357 0ustar liggesusersBZh91AY&SY]8/|Cf='|*4H P>xhPPPPPPP}QFRյm*-[JQBxRl4keyMJU=_PCF h4d&@)&LbdɉLMOMM 1Lz01dɕLM4SybO@0?54zM L2hLb@F4M4Dژ&i&yM==aAM02(5S&) @hFb e~jm4i=F4OIҏFh4h_dIx=>ZIuߟ)8#NPɓ,4s38(PK]aLX plUZjLi4RNo S5LAqQ"Ur\QG+,GZ)c7 fd9ks}*e0p.ޘbH*@bĀ@:=z@2?WBCJM&i H G($L ȰS $ B '&m2o(xIa ɷxUViZbīX"Z6i PPTDj3ek3p7DH) IiH`!)$bW&*ֵVm2JIJMR]EKssJ;^j']l}ěXfGCniq9~jHB_ ?j c@Q9 d<;2w["k<ƢFoUU.j\W~HyC0{`GjdѣKI'SU t hlP@nm oiqW ȷ,+{yY:_ vҌx{vwLe0{L>F9\.jwnw}=Uh{ep 0ǒD -yZȼv붌Tɱsи^H? ó–[,޺T g2jB !b, nk</#%ǣk;#2y-47k{X{|;9Lٖaoշ "C16/쑺au+'*y˶ψyj>4CsZf(YyS.IN")-h=n*~)OfN"B~_ 8ϯʜqߩfer1R}JETxRH^,O]. 7 @ݨB am ;*_ڻD'ɴ2Z/N 94d%! Y|zHЃ,2 wnݪSl֔6#|U|^SW)i3C~k>iȡxhsۣ;hu{2mYo]^xm>R0RZdt{>f}1nefȡ` ؐVf˧}߿eP7*Cٌq%طT,R+ Sf$Nڒ;P7f D[K`Ӗ2NQ0U-yτ  Ϙi- g, $}Vt>p BYI|N}O*O7K8 LFU@i6'@a%OQהiIq2\ð! fpR##i\Hyt.4an_,>lNKfs1v-hӿ6ҊK 4Ll^D_^/|l2z0 {ʑV^D@+N䚟&`jWօQT[9^Ōyh/'[eTx@E=ɾI|U=lRjֻ+= hg:..\U(y8q[i@ <ÝH$ bK€TNioB:#QLʘKuAB"MapAf1q- 9WX?]h0퍪Y PI,uė[~]VAAN*{C0Q޾c7 @a ~ nJ5i^W&qPpvJUr"jd{m5ϵJ*Zx\ F +5}7PX\!%5PMy9 lpM 'Yg!WPK;$@7_{ a~B `;aCbl Sْs .?9HZOAzuOK0:zO=K[NLJƮ% ȸPҬXس]qrVylz#h&JRlrbZځ9wwwh!+3ECr ; HkhC:;fjHѷT4x#Ah+g\c(Gi|żO\fZ80MR:{~˲*:oZ2'9AVLzkxIV/4yC<=kބԑƒ)Ki‹9U/K KPDDF4K0R> n'2pȈٌh7N?mxszj=F@zA['R63GS=Ȃj,ad v7q*LP%[e3''?73ow(̈]]f9Œ˺#TX#leRR^ EĂLHUt6vgD}=cZn+p[ ]\fߣj{b5r8e=v1L*6Yki`Kv}ڍ ϓ6y9C*[nn'? `I)Y ;,2SŦɨZ+h XF[ME'"4EnDoZ|m?yޓ[ (|^3u+pV:c09ۚ2x]=&dbD3SK䵂eTr|vMg=7ɇ&"\ؓ,#d\okKgRqJb]܁%<+1 {VtWt8D R MٞgJR1~ fَ݃`gծr&gg5OWICPl_o)J:0 .P84 r|1k׍?9M=pwz}{; _s|t)N&2O=v\Cح +VWA˜э[F?lăD$;6|0#~d6mגoaX+D:&׋kbb3$ҒZ?]-l]# SQyQa *xv AzoX|R{Aq]dƔ6 \(+/uO>~5n+'GiZW$NMUbQ IqJ=v;]-4z/g:qcc/}{5CKQwȅpE\_ u䓄ѪܞsBx!}'Wݙ`xnDdsn{B8|Oc9g kGUۍnyJ]qm'; ine@ctD\|Y0' `Lc[C4=lat22iPW U_{sQI/gH"dhtV9,1kASM]:EW!>HL( 6;ޓP9\ZlĜ3aoa`NcA1F\`ꤺlmP l D= }ĩ-Z{컵UgqtVp7oӍy@ vwjnS*b^ހOd#qrsҩ#ZT@ zXu@] GܣA՞hϛ  UB P ճ5hpxe lwƋWQ M K^@*#]˃tdz=hZq^&}r`%o6TX\ɶ`w6nUOovAXC}}B >JåLbw,N4THBtֹUT ƹֳ$+Ǒc~HRPId/naw-Z:~k _8BIdRϤD7Zk T~)7,P%.is܆=zNJʧ !ў4x-FǿTyd3  cK@QY?2qd2,yj!̾y9ԝv7qL5/݌״OVĞFMp%Nv(/Maf4r1g]E9H gNz~ HHx?_St&9w9թ~ԀD5}$ht&G{b?Ɔz`[}E3Îи'1ךV*7cP(^[*b!x1ڥ"jHWeA I8k-u3A@VwsjC^سJ̀D9x$R28] &< zyq`7Q=i$#wf)/Ƴ'atNAg%.KP?r(Լm(C"@?lg]9X>MB˝OB?T%ZZZ)<ք0BbPM?hMPe' z_lt)p(}ticKZC>6Y&ؐm $RY]glzQ5%s G$R29Ƽ,:]eK)lV47|W1Gmj'Nkҗv"VkW>@MϿq.]ޭzJ UR^ϓ۝M{8]cJv eMd><]o_XeSo-Q0i ,mAgs6c[6k㘯%sXk}L0pwmV3՞7 Dh#i]µ#q\39tѢ|ycI,U* .x51>dz0.)(5~9zW=3^4$CE%QEQJ"TEj PDRiTGjUb-* OhjYL4QfQT*S(HQjT,ZJQT%+IC*TSjU(RRe&3ۀ(7~g* F (Ʌ]G9U~X/K/: I^9{t5,6`!x/qsl,OzAW^e-8}泫E)ש椩Y~p oRڂbg; dZ7e[LxC=C*wCCUH:%LdKGҖ qv 8rO"Gow['Rpr.H'-_"0Tcs zڞ^:FkVءbД3"mNARӉ+8nx:O.M$1;U0 3MSJY12#,Q9}JNukv\`?N.z\մө>R&dp\Nb*lcZ)mmYo: ڈlwЧ,c U.z!>?njeK]僀lڏ`,CдT<0dpKg:̌{pwzȩ*LK>$mg[_N0u02j^&X{7m^f*hKlظۀF\Պ-]ЌJ>էRu_}oQxFB ϻa26;/y3Ͱ`ǠM?m$ÊXh-ŷT#vip&alr~'σpm߻b\9̞ZIɂ(U8f ^^,e92nj+Rʔ^v+m]?`rHLk܃KyB#Mb~ wKd,0o폶N.ZVp^7'$9O',eK,q!ml ]”>`rޫR5upP,(_i>60l[rֶW$?Y96Ы[O-!`Wƙ?}{q'R精㦗uSWi+7ɫѲi\# Ǽ-aio} 'xg([_냼?|0=Uʜ(8 ;=44$J݃U*äVCm 8ib%: &_hٯi&5h2@OW^mMGI.P K@_A)3W-y٬(AbBDܤn&=aȟ=x>E8\iptFHWު y*Stk8 7im8x8yuIX!lBK -֝{qOE]Ou %^Tm:Frq8QOE}Š* ؿ}!_#b\o8K]/-B:Raqz+V"X&{V4q"ɤ)F\tK` 0QUާ\O1xRS@D(:fS⯁fƯ_)eàڮ㼷m_tqG aIWW𳩡}ͨj(͖0W$Tn=?DfȒ< _P$Gޑĸ$:]Vv|x0p1?~VWGy`HTu• єFcjV,Z|#Ie{$&2l$ڷo5SsE\mg%Ή=D.5~z.Msf3ՕʑT{i-E䯤GnvQLMred 96~'^b'ogp>uT|Gs 5{Yߢ=  )K-0{?#v&S4fB֠hN'>`r$MpBw;u&9;DD&z~hӠZ2$|򟾚&5]]tcp*f`6P ݟ4`HwRoE}G}>[8n%X20|L-eaB'k:y}bDy3*\C@5֖mϓ7l4Kxhafu:\7JBq\dXs.j.vsA .~7p!xHG^H [ $,r6r-Dij$~jd~'A⭷B(c0gAz@,&-%n jK+2 (|$ Ku,LRo;p,2{84N5sLyo]:1GXG:,?ӑ9^$N)ҙNǟ|ST6VU9Y\jRC]'-<^g,K;"9F(va%Zr\q<'ajKG@b`v Q-P\Ap0Q'$ђ9RuL6 Pu-LF #/WoQHxFGy[<ίEc *Fl.?$&ح& %XA$dFBHj'+y~m)-NQk2(` e'f'$GB,FT{Is*@w)%8`=Y!Icu^ШacL(b<~!N-Μ[|z T&?hfT4N!xDŦcMp\f܅!y-VOrL㉩MdHǔ!̩!]/nNqGDٓPũLHi)2pDb}9{d3'#P My<r  R 4(͂( Y^ ^ u[AC"8p_+7J#out~1A^SAc*FCю@,̬}Vr߻nzBq 445pøsۊJdgK6x"X5,RSk 5 ?̛ <Ю#n3AM`0S~( iM[p2 6NB$Mc >vޤxHP[`^MLU ydSł}zwsw?mx)'Ifo$'DV!;~ճ$mXQ%Z ?YxWItZ)b B ŭ*iKbIٽr4H,~9# 4 HD׌,Q<X&!&?h0TpYDjc J4 \PK %U$(1ƓaU -c/@1"z[闆:>lmwvMJG LƦURទ6 #1>c6HO-G;;Vx`V˜ 3e(`74Kvp83 ȳenR4=UN,Ơq$f: ];go,V/ wBY & E|2~8es|94+:;}iKcG,h+zm;ymK#|Rk] MRKID] )CgWl-SO{0Iv8ӜT%B}I p 4AMSGx#SribݾNsOO_$BݾRLR{7@=q$Rw_+" [tKm2Yo"͠9ƱփZn7r ZWy:̧+8H>bA((}[Jd3sz>V{.-7XP*sq. vLy/&-?'^۳i{ً; E'Qdo3:>4`ϱulB lk=g3wFؓ<`Lb.Ċ4@{p^?ʓ,>: i,!s2 <ΞTHϾeyI}5ޅU \n[C9饱q@Iny]8T ӿҁ O (A0zA#]V>;5/|=Qx_T Z?Q+)8+JU,y2ߩ]'q{>:Ycl}Z 4Ew/˅ooMe\rE gc ̌Ec@Pf45GLn=啠$!ـ]e۳-ˋ)&2h43so9|/~%DTEg84Mƶ_pӦ(&aucMμE~ M6 m:Ϣ4 pH|B blmZ gJThDTwmAKw&5T˧[:Z|ݳfV&pBLw~oc >WPíf"'1M۩pRqRzņd'BP\5B4QG~>G3ے`iqī "K$dL?f\fVO "Q_uǺqn!f% q_*O8.!h52:D7pee;;sMӀS?%?ڇ9b<j@ER_dp~K"JUԌ985b3pz-µ(cZ̻qs.BoΦjظH)95 `,lЇ!A'Ǟ𭾂A(/LYGg+U}I@=S5Ƴ69w bV4o)uĢfI3\:%Q@U,_XDRf Mr%4EuF^L"%N`o/ڌ@v=<[N<$Cqb%BKp.;cP@r*X9pjFGY!"<؟]+om꒽IDq,xsT>dǗ:k|WQ0&mwAnVf]}ԫHd9 ^5ص$6хKGs{U:Kn%%GkV8l:;׉(*왤3`7徒}f ̫ t:<\\P!Eb.hz"I!KFi΅OMugJa8AY_k.C7#S~O: n_տJ1{·mRa}<碐K $߹o>~V>W뷘nԑ\3RcM $KKccW' pAܲVp`K}zo\S8"B R(UmM?Pe]5g^V7)u2?ߺgzKsK* ψQUeИ5D&%A '{MZ{Cp ,bRgɠyOq%NH#r:JQ\ȗ}yD]>yV;ƭ `qeO%i0S9@=c#)ݰU4%Wu[ )1h(m^r{0G/,-žځ $l!+8j$ sYp†z$r}'jKs%]NtAEBc=Xw䏦էv]$u* ޅ&9c'~(_~(Z@&k(0_(أ(fW6Ņ[?)q̆e#3RnȾXߺ;,@eW:{!&Ӌ/H>t;\W뵨1/"TaNGDG벸AF9}S!͒]l揄K ۸Iic38dٝlMi8 CTʌ kkBz [?"ܟeLqcGzRLПy0Ӽn]xU)&bp-Q@xu GK`%z-bPWIooLwYǾV{_:+_OrBE&wtmfeܫś##]R3 ]Z-An,gr~mltJp z$%*`2v2`yRư'm,zTcJQ:J(+hA {PfIm4'<}d,PMTpsCx\|DRyor 7 Y.5pw/YN`nlB`8VGU :]^Ogsھy?7)0:5;5H1gQO=V(a-w''`*܇p39(Վ˩0kF~}O_ص9hItIdVvK_Rؗ` V]Pz,UɃ2?e`VQǤt>瞆HK z[3h._:[SﯾXy>-ſwɔaYO)<픙 w>1zm53#%-_9soFrOةDA4rMJ,Ba.\"z=+ip[xqљOiD6~O WX-J$Zb ,孆΋UPEZ{ wغŻYi2ywINZ1c%LLk(آlq[U0Mj ~=Œ"Xcnt,D5A?T}in. Ĩ6@ 414GwX6kծ cǑ%=5KȂ ^nGn]V9Fh(c|^F9ktmy"G j {N.:WE)Tȟs43r[RAh|jǫ"*](5+qGҳ/ ؆fFMSԔ=j. !Q2 k%纸^RYD3 .' C ݠf6!8LC={m08p)H=cV`&2ڤFW/y̆i2,W9/E̾:}9\oHԣEz+h$-v.T_Uv$BKa=gh-0es@,Ѳjf4M ̳Ѝ':0=:g 4.QW jk -N(39[Y* PrtR1" O>)4/`P~gWqȕ>%Jl{\x03"T )Ӕ_ g@B@pq>C"h c%!IŎ3AFN kI+XĂ *]aV7<0]xh[KCNᛯ"c\WFA(wȆ]d!ʹxo1%\S7$C2q9].G۔BPA@46}6YWo{>ݚ 9 kC nip5448Õo|v'~$L"ufNEO3M"A ?;3x#rYBbY0 >c?*k2K3 b 6ϫg2jkA;aA0Ie Xf|iqFm:=B `rZB_poFqG?`0O`̗U[GY/08;S*sVZvUs-T^G6QUwykQN pg_L=h`8O HYދQTm?mK-;ҿ V@">d=, mL0VaRݧ &}9W|{PPMoȩ- V Y;7u*Q0KgccvZ?G(^_?e{v'F.M]9 3mf%z`H60FJ`@c8+fW ؄|OP1x^J5M܃ܼ^0͌NDSՍ)j\ 98DfuAWf DOQb Bzgo.^ʛ.SI0k 7ľdhCM:xyo6bT*N@2i[Vl;$}Bˊn{ jlldC G ?\x‘V҂kq5ERXgT(=#}@WJosմMO%%kϘ;4^ ] P-R퉁 >7x Z5_OP$X`TzmFRRz 8ͩmƩLm}'$kvgJ\ʤG 0p&k`Ԃr֚B;UFеa_3ш_ͫKn+ ,61x:OO73&0PAky\j0S1+&-4uU׼D 3H߆ʶ!ffPхd?ckgm& )Az6p2GC\8f'вcY!p7W~koˢlb>ߎ\ё_Zx}1uV·`P/3_3;}`w=]\Wѣí^U콰6 k7cTM$`RG$o:%(SzԬ5`#WCOȪ*AwQ@~J֌=L 6Yzlz͵m?)9 ބ M*t:5dKwo(DO~rJHC"[xd7k1(0ʴذ~fj]jk?XHXP%4Ն7ZvtYCEӁ A&)L!p:>?Y:F" NFC7>#-Xla{cbs?)wp1bOdK}6Į@oُ (u]*Z-O)q|gs!+C@x>%Lo0+,j2D<_kP+t{niM>ϞA0δM9.@8Q|SnyVʟgb"- 6Sj %G!;]ySy,4g#W#'kũxJè@3p z*l5Wm3t\:P;5fSA.j "ovNJ )pipԣ5s>>]:V}Ӯ$W6MD~8! x6D% g/%c M*gqQ@K؈POk=^qmVQ;;4RA;: uqs].jfIGyK$4Ή.{v_ov1œ\֪W'xǮޕyD0hkOGa$Vx_|J-Dϋ[g8<~ª{,"+nNfAب T$iȵ2O~ɲ^}v ԫwys:';wںuˆ (y05w4yG`: c昰6Ҋ61=B޽U/&CKRȔ[YB;Z2}÷خqÈ$+|鷡T9! ҧ<)wmZ5%hF:85he't]1Uϫ- w]Icc/{KC]/XGd8O/庤}S8Lމ: gu`M>OGV?:#xst3n> jR~" bf1 |4h\%"=K6^\qq *u05.-5S) ͑ߍh"DV=jN_+ۥ4ƣ"~5 zQ3R?wB2Ā]J*w'Bз;Xخ!9zmSc)xEu{5qEum#߻y>:=k.܂4A?R67PW4zl>wƌۥ6mZ4.;  [M F&dNdqڣo>n];Ѹf~,6HTQut̔|6V>4 >]Z幥ןfSvms}źSA2'M0`5355=4ɑꙪ~TFhiFLe␒(Ifa$&BI#Ih 6$96$΂q $!&I 3 HH!5RC9/%k|ur.K\̎\w() ]4Ui0Lw kmX?K +B~^ւfHH?N+QMchW]'h`;#Y{>oM- g[F}wqp財 ~dFd@~nk e1ևkZf$NnD4mT`23>@,16z"<6P+ AA Hq+8Hd_K?Z&un{ۖ~ԥ͹r;qN9t(C<ߺw>@k%DcptnS+a:Ig.}U7J$4%.2a$f8]o-Y+@$~+ڼ~2ݜahNJ2_F1nN75t #Q嬚y5DNv2"봕x mO{%'9 l,on ] ;RQUJDvޡGsH>QͪQ`Yp222nbk,0g&8\Tp7t,6gh,հ<57WyRF!<< #;k>)Fg[(IبË_r"HAvo,A2Nķ,v7Z</1\8.{ry=#A8LZ3B腵[ `nQj(#/)zXMRщ,Gz㦓Iv헔F~ҽjH;vYeЂp>7[J#|FpXWroc=N{Ozeꝙ䘦uwXt?OOqwp36eX&RmQT7(xgΌ LǠ#=Y~ /Bڱ˗3E}mdXI,mfϧO{y:CVȅ{>T2K ְΞv/!&vCaՀX/R|Dli%{5Ӗ=&3}onj)nЊ]eNcY!1ft!Qb G.*pu#>eRsA0 B 4/x`$U(njmR~Tõݕw=%e-+vFsɖO%.jF|KP%,[~EM1JumB0eJdX|Iiz.A@2X7<^C .9 "'22߽܉ Fŏ3=oaѓ&֚iTsU/jfJւhg9Q+u2;kl5_Pm[隺!){}Ngz HT豗xcaGV1'qgrT{ 4|Då Ĭ3J%uA_Ovt},c?5l&4;`> M8ةCP"aTVƜ3 bŏ iP XuUtz8C#9v_k}[ܵc`ߋ {exɰ|Nr(]'-JΫJoׯ"c`>P1sWj]بTh%Yc~FrլoبLe1g#߁B$B5&Ҭް⑦dS&R5B?8DW+'ݹAOPTJJ.cp`ͷ7ߜ.uDC\l;1O93RQ)įSw|]BQF5+`πm^=?5Sw|lX=Q7TO1K"DB'bo{_Hn7嬑QĔ%Z& )% F iJTQȘq!"gN76hnb2LF $2@&e4dQ dDi`;#-4Md)R 6Rj座 D&B-,JR ( x*5& V0$L@QF%ݽ\B"|'mw7=\'_4} FogXņ@nkPXiBVdoxYI0nɅgqRDUmq#޼UӬ2KoXo>)DΙt%v78澿I q\ç}Wq9t¼MuU+Q >1ҞA6QaѴx&=> _ikI w-S4FӞt0oBǭM9{?%u;{=bA0ԢWaAn^[zfSA~vP80\qe`ȟJvk~Ϗݘ̬7) sr5Qm-~S9%o!qWaTj*Ս?)eS}##`0N8< uO[506NUp])㛹=ô1okkY( 06b z! H1/x%r'ńxh_QTÞjRae-ghT⼴I3>![R)pxeiFlEUk3*L{9%ʩRM5LsCp!Te dHJ鿵״ܩ&N r_c4w Gn"[RȉPqPxK>4kv5+5cʕnF㓤"J >ym/Q̋ڪZx7ҽ1B͹'@*P%3_^u"\j\^=^-rȺ>?J6iGG5J;"o@ڙ lB%RWb/oAdӦg83Hry.uΈh ڧoIm UO&&pPRIV'T1vwۯ?:]YK(CBNcD.QφLhH0pQ?HH8@0\#)n%,`+ K,35aX`K&FD$?TSA؄9) PR 6]n&LRK:IN[Pn뼛ѧ);K˔ u ɨԭxiEk=w@9̔8[2U16`$xSYvdn:.vJEgts)7̘c /Tdu*%c|Shj^2hVRYg|^ ,BnS {!ڒ[E 8IO,[b+;2lfhhdC* T-f"p#78BO.5*KO)p = B:]FQߖ}>XY.D$CzKp T%}$Qc ¸CͶ`-OPGFXc+h9},(4e> \腇؍ADk'oVf76q7 u"@0!]>l"’pu=!O [{~Dr ՖB(ejl %DQ@(H"E" vDf.fN\J e!@R#céL^%SbH3"EM;yUw)^ ,՝GtwҌ;~z?nzޟĶs(|&¹`n`&6ƙMNᢜ̆a3!t!PƎH?(A0t~G^=i>;0Hg>*T[{S>_Gq9, Pè6yg;4P'VFgK`toIR=1u]=A}Eoxzs휇71&#H۳N^Fxq\:WzYާk5ľ_dZCΰu4گs<: Q\AM#(XQn>(nDp* ҡXAmwH "fwa?F.0;sShf l(fߘ $~kYIA8n QY[agX"Y0t6@ +F']Paat9Ҵxd7vͰ#\Dز%/!" 0F .Q_ax^v{~?.>GYcu+`I$@ͷjjtGY[ a4t:vXZޮaT3Nu~?d)\ͧͿmn̎}>ܱuE<6wY PѵʴrgH2 ! M-=dNhNjl>%n#/1s_QΡp;z7X>Y ://~k Ě~6=uM֟cknj<ŶW+CpԦ SIoaw8*.ˆ&t}p9h({Q&8/$3&swI2uBC,bhc*Tu95?gLcu xe/4&x):$ l`Sϔn|"(<[gcЌ59:[QS\Klxv jt6N` Z}?~Y>ӖY; DJc6zvh-;`&BT8+k}Xa@7)4tl&["PI0F)„esmcfcs/man/0000755000176200001440000000000014062655673012321 5ustar liggesuserssmcfcs/man/ex_ncc.Rd0000644000176200001440000000135114060150767014037 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.r \docType{data} \name{ex_ncc} \alias{ex_ncc} \title{Simulated nested case-control data} \format{ A data frame with 728 rows and 8 variables: \describe{ \item{t}{Time to event or censoring} \item{d}{Indicator of whether event 1 occurred (d=1), or not (d=0)} \item{x}{Partially observed binary covariate} \item{z}{Fully observed covariate} \item{id}{An id variable} \item{numrisk}{Number of patients at risk at time of case's event} \item{setno}{The case-control set number} \item{case}{Binary indicator of case (=1) or control (=0)} } } \usage{ ex_ncc } \description{ A dataset containing simulated nested case-control data. } \keyword{datasets} smcfcs/man/plot.smcfcs.Rd0000644000176200001440000000315714062220333015026 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/plot_convergence.R \name{plot.smcfcs} \alias{plot.smcfcs} \title{Assess convergence of a smcfcs object} \usage{ \method{plot}{smcfcs}(x, include = "all", ...) } \arguments{ \item{x}{An object of class 'smcfcs'} \item{include}{Character vector of coefficient names for which to return the convergence plot. Default is "all" and returns plots for all coefficients in a facetted manner. Recommendation is to plot first with include = "all", and then select coefficient names to zoom in to. For competing risks, the coefficients are indexed by their cause. E.g. for coefficient of a variable x1 in a model for cause 2, will be labelled "x1-cause2".} \item{...}{Additional parameters to pass on to ggplot2::facet_wrap(), eg. nrow = 2} } \value{ A ggplot2 object, containing the convergence plots, facetted per covariate in the substantive model } \description{ Visualises the contents of smCoefIter. Specifically, it plots the parameter estimates of the substantive model against the number of iterations from the imputation procedure. This is done for each regression coefficient, and each line corresponds to an imputed dataset. } \details{ Requires loading of ggplot2 plotting library. } \examples{ \dontrun{ # Use simulated competing risks example in package imps <- smcfcs( originaldata = ex_compet, smtype = "compet", smformula = list( "Surv(t, d == 1) ~ x1 + x2", "Surv(t, d == 2) ~ x1 + x2" ), method = c("", "", "norm", "norm") ) plot(imps) plot(imps, include = c("x1-cause1", "x2-cause2")) } } \author{ Edouard F. Bonneville \email{e.f.bonneville@lumc.nl} } smcfcs/man/ex_poisson.Rd0000644000176200001440000000127513757721034014776 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.r \docType{data} \name{ex_poisson} \alias{ex_poisson} \title{Simulated example data with count outcome, modelled using Poisson regression} \format{ A data frame with 1000 rows and 3 variables: \describe{ \item{y}{Count outcome} \item{z}{Fully observed covariate, with linear effect on outcome} \item{x}{Partially observed normally distributed covariate, with linear effect on outcome} } } \usage{ ex_poisson } \description{ A dataset containing simulated data where the count outcome depends on two covariates, x and z, with missing values in x. The substantive model is Poisson regression. } \keyword{datasets} smcfcs/man/smcfcs.nestedcc.Rd0000644000176200001440000001265213757721034015656 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/smcfcs.r \name{smcfcs.nestedcc} \alias{smcfcs.nestedcc} \title{Substantive model compatible fully conditional specification imputation of covariates for nested case control studies} \usage{ smcfcs.nestedcc( originaldata, smformula, set, event, nrisk, method, predictorMatrix = NULL, m = 5, numit = 10, rjlimit = 1000, noisy = FALSE, errorProneMatrix = NULL ) } \arguments{ \item{originaldata}{The nested case-control data set (NOT a full cohort data set with a case-cohort substudy within it)} \item{smformula}{A formula of the form "Surv(t,case)~x+strata(set)", where case is case-control indicator, t is the event or censoring time. Note that t could be set to the case's event time for the matched controls in a given set. The right hand side should include the case control set as a strata term (see example).} \item{set}{variable identifying matched sets in nested case-control study} \item{event}{variable which indicates who is a case/control in the nested case-control sample. Note that this is distinct from d.} \item{nrisk}{variable which is the number at risk (in the underlying full cohort) at the event time for the case in each matched set (i.e. nrisk is the same for all individuals in a matched set).} \item{method}{A required vector of strings specifying for each variable either that it does not need to be imputed (""), the type of regression model to be be used to impute. Possible values are \code{"norm"} (normal linear regression), \code{"logreg"} (logistic regression), \code{"poisson"} (Poisson regression), \code{"podds"} (proportional odds regression for ordered categorical variables), \code{"mlogit"} (multinomial logistic regression for unordered categorical variables), or a custom expression which defines a passively imputed variable, e.g. \code{"x^2"} or \code{"x1*x2"}. \code{"latnorm"} indicates the variable is a latent normal variable which is measured with error. If this is specified for a variable, the \code{"errorProneMatrix"} argument should also be used.} \item{predictorMatrix}{An optional predictor matrix. If specified, the matrix defines which covariates will be used as predictors in the imputation models (the outcome must not be included). The i'th row of the matrix should consist of 0s and 1s, with a 1 in the j'th column indicating the j'th variable be used as a covariate when imputing the i'th variable. If not specified, when imputing a given variable, the imputation model covariates are the other covariates of the substantive model which are partially observed (but which are not passively imputed) and any fully observed covariates (if present) in the substantive model. Note that the outcome variable is implicitly conditioned on by the rejection sampling scheme used by smcfcs, and should not be specified as a predictor in the predictor matrix.} \item{m}{The number of imputed datasets to generate. The default is 5.} \item{numit}{The number of iterations to run when generating each imputation. In a (limited) range of simulations good performance was obtained with the default of 10 iterations. However, particularly when the proportion of missingness is large, more iterations may be required for convergence to stationarity.} \item{rjlimit}{Specifies the maximum number of attempts which should be made when using rejection sampling to draw from imputation models. If the limit is reached when running a warning will be issued. In this case it is probably advisable to increase the \code{rjlimit} until the warning does not appear.} \item{noisy}{logical value (default FALSE) indicating whether output should be noisy, which can be useful for debugging or checking that models being used are as desired.} \item{errorProneMatrix}{An optional matrix which if specified indicates that some variables are measured with classical measurement error. If the i'th variable is measured with error by variables j and k, then the (i,j) and (i,k) entries of this matrix should be 1, with the remainder of entries 0. The i'th element of the method argument should then be specified as \code{"latnorm"}. See the measurement error vignette for more details.} } \description{ Multiply imputes missing covariate values using substantive model compatible fully conditional specification for nested case control studies. } \details{ This version of \code{smcfcs} is designed for use with nested case control studies. The function's arguments are the same as for the main smcfcs function, except for \code{smformula}, \code{set}, \code{event} and \code{nrisk} - see above for details on how these should be specified. } \examples{ #the following example is not run when the package is compiled on CRAN #(to keep computation time down), but it can be run by package users \dontrun{ predictorMatrix <- matrix(0,nrow=dim(ex_ncc)[2],ncol=dim(ex_ncc)[2]) predictorMatrix[which(colnames(ex_ncc)=="x"),c(which(colnames(ex_ncc)=="z"))] <- 1 imps <- smcfcs.nestedcc(originaldata=ex_ncc,set="setno",nrisk="numrisk",event="d", smformula="Surv(t,case)~x+z+strata(setno)", method=c("", "", "logreg", "", "", "", "", ""), predictorMatrix=predictorMatrix) library(mitools) impobj <- imputationList(imps$impDatasets) models <- with(impobj, clogit(case~x+z+strata(setno))) summary(MIcombine(models)) } } \author{ Ruth Keogh \email{ruth.keogh@lshtm.ac.uk} Jonathan Bartlett \email{j.w.bartlett@bath.ac.uk} } smcfcs/man/ex_compet.Rd0000644000176200001440000000153313757721034014570 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.r \docType{data} \name{ex_compet} \alias{ex_compet} \title{Simulated example data with competing risks outcome and partially observed covariates} \format{ A data frame with 1000 rows and 4 variables: \describe{ \item{t}{Time to event or censoring} \item{d}{Indicator of whether event 1 occurred (d=1), event 2 occurred (d=2) or individual was censored (d=0)} \item{x1}{Partially observed binary covariate, with linear effects on log competing risk hazards} \item{x2}{Partially observed normally distributed (conditional on x1) covariate, with linear effects on log competing risk hazards} } } \usage{ ex_compet } \description{ A dataset containing simulated competing risks data. There are two competing risks, and some times are also censored. } \keyword{datasets} smcfcs/man/smcfcs.parallel.Rd0000644000176200001440000000460514062657540015661 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/smcfcs_parallel.r \name{smcfcs.parallel} \alias{smcfcs.parallel} \title{Parallel substantive model compatible imputation} \usage{ smcfcs.parallel( smcfcs_func = "smcfcs", seed, m = 5, n_cores = parallel::detectCores() - 1, cl_type = "PSOCK", outfile = "", ... ) } \arguments{ \item{smcfcs_func}{Specifies which base smcfcs function to call. Possible values are `smcfcs`, `smcfcs.casecohort`, `smcfcs.dtasam`, `smcfcs.nestedcc`. Defaults to `smcfcs`.} \item{seed}{A required seed, set as `set.seed` when `n_cores = 1`, or as `parallel::clusterSetRNGStream` when `n_cores > 1`.} \item{m}{Number of imputed datasets to generate.} \item{n_cores}{Number of cores over which to split the `m` imputations. If `n_cores` is not divisible exactly by `m`, one of the cores will perform more/less imputations that the rest such that the final result still contains `m` imputed datasets.} \item{cl_type}{Either "PSOCK" or "FORK". If running on a Windows system "PSOCK" is recommended, otherwise for Linux/Mac machines "FORK" tends to offer faster computation - see \link[mice]{parlmice}.} \item{outfile}{Optional character path to location for output from the workers. Useful to diagnose rejection sampling warnings. File path must be formulated as "path/to/filename.txt".} \item{...}{Additional arguments to pass on to \link[smcfcs]{smcfcs}, \link[smcfcs]{smcfcs.casecohort}, \link[smcfcs]{smcfcs.dtsam}, or \link[smcfcs]{smcfcs.nestedcc}.} } \value{ An object of type "smcfcs", as would usually be returned from \link[smcfcs]{smcfcs}. } \description{ Runs substantive model compatible imputation using parallel cores } \details{ This function can be used to call one of the substantive model compatible imputation methods using parallel cores, to reduce computation time. You must specify the arguments required for the standard smcfcs call, and then specify your the arguments for how to use parallel cores. } \examples{ \dontrun{ # Detect number of cores parallel::detectCores() imps <- smcfcs.parallel( smcfcs_func="smcfcs", seed = 2021, n_cores = 2, originaldata = smcfcs::ex_compet, m = 10, smtype = "compet", smformula = list( "Surv(t, d == 1) ~ x1 + x2", "Surv(t, d == 2) ~ x1 + x2" ), method = c("", "", "norm", "norm") ) } } \author{ Edouard F. Bonneville \email{e.f.bonneville@lumc.nl} Jonathan Bartlett \email{j.w.bartlett@bath.ac.uk} } smcfcs/man/ex_coxquad.Rd0000644000176200001440000000166613757721034014754 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.r \docType{data} \name{ex_coxquad} \alias{ex_coxquad} \title{Simulated example data with time to event outcome and quadratic covariate effects} \format{ A data frame with 1000 rows and 6 variables: \describe{ \item{t}{Time to event or censoring} \item{d}{Binary indicator of whether event occurred or individual was censored} \item{z}{Fully observed covariate, with linear effect on outcome (on log hazard scale)} \item{x}{Partially observed normally distributed covariate, with quadratic effect on outcome (on log hazard scale)} \item{xsq}{The square of x, which thus has missing values also} \item{v}{An auxiliary variable (i.e. not contained in the substantive model)} } } \usage{ ex_coxquad } \description{ A dataset containing simulated data where a time to event outcome depends quadratically on a partially observed covariate. } \keyword{datasets} smcfcs/man/smcfcs.dtsam.Rd0000644000176200001440000001323314060150767015167 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/smcfcs.r \name{smcfcs.dtsam} \alias{smcfcs.dtsam} \title{Substantive model compatible fully conditional specification imputation of covariates for discrete time survival analysis} \usage{ smcfcs.dtsam( originaldata, smformula, timeEffects = "factor", method, predictorMatrix = NULL, m = 5, numit = 10, rjlimit = 1000, noisy = FALSE, errorProneMatrix = NULL ) } \arguments{ \item{originaldata}{The data in wide form (i.e. one row per subject)} \item{smformula}{A formula of the form "Surv(t,d)~x1+x2+x3", where t is the discrete time variable, d is the binary event indicator, and the covariates should not include time. The time variable should be an integer coded numeric variable taking values from 1 up to the final time period.} \item{timeEffects}{Specifies how the effect of time is modelled. \code{timeEffects="factor"} (the default) models time as a factor variable. \code{timeEffects="linear"} and \code{timeEffects="quad"} specify that time be modelled as a continuous linear or quadratic effect on the log odds scale respectively.} \item{method}{A required vector of strings specifying for each variable either that it does not need to be imputed (""), the type of regression model to be be used to impute. Possible values are \code{"norm"} (normal linear regression), \code{"logreg"} (logistic regression), \code{"poisson"} (Poisson regression), \code{"podds"} (proportional odds regression for ordered categorical variables), \code{"mlogit"} (multinomial logistic regression for unordered categorical variables), or a custom expression which defines a passively imputed variable, e.g. \code{"x^2"} or \code{"x1*x2"}. \code{"latnorm"} indicates the variable is a latent normal variable which is measured with error. If this is specified for a variable, the \code{"errorProneMatrix"} argument should also be used.} \item{predictorMatrix}{An optional predictor matrix. If specified, the matrix defines which covariates will be used as predictors in the imputation models (the outcome must not be included). The i'th row of the matrix should consist of 0s and 1s, with a 1 in the j'th column indicating the j'th variable be used as a covariate when imputing the i'th variable. If not specified, when imputing a given variable, the imputation model covariates are the other covariates of the substantive model which are partially observed (but which are not passively imputed) and any fully observed covariates (if present) in the substantive model. Note that the outcome variable is implicitly conditioned on by the rejection sampling scheme used by smcfcs, and should not be specified as a predictor in the predictor matrix.} \item{m}{The number of imputed datasets to generate. The default is 5.} \item{numit}{The number of iterations to run when generating each imputation. In a (limited) range of simulations good performance was obtained with the default of 10 iterations. However, particularly when the proportion of missingness is large, more iterations may be required for convergence to stationarity.} \item{rjlimit}{Specifies the maximum number of attempts which should be made when using rejection sampling to draw from imputation models. If the limit is reached when running a warning will be issued. In this case it is probably advisable to increase the \code{rjlimit} until the warning does not appear.} \item{noisy}{logical value (default FALSE) indicating whether output should be noisy, which can be useful for debugging or checking that models being used are as desired.} \item{errorProneMatrix}{An optional matrix which if specified indicates that some variables are measured with classical measurement error. If the i'th variable is measured with error by variables j and k, then the (i,j) and (i,k) entries of this matrix should be 1, with the remainder of entries 0. The i'th element of the method argument should then be specified as \code{"latnorm"}. See the measurement error vignette for more details.} } \description{ Multiply imputes missing covariate values using substantive model compatible fully conditional specification for discrete time survival analysis. } \details{ For this substantive model type, like for the other substantive model types, \code{smcfcs} expects the \code{originaldata} to have one row per subject. Variables indicating the discrete time of failure/censoring and the event indicator should be passed in \code{smformula}, as described. The default is to model the effect of time as a factor. This will not work in datasets where there is not at least one observed event in each time period. In such cases you must specify a simpler parametric model for the effect of time. At the moment you can specify either a linear or quadratic effect of time (on the log odds scale). } \examples{ #the following example is not run when the package is compiled on CRAN #(to keep computation time down), but it can be run by package users \dontrun{ #discrete time survival analysis example M <- 5 imps <- smcfcs.dtsam(ex_dtsam, "Surv(failtime,d)~x1+x2", method=c("logreg","", "", ""),m=M) #fit dtsam model to each dataset manually, since we need #to expand to person-period data form first ests <- vector(mode = "list", length = M) vars <- vector(mode = "list", length = M) for (i in 1:M) { longData <- survSplit(Surv(failtime,d)~x1+x2, data=imps$impDatasets[[i]], cut=unique(ex_dtsam$failtime[ex_dtsam$d==1])) mod <- glm(d~-1+factor(tstart)+x1+x2, family="binomial", data=longData) ests[[i]] <- coef(mod) vars[[i]] <- diag(vcov(mod)) } library(mitools) summary(MIcombine(ests,vars)) } } \author{ Jonathan Bartlett \email{j.w.bartlett@bath.ac.uk} } smcfcs/man/smcfcs.Rd0000644000176200001440000002361614060150767014066 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/smcfcs.r \name{smcfcs} \alias{smcfcs} \title{Substantive model compatible fully conditional specification imputation of covariates.} \usage{ smcfcs( originaldata, smtype, smformula, method, predictorMatrix = NULL, m = 5, numit = 10, rjlimit = 1000, noisy = FALSE, errorProneMatrix = NULL ) } \arguments{ \item{originaldata}{The original data frame with missing values.} \item{smtype}{A string specifying the type of substantive model. Possible values are \code{"lm"}, \code{"logistic"}, \code{"poisson"}, \code{"weibull"}, \code{"coxph"}, \code{"compet"}.} \item{smformula}{The formula of the substantive model. For \code{"weibull"} and \code{"coxph"} substantive models the left hand side should be of the form \code{"Surv(t,d)"}. For \code{"compet"} substantive models, a list should be passed consisting of the Cox models for each cause of failure (see example).} \item{method}{A required vector of strings specifying for each variable either that it does not need to be imputed (""), the type of regression model to be be used to impute. Possible values are \code{"norm"} (normal linear regression), \code{"logreg"} (logistic regression), \code{"poisson"} (Poisson regression), \code{"podds"} (proportional odds regression for ordered categorical variables), \code{"mlogit"} (multinomial logistic regression for unordered categorical variables), or a custom expression which defines a passively imputed variable, e.g. \code{"x^2"} or \code{"x1*x2"}. \code{"latnorm"} indicates the variable is a latent normal variable which is measured with error. If this is specified for a variable, the \code{"errorProneMatrix"} argument should also be used.} \item{predictorMatrix}{An optional predictor matrix. If specified, the matrix defines which covariates will be used as predictors in the imputation models (the outcome must not be included). The i'th row of the matrix should consist of 0s and 1s, with a 1 in the j'th column indicating the j'th variable be used as a covariate when imputing the i'th variable. If not specified, when imputing a given variable, the imputation model covariates are the other covariates of the substantive model which are partially observed (but which are not passively imputed) and any fully observed covariates (if present) in the substantive model. Note that the outcome variable is implicitly conditioned on by the rejection sampling scheme used by smcfcs, and should not be specified as a predictor in the predictor matrix.} \item{m}{The number of imputed datasets to generate. The default is 5.} \item{numit}{The number of iterations to run when generating each imputation. In a (limited) range of simulations good performance was obtained with the default of 10 iterations. However, particularly when the proportion of missingness is large, more iterations may be required for convergence to stationarity.} \item{rjlimit}{Specifies the maximum number of attempts which should be made when using rejection sampling to draw from imputation models. If the limit is reached when running a warning will be issued. In this case it is probably advisable to increase the \code{rjlimit} until the warning does not appear.} \item{noisy}{logical value (default FALSE) indicating whether output should be noisy, which can be useful for debugging or checking that models being used are as desired.} \item{errorProneMatrix}{An optional matrix which if specified indicates that some variables are measured with classical measurement error. If the i'th variable is measured with error by variables j and k, then the (i,j) and (i,k) entries of this matrix should be 1, with the remainder of entries 0. The i'th element of the method argument should then be specified as \code{"latnorm"}. See the measurement error vignette for more details.} } \value{ A list containing: \code{impDatasets} a list containing the imputed datasets \code{smCoefIter} a three dimension matrix containing the substantive model parameter values. The matrix is indexed by [imputation,parameter number,iteration] } \description{ Multiply imputes missing covariate values using substantive model compatible fully conditional specification. } \details{ smcfcs imputes missing values of covariates using the Substantive Model Compatible Fully Conditional Specification multiple imputation approach proposed by Bartlett \emph{et al} 2015 (see references). Imputation is supported for linear regression (\code{"lm"}), logistic regression (\code{"logistic"}), Poisson regression (\code{"poisson"}), Weibull (\code{"weibull"}) and Cox regression for time to event data (\code{"coxph"}), and Cox models for competing risks data (\code{"compet"}). For the latter, a Cox model is assumed for each cause of failure, and the event indicator should be integer coded with 0 corresponding to censoring, 1 corresponding to failure from the first cause etc. The function returns a list. The first element \code{impDataset} of the list is a list of the imputed datasets. Models (e.g. the substantive model) can be fitted to each and results combined using Rubin's rules using the mitools package, as illustrated in the examples. The second element \code{smCoefIter} is a three dimensional array containing the values of the substantive model parameters obtained at the end of each iteration of the algorithm. The array is indexed by: imputation number, parameter number, iteration. If the substantive model is linear, logistic or Poisson regression, \code{smcfcs} will automatically impute missing outcomes, if present, using the specified substantive model. However, even in this case, the user should specify "" in the element of method corresponding to the outcome variable. The development of this package was supported by a UK Medical Research Council Fellowship (MR/K02180X/1). Part of its development took place while the author was kindly hosted by the University of Michigan's Department of Biostatistics & Institute for Social Research. The structure of many of the arguments to \code{smcfcs} are based on those of the excellent \code{mice} package. } \examples{ #set random number seed to make results reproducible set.seed(123) #linear substantive model with quadratic covariate effect imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq", method=c("","","norm","x^2","")) #if mitools is installed, fit substantive model to imputed datasets #and combine results using Rubin's rules if (requireNamespace("mitools", quietly = TRUE)) { library(mitools) impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~z+x+xsq)) summary(MIcombine(models)) } #the following examples are not run when the package is compiled on CRAN #(to keep computation time down), but they can be run by package users \dontrun{ #examining convergence, using 100 iterations, setting m=1 imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq", method=c("","","norm","x^2",""),m=1,numit=100) #convergence plot from first imputation for third coefficient of substantive model plot(imps$smCoefIter[1,3,]) #include auxiliary variable assuming it is conditionally independent of Y (which it is here) predMatrix <- array(0, dim=c(ncol(ex_linquad),ncol(ex_linquad))) predMatrix[3,] <- c(0,1,0,0,1) imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq", method=c("","","norm","x^2",""),predictorMatrix=predMatrix) #impute missing x1 and x2, where they interact in substantive model imps <- smcfcs(ex_lininter, smtype="lm", smformula="y~x1+x2+x1*x2", method=c("","norm","logreg")) #logistic regression substantive model, with quadratic covariate effects imps <- smcfcs(ex_logisticquad, smtype="logistic", smformula="y~z+x+xsq", method=c("","","norm","x^2","")) #Poisson regression substantive model imps <- smcfcs(ex_poisson, smtype="poisson", smformula="y~x+z", method=c("","norm","")) if (requireNamespace("mitools", quietly = TRUE)) { library(mitools) impobj <- imputationList(imps$impDatasets) models <- with(impobj, glm(y~x+z,family=poisson)) summary(MIcombine(models)) } #Cox regression substantive model, with only main covariate effects if (requireNamespace("survival", quietly = TRUE)) { imps <- smcfcs(ex_coxquad, smtype="coxph", smformula="Surv(t,d)~z+x+xsq", method=c("","","","norm","x^2","")) #competing risks substantive model, with only main covariate effects imps <- smcfcs(ex_compet, smtype="compet", smformula=c("Surv(t,d==1)~x1+x2", "Surv(t,d==2)~x1+x2"), method=c("","","logreg","norm")) } #if mitools is installed, fit model for first competing risk if (requireNamespace("mitools", quietly = TRUE)) { library(mitools) impobj <- imputationList(imps$impDatasets) models <- with(impobj, coxph(Surv(t,d==1)~x1+x2)) summary(MIcombine(models)) } #discrete time survival analysis example M <- 5 imps <- smcfcs(ex_dtsam, "dtsam", "Surv(failtime,d)~x1+x2", method=c("logreg","", "", ""),m=M) #fit dtsam model to each dataset manually, since we need #to expand to person-period data form first ests <- vector(mode = "list", length = M) vars <- vector(mode = "list", length = M) for (i in 1:M) { longData <- survSplit(Surv(failtime,d)~x1+x2, data=imps$impDatasets[[i]], cut=unique(ex_dtsam$failtime[ex_dtsam$d==1])) mod <- glm(d~-1+factor(tstart)+x1+x2, family="binomial", data=longData) ests[[i]] <- coef(mod) vars[[i]] <- diag(vcov(mod)) } summary(MIcombine(ests,vars)) } } \references{ Bartlett JW, Seaman SR, White IR, Carpenter JR. Multiple imputation of covariates by fully conditional specification: accommodating the substantive model. Statistical Methods in Medical Research 2015; 24(4): 462-487. \doi{10.1177/0962280214521348} } \author{ Jonathan Bartlett \email{j.w.bartlett@bath.ac.uk} \url{https://thestatsgeek.com} \url{http://www.missingdata.org.uk} } smcfcs/man/ex_dtsam.Rd0000644000176200001440000000110214060150767014376 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.r \docType{data} \name{ex_dtsam} \alias{ex_dtsam} \title{Simulated discrete time survival data set} \format{ A data frame with 1000 rows and 8 variables: \describe{ \item{x1}{A binary variable with missing values} \item{x2}{A fully observed continuous variable} \item{failtime}{The discrete failure/censoring time} \item{d}{Indicator of failure (=1) or censoring (=0)} } } \usage{ ex_dtsam } \description{ A dataset containing simulated discrete time survival data. } \keyword{datasets} smcfcs/man/ex_linquad.Rd0000644000176200001440000000144113757721034014734 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.r \docType{data} \name{ex_linquad} \alias{ex_linquad} \title{Simulated example data with continuous outcome and quadratic covariate effects} \format{ A data frame with 1000 rows and 5 variables: \describe{ \item{y}{Continuous outcome} \item{z}{Fully observed covariate, with linear effect on outcome} \item{x}{Partially observed normally distributed covariate, with quadratic effect on outcome} \item{xsq}{The square of x, which thus has missing values also} \item{v}{An auxiliary variable (i.e. not contained in the substantive model)} } } \usage{ ex_linquad } \description{ A dataset containing simulated data where the outcome depends quadratically on a partially observed covariate. } \keyword{datasets} smcfcs/man/ex_logisticquad.Rd0000644000176200001440000000152713757721034015774 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.r \docType{data} \name{ex_logisticquad} \alias{ex_logisticquad} \title{Simulated example data with binary outcome and quadratic covariate effects} \format{ A data frame with 1000 rows and 5 variables: \describe{ \item{y}{Binary outcome} \item{z}{Fully observed covariate, with linear effect on outcome (on log odds scale)} \item{x}{Partially observed normally distributed covariate, with quadratic effect on outcome (on log odds scale)} \item{xsq}{The square of x, which thus has missing values also} \item{v}{An auxiliary variable (i.e. not contained in the substantive model)} } } \usage{ ex_logisticquad } \description{ A dataset containing simulated data where the binary outcome depends quadratically on a partially observed covariate. } \keyword{datasets} smcfcs/man/ex_lininter.Rd0000644000176200001440000000122213757721034015120 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.r \docType{data} \name{ex_lininter} \alias{ex_lininter} \title{Simulated example data with continuous outcome and interaction between two partially observed covariates} \format{ A data frame with 1000 rows and 4 variables: \describe{ \item{y}{Continuous outcome} \item{x1}{Partially observed normally distributed covariate} \item{x2}{Partially observed binary covariate} } } \usage{ ex_lininter } \description{ A dataset containing simulated data where the outcome depends on both main effects and interaction of two partially observed covariates. } \keyword{datasets} smcfcs/man/ex_cc.Rd0000644000176200001440000000141013757721034013660 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.r \docType{data} \name{ex_cc} \alias{ex_cc} \title{Simulated case cohort data} \format{ A data frame with 1571 rows and 7 variables: \describe{ \item{t}{Time to event or censoring} \item{d}{Indicator of whether event 1 occurred (d=1), or not (d=0)} \item{x}{Partially observed continuous covariate} \item{z}{Fully observed covariate} \item{in.subco}{A binary indicator of whether the subject is in the sub-cohort} \item{id}{An id variable} \item{entertime}{The entry time variable to be used in the analysis} } } \usage{ ex_cc } \description{ A dataset containing simulated case cohort data, where the sub-cohort was a 10\% random sample of the full cohort. } \keyword{datasets} smcfcs/man/smcfcs.casecohort.Rd0000644000176200001440000001242613757721034016217 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/smcfcs.r \name{smcfcs.casecohort} \alias{smcfcs.casecohort} \title{Substantive model compatible fully conditional specification imputation of covariates for case cohort studies} \usage{ smcfcs.casecohort( originaldata, smformula, sampfrac, in.subco, method, predictorMatrix = NULL, m = 5, numit = 10, rjlimit = 1000, noisy = FALSE, errorProneMatrix = NULL ) } \arguments{ \item{originaldata}{The case-cohort data set (NOT a full cohort data set with a case-cohort substudy within it)} \item{smformula}{A formula of the form "Surv(entertime,t,d)~x", where d is the event (d=1) or censoring (d=0) indicator, t is the event or censoring time and entertime is equal to the time origin (typically 0) for individuals in the subcohort and is equal to (t-0.001) for cases outside the subcohort [this sets cases outside the subcohort to enter follow-up just before their event time. The value 0.001 may need to be modified depending on the time scale.]} \item{sampfrac}{The proportion of individuals from the underlying full cohort who are in the subcohort} \item{in.subco}{The name of a column in the dataset with 0/1s that indicates whether the subject is in the subcohort} \item{method}{A required vector of strings specifying for each variable either that it does not need to be imputed (""), the type of regression model to be be used to impute. Possible values are \code{"norm"} (normal linear regression), \code{"logreg"} (logistic regression), \code{"poisson"} (Poisson regression), \code{"podds"} (proportional odds regression for ordered categorical variables), \code{"mlogit"} (multinomial logistic regression for unordered categorical variables), or a custom expression which defines a passively imputed variable, e.g. \code{"x^2"} or \code{"x1*x2"}. \code{"latnorm"} indicates the variable is a latent normal variable which is measured with error. If this is specified for a variable, the \code{"errorProneMatrix"} argument should also be used.} \item{predictorMatrix}{An optional predictor matrix. If specified, the matrix defines which covariates will be used as predictors in the imputation models (the outcome must not be included). The i'th row of the matrix should consist of 0s and 1s, with a 1 in the j'th column indicating the j'th variable be used as a covariate when imputing the i'th variable. If not specified, when imputing a given variable, the imputation model covariates are the other covariates of the substantive model which are partially observed (but which are not passively imputed) and any fully observed covariates (if present) in the substantive model. Note that the outcome variable is implicitly conditioned on by the rejection sampling scheme used by smcfcs, and should not be specified as a predictor in the predictor matrix.} \item{m}{The number of imputed datasets to generate. The default is 5.} \item{numit}{The number of iterations to run when generating each imputation. In a (limited) range of simulations good performance was obtained with the default of 10 iterations. However, particularly when the proportion of missingness is large, more iterations may be required for convergence to stationarity.} \item{rjlimit}{Specifies the maximum number of attempts which should be made when using rejection sampling to draw from imputation models. If the limit is reached when running a warning will be issued. In this case it is probably advisable to increase the \code{rjlimit} until the warning does not appear.} \item{noisy}{logical value (default FALSE) indicating whether output should be noisy, which can be useful for debugging or checking that models being used are as desired.} \item{errorProneMatrix}{An optional matrix which if specified indicates that some variables are measured with classical measurement error. If the i'th variable is measured with error by variables j and k, then the (i,j) and (i,k) entries of this matrix should be 1, with the remainder of entries 0. The i'th element of the method argument should then be specified as \code{"latnorm"}. See the measurement error vignette for more details.} } \description{ Multiply imputes missing covariate values using substantive model compatible fully conditional specification for case cohort studies. } \details{ This version of \code{smcfcs} is designed for use with case cohort studies but where the analyst does not wish to, or cannot (due to not having the necessary data) impute the full cohort. The function's arguments are the same as for the main smcfcs function, except for \code{smformula}, \code{in.subco}, and \code{sampfrac} - see above for details on how these should be specified. } \examples{ #the following example is not run when the package is compiled on CRAN #(to keep computation time down), but it can be run by package users \dontrun{ #as per the documentation for ex_cc, the sampling fraction is 10\% imps <- smcfcs.casecohort(ex_cc, smformula="Surv(entertime, t, d)~x+z", sampfrac=0.1, in.subco="in.subco", method=c("", "", "norm", "", "", "", "")) library(mitools) impobj <- imputationList(imps$impDatasets) models <- with(impobj, coxph(Surv(entertime,t,d)~x+z+cluster(id))) summary(MIcombine(models)) } } \author{ Ruth Keogh \email{ruth.keogh@lshtm.ac.uk} Jonathan Bartlett \email{j.w.bartlett@bath.ac.uk} } smcfcs/DESCRIPTION0000644000176200001440000000251514062674212013245 0ustar liggesusersPackage: smcfcs Title: Multiple Imputation of Covariates by Substantive Model Compatible Fully Conditional Specification Version: 1.6.0 Authors@R: c(person("Jonathan", "Bartlett", email = "j.w.bartlett@bath.ac.uk",role = c("aut", "cre")), person("Ruth", "Keogh", email = "ruth.keogh@lshtm.ac.uk",role = c("aut")), person("Edouard F.", "Bonneville",role = c("aut")), person("Claus Thorn", "Ekstrøm",role = c("ctb"))) URL: https://github.com/jwb133/smcfcs Description: Implements multiple imputation of missing covariates by Substantive Model Compatible Fully Conditional Specification. This is a modification of the popular FCS/chained equations multiple imputation approach, and allows imputation of missing covariate values from models which are compatible with the user specified substantive model. Depends: R (>= 3.1.2) License: GPL-3 LazyData: true Imports: MASS, survival, VGAM, stats, rlang, checkmate, abind Suggests: knitr, rmarkdown, mitools, ggplot2 VignetteBuilder: knitr RoxygenNote: 7.1.1 Encoding: UTF-8 NeedsCompilation: no Packaged: 2021-06-17 16:06:57 UTC; Jonathan Author: Jonathan Bartlett [aut, cre], Ruth Keogh [aut], Edouard F. Bonneville [aut], Claus Thorn Ekstrøm [ctb] Maintainer: Jonathan Bartlett Repository: CRAN Date/Publication: 2021-06-17 16:30:02 UTC smcfcs/build/0000755000176200001440000000000014062671441012634 5ustar liggesuserssmcfcs/build/vignette.rds0000644000176200001440000000034714062671441015177 0ustar liggesusersuPA0,$&<}xboUI(x[#l3SNcl W;78(]"~$ b uH˶m6Z|U=QϻKoZĭz֢/=գkƊ=Sa93.@loc7[Z&hwb;x=s}{D,VXʲ,+Ȁ^5/+>N smcfcs/build/partial.rdb0000644000176200001440000002417714062671362014776 0ustar liggesusers}F^Dݧ%[%Ae7%SdElyܲl@@'&76&d!vR P,l#^իW r\ߝ$ga?$<~>eX|[z,+^խqE]3<`I\G O2IƾٙovWOyZW}*37-;[]O<|#t*ۚaUC5y.Knko~CWB3xj&0<̏ln=s ^PWG/=T-DmXwֈ)VlS8|x˗nyvKUm쥹U8SEq~aص+״cEVbM ͇gU ydZ jfײ[|Q=َ> VÐ_ݷD4/(s5ܨ閧zm) mm{p`jG_Wp=w\9}v^'r}$Yꮒw#<`[?$ mm{!'RwTPݘrwANV?, 䳅",XѕRkueM]4LsbTܺ^6*FnVo#vssЬ!?ϰ=3z.4+W~S/ĕnήGٍ&Wj4>LȄEj0TO-H8OQܚ^  5&tUl0T#qURMlM~؟i%Vⴲg;3kʄÇiȧSjQ*Gh5R9(V edX0g86Si; 2 KM(-p:k:QG0{qlgα- 24Ai"BbVb`&(-$U"gy#{q%($9?29% Of=)jxKJp]ê*+ِO-lkxz-Iȓ7t*M$j ~#ǔބ9K9 q=l`O*ISO2g3g3SZ& ?I;EutE[hjB!$hVoe>r 82k˜bOB>~/$i7Q7zF9Q!.ӯ'kK/e.{,vm+Q!wY [omSN@ȰYVucaCC,w3g2hفY{K*oB>۝V9 <\[vC+ϛM|*_@\ݦ!lgos[9W|8 =N@Eۃwh1y`;Jǀ ' ='M<w)OS.E$-8yngb99_7l o+B@\)i.^x2KvԔE=d8ކ|;3߿pV^A,b4(.,*nM;3&'lGt.B^N<!xM@\)iLw*zBGkVҊU Uo!OV'|%6\*a6]ɻkjnꃲY0$CrE+&~[(vr-iӣ/ <1shӐX0[!N0 WtJ |/7#(!N7X?ud8 ؐjk+ٮ5еdڵ G^|;^|=uczHկ #&Eku[\z]{+f70]S#.EzUOڎQf+ߪacYz 4\W4\c%_klf :='oنq^}C<6gdXW+lgqތ&U >T=ǐ?Rw}5*m4 CN#gB*&|l^E~u̵,&F.%k7g NhG}x(I* *SYb ,ÐS7˻ai$/7'9?VEɺ8b8|9ZVMf{51C5aG}(eBrIa爌V%^&elԬ  5zFCЂ!Dym}Rl49t7D+QK ݉DV" GnW*Z6]nI4L 9xJ;؋țf bxtD ~Z8"PAlQ!%)8FSOI~l JSi ORr0*c [f×cP| /H Fc`[_=TO*Mj w$iўQa:BYڢ3U]z=vݫ8 X6LUY3'@~f~I] m_T6w<$݄yZyzP=j6*q#wiy>Ozs8|9LzժFԀQն5;9Ze^T6W d~ 9}BR#B )۫ȴsXv}U[|&S[P0#*;l WS)iR, ᘮXs1t}cិ.h-PŎ\U8ڛBه 4&PnD|J*ł"uga%5jU=fAufB"tMդG89}g4a*3C5G]U*]\CÎGGF]g?K׍yԱ:\ V 'mSt欯lڊgj4!% Պ%襱G iȉF1j Gi,?|2q Pƞ"rl|!\q^zJ zd{V\=sBv1E o>Tުs%EXu2A(w<0]##v)$^"XyȤ `-2S'Oaa\76 6#v:J]YHN6^HE !>1Ƕ>`zX$L.׆]AbT-My׷4S SQp JikOĕJ zfrOUT|iPеGl^up|l[ qYbC#wryL]~Vw6GG!z;J <9o?i!8%e1$aVfa=RΊPQfkEڔW=ݑ50>ڈ Oό[r lݐYuU:Uܓe{~@k8ќǼЁrXTg}Z/4cӡ|{.{Gr͗nPq=/``t&&ǀg ɰyN| @g!&N;tNmM KQ 5N[}o}vbsxr*=x8y05'i<pdFp\ړ3= CNt:Qq7 kJ1w *kWD&prո6rF 3ôGaIo!H>fF5G\ND R ʗu˵02NeA(lFԩ?8ǜg.mѽ]7~TY:0;SMptX.,=$I%,B.f7km2:Lknä?~ԍ^/7bY਴I :lxˮ'7/)S`?*Nl[[m3jyY' UW1Lzh!/Ҿj >@f㫎;ru K^ aܛi䁭GTw!|XPMEuu=oGɚ1|9bif"`L#̃&-դ20iD~;]{eHP:/ZIcBiwM5`68&Hu4.t.JϜ-'ȗ7eSSEΏП0cw'iՆgטїZ~4LǁNnAiJUG|%!lheI3$AZ89x@V:ڂ0O&1Cר㷤Pp0sPt۔Fh7SE+i[Oͨg^\gO:l65LY<(B8 y6R tӴW%g拟~VRTϲqfsene~.?@X*ր2%|g/..ZX>q\['fQUiFNzϰ)4,{ʴ$?" t"2uRwt.YIUP!.%XMl({Fn |"5׶>.CCHJp6 6_5,"u(C⧇u2 ߃|(3e]t [<2tSOn}X, i` {Jxz1`=Un[c&*G@\ Mf35ĕZGiv(/z|˰ZQvq,oЌi]>Dd#Wb%}!L{5Bfc8v nG.JE/Ǿq%V_ ҄'<$?\km hE|yϩԊ3)SfFi~P#<P'HЛ''Z%2jf u0N{Ϛ]qLO&l0> ]"SF.^R.m? ?.ō-nUGnhG(ar6GQț0'bcP0 CdĮ1(roGn^~DDle[iï pVē,lUh-kq$Eػ{m0yW#ȏRtc 3 * ovk(:]tu@vW1I?v7@0Qa3NL   ~a*1MhAݴnl=ko-m6J'qwiap'?ۉ6plF/U8]wS?bS:ߚ)?QLx/N1J'FOPtxK̃j`O j|*Ҍd S$Rj{eUY: BޛΝN\Ƃ hNr $Y9xށ|g V8 H ~Qzʌtw`K]@tY/ [ 5| ?`A+bi[oV`)@d5[k[M ld9+$wЀ0S"ơesG.UTn9% Yf D+h_i= n6iD. a ai߆ y&APYJFxm ~J'.)P ?Y~_PtCR4QOO[rqeT{KETAпL\=Q9q+~>,* LRN9m'CL^$E COu5/(W2X̭^[ 3|6%Z!?OEPv-DǕkn\R$wp$LwgOoON8ZuUXl_s^}/4~/xkdxhdk7GGƮ\d.ܟc!r5*foމ1|kqgoLӂ ITWF|\r%tḲyuwXdNwණQ2ZVVRoȳe,{eɈ*3rѥ솷Uc?vH)+SrM]μOllg %~[kOGh[mìeW-ؾQM7ܲowmybzٔ7|gϼ`-4ݺ2%nԈR,3~mRkF[KwgQUIJGt{95@\)GciZJ7O912N|9:j,2Cjyi0~wISqԍ#I +6z+%ueGEJPEX?m/UD7[:=Hr񽺯zvKL7 U %^듩g{h&wlOCNv NtvM7 Ut c]Si9xCcMk(u5{{: KŮ_jp"YKjYX)y5zL.5.bkAEXo{ vM1>046>:=NTw6C7DXt:=uhީ&?<Y!^©DOPԩI\{eF@ $s>Yȕ,NevulL<}2Jv?Cc/7ߜ1}s ^`GULЋ0*y(ݢ:zq^+ʢ2>Lmy+lp,0Xaޏ*Wׯ|閇.jW~T^aWO^>UYh_y]rM߸:V kጻ͑ҹ9Od-;3Min>?0ib'aVgj^Ogo%W|+ +az7߼Gaī0R긗M쪩RE{FY+j`4ePT#!/?r_A*3 /LO=}M]$!2m>PPXʢ W(}?4&xy ,NcݩqZF<=_}Fm>%&Z 5Z24E k36 6'#x<@?,+ smcfcs/tests/0000755000176200001440000000000013447725652012711 5ustar liggesuserssmcfcs/tests/testthat/0000755000176200001440000000000014062657471014546 5ustar liggesuserssmcfcs/tests/testthat/test_casecohort.r0000644000176200001440000000515113447725652020127 0ustar liggesuserslibrary(smcfcs) library(survival) library(mitools) context("Case cohort testing") test_that("Case cohort imputation runs and is approximately unbiased, binary covariate missing", { skip_on_cran() expect_equal({ set.seed(1234) #run simulation study nSims <- 100 xEsts <- array(0, dim=nSims) n <- 10000 for (sim in 1:nSims) { print(sim) z <- rnorm(n) x <- 1*(runif(n)<(exp(z)/(1+exp(z)))) t <- -log(runif(n))/(0.01*exp(x+z)) d <- 1*(t<2) t[d==0] <- 2 x[(runif(n)<0.5)] <- NA fullcohortdata <- data.frame(t,d,x,z) fullcohortdata$in.subco <- 0 #we sample a 10% subcohort fullcohortdata$in.subco[sample(n, size=n*0.1)] <- 1 fullcohortdata$id <- 1:n ccdata <- fullcohortdata[(fullcohortdata$in.subco==1) | (fullcohortdata$d==1),] ccdata$entertime <- 0 ccdata$entertime[ccdata$in.subco==0] <- ccdata$t[ccdata$in.subco==0] - 0.000001 imps <- smcfcs.casecohort(ccdata, smformula="Surv(entertime, t, d)~x+z", sampfrac=0.1, in.subco="in.subco", method=c("", "", "logreg", "", "", "", "")) impobj <- imputationList(imps$impDatasets) models <- with(impobj, coxph(Surv(entertime,t,d)~x+z+cluster(id))) xEsts[sim] <- summary(MIcombine(models))[1,1] } print(mean(xEsts)) abs(mean(xEsts-1))<0.1 }, TRUE) }) test_that("Case cohort imputation runs and is approximately unbiased, continuous covariate missing", { skip_on_cran() expect_equal({ set.seed(1234) #run simulation study nSims <- 100 xEsts <- array(0, dim=nSims) n <- 10000 for (sim in 1:nSims) { print(sim) z <- rnorm(n) x <- z+rnorm(n) t <- -log(runif(n))/(0.01*exp(x+z)) d <- 1*(t<1) t[d==0] <- 1 x[(runif(n)<0.5)] <- NA fullcohortdata <- data.frame(t,d,x,z) fullcohortdata$in.subco <- 0 #we sample a 10% subcohort fullcohortdata$in.subco[sample(n, size=n*0.1)] <- 1 fullcohortdata$id <- 1:n ccdata <- fullcohortdata[(fullcohortdata$in.subco==1) | (fullcohortdata$d==1),] ccdata$entertime <- 0 ccdata$entertime[ccdata$in.subco==0] <- ccdata$t[ccdata$in.subco==0] - 0.000001 imps <- smcfcs.casecohort(ccdata, smformula="Surv(entertime, t, d)~x+z", sampfrac=0.1, in.subco="in.subco", method=c("", "", "norm", "", "", "", "")) impobj <- imputationList(imps$impDatasets) models <- with(impobj, coxph(Surv(entertime,t,d)~x+z+cluster(id))) xEsts[sim] <- summary(MIcombine(models))[1,1] } print(mean(xEsts)) abs(mean(xEsts-1))<0.1 }, TRUE) }) smcfcs/tests/testthat/test_dtsam.r0000644000176200001440000003151514060150767017077 0ustar liggesuserslibrary(smcfcs) library(survival) context("Discrete time survival analysis testing") test_that("Basic setup runs (CRAN check)", { expect_error({ set.seed(1234) n <- 1000 x1 <- 1*(runif(n)<0.5) x2 <- x1+rnorm(n) T <- 10 #define vector of intercepts alpha <- -3+0.2*(1:T) beta <- c(1,-1) yMat <- array(0, dim=c(n,T)) for (i in 1:T) { yMat[,i] <- 1*(runif(n)c(alpha,beta)) mean(ciIncluded)==1 }, TRUE) }) test_that("MAR is unbiased, binary covariate missing", { skip_on_cran() expect_equal({ set.seed(1234) n <- 100000 x1 <- 1*(runif(n)<0.5) x2 <- x1+rnorm(n) T <- 10 #define vector of intercepts alpha <- -3+0.2*(1:T) beta <- c(1,-1) yMat <- array(0, dim=c(n,T)) for (i in 1:T) { yMat[,i] <- 1*(runif(n)c(alpha,beta)) mean(ciIncluded)==1 }, TRUE) }) test_that("MCAR is unbiased, cts covariate missing", { skip_on_cran() expect_equal({ set.seed(7234423) n <- 1000 x1 <- 1*(runif(n)<0.5) x2 <- x1+rnorm(n) T <- 10 #define vector of intercepts alpha <- -3+0.2*(1:T) beta <- c(1,-1) yMat <- array(0, dim=c(n,T)) for (i in 1:T) { yMat[,i] <- 1*(runif(n)c(alpha,beta)) mean(ciIncluded)==1 }, TRUE) }) test_that("MAR is unbiased, binary covariate missing, linear time effect", { skip_on_cran() expect_equal({ set.seed(1234) n <- 100000 x1 <- 1*(runif(n)<0.5) x2 <- x1+rnorm(n) T <- 10 #define vector of intercepts alpha <- c(-2,0.1) beta <- c(1,-1) yMat <- array(0, dim=c(n,T)) for (i in 1:T) { yMat[,i] <- 1*(runif(n)c(alpha,beta)) mean(ciIncluded)==1 }, TRUE) }) test_that("MAR is unbiased, binary covariate missing, quadratic time effect", { skip_on_cran() expect_equal({ set.seed(1234) n <- 100000 x1 <- 1*(runif(n)<0.5) x2 <- x1+rnorm(n) T <- 10 #define vector of intercepts alpha <- c(-3,0.1,0.02) beta <- c(1,-1) yMat <- array(0, dim=c(n,T)) for (i in 1:T) { yMat[,i] <- 1*(runif(n)c(alpha,beta)) mean(ciIncluded)==1 }, TRUE) }) smcfcs/tests/testthat/test_parallel.r0000644000176200001440000001412314062657371017564 0ustar liggesuserslibrary(smcfcs) library(survival) context("Testing parallel computation") test_that("Cox imputation runs in parallel", { expect_error({ set.seed(1234) n <- 10000 z <- rnorm(n) x <- z+rnorm(n) t <- -log(runif(n))/(1*exp(x+z)) d <- 1*(t<10) t[d==0] <- 10 x[(runif(n)<0.5)] <- NA simData <- data.frame(t,d,x,z) imps <- smcfcs.parallel(originaldata=simData, smtype="coxph", smformula="Surv(t, d)~x+z", method=c("", "", "norm", ""), m=5, n_cores=2, seed=7243) }, NA) }) test_that("smcfcs.parallel works with 1 imputation per core", { expect_error({ set.seed(1234) n <- 100 z <- rnorm(n) x <- z+rnorm(n) t <- -log(runif(n))/(1*exp(x+z)) d <- 1*(t<10) t[d==0] <- 10 x[(runif(n)<0.5)] <- NA simData <- data.frame(t,d,x,z) imps <- smcfcs.parallel(originaldata=simData, smtype="coxph", smformula="Surv(t, d)~x+z", method=c("", "", "norm", ""), m=2, n_cores=2, seed=7243) }, NA) }) test_that("smcfcs.parallel throws error if you specify more cores than necessary for 1 imp per core", { expect_error({ set.seed(1234) n <- 100 z <- rnorm(n) x <- z+rnorm(n) t <- -log(runif(n))/(1*exp(x+z)) d <- 1*(t<10) t[d==0] <- 10 x[(runif(n)<0.5)] <- NA simData <- data.frame(t,d,x,z) imps <- smcfcs.parallel(originaldata=simData, smtype="coxph", smformula="Surv(t, d)~x+z", method=c("", "", "norm", ""), m=5, n_cores=10, seed=7243) }, NULL) }) test_that("smcfcs.parallel throws error if you specify negative seed", { expect_error({ set.seed(1234) n <- 100 z <- rnorm(n) x <- z+rnorm(n) t <- -log(runif(n))/(1*exp(x+z)) d <- 1*(t<10) t[d==0] <- 10 x[(runif(n)<0.5)] <- NA simData <- data.frame(t,d,x,z) imps <- smcfcs.parallel(originaldata=simData, smtype="coxph", smformula="Surv(t, d)~x+z", method=c("", "", "norm", ""), m=5, n_cores=2, seed=-7243) }, NULL) }) test_that("smcfcs.parallel throws error if you specify non-integer seed", { expect_error({ set.seed(1234) n <- 100 z <- rnorm(n) x <- z+rnorm(n) t <- -log(runif(n))/(1*exp(x+z)) d <- 1*(t<10) t[d==0] <- 10 x[(runif(n)<0.5)] <- NA simData <- data.frame(t,d,x,z) imps <- smcfcs.parallel(originaldata=simData, smtype="coxph", smformula="Surv(t, d)~x+z", method=c("", "", "norm", ""), m=5, n_cores=2, seed=1.5) }, NULL) }) test_that("Test case cohort imputation runs", { expect_error({ set.seed(1234) #run simulation study n <- 10000 z <- rnorm(n) x <- 1*(runif(n)<(exp(z)/(1+exp(z)))) t <- -log(runif(n))/(0.01*exp(x+z)) d <- 1*(t<2) t[d==0] <- 2 x[(runif(n)<0.5)] <- NA fullcohortdata <- data.frame(t,d,x,z) fullcohortdata$in.subco <- 0 #we sample a 10% subcohort fullcohortdata$in.subco[sample(n, size=n*0.1)] <- 1 fullcohortdata$id <- 1:n ccdata <- fullcohortdata[(fullcohortdata$in.subco==1) | (fullcohortdata$d==1),] ccdata$entertime <- 0 ccdata$entertime[ccdata$in.subco==0] <- ccdata$t[ccdata$in.subco==0] - 0.000001 imps <- smcfcs.parallel(originaldata=ccdata, smformula="Surv(entertime, t, d)~x+z", sampfrac=0.1, in.subco="in.subco", method=c("", "", "logreg", "", "", "", ""), smcfcs_func = "smcfcs.casecohort", m=5, n_cores=2, seed=7243) }, NA) }) test_that("Nested case control imputation runs", { expect_error({ set.seed(1234) n <- 10000 z <- rnorm(n) x <- z+rnorm(n) t <- -log(runif(n))/(0.01*exp(x+z)) d <- 1*(t<1) t[d==0] <- 1 x[(runif(n)<0.5)] <- NA fullcohortdata <- data.frame(t,d,x,z) fullcohortdata$id <- 1:n # Compute number at risk at each event time using the full cohort data nrisk.fit <- survfit(Surv(t,d)~1,data=fullcohortdata) ord.t.d1 <- order(fullcohortdata$t[fullcohortdata$d==1]) m=1 #1 control per case ncc=NULL no.sample=0 for (i in which(fullcohortdata$d==1)) { #select control(s) for nested case-control possible.controls <- which(fullcohortdata$t>=fullcohortdata$t[i]) #remove the case from this vector possible.controls <- possible.controls[which(possible.controls!=i)] if (length(possible.controls)>=m){ controls <- sample(possible.controls,m) numAtRisk <- 1+length(possible.controls) ncc <- rbind(ncc,cbind(fullcohortdata[i,],numrisk=numAtRisk)) ncc <- rbind(ncc,cbind(fullcohortdata[controls,], numrisk=numAtRisk)) no.sample <- no.sample+1} } ncc$setno <- rep(1:no.sample,each=m+1) ncc$case <- rep(c(1,rep(0,m)),no.sample) predictorMatrix <- matrix(0,nrow=dim(ncc)[2],ncol=dim(ncc)[2]) predictorMatrix[which(colnames(ncc)=="x"),c(which(colnames(ncc)=="z"))] <- 1 imps <- smcfcs.parallel(originaldata=ncc,set="setno",nrisk="numrisk",event="d",smformula="Surv(t,case)~x+z+strata(setno)", method=c("", "", "norm", "", "", "", "", ""),predictorMatrix=predictorMatrix, smcfcs_func = "smcfcs.nestedcc", m=5, n_cores=2, seed=7243) }, NA) }) test_that("DTSAM imputation runs", { expect_error({ set.seed(1234) n <- 1000 x1 <- 1*(runif(n)<0.5) x2 <- x1+rnorm(n) T <- 10 #define vector of intercepts alpha <- -3+0.2*(1:T) beta <- c(1,-1) yMat <- array(0, dim=c(n,T)) for (i in 1:T) { yMat[,i] <- 1*(runif(n)1))-0.95)<(qnorm(0.999)*((0.95*0.05)/nSim)^0.5) }, TRUE) }) smcfcs/tests/testthat/test_weibull.r0000644000176200001440000000325013447725652017436 0ustar liggesuserslibrary(smcfcs) library(survival) context("Weibull model testing") test_that("Weibull imputation runs, binary covariate", { expect_error({ set.seed(1234) n <- 100 x <- 1*(runif(n)<0.5) z <- x+rnorm(n) t <- rsurvreg(n, mean=x+z, scale=2) d <- 1*(t<10) t[d==0] <- 10 x[(runif(n)<0.5)] <- NA simData <- data.frame(t,d,x,z) imps <- smcfcs(simData, smtype="weibull", smformula="Surv(t, d)~x+z", method=c("", "", "logreg", ""), m=1) }, NA) }) test_that("Weibull imputation is consistent, binary covariate", { skip_on_cran() expect_equal({ set.seed(1234) n <- 100000 x <- 1*(runif(n)<0.5) z <- x+rnorm(n) t <- rsurvreg(n, mean=x+z, scale=2) d <- 1*(t<10) t[d==0] <- 10 x[(runif(n)<0.5)] <- NA simData <- data.frame(t,d,x,z) imps <- smcfcs(simData, smtype="weibull", smformula="Surv(t, d)~x+z", method=c("", "", "logreg", ""), m=1) fitmod <- survreg(Surv(t,d)~x+z, data=imps$impDatasets[[1]]) as.logical((abs(coef(fitmod)[2]-1)<0.05) & (abs(fitmod$scale-2)<0.05)) }, TRUE) }) test_that("Weibull imputation is consistent, cts covariate", { skip_on_cran() expect_equal({ set.seed(1234) n <- 100000 x <- rnorm(n) z <- x+rnorm(n) t <- rsurvreg(n, mean=x+z, scale=2) d <- 1*(t<10) t[d==0] <- 10 x[(runif(n)<0.5)] <- NA simData <- data.frame(t,d,x,z) imps <- smcfcs(simData, smtype="weibull", smformula="Surv(t, d)~x+z", method=c("", "", "norm", ""), m=1) fitmod <- survreg(Surv(t,d)~x+z, data=imps$impDatasets[[1]]) as.logical((abs(coef(fitmod)[2]-1)<0.05) & (abs(fitmod$scale-2)<0.05)) }, TRUE) }) smcfcs/tests/testthat/test_errorchecks.R0000644000176200001440000001150513447725652020247 0ustar liggesuserslibrary(smcfcs) library(survival) context("Error trap testing") test_that("Checking outcome model check for logistic models", { expect_error({ set.seed(1234) n <- 100 x <- rnorm(n) y <- as.factor(1*(runif(n)<0.5)) x[(runif(n)<0.5)] <- NA simData <- data.frame(x,y) imps <- smcfcs(simData, smtype="logistic", smformula="y~x", method=c("norm", "")) }) }) test_that("Checking outcome model check for logistic models", { expect_error({ set.seed(1234) n <- 100 x <- rnorm(n) y <- 1+1*(runif(n)<0.5) x[(runif(n)<0.5)] <- NA simData <- data.frame(x,y) imps <- smcfcs(simData, smtype="logistic", smformula="y~x", method=c("norm", "")) }) }) test_that("Checking outcome model check for logistic models", { expect_output({ set.seed(1234) n <- 100 x <- rnorm(n) y <- 1*(runif(n)<0.5) x[(runif(n)<0.5)] <- NA simData <- data.frame(x,y) imps <- smcfcs(simData, smtype="logistic", smformula="y~x", method=c("norm", "")) }) }) test_that("Checking error trap for method statement 1", { expect_error({ set.seed(1234) n <- 100 x1 <- rnorm(n) x2 <- rnorm(n) y <- y <- x1+x2+rnorm(n) x1[(runif(n)<0.5)] <- NA simData <- data.frame(x1,x2,y) imps <- smcfcs(simData, smtype="lm", smformula="y~x1+x2", method=c("", "", "")) }) }) test_that("Checking error trap for method statement 2", { expect_error({ set.seed(1234) n <- 100 x1 <- rnorm(n) x2 <- rnorm(n) y <- y <- x1+x2+rnorm(n) x1[(runif(n)<0.5)] <- NA simData <- data.frame(x1,x2,y) imps <- smcfcs(simData, smtype="lm", smformula="y~x1+x2", method=c("", "norm", "")) }) }) test_that("Checking measurement error error checks 1", { expect_error({ set.seed(1234) n <- 100 x <- rnorm(n) w1 <- x+rnorm(n) w2 <- x+rnorm(n) y <- y <- x+rnorm(n) x <- rep(NA, n) simData <- data.frame(x,w1,w2,y) imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("latnorm", "", "", "")) }) }) test_that("Checking measurement error error checks 2", { expect_error({ set.seed(1234) n <- 100 x <- rnorm(n) w1 <- x+rnorm(n) y <- y <- x+rnorm(n) x <- rep(NA, n) simData <- data.frame(x,w1,y) errMat <- array(0, dim=c(3,3)) imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("latnorm", "", ""), errorProneMatrix=errMat) }) }) test_that("Checking measurement error error checks 3", { expect_error({ set.seed(1234) n <- 100 x <- rnorm(n) w1 <- x+rnorm(n) y <- y <- x+rnorm(n) x <- rep(NA, n) simData <- data.frame(x,w1,y) errMat <- array(0, dim=c(3,3)) errMat[1,1] <- 1 imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("latnorm", "", ""), errorProneMatrix=errMat) }) }) test_that("Checking measurement error error checks 4", { expect_error({ set.seed(1234) n <- 100 x <- rnorm(n) w1 <- x+rnorm(n) w2 <- x+rnorm(n) y <- y <- x+rnorm(n) x <- rep(NA, n) simData <- data.frame(x,w1,w2,y) errMat <- array(0, dim=c(4,4)) errMat[1,2] <- 1 errMat[1,3] <- 1 errMat[4,2] <- 1 imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("latnorm", "", "", ""), errorProneMatrix=errMat) }) }) test_that("Checking measurement error error checks 5", { expect_error({ set.seed(1234) n <- 100 x <- rnorm(n) w1 <- x+rnorm(n) w2 <- x+rnorm(n) y <- y <- x+rnorm(n) x <- rep(NA, n) simData <- data.frame(x,w1,w2,y) errMat <- array(0, dim=c(4,4)) errMat[1,2] <- 1 errMat[1,3] <- 1 errMat[4,2] <- 2 imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("latnorm", "", "", ""), errorProneMatrix=errMat) }) }) test_that("Checking measurement error error checks 6", { expect_error({ set.seed(1234) n <- 100 x <- rnorm(n) w1 <- x+rnorm(n) w2 <- x+rnorm(n) y <- y <- x+rnorm(n) x <- rep(NA, n) simData <- data.frame(x,w1,w2,y) errMat <- array(0, dim=c(5,5)) errMat[1,2] <- 1 errMat[1,3] <- 1 imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("latnorm", "", "", ""), errorProneMatrix=errMat) }) }) test_that("Checking measurement error error checks 7", { expect_error({ set.seed(1234) n <- 100 x <- rnorm(n) w1 <- x+rnorm(n) w2 <- x+rnorm(n) y <- y <- x+rnorm(n) x <- rep(NA, n) z <- rnorm(n) z[1:50] <- NA simData <- data.frame(w1,w2,y,z) errMat <- array(0, dim=c(4,4)) errMat[3,1] <- 1 errMat[3,2] <- 1 imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("", "", "","norm"), errorProneMatrix=errMat) }) }) smcfcs/tests/testthat/test_nestedcc.R0000644000176200001440000001047713447725652017534 0ustar liggesuserslibrary(smcfcs) library(survival) library(mitools) context("Nested case control testing") test_that("Nested case control imputation runs and is approximately unbiased, continuous covariate missing", { skip_on_cran() expect_equal({ set.seed(1234) #run simulation study nSims <- 100 xEsts <- array(0, dim=nSims) n <- 10000 for (sim in 1:nSims) { print(sim) z <- rnorm(n) x <- z+rnorm(n) t <- -log(runif(n))/(0.01*exp(x+z)) d <- 1*(t<1) t[d==0] <- 1 x[(runif(n)<0.5)] <- NA fullcohortdata <- data.frame(t,d,x,z) fullcohortdata$id <- 1:n # Compute number at risk at each event time using the full cohort data nrisk.fit <- survfit(Surv(t,d)~1,data=fullcohortdata) ord.t.d1 <- order(fullcohortdata$t[fullcohortdata$d==1]) m=1 #1 control per case ncc=NULL no.sample=0 for (i in which(fullcohortdata$d==1)) { #select control(s) for nested case-control possible.controls <- which(fullcohortdata$t>=fullcohortdata$t[i]) #remove the case from this vector possible.controls <- possible.controls[which(possible.controls!=i)] if (length(possible.controls)>=m){ controls <- sample(possible.controls,m) numAtRisk <- 1+length(possible.controls) ncc <- rbind(ncc,cbind(fullcohortdata[i,],numrisk=numAtRisk)) ncc <- rbind(ncc,cbind(fullcohortdata[controls,], numrisk=numAtRisk)) no.sample <- no.sample+1} } ncc$setno <- rep(1:no.sample,each=m+1) ncc$case <- rep(c(1,rep(0,m)),no.sample) predictorMatrix <- matrix(0,nrow=dim(ncc)[2],ncol=dim(ncc)[2]) predictorMatrix[which(colnames(ncc)=="x"),c(which(colnames(ncc)=="z"))] <- 1 imps <- smcfcs.nestedcc(originaldata=ncc,set="setno",nrisk="numrisk",event="d",smformula="Surv(t,case)~x+z+strata(setno)", method=c("", "", "norm", "", "", "", "", ""),predictorMatrix=predictorMatrix) impobj <- imputationList(imps$impDatasets) models <- with(impobj, clogit(case~x+z+strata(setno))) xEsts[sim] <- summary(MIcombine(models))[1,1] } print(mean(xEsts)) abs(mean(xEsts)-1)<0.1 }, TRUE) }) test_that("Nested case control imputation runs and is approximately unbiased, binary covariate missing", { skip_on_cran() expect_equal({ set.seed(5678) #perform simulation study nSims <- 100 xEsts <- array(0, dim=nSims) n <- 10000 for (sim in 1:nSims) { print(sim) z <- rnorm(n) x <- rbinom(n,1,exp(z)/(1+exp(z))) t <- -log(runif(n))/(0.01*exp(x+z)) d <- 1*(t<1) t[d==0] <- 1 x[(runif(n)<0.5)] <- NA fullcohortdata <- data.frame(t,d,x,z) fullcohortdata$id <- 1:n # Compute number at risk at each event time using the full cohort data nrisk.fit <- survfit(Surv(t,d)~1,data=fullcohortdata) ord.t.d1 <- order(fullcohortdata$t[fullcohortdata$d==1]) m=1 #1 control per case ncc=NULL no.sample=0 for (i in which(fullcohortdata$d==1)) { #select control(s) for nested case-control possible.controls <- which(fullcohortdata$t>=fullcohortdata$t[i]) #remove the case from this vector possible.controls <- possible.controls[which(possible.controls!=i)] if (length(possible.controls)>=m){ controls <- sample(possible.controls,m) numAtRisk <- 1+length(possible.controls) ncc <- rbind(ncc,cbind(fullcohortdata[i,],numrisk=numAtRisk)) ncc <- rbind(ncc,cbind(fullcohortdata[controls,], numrisk=numAtRisk)) no.sample <- no.sample+1} } ncc$setno <- rep(1:no.sample,each=m+1) ncc$case <- rep(c(1,rep(0,m)),no.sample) predictorMatrix <- matrix(0,nrow=dim(ncc)[2],ncol=dim(ncc)[2]) predictorMatrix[which(colnames(ncc)=="x"),c(which(colnames(ncc)=="z"))] <- 1 imps <- smcfcs.nestedcc(originaldata=ncc,set="setno",nrisk="numrisk",event="d",smformula="Surv(t,case)~x+z+strata(setno)", method=c("", "", "logreg", "", "", "", "", ""),predictorMatrix=predictorMatrix) impobj <- imputationList(imps$impDatasets) models <- with(impobj, clogit(case~x+z+strata(setno))) xEsts[sim] <- summary(MIcombine(models))[1,1] } print(mean(xEsts)) abs(mean(xEsts)-1)<0.1 }, TRUE) }) smcfcs/tests/testthat/test_coxph.r0000644000176200001440000000235313640330603017076 0ustar liggesuserslibrary(smcfcs) library(survival) context("Cox proportional hazards model testing") test_that("Cox imputation is approximately unbiased", { skip_on_cran() expect_equal({ set.seed(1234) n <- 10000 z <- rnorm(n) x <- z+rnorm(n) t <- -log(runif(n))/(1*exp(x+z)) d <- 1*(t<10) t[d==0] <- 10 x[(runif(n)<0.5)] <- NA simData <- data.frame(t,d,x,z) imps <- smcfcs(simData, smtype="coxph", smformula="Surv(t, d)~x+z", method=c("", "", "norm", "")) library(mitools) impobj <- imputationList(imps$impDatasets) models <- with(impobj, coxph(Surv(t,d)~x+z)) abs(summary(MIcombine(models))[1,1]-1)<0.1 }, TRUE) }) test_that("Cox imputation works with only one covariate", { skip_on_cran() expect_equal({ set.seed(1234) n <- 10000 x <- rnorm(n) t <- -log(runif(n))/(0.01*exp(x)) d <- 1*(t<10) t[d==0] <- 10 x[(runif(n)<0.5)] <- NA simData <- data.frame(t,d,x) imps <- smcfcs(simData, smtype="coxph", smformula="Surv(t, d)~x", method=c("", "", "norm")) library(mitools) impobj <- imputationList(imps$impDatasets) models <- with(impobj, coxph(Surv(t,d)~x)) abs(summary(MIcombine(models))[1,1]-1)<0.1 }, TRUE) }) smcfcs/vignettes/0000755000176200001440000000000014062671441013545 5ustar liggesuserssmcfcs/vignettes/smcfcs-vignette.Rmd0000644000176200001440000003762113763376371017336 0ustar liggesusers--- title: "smcfcs" author: "Jonathan Bartlett" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{smcfcs} %\VignetteEngine{knitr::rmarkdown} %\usepackage[utf8]{inputenc} --- # Introduction Missing data are a common issue in many fields of empirical research. An popular approach to handling missing data is the method of multiple imputation (MI). Multiple imputation involves replacing missing values by a number of imputations, creating multiple imputed datasets. Each completed dataset is then analysed as usual, and estimates and standard errors are combined across imputations using rules developed by Rubin. The most popular approach to imputation uses parametric models for the missing variables given the observed. Multiple imputation gives valid inferences provided that the missing data satisfy the so called missing at random (MAR) assumption and that the imputation models used are correctly specified. ## Joint model and FCS multiple imputation When multiple variables are affected by missingness, the traditional approach to imputation is to specify a joint (or multivariate model) for the partially observed variables. One of the earliest examples of this was MI using the multivariate normal model. Rather than specifying a joint model directly, a popular alternative is the fully conditional specification (FCS), or chained equations approach. In FCS MI separate conditional models are specified for each partially observed variable. In each of these conditional models, by default all of the variables serve as predictors. For an overview of the FCS MI and an implementation of it in R, see van Buuren and Groothuis-Oudshoorn. ## Imputation model compatibility When missing values are imputed from a misspecified model, in general invalid inferences will result. One way in which misspecification can occur is when the imputation and substantive (analysis) model of interest are incompatible. Loosely speaking, this means there exists no joint model which contains the imputation model and the substantive model as the corresponding conditionals. In this case, as described by Bartlett *et al* (2015), assuming that the substantive model is correctly specified, unless the imputation and substantive models can be made compatible by imposing a restriction on the imputation model, incompatibility implies the imputation model is misspecified. Such incompatibility between the imputation model used to impute a partially observed covariate and the substantive/outcome model can arise for example when the latter includes interactions or non-linear effects of variables. A further example is when the substantive model is a Cox proportional hazards model for a censored time to event outcome. In these cases, it may be difficult or impossible to specify an imputation model for a covariate which is compatible with the model for the outcome (the substantive model) using standard imputation models as available in existing packages. # Substantive Model Compatible Fully Conditional Specification multiple imputation The substantive model compatible modification of FCS MI (SMC-FCS), proposed by Bartlett *et al* (2015), ensures that each partially observed variable is imputed from an imputation model which is compatible with a user specified model for the outcome (which is typically the substantive model of interest, although see below regarding auxiliary variables). As described in further detail in the linked paper, for each partially observed variable, e.g. `x1`, in SMC-FCS a model is specified for the conditional distribution of `x1` given the other partially observed variables `x2,x3,..,xp` and fully observed covariates `z`. This, together with the specified substantive model (a model for the outcome `y`) defines an imputation model for `x1` which is guaranteed to be compatible with this specified substantive model. ## Sampling from the imputation distribution Unfortunately, the resulting imputation model for each partially observed variable generally does not belong to a standard parametric family, complicating the imputation of missing values. To overcome this, `smcfcs` uses the method of rejection sampling, which is more computationally intensive than direct sampling methods. ## Statistical properties SMC-FCS ensures compatibility between each partially observed covariate's imputation model with the substantive model. However, when there is more than one partially observed variable, it does not guarantee that the corresponding different imputation models are mutually compatible. Consequently, as described further by Bartlett *et al* (2015), only in special cases does SMC-FCS generate imputations from a well defined Bayesian joint model. Nonetheless, by ensuring compatibility between each partially observed variable's imputation model and the substantive model, it arguably overcomes (compared to standard FCS MI) the type of model incompatibility which is most likely to adversely affect inferences. ## When SMC-FCS may be preferable to FCS/MICE In certain situations it may be advantageous to use SMC-FCS rather than traditional FCS MI. Important examples, as mentioned previously, include situations where the substantive (outcome) model includes interactions or non-linear effects of some of the covariates, or where the outcome model is itself non-linear, such as a Cox proportional hazards model. See Bartlett *et al* (2015) for simulation results comparing the two approaches in these situations. # The `smcfcs` package The `smcfcs` function in the `smcfcs` package implements the SMC-FCS procedure. Currently linear, logistic and Cox proportional hazards substantive models. Competing risks outcome data can also be accommodated, with a Cox proportional hazards model used to model each cause specific hazard function. Partially observed variables can be imputed using normal linear regression, logistic regression (for binary variables), proportional odds regression (sometimes known as ordinal logistic regression, suitable for ordered categorical variables), multinomial logistic regression (for unordered categorical variables), and Poisson regression (for count variables). In the following we describe some of the important aspects of using `smcfcs` by way of an example data frame. ## Example - linear regression substantive model with quadratic covariate effects To illustrate the package, we use the simple example data frame `ex_linquad`, which is included with the package. This data frame was simulated for `n=1000` independent rows. For each row, variables `y,x,z,v` were intended to be collected, but there are missing values in `x`. The values have been made artificially missing, with the probability of missingness dependent on (the fully observed) `y` variable. Below the first 10 rows of the data frame are shown: ```{r} library(smcfcs) ex_linquad[1:10,] ``` As shown, the `xsq` variable is equal to the square of the `x` variable. Since the latter has missing values, so does the former. We now impute the missing values in `x` and `xsq`, compatibly with a substantive model for the outcome `y` which is specified as a linear regression, with `z`, `x` and `xsq` as covariates: ```{r} set.seed(123) #impute missing values in x, compatibly with quadratic substantive model imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq",method=c("","","norm","x^2","")) ``` As demonstrated here, the minimal arguments to pass to `smcfcs` are the data frame to be used, the substantive model type, the substantive model formula, and a method vector. The substantive model type specifies whether the model for the outcome is linear, logistic or Cox regression, or a competing risks analysis (see documentation). The `smformula` specifies the linear predictor of the substantive/outcome model. Here we specified that the outcome `y` is assumed to follow a linear regression model, with `z`, `x` and `xsq` as predictors. Lastly, we passed a vector of strings as the `method` argument. This specifies, for each column in the data frame, the method to use for imputation. As in the example, empty strings should be passed for those columns which are fully observed and thus are not to be imputed. For `x` we specify `norm`, in order to impute using a normal linear regression model. See the help for `smcfcs` for the syntax for other imputation model types. For `xsq` we specify `"x^2"` as the imputation method. This instructs `smcfcs` to impute `xsq` by simply squaring the imputed values of `x`. Such a specification could also be used with the `mice` package, which implements standard FCS MI. Note however that here, through specifying the substantive model as including an effect of `xsq`, `smcfcs` is imputing the missing values in `x` which allows for a quadratic effect on `y`. Having generated the imputed datasets, we can now fit our substantive model of interest. Here we make use of the `mitools` package to fit our substantive model to each imputed dataset, collect the results, and combine them using Rubin's rules: ```{r} # fit substantive model library(mitools) impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~z+x+xsq)) summary(MIcombine(models)) ``` Here the data were simulated such that the coefficients of `z`, `x` and `xsq` are all 1. The estimates we have obtained are (reassuringly) close to these true parameter values. To illustrate the dangers of imputing a covariate using an imputation model which is not compatible with the substantive model, we now re-impute `x`, but this time imputing compatibly with a model for `y` which does not allow for the quadratic effect: ```{r} #impute missing values in x, compatibly with model for y which omits the quadratic effect imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x",method=c("","","norm","x^2","")) ``` `smcfcs` has issued some warnings about rejection sampling. We discuss this later in this vignette, but here we will continue and proceed to fit a model for `y` which includes both `x` and `xsq` (plus `z`) as covariates: ```{r} # fit substantive model impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~z+x+xsq)) summary(MIcombine(models)) ``` Now we have an estimate of the coefficient of `xsq` of 0.60, which is considerably smaller than the true value 1 used to simulate the data. This bias is due to the imputation model we have just used for `x` being misspecified. In particular, it was misspecified due to the fact it wrongly assumed a linear dependence of `y` on `x`, rather than allowing a quadratic dependence. ## Imputing using auxiliary variables with `smcfcs` One of the strengths of multiple imputation in general is the possibility to use variables in imputation models which are subsequently not involved in the substantive model. This may be useful in order to condition or adjust for variables which are predictive of missingness, but which are not used in the substantive model of interest. Moreover, adjusting for auxiliary variables which are strongly correlated with one or more variables which are being imputed improves efficiency. When using `smcfcs` to impute missing covariates, auxiliary variables `v` can be included by adding them as an additional covariate in the substantive model, as passed using the `smformula` argument. Here we are imputing `x` compatibly with a certain specification of model for the outcome. Our substantive model of interest is then a simpler model which omits `v`. For example, in the quadratic example dataset, we can add the auxiliary variable `v` using: ```{r} #impute, including v as a covariate in the substantive/outcome model imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq+v",method=c("","","norm","x^2","")) # fit substantive model, which omits v impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~z+x+xsq)) summary(MIcombine(models)) ``` For outcome models other than linear regression, this approach is not entirely justifiable due to the lack of collapsibility of non-linear models. For example, if a Cox model is assumed for a failure time given variables `x` and `v`, the hazard function given only `x` (i.e. omitting `v` from the model) is no longer a Cox model. Further research is warranted to explore how this might affect the resulting inferences. It is also possible to include the auxiliary variable `v` without adding it to the outcome model (as given in the `smformula` argument), through specification of the `predictorMatrix` argument. Doing so conditions on `v`, but assumes that the outcome is independent of `v`, conditional on whatever covariates are specified in `smformula`. This should thus only be used when the latter assumption is justified. When it is, inferences will in general be more efficient. To make this assumption when imputing `x` in the `ex_linquad` data, we define a `predictorMatrix` which will specify that `x` be imputed using both `z` and `v`, but we omit `v` from the `smformula` argument: ```{r} predMatrix <- array(0, dim=c(ncol(ex_linquad),ncol(ex_linquad))) predMatrix[3,] <- c(0,1,0,0,1) imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq",method=c("","","norm","x^2",""),predictorMatrix=predMatrix) impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~z+x+xsq)) summary(MIcombine(models)) ``` ## Rejection sampling warnings Sometimes when running `smcfcs` you may receive warnings that the rejection sampling that `smcfcs` uses has failed to draw from the required distribution on a couple of occasions. Upon receiving this warning, it is generally good idea to re-run `smcfcs`, specifying a value for `rjlimit` which is larger than the default, until the warning is no longer issued. Having said that, when only a small number of warnings are issued, it may be fine to ignore the warnings, especially when the dataset is large. ## Assessing convergence Like standard chained equations or FCS imputation, the SMC-FCS algorithm must be run for a sufficient number of iterations for the process to converge to its stationary distribution. The default number of iterations used is 10, but this may not be sufficient in any given dataset and model specification To assess convergence, the object returned by `smcfcs` includes an object called `smCoefIter`. This matrix contains the parameter estimates of the substantive model, and is indexed by imputation number, parameter number, and iteration number. To assess convergence, one can call smcfcs with `m=1` and `numit` suitably chosen (e.g. `numit=100`). The values in the resulting smCoefIter matrix can then be plotted to assess convergence. To illustrate, we re-run the imputation model used previously with the example data, but asking for only `m=1` imputation to be generated, and with 100 iterations. ```{r, fig.width = 6, fig.height = 4} # impute once with a larger number of iterations than the default 10 imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq",method=c("","","norm","x^2",""),predictorMatrix=predMatrix,m=1,numit=100) # plot estimates of the fourth parameter of the substantive model against iteration number plot(imps$smCoefIter[1,4,]) ``` The plot shows that the process appears to converge rapidly, such that the default choice of `numit=10` is probably fine here. Of course we should also examine the corresponding plots for the other parameters of the substantive model, since convergence may require more than 10 iterations for some of these.

References

Bartlett JW, Seaman SR, White IR, Carpenter JR. Multiple imputation of covariates by fully conditional specification: accommodating the substantive model. Statistical Methods in Medical Research, 2015; 24(4):462-487 van Buuren S, Groothuis-Oudshoorn K. mice: Multivariate Imputation by Chained Equations in R. Journal of Statistical Software, 2011; 45(3) smcfcs/vignettes/smcfcs_coverror-vignette.Rmd0000644000176200001440000001516413763410505021241 0ustar liggesusers--- title: "smcfcs for covariate measurement error correction" author: "Jonathan Bartlett" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{smcfcs_measerror} %\VignetteEngine{knitr::rmarkdown} %\usepackage[utf8]{inputenc} --- This short vignette introduces the capabilities of `smcfcs` to accommodate classical covariate measurement error. We consider the cases where internal validation data and then internal replication data are available. # Validation data We will simulate a dataset with internal validation data where the true covariate (x) is observed for 10\% of the sample, while every subject has an error-prone measurement (w) observed: ```{r} set.seed(1234) n <- 1000 x <- rnorm(n) w <- x+rnorm(n) y <- x+rnorm(n) x[(n*0.1):n] <- NA simData <- data.frame(x,w,y) ``` We have generated code where the error-prone measurement w is equal to the true covariate x plus some independent normally distributed measurement error. Since x is observed for some of the subjects in the case of interval validation data, this is a regular missing data problem. The error-prone measurement w serves as an auxiliary variable for the purposes of imputation of x. In particular, we will impute using `smcfcs' such that w is not in the substantive model. This encodes the so called non-differential error assumption, that says that conditional on x, the error-prone measurement w provides no independent information about the outcome y. An initial attempt to do this is: ```{r} library(smcfcs) imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("norm", "", ""),m=5) ``` We see from the output that `smcfcs` has not mentioned that it is using w anywhere. This is because w is fully observed and is not involved in the substantive model. To force w to be conditioned on when imputing x, we must pass an appropriate `predictorMatrix` to `smcfcs`: ```{r} predMat <- array(0, dim=c(3,3)) predMat[1,2] <- 1 ``` We have specified that the first variable, x, be imputed using w. Note that we do not need to tell `smcfcs` to impute x using y, as this will occur automatically by virtue of y being the outcome variable in the substantive model. We can now impute again, passing `predMat` as the `predictorMatrix`: ```{r} imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("norm", "", ""),m=5, predictorMatrix=predMat) ``` Now we can fit the substantive model to each imputed dataset and use the `mitools` package to pool the estimates and standard errors using Rubin's rules: ```{r} library(mitools) impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~x)) summary(MIcombine(models)) ``` We note from the results that the fraction of missing information for the coefficient of x is high. This should not surprise us, given that x was missing for 90\% of the sample and the error-prone measurement w is quite a noisy measure of x. # Replication data We will now demonstrate how `smcfcs` can be used to impute a covariate x which is not observed for any subjects, but we have for at least a subset of the sample two or more error-prone replicate measurements. We first simulate the dataset: ```{r} x <- rnorm(n) w1 <- x+rnorm(n) w2 <- x+rnorm(n) w2[(n*0.1):n] <- NA y <- x+rnorm(n) x <- rep(NA,n) simData <- data.frame(x,w1,w2,y) ``` Note that now x is missing for every subject. Every subject has an error-prone measurement w1 of x, and 10\% of the sample have a replicated measurement w2. We will now impute x using `smcfcs`. To do this we specify that x be imputed using the `latnorm` method. In addition, we pass a matrix to the `errorProneMatrix` argument of `smcfcs`, whose role is to specify, for each latent normal variable to be imputed, which variables in the data frame are error-prone measurements. `smcfcs` then imputes the missing values in x, assuming a normal classical error model for the error-prone replicates. ```{r} errMat <- array(0, dim=c(4,4)) errMat[1,c(2,3)] <- 1 imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("latnorm", "", "",""),m=5, errorProneMatrix=errMat) ``` Analysing the imputed datasets, we obtain: ```{r} impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~x)) summary(MIcombine(models)) ``` If we summarise one of the imputed datasets (below), we will see that `smcfcs` has not only imputed the missing values in x, but also the 'missing' values in w2. We hyphenate missing here because typically a study with replicate error-prone measurements will have intentionally planned to only take a second error-prone measurement on a random subset, so the values were never intended to be measured. ```{r} summary(imps$impDatasets[[1]]) ``` One thing to be wary of when imputing covariates measured with error, particularly with replication data, is that convergence may take longer than in the regular missing data setting. To examine this, we re-impute one dataset using 100 iterations, and then plot the estimates against iteration number: ```{r, fig.width=6} imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("latnorm", "", "",""),m=1,numit=100, errorProneMatrix=errMat) plot(imps$smCoefIter[1,2,]) ``` This plot suggests it would probably be safer to impute using more than 10 iterations per imputation. ## Multiple covariates measured with error `smcfcs` can impute multiple covariates measured with error when internal replication data are available. It allows for a separate error variance for each such covariate. The following code adds a second covariate which is itself measured by two error-prone measurements, but this time with a smaller error variance. It then defines the `errorProneMatrix`, imputes and analyses the imputed datasets: ```{r} x <- rnorm(n) x1 <- x+rnorm(n) x2 <- x+rnorm(n) w2[(n*0.1):n] <- NA z <- x+rnorm(n) z1 <- z+0.1*rnorm(n) z2 <- z+0.1*rnorm(n) y <- x-z+rnorm(n) x <- rep(NA,n) z <- rep(NA,n) simData <- data.frame(x,x1,x2,z,z1,z2,y) errMat <- array(0, dim=c(7,7)) errMat[1,c(2,3)] <- 1 errMat[4,c(5,6)] <- 1 imps <- smcfcs(simData, smtype="lm", smformula="y~x+z", method=c("latnorm", "", "","latnorm", "", "", ""),m=5, errorProneMatrix=errMat) ``` We now analyse the imputed datasets, remembering to add z into the substantive model: ```{r} impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~x+z)) summary(MIcombine(models)) ``` We see that the fraction of missing information is lower for z than for x. This is a consequence of the fact that we generated the error-prone measurements of z to have smaller error variance than for the corresponding error-prone measurements of x. smcfcs/R/0000755000176200001440000000000014062655673011747 5ustar liggesuserssmcfcs/R/data.r0000644000176200001440000001274014060150767013037 0ustar liggesusers #' Simulated example data with continuous outcome and quadratic covariate effects #' #' A dataset containing simulated data where the outcome depends quadratically #' on a partially observed covariate. #' #' @format A data frame with 1000 rows and 5 variables: #' \describe{ #' \item{y}{Continuous outcome} #' \item{z}{Fully observed covariate, with linear effect on outcome} #' \item{x}{Partially observed normally distributed covariate, with quadratic effect on outcome} #' \item{xsq}{The square of x, which thus has missing values also} #' \item{v}{An auxiliary variable (i.e. not contained in the substantive model)} #' } #' "ex_linquad" #' Simulated example data with continuous outcome and interaction between two partially observed covariates #' #' A dataset containing simulated data where the outcome depends on both main #' effects and interaction of two partially observed covariates. #' #' @format A data frame with 1000 rows and 4 variables: #' \describe{ #' \item{y}{Continuous outcome} #' \item{x1}{Partially observed normally distributed covariate} #' \item{x2}{Partially observed binary covariate} #' } #' "ex_lininter" #' Simulated example data with binary outcome and quadratic covariate effects #' #' A dataset containing simulated data where the binary outcome depends quadratically #' on a partially observed covariate. #' #' @format A data frame with 1000 rows and 5 variables: #' \describe{ #' \item{y}{Binary outcome} #' \item{z}{Fully observed covariate, with linear effect on outcome (on log odds scale)} #' \item{x}{Partially observed normally distributed covariate, with quadratic effect on outcome (on log odds scale)} #' \item{xsq}{The square of x, which thus has missing values also} #' \item{v}{An auxiliary variable (i.e. not contained in the substantive model)} #' } #' "ex_logisticquad" #' Simulated example data with count outcome, modelled using Poisson regression #' #' A dataset containing simulated data where the count outcome depends on two #' covariates, x and z, with missing values in x. The substantive model is #' Poisson regression. #' #' @format A data frame with 1000 rows and 3 variables: #' \describe{ #' \item{y}{Count outcome} #' \item{z}{Fully observed covariate, with linear effect on outcome} #' \item{x}{Partially observed normally distributed covariate, with linear effect on outcome} #' } #' "ex_poisson" #' Simulated example data with time to event outcome and quadratic covariate effects #' #' A dataset containing simulated data where a time to event outcome depends quadratically #' on a partially observed covariate. #' #' @format A data frame with 1000 rows and 6 variables: #' \describe{ #' \item{t}{Time to event or censoring} #' \item{d}{Binary indicator of whether event occurred or individual was censored} #' \item{z}{Fully observed covariate, with linear effect on outcome (on log hazard scale)} #' \item{x}{Partially observed normally distributed covariate, with quadratic effect on outcome (on log hazard scale)} #' \item{xsq}{The square of x, which thus has missing values also} #' \item{v}{An auxiliary variable (i.e. not contained in the substantive model)} #' } #' "ex_coxquad" #' Simulated example data with competing risks outcome and partially observed covariates #' #' A dataset containing simulated competing risks data. There are two competing risks, and #' some times are also censored. #' #' @format A data frame with 1000 rows and 4 variables: #' \describe{ #' \item{t}{Time to event or censoring} #' \item{d}{Indicator of whether event 1 occurred (d=1), event 2 occurred (d=2) or individual was censored (d=0)} #' \item{x1}{Partially observed binary covariate, with linear effects on log competing risk hazards} #' \item{x2}{Partially observed normally distributed (conditional on x1) covariate, with linear effects #' on log competing risk hazards} #' } #' "ex_compet" #' Simulated case cohort data #' #' A dataset containing simulated case cohort data, where the sub-cohort was a 10\% random sample of the full cohort. #' #' @format A data frame with 1571 rows and 7 variables: #' \describe{ #' \item{t}{Time to event or censoring} #' \item{d}{Indicator of whether event 1 occurred (d=1), or not (d=0)} #' \item{x}{Partially observed continuous covariate} #' \item{z}{Fully observed covariate} #' \item{in.subco}{A binary indicator of whether the subject is in the sub-cohort} #' \item{id}{An id variable} #' \item{entertime}{The entry time variable to be used in the analysis} #' } #' "ex_cc" #' Simulated nested case-control data #' #' A dataset containing simulated nested case-control data. #' #' @format A data frame with 728 rows and 8 variables: #' \describe{ #' \item{t}{Time to event or censoring} #' \item{d}{Indicator of whether event 1 occurred (d=1), or not (d=0)} #' \item{x}{Partially observed binary covariate} #' \item{z}{Fully observed covariate} #' \item{id}{An id variable} #' \item{numrisk}{Number of patients at risk at time of case's event} #' \item{setno}{The case-control set number} #' \item{case}{Binary indicator of case (=1) or control (=0)} #' } #' "ex_ncc" #' Simulated discrete time survival data set #' #' A dataset containing simulated discrete time survival data. #' #' @format A data frame with 1000 rows and 8 variables: #' \describe{ #' \item{x1}{A binary variable with missing values} #' \item{x2}{A fully observed continuous variable} #' \item{failtime}{The discrete failure/censoring time} #' \item{d}{Indicator of failure (=1) or censoring (=0)} #' } #' "ex_dtsam" smcfcs/R/smcfcs.r0000644000176200001440000017010114062220333013365 0ustar liggesusers#' Substantive model compatible fully conditional specification imputation of covariates. #' #' Multiply imputes missing covariate values using substantive model compatible #' fully conditional specification. #' #' smcfcs imputes missing values of covariates using the Substantive Model Compatible #' Fully Conditional Specification multiple imputation approach proposed by #' Bartlett \emph{et al} 2015 (see references). #' #' Imputation is supported for linear regression (\code{"lm"}), #' logistic regression (\code{"logistic"}), Poisson regression #' (\code{"poisson"}), Weibull (\code{"weibull"}) and Cox regression #' for time to event data (\code{"coxph"}), #' and Cox models for competing risks data (\code{"compet"}). For the latter, a #' Cox model is assumed for each cause of failure, and the event indicator #' should be integer coded with 0 corresponding to censoring, 1 corresponding to #' failure from the first cause etc. #' #' The function returns a list. The first element \code{impDataset} of the list is a list of the imputed #' datasets. Models (e.g. the substantive model) can be fitted to each and results #' combined using Rubin's rules using the mitools package, as illustrated in the examples. #' #' The second element \code{smCoefIter} is a three dimensional array containing the values #' of the substantive model parameters obtained at the end of each iteration of the algorithm. #' The array is indexed by: imputation number, parameter number, iteration. #' #' If the substantive model is linear, logistic or Poisson regression, #' \code{smcfcs} will automatically impute missing outcomes, if present, using #' the specified substantive model. However, even in this case, the user should #' specify "" in the element of method corresponding to the outcome variable. #' #' #' The development of this package was supported by a UK Medical Research Council #' Fellowship (MR/K02180X/1). Part of its development took place while the author was #' kindly hosted by the University of Michigan's Department of Biostatistics & Institute for #' Social Research. #' #' The structure of many of the arguments to \code{smcfcs} are based on those of #' the excellent \code{mice} package. #' #' @param originaldata The original data frame with missing values. #' @param smtype A string specifying the type of substantive model. Possible #' values are \code{"lm"}, \code{"logistic"}, \code{"poisson"}, \code{"weibull"}, #' \code{"coxph"}, \code{"compet"}. #' @param smformula The formula of the substantive model. For \code{"weibull"} and \code{"coxph"} #' substantive models the left hand side should be of the form \code{"Surv(t,d)"}. For \code{"compet"} #' substantive models, a list should be passed consisting of the Cox models #' for each cause of failure (see example). #' @param method A required vector of strings specifying for each variable either #' that it does not need to be imputed (""), the type of regression model to be #' be used to impute. Possible values are \code{"norm"} (normal linear regression), #' \code{"logreg"} (logistic regression), \code{"poisson"} (Poisson regression), #' \code{"podds"} (proportional odds regression for ordered categorical variables), #' \code{"mlogit"} (multinomial logistic regression for unordered categorical variables), #' or a custom expression which defines a passively imputed variable, e.g. #' \code{"x^2"} or \code{"x1*x2"}. \code{"latnorm"} indicates the variable is a latent #' normal variable which is measured with error. If this is specified for a variable, #' the \code{"errorProneMatrix"} argument should also be used. #' @param predictorMatrix An optional predictor matrix. If specified, the matrix defines which #' covariates will be used as predictors in the imputation models #' (the outcome must not be included). The i'th row of the matrix should consist of #' 0s and 1s, with a 1 in the j'th column indicating the j'th variable be used #' as a covariate when imputing the i'th variable. If not specified, when #' imputing a given variable, the imputation model covariates are the other #' covariates of the substantive model which are partially observed #' (but which are not passively imputed) and any fully observed covariates (if present) #' in the substantive model. Note that the outcome variable is implicitly conditioned #' on by the rejection sampling scheme used by smcfcs, and should not be specified as a predictor #' in the predictor matrix. #' @param m The number of imputed datasets to generate. The default is 5. #' @param numit The number of iterations to run when generating each imputation. #' In a (limited) range of simulations good performance was obtained with the #' default of 10 iterations. However, particularly when the proportion of missingness #' is large, more iterations may be required for convergence to stationarity. #' @param rjlimit Specifies the maximum number of attempts which should be made #' when using rejection sampling to draw from imputation models. If the limit is reached #' when running a warning will be issued. In this case it is probably advisable to #' increase the \code{rjlimit} until the warning does not appear. #' @param noisy logical value (default FALSE) indicating whether output should be noisy, which can #' be useful for debugging or checking that models being used are as desired. #' @param errorProneMatrix An optional matrix which if specified indicates that some variables #' are measured with classical measurement error. If the i'th variable is measured with error #' by variables j and k, then the (i,j) and (i,k) entries of this matrix should be 1, with the #' remainder of entries 0. The i'th element of the method argument should then be specified #' as \code{"latnorm"}. See the measurement error vignette for more details. #' #' @return A list containing: #' #' \code{impDatasets} a list containing the imputed datasets #' #' \code{smCoefIter} a three dimension matrix containing the substantive model parameter #' values. The matrix is indexed by [imputation,parameter number,iteration] #' #' @author Jonathan Bartlett \email{j.w.bartlett@@bath.ac.uk} \url{https://thestatsgeek.com} #' \url{http://www.missingdata.org.uk} #' #' @example data-raw/examples.r #' #' @references Bartlett JW, Seaman SR, White IR, Carpenter JR. Multiple imputation of covariates #' by fully conditional specification: accommodating the substantive model. Statistical Methods #' in Medical Research 2015; 24(4): 462-487. \doi{10.1177/0962280214521348} #' @import stats #' @importFrom survival Surv #' @export smcfcs <- function(originaldata,smtype,smformula,method,predictorMatrix=NULL,m=5,numit=10,rjlimit=1000,noisy=FALSE,errorProneMatrix=NULL) { #call core smcfcs function, passing through arguments smcfcs.core(originaldata,smtype,smformula,method,predictorMatrix,m,numit,rjlimit,noisy,errorProneMatrix=errorProneMatrix) } #' Substantive model compatible fully conditional specification imputation of covariates for case cohort studies #' #' Multiply imputes missing covariate values using substantive model compatible #' fully conditional specification for case cohort studies. #' #' This version of \code{smcfcs} is designed for use with case cohort studies but where the analyst does not wish to, #' or cannot (due to not having the necessary data) impute the full cohort. The function's arguments are the same #' as for the main smcfcs function, except for \code{smformula}, \code{in.subco}, and \code{sampfrac} - see above #' for details on how these should be specified. #' #' @author Ruth Keogh \email{ruth.keogh@@lshtm.ac.uk} #' @author Jonathan Bartlett \email{j.w.bartlett@@bath.ac.uk} #' #' @param originaldata The case-cohort data set (NOT a full cohort data set with a case-cohort substudy within it) #' @param smformula A formula of the form "Surv(entertime,t,d)~x", where d is the event (d=1) or censoring (d=0) indicator, t is the event or censoring time and entertime is equal to the time origin (typically 0) for individuals in the subcohort and is equal to (t-0.001) for cases outside the subcohort [this sets cases outside the subcohort to enter follow-up just before their event time. The value 0.001 may need to be modified depending on the time scale.] #' @param in.subco The name of a column in the dataset with 0/1s that indicates whether the subject is in the subcohort #' @param sampfrac The proportion of individuals from the underlying full cohort who are in the subcohort #' #' @inheritParams smcfcs #' #' @example data-raw/cc_example.r #' #' @export smcfcs.casecohort <- function(originaldata,smformula,sampfrac,in.subco,method,predictorMatrix=NULL,m=5,numit=10,rjlimit=1000,noisy=FALSE, errorProneMatrix=NULL) { smcfcs.core(originaldata,smtype="casecohort",smformula,method,predictorMatrix,m,numit,rjlimit,noisy,sampfrac=sampfrac,in.subco=in.subco, errorProneMatrix=errorProneMatrix) } #' Substantive model compatible fully conditional specification imputation of covariates for nested case control #' studies #' #' Multiply imputes missing covariate values using substantive model compatible #' fully conditional specification for nested case control studies. #' #' This version of \code{smcfcs} is designed for use with nested case control studies. The function's arguments are the same #' as for the main smcfcs function, except for \code{smformula}, \code{set}, \code{event} and \code{nrisk} - see above #' for details on how these should be specified. #' #' @author Ruth Keogh \email{ruth.keogh@@lshtm.ac.uk} #' @author Jonathan Bartlett \email{j.w.bartlett@@bath.ac.uk} #' #' @param originaldata The nested case-control data set (NOT a full cohort data set with a case-cohort substudy within it) #' @param smformula A formula of the form "Surv(t,case)~x+strata(set)", where case is case-control indicator, t is the event or censoring time. Note that t could be set to the case's event time for the matched controls in a given set. The right hand side should include the case control set as a strata term (see example). #' @param set variable identifying matched sets in nested case-control study #' @param event variable which indicates who is a case/control in the nested case-control sample. Note that this is distinct from d. #' @param nrisk variable which is the number at risk (in the underlying full cohort) at the event time for the case in each matched set (i.e. nrisk is the same for all individuals in a matched set). #' #' @inheritParams smcfcs #' @example data-raw/ncc_example.r #' @export smcfcs.nestedcc <- function(originaldata,smformula,set,event,nrisk,method,predictorMatrix=NULL,m=5,numit=10,rjlimit=1000,noisy=FALSE,errorProneMatrix=NULL) { smcfcs.core(originaldata,smtype="nestedcc",smformula,method,predictorMatrix,m,numit,rjlimit,noisy,set=set,event=event,nrisk=nrisk, errorProneMatrix=errorProneMatrix) } #' Substantive model compatible fully conditional specification imputation of covariates for #' discrete time survival analysis #' #' Multiply imputes missing covariate values using substantive model compatible #' fully conditional specification for discrete time survival analysis. #' #' For this substantive model type, like for the other substantive model types, \code{smcfcs} expects the \code{originaldata} to have #' one row per subject. Variables indicating the discrete time of failure/censoring #' and the event indicator should be passed in \code{smformula}, as described. #' #' The default is to model the effect of time as a factor. This will not work in datasets where #' there is not at least one observed event in each time period. In such cases you must specify #' a simpler parametric model for the effect of time. At the moment you can specify either a linear or quadratic #' effect of time (on the log odds scale). #' #' @author Jonathan Bartlett \email{j.w.bartlett@@bath.ac.uk} #' #' @param originaldata The data in wide form (i.e. one row per subject) #' @param smformula A formula of the form "Surv(t,d)~x1+x2+x3", where t is the discrete time variable, d is the binary event #' indicator, and the covariates should not include time. The time variable should be #' an integer coded numeric variable taking values from 1 up to the final time period. #' @param timeEffects Specifies how the effect of time is modelled. \code{timeEffects="factor"} (the default) models time as a #' factor variable. \code{timeEffects="linear"} and \code{timeEffects="quad"} specify that time be modelled as a continuous #' linear or quadratic effect on the log odds scale respectively. #' #' @inheritParams smcfcs #' @example data-raw/dtsam_example.r #' @export smcfcs.dtsam <- function(originaldata,smformula,timeEffects="factor",method,predictorMatrix=NULL,m=5,numit=10,rjlimit=1000,noisy=FALSE,errorProneMatrix=NULL) { smcfcs.core(originaldata,smtype="dtsam",smformula,method,predictorMatrix,m,numit,rjlimit,noisy,timeEffects=timeEffects, errorProneMatrix=errorProneMatrix) } #this is the core of the smcfcs function, called by wrapper functions for certain different substantive models smcfcs.core <- function(originaldata,smtype,smformula,method,predictorMatrix=NULL,m=5,numit=10,rjlimit=1000,noisy=FALSE,errorProneMatrix=NULL, ...) { #get extra arguments passed in ... extraArgs <- list(...) stopifnot(is.data.frame(originaldata)) if (ncol(originaldata)!=length(method)) stop("Method argument must have the same length as the number of columns in the data frame.") n <- dim(originaldata)[1] #create matrix of response indicators r <- 1*(is.na(originaldata)==0) if ((smtype %in% c("lm", "logistic", "poisson", "coxph", "compet", "casecohort","nestedcc", "weibull","dtsam"))==FALSE) stop(paste("Substantive model type ",smtype," not recognised.",sep="")) #find column numbers of partially observed, fully observed variables, and outcome if (smtype=="coxph") { timeCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(as.formula(smformula)[[2]][[2]])] dCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(as.formula(smformula)[[2]][[3]])] outcomeCol <- c(timeCol, dCol) d <- originaldata[,dCol] nullMod <- survival::coxph(survival::Surv(originaldata[,timeCol],originaldata[,dCol])~1, control = survival::coxph.control(timefix = FALSE)) basehaz <- survival::basehaz(nullMod) H0indices <- match(originaldata[,timeCol], basehaz[,2]) rm(nullMod) } else if (smtype=="weibull") { timeCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(as.formula(smformula)[[2]][[2]])] dCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(as.formula(smformula)[[2]][[3]])] outcomeCol <- c(timeCol, dCol) d <- originaldata[,dCol] } else if (smtype=="dtsam") { timeCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(as.formula(smformula)[[2]][[2]])] dCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(as.formula(smformula)[[2]][[3]])] outcomeCol <- c(timeCol, dCol) d <- originaldata[,dCol] #determine cut points cutPoints <- 1:max(originaldata[,timeCol]) nTimePoints <- length(cutPoints) #check all time points are integers if (!all(unique(originaldata[,timeCol]) == floor(unique(originaldata[,timeCol])))) { stop("Your time variable must only take positive integer values.") } #check all time points are positive if (any(unique(originaldata[,timeCol]) <= 0)) { stop("Your time variable must only take positive integer values.") } #if factor time effects, check there are some events at each integer value #so that model can fit if (extraArgs$timeEffects=="factor") { if (!identical(sort(unique(originaldata[,timeCol][originaldata[,dCol]==1])), as.numeric(cutPoints))) { stop("You cannot fit a dtsam model with factor time effects since there are some periods with no events. See documentation for timeEffects argument for parametric alternatives") } } } else if (smtype=="compet") { timeCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(as.formula(smformula[[1]])[[2]][[2]])] dCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(as.formula(smformula[[1]])[[2]][[3]][[2]])] outcomeCol <- c(timeCol, dCol) d <- originaldata[,dCol] numCauses <- length(smformula) H0 <- vector("list", numCauses) H0indices <- vector("list", numCauses) outcomeModBeta <- vector("list", numCauses) linpred <- vector("list", numCauses) for (cause in 1:numCauses) { nullMod <- survival::coxph(as.formula(paste(strsplit(smformula[[cause]],"~")[[1]][1],"~1")), originaldata, control = survival::coxph.control(timefix = FALSE)) basehaz <- survival::basehaz(nullMod) H0[[cause]] <- basehaz[,1] H0indices[[cause]] <- match(originaldata[,timeCol], basehaz[,2]) linpred[[cause]] <- as.formula(smformula[[cause]]) } rm(nullMod) } else if (smtype=="casecohort") { subcoCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% extraArgs$in.subco] #subcoMembers is a vector of row numbers of those in the subcohort subcoMembers <- which(originaldata[,subcoCol]==1) #generate weights for use in later analysis which we use to obtain baseline cumulative hazard #assign a weight of /samp.frac to individuals in the subcohort and 0 to those outside the subcohort subco.weight<-ifelse(originaldata[,subcoCol]==1,1/extraArgs$sampfrac,0) entertimeCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(as.formula(smformula)[[2]][[2]])] timeCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(as.formula(smformula)[[2]][[3]])] dCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(as.formula(smformula)[[2]][[4]])] outcomeCol <- c(entertimeCol,timeCol, dCol) d <- originaldata[,dCol] #list of unique event times - used in calculation of baseline cumulative hazard list.times=sort(unique(originaldata[,timeCol][originaldata[,dCol]==1])) #RUTH 21/03/17: ADDED THIS LINE smcfcsid <- 1:n smformula2<-paste(smformula,"+cluster(smcfcsid)",sep="") } else if (smtype=="nestedcc") { timeCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(as.formula(smformula)[[2]][[2]])] dCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(as.formula(smformula)[[2]][[3]])] outcomeCol <- c(timeCol, dCol) setCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(extraArgs$set)] nriskCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(extraArgs$nrisk)] eventCol <- (1:dim(originaldata)[2])[colnames(originaldata) %in% toString(extraArgs$event)] #this is distinct from the dCol #the below command creates "Surv(t,case)~x" from "Surv(t,case)~x+strata(setno)" (for example) (i.e. it removes the strata part of the formula) #this is used when obtaining outmodxb #note this is done slightly oddly, but this is because as.formula does not work well for long formulas as it splits across lines exp1=as.formula(paste(smformula))[[2]] exp2=as.formula(smformula)[[3]][[2]] smformula2<-paste(deparse(exp1),"~",deparse(exp2,width.cutoff = 500L)) #This is the indicator of whether an individual ever has the event (regardless of whether they are sometimes used as a control and sometimes (one) as a case) d <- originaldata[,eventCol] #noncases is a vector of row numbers of those who never have the event (which is a subset of the controls) noncases <- which(originaldata[,eventCol]==0) #number of individuals in each sampled risk set (matched set) num.sampriskset<-ave(rep(1,dim(originaldata)[1]), originaldata[,setCol], FUN = function(x) sum(x)) } else { outcomeCol <- which(colnames(originaldata)==as.formula(smformula)[[2]]) } if (smtype=="logistic") { if (is.numeric(originaldata[,outcomeCol])==FALSE) { stop("For logistic substantive models the outcome variable must be numeric 0/1.") } else { if (all.equal(unique(originaldata[,outcomeCol]),c(0,1))==FALSE) { stop("For logistic substantive models the outcome variable must be coded 0/1.") } } } if (smtype=="compet") { smcovnames <- attr(terms(as.formula(smformula[[1]])), "term.labels") for (cause in 2:numCauses) { smcovnames <- c(smcovnames, attr(terms(as.formula(smformula[[cause]])), "term.labels")) } smcovnames <- unique(smcovnames) } else if (smtype=="nestedcc") { smcovnames <- attr(terms(as.formula(smformula)), "term.labels")[-length(attr(terms(as.formula(smformula)), "term.labels"))] } else { smcovnames <- attr(terms(as.formula(smformula)), "term.labels") } smcovcols <- (1:ncol(originaldata))[colnames(originaldata) %in% smcovnames] #partial vars are those variables for which an imputation method has been specified among the available regression types partialVars <- which((method=="norm") | (method=="latnorm") | (method=="logreg") | (method=="poisson") | (method=="podds") | (method=="mlogit")) if (length(partialVars)==0) stop("You have not specified any valid imputation methods in the method argument.") #check that methods are given for each partially observed column, and not given for fully observed columns for (colnum in 1:ncol(originaldata)) { if (method[colnum]!="") { #an imputation method has been specified if (colnum %in% outcomeCol) { stop(paste("An imputation method has been specified for ",colnames(originaldata)[colnum], ". Elements of the method argument corresponding to the outcome variable(s) should be empty.",sep="")) } else { if (sum(r[,colnum])==n) { stop(paste("An imputation method has been specified for ",colnames(originaldata)[colnum], ", but it appears to be fully observed.",sep="")) } } } else { #no imputation method has been specified if (sum(r[,colnum])1)>0) { stop("Each error-prone measurement should be allocated to exactly one latnorm variable.") } } } if (is.null(errorProneMatrix)==FALSE) { if (("latnorm" %in% method)==FALSE) { stop("If you specify errorProneMatrix then at least one variable must be imputed using latnorm.") } } #fully observed vars are those that are fully observed and are covariates in the substantive model fullObsVars <- which((colSums(r)==n) & (colnames(originaldata) %in% smcovnames)) #passive variables passiveVars <- which((method!="") & (method!="norm") & (method!="logreg") & (method!="poisson") & (method!="podds") & (method!="mlogit") & (method!="latnorm")) print(paste("Outcome variable(s):", paste(colnames(originaldata)[outcomeCol],collapse=','))) print(paste("Passive variables:", paste(colnames(originaldata)[passiveVars],collapse=','))) print(paste("Partially obs. variables:", paste(colnames(originaldata)[partialVars],collapse=','))) print(paste("Fully obs. substantive model variables:", paste(colnames(originaldata)[fullObsVars],collapse=','))) imputations <- list() for (imp in 1:m) { imputations[[imp]] <- originaldata } rjFailCount <- 0 for (imp in 1:m) { print(paste("Imputation ",imp)) #initial imputation of each partially observed variable based on observed values for (var in 1:length(partialVars)) { targetCol <- partialVars[var] if (method[targetCol]=="latnorm") { #first impute any missing replicate error-prone measurements of this variable by a randomly chosen observed value errorProneCols <- which(errorProneMatrix[targetCol,]==1) for (measure in 1:length(errorProneCols)) { if (sum(r[,errorProneCols[measure]])0) { xmodformula <- as.formula(paste(colnames(imputations[[imp]])[targetCol], "~", paste(colnames(imputations[[imp]])[predictorCols], collapse="+"),sep="")) } else { xmodformula <- as.formula(paste(colnames(imputations[[imp]])[targetCol], "~1",sep="")) } if (smtype=="casecohort") { xmoddata <- imputations[[imp]][subcoMembers,] } else if (smtype=="nestedcc"){ xmoddata <- imputations[[imp]][noncases,] } else { xmoddata <- imputations[[imp]] } if (method[targetCol]=="norm") { #estimate parameters of covariate model xmod <- lm(xmodformula, data=xmoddata) #take draw from posterior of covariate model parameters beta <- xmod$coef sigmasq <- summary(xmod)$sigma^2 newsigmasq <- (sigmasq*xmod$df) / rchisq(1,xmod$df) covariance <- (newsigmasq/sigmasq)*vcov(xmod) newbeta = beta + MASS::mvrnorm(1, mu=rep(0,ncol(covariance)), Sigma=covariance) #calculate fitted values if ((smtype=="casecohort")|(smtype=="nestedcc")) { xfitted <- model.matrix(xmodformula, data=imputations[[imp]]) %*% newbeta } else { xfitted <- model.matrix(xmod) %*% newbeta } } else if (method[targetCol]=="latnorm") { #estimate parameters of covariate model xmod <- lm(xmodformula, data=xmoddata) #take draw from posterior of covariate model parameters beta <- xmod$coef sigmasq <- summary(xmod)$sigma^2 #draw from sigmasq posterior based on proper inverse gamma prior for sigmasq #prior equivalent to 1 observation and guess of sigmasq=1 newsigmasq <- 1/rgamma(1,shape=((n+1)/2), rate=((n*sigmasq+1)/2)) covariance <- (newsigmasq/sigmasq)*vcov(xmod) newbeta = beta + MASS::mvrnorm(1, mu=rep(0,ncol(covariance)), Sigma=covariance) #calculate fitted values if ((smtype=="casecohort")|(smtype=="nestedcc")) { xfitted <- model.matrix(xmodformula, data=imputations[[imp]]) %*% newbeta } else { xfitted <- model.matrix(xmod) %*% newbeta } #estimate error variance and draw new value of error variance errorProneCols <- which(errorProneMatrix[targetCol,]==1) xmat <- matrix(imputations[[imp]][,targetCol], nrow=nrow(imputations[[imp]]), ncol=length(errorProneCols)) uVec <- c(as.matrix(imputations[[imp]][,errorProneCols] - xmat)) sigmausq <- mean(uVec^2) #take draw from posterior of error variance, using proper inverse gamma prior sum_ni <- n*length(errorProneCols) sigmausq <- 1/rgamma(1,shape=((sum_ni+1)/2), rate=((sum_ni*sigmausq+1)/2)) #re-impute any originally missing error-prone measurements, based on classical error model assumption for (measure in 1:length(errorProneCols)) { nToImpute <- n-sum(r[,errorProneCols[measure]]) if (nToImpute>0) { #then some values need imputing imputations[[imp]][r[,errorProneCols[measure]]==0,errorProneCols[measure]] <- imputations[[imp]][r[,errorProneCols[measure]]==0,targetCol] + rnorm(nToImpute, 0, sd=sqrt(sigmausq)) } } #calculate conditional mean and variance of X|everything else except outcome wmean <- rowMeans(imputations[[imp]][,errorProneCols]) lambda <- newsigmasq/(newsigmasq+sigmausq/length(errorProneCols)) xfitted <- xfitted + lambda * (wmean - xfitted) newsigmasq <- rep(newsigmasq*(1-lambda), n) } else if (method[targetCol]=="logreg") { xmod <- glm(xmodformula, family="binomial",data=xmoddata) newbeta = modPostDraw(xmod) if ((smtype=="casecohort")|(smtype=="nestedcc")) { xfitted <- expit(model.matrix(xmodformula, data=imputations[[imp]]) %*% newbeta) } else { xfitted <- expit(model.matrix(xmod) %*% newbeta) } } else if (method[targetCol]=="poisson") { xmod <- glm(xmodformula, family="poisson", data=xmoddata) newbeta = modPostDraw(xmod) if ((smtype=="casecohort")|(smtype=="nestedcc")) { xfitted <- exp(model.matrix(xmodformula, data=imputations[[imp]]) %*% newbeta) } else { xfitted <- exp(model.matrix(xmod) %*% newbeta) } } else if (method[targetCol]=="podds") { if (is.ordered(imputations[[imp]][,targetCol])==FALSE) stop("Variables to be imputed using method podds must be stored as ordered factors.") xmod <- VGAM::vglm(xmodformula, VGAM::propodds, data=xmoddata) xmod.dummy <- VGAM::vglm(xmodformula, VGAM::propodds, data=imputations[[imp]]) newbeta <- VGAM::coef(xmod) + MASS::mvrnorm(1, mu=rep(0,ncol(VGAM::vcov(xmod))), Sigma=VGAM::vcov(xmod)) linpreds <- matrix((VGAM::model.matrix(xmod.dummy)) %*% newbeta, byrow=TRUE, ncol=(nlevels(imputations[[imp]][,targetCol])-1)) cumprobs <- cbind(1/(1+exp(linpreds)), rep(1,nrow(linpreds))) xfitted <- cbind(cumprobs[,1] ,cumprobs[,2:ncol(cumprobs)] - cumprobs[,1:(ncol(cumprobs)-1)]) } else if (method[targetCol]=="mlogit") { if (is.factor(imputations[[imp]][,targetCol])==FALSE) stop("Variables to be imputed using method modds must be stored as factors.") xmod <- VGAM::vglm(xmodformula, VGAM::multinomial(refLevel=1), data=xmoddata) xmod.dummy <- VGAM::vglm(xmodformula, VGAM::multinomial(refLevel=1), data=imputations[[imp]]) newbeta <- VGAM::coef(xmod) + MASS::mvrnorm(1, mu=rep(0,ncol(VGAM::vcov(xmod))), Sigma=VGAM::vcov(xmod)) linpreds <- matrix((VGAM::model.matrix(xmod.dummy)) %*% newbeta, byrow=TRUE, ncol=(nlevels(imputations[[imp]][,targetCol])-1)) denom <- 1+rowSums(exp(linpreds)) xfitted <-cbind(1/denom, exp(linpreds) / denom) } if (noisy==TRUE) { print(summary(xmod)) } #estimate parameters of substantive model if (smtype=="lm") { ymod <- lm(as.formula(smformula),imputations[[imp]]) beta <- ymod$coef sigmasq <- summary(ymod)$sigma^2 varcov <- vcov(ymod) outcomeModResVar <- (sigmasq*ymod$df) / rchisq(1,ymod$df) covariance <- (outcomeModResVar/sigmasq)*vcov(ymod) outcomeModBeta = beta + MASS::mvrnorm(1, mu=rep(0,ncol(covariance)), Sigma=covariance) if (noisy==TRUE) { print(summary(ymod)) } } else if (smtype=="logistic") { ymod <- glm(as.formula(smformula),family="binomial",imputations[[imp]]) outcomeModBeta = modPostDraw(ymod) if (noisy==TRUE) { print(summary(ymod)) } } else if (smtype=="dtsam") { #split data to long form longData <- survival::survSplit(as.formula(smformula), data=imputations[[imp]], cut=cutPoints) #fit logistic model if (extraArgs$timeEffects=="factor") { dtsamFormula <- paste(colnames(imputations[[imp]])[dCol],"~-1+factor(tstart)+", strsplit(smformula, "~")[[1]][2],sep="") } else if (extraArgs$timeEffects=="linear") { #linear time effect dtsamFormula <- paste(colnames(imputations[[imp]])[dCol],"~tstart+", strsplit(smformula, "~")[[1]][2],sep="") } else { #quadratic effect of time dtsamFormula <- paste(colnames(imputations[[imp]])[dCol],"~tstart+I(tstart^2)+", strsplit(smformula, "~")[[1]][2],sep="") } ymod <- glm(as.formula(dtsamFormula), family="binomial", data=longData) outcomeModBeta = modPostDraw(ymod) if (noisy==TRUE) { print(summary(ymod)) } } else if (smtype=="poisson") { ymod <- glm(as.formula(smformula),family="poisson",imputations[[imp]]) outcomeModBeta = modPostDraw(ymod) if (noisy==TRUE) { print(summary(ymod)) } } else if (smtype=="coxph") { ymod <- survival::coxph(as.formula(smformula), imputations[[imp]], control = survival::coxph.control(timefix = FALSE)) outcomeModBeta <- modPostDraw(ymod) ymod$coefficients <- outcomeModBeta basehaz <- survival::basehaz(ymod, centered=FALSE)[,1] H0 <- basehaz[H0indices] if (noisy==TRUE) { print(summary(ymod)) } } else if (smtype=="weibull") { ymod <- survival::survreg(as.formula(smformula), data=imputations[[imp]], dist="weibull") outcomeModBeta <- c(coef(ymod), log(ymod$scale)) + MASS::mvrnorm(1, mu=rep(0,ncol(vcov(ymod))), Sigma=vcov(ymod)) weibullScale <- exp(utils::tail(outcomeModBeta,1)) outcomeModBeta <- utils::head(outcomeModBeta, -1) if (noisy==TRUE) { print(summary(ymod)) } } else if (smtype=="compet") { for (cause in 1:numCauses) { ymod <- survival::coxph(as.formula(smformula[[cause]]), imputations[[imp]], control = survival::coxph.control(timefix = FALSE)) outcomeModBeta[[cause]] <- modPostDraw(ymod) ymod$coefficients <- outcomeModBeta[[cause]] basehaz <- survival::basehaz(ymod, centered=FALSE)[,1] H0[[cause]] <- basehaz[H0indices[[cause]]] if (noisy==TRUE) { print(summary(ymod)) } } } else if (smtype=="casecohort") { ymod <- survival::coxph(as.formula(smformula2), imputations[[imp]], control = survival::coxph.control(timefix = FALSE)) outcomeModBeta <- modPostDraw(ymod) cumhaz.denom.elements=exp(model.matrix(as.formula(smformula),imputations[[imp]])[,-1] %*% outcomeModBeta) cumhaz.denom=sapply(list.times,function(x){sum(cumhaz.denom.elements[which(originaldata[,timeCol]>=x)]*subco.weight[which(originaldata[,timeCol]>=x)])}) exp.func.denom=cumsum(1/cumhaz.denom) H0.fun=stepfun(list.times,c(0,exp.func.denom)) H0=H0.fun(originaldata[,timeCol]) if (noisy==TRUE) { print(summary(ymod)) } } else if (smtype=="nestedcc") { ymod <- survival::coxph(as.formula(smformula), imputations[[imp]], control = survival::coxph.control(timefix = FALSE)) outcomeModBeta <- modPostDraw(ymod) explan.matrix<-model.matrix(ymod) cumbasehaz.denom<-exp(matrix(outcomeModBeta,nrow=1)%*%t(explan.matrix))*originaldata[,nriskCol]/num.sampriskset cumbasehaz.denom<-ave(cumbasehaz.denom, originaldata[,setCol], FUN = sum)[originaldata[,dCol]==1] #this is the denominator of the contribution to the cumulative baseline hazard at each event time cumbasehaz.t<-originaldata[,timeCol][originaldata[,dCol]==1] #times to which the baseline cumulative hazards refer H0<-unlist(lapply(originaldata[,timeCol],function(x) {sum((1/cumbasehaz.denom)[cumbasehaz.t<=x])})) if (noisy==TRUE) { print(summary(ymod)) } } if ((imp==1) & (cyclenum==1) & (var==1)) { if (smtype=="compet") { totalCoefVec <- outcomeModBeta[[1]] for (cause in 2:numCauses) { totalCoefVec <- c(totalCoefVec, outcomeModBeta[[cause]]) } smCoefIter <- array(0, dim=c(m, length(totalCoefVec), numit)) } else { smCoefIter <- array(0, dim=c(m, length(outcomeModBeta), numit)) } } if (var==length(partialVars)) { #then we have reached end of a cycle if (smtype=="compet") { totalCoefVec <- outcomeModBeta[[1]] for (cause in 2:numCauses) { totalCoefVec <- c(totalCoefVec, outcomeModBeta[[cause]]) } smCoefIter[imp,,cyclenum] <- totalCoefVec } else { smCoefIter[imp,,cyclenum] <- outcomeModBeta } } #impute x, either directly where possibly, or using rejection sampling otherwise imputationNeeded <- (1:n)[r[,targetCol]==0] if ((method[targetCol]=="logreg") | (method[targetCol]=="podds") | (method[targetCol]=="mlogit")) { #directly sample if (method[targetCol]=="logreg") { numberOutcomes <- 2 fittedMean <- cbind(1-xfitted, xfitted) } else { numberOutcomes <- nlevels(imputations[[imp]][,targetCol]) fittedMean <- xfitted } outcomeDensCovDens = array(dim=c(length(imputationNeeded),numberOutcomes),0) for (xMisVal in 1:numberOutcomes) { if (method[targetCol]=="logreg") { if (is.factor(imputations[[imp]][,targetCol])==TRUE) { valToImpute <- levels(imputations[[imp]][,targetCol])[xMisVal] } else { valToImpute <- xMisVal-1 } } else { valToImpute <- levels(imputations[[imp]][,targetCol])[xMisVal] } imputations[[imp]][imputationNeeded,targetCol] <- valToImpute #update passive variables imputations[[imp]] <- updatePassiveVars(imputations[[imp]], method, passiveVars) if (smtype=="lm") { outmodxb <- model.matrix(as.formula(smformula),imputations[[imp]]) %*% outcomeModBeta deviation <- imputations[[imp]][imputationNeeded,outcomeCol] - outmodxb[imputationNeeded] outcomeDens <- dnorm(deviation, mean=0, sd=outcomeModResVar^0.5) } else if (smtype=="logistic") { outmodxb <- model.matrix(as.formula(smformula),imputations[[imp]]) %*% outcomeModBeta prob <- expit(outmodxb[imputationNeeded]) outcomeDens <- prob*imputations[[imp]][imputationNeeded,outcomeCol] + (1-prob)*(1-imputations[[imp]][imputationNeeded,outcomeCol]) } else if (smtype=="dtsam") { outcomeDens <- dtsamOutcomeDens(imputations[[imp]],extraArgs$timeEffects,outcomeModBeta,nTimePoints ,smformula,timeCol,dCol)[imputationNeeded] } else if (smtype=="poisson") { outmodxb <- model.matrix(as.formula(smformula),imputations[[imp]]) %*% outcomeModBeta outcomeDens <- dpois(imputations[[imp]][imputationNeeded,outcomeCol], exp(outmodxb[imputationNeeded])) } else if (smtype=="weibull") { outmodxb <- model.matrix(as.formula(smformula),imputations[[imp]]) %*% outcomeModBeta #weibull survival function outcomeDens <- (1-d[imputationNeeded])*(1-survival::psurvreg(imputations[[imp]][imputationNeeded,timeCol], mean=outmodxb[imputationNeeded], scale=weibullScale))+ d[imputationNeeded]*(survival::dsurvreg(imputations[[imp]][imputationNeeded,timeCol], mean=outmodxb[imputationNeeded], scale=weibullScale)) } else if ((smtype=="coxph") | (smtype=="casecohort")) { outmodxb <- model.matrix(as.formula(smformula),imputations[[imp]]) outmodxb <- as.matrix(outmodxb[,2:dim(outmodxb)[2]]) %*% as.matrix(outcomeModBeta) outcomeDens <- exp(-H0[imputationNeeded] * exp(outmodxb[imputationNeeded]))* (exp(outmodxb[imputationNeeded])^d[imputationNeeded]) } else if (smtype=="nestedcc") { outmodxb <- model.matrix(as.formula(smformula2),imputations[[imp]]) outmodxb <- as.matrix(outmodxb[,2:dim(outmodxb)[2]]) %*% as.matrix(outcomeModBeta) outcomeDens <- exp(-H0[imputationNeeded] * exp(outmodxb[imputationNeeded]))* (exp(outmodxb[imputationNeeded])^d[imputationNeeded]) } else if (smtype=="compet") { outcomeDens <- rep(1,length(imputationNeeded)) for (cause in 1:numCauses) { outmodxb <- model.matrix(linpred[[cause]],imputations[[imp]]) outmodxb <- as.matrix(outmodxb[,2:dim(outmodxb)[2]]) %*% as.matrix(outcomeModBeta[[cause]]) outcomeDens <- outcomeDens * exp(-H0[[cause]][imputationNeeded] * exp(outmodxb[imputationNeeded]))* (exp(outmodxb[imputationNeeded])^(d[imputationNeeded]==cause)) } } outcomeDensCovDens[,xMisVal] <- outcomeDens * fittedMean[imputationNeeded,xMisVal] } directImpProbs = outcomeDensCovDens / rowSums(outcomeDensCovDens) if (method[targetCol]=="logreg") { directImpProbs = directImpProbs[,2] if (is.factor(imputations[[imp]][,targetCol])==TRUE) { imputations[[imp]][imputationNeeded,targetCol] <- levels(imputations[[imp]][,targetCol])[1] imputations[[imp]][imputationNeeded,targetCol][rbinom(length(imputationNeeded),1,directImpProbs)==1] <- levels(imputations[[imp]][,targetCol])[2] } else { imputations[[imp]][imputationNeeded,targetCol] <- rbinom(length(imputationNeeded),1,directImpProbs) } } else { imputations[[imp]][imputationNeeded,targetCol] <- levels(imputations[[imp]][,targetCol])[apply(directImpProbs, 1, catdraw)] } #update passive variables imputations[[imp]] <- updatePassiveVars(imputations[[imp]], method, passiveVars) } else { #use rejection sampling #first draw for all subjects who need imputing, using a small number of attempts firstTryLimit <- 25 j <- 1 while ((length(imputationNeeded)>0) & (j -(deviation^2) / (2*array(outcomeModResVar,dim=c(length(imputationNeeded),1)))) } else if (smtype=="logistic") { outmodxb <- model.matrix(as.formula(smformula),imputations[[imp]]) %*% outcomeModBeta prob = expit(outmodxb[imputationNeeded]) prob = prob*imputations[[imp]][imputationNeeded,outcomeCol] + (1-prob)*(1-imputations[[imp]][imputationNeeded,outcomeCol]) reject = 1*(uDraw>prob) } else if (smtype=="dtsam") { prob <- dtsamOutcomeDens(imputations[[imp]],extraArgs$timeEffects,outcomeModBeta,nTimePoints ,smformula,timeCol,dCol)[imputationNeeded] reject = 1*(uDraw>prob) } else if (smtype=="poisson") { outmodxb <- model.matrix(as.formula(smformula),imputations[[imp]]) %*% outcomeModBeta prob = dpois(imputations[[imp]][imputationNeeded,outcomeCol], exp(outmodxb[imputationNeeded])) reject = 1*(uDraw>prob) } else if (smtype=="weibull") { outmodxb <- model.matrix(as.formula(smformula),imputations[[imp]]) %*% outcomeModBeta s_t <- 1-survival::psurvreg(imputations[[imp]][imputationNeeded,timeCol], mean=outmodxb[imputationNeeded], scale=weibullScale) prob <- -exp(1)*log(s_t)*s_t prob <- d[imputationNeeded]*prob + (1-d[imputationNeeded])*s_t reject <- 1*(uDraw>prob) } else if ((smtype=="coxph") | (smtype=="casecohort")) { outmodxb <- model.matrix(as.formula(smformula),imputations[[imp]]) outmodxb <- as.matrix(outmodxb[,2:dim(outmodxb)[2]]) %*% as.matrix(outcomeModBeta) s_t = exp(-H0[imputationNeeded]* exp(outmodxb[imputationNeeded])) prob = exp(1 + outmodxb[imputationNeeded] - (H0[imputationNeeded]* exp(outmodxb[imputationNeeded])) ) * H0[imputationNeeded] prob = d[imputationNeeded]*prob + (1-d[imputationNeeded])*s_t reject = 1*(uDraw > prob ) } else if (smtype=="nestedcc") { outmodxb <- model.matrix(as.formula(smformula2),imputations[[imp]]) outmodxb <- as.matrix(outmodxb[,2:dim(outmodxb)[2]]) %*% as.matrix(outcomeModBeta) s_t = exp(-H0[imputationNeeded]* exp(outmodxb[imputationNeeded])) prob = exp(1 + outmodxb[imputationNeeded] - (H0[imputationNeeded]* exp(outmodxb[imputationNeeded])) ) * H0[imputationNeeded] prob = d[imputationNeeded]*prob + (1-d[imputationNeeded])*s_t reject = 1*(uDraw > prob ) } else if (smtype=="compet") { prob <- rep(1,length(imputationNeeded)) for (cause in 1:numCauses) { outmodxb <- model.matrix(linpred[[cause]],imputations[[imp]]) outmodxb <- as.matrix(outmodxb[,2:dim(outmodxb)[2]]) %*% as.matrix(outcomeModBeta[[cause]]) prob = prob * exp(-H0[[cause]][imputationNeeded] * exp(outmodxb[imputationNeeded]))* (H0[[cause]][imputationNeeded]*exp(1+outmodxb[imputationNeeded]))^(d[imputationNeeded]==cause) } reject = 1*(uDraw > prob ) } imputationNeeded <- imputationNeeded[reject==1] j <- j+1 } #now, for those remaining, who must have low acceptance probabilities, sample by subject for (i in imputationNeeded) { tempData <- imputations[[imp]][i,] tempData <- tempData[rep(1,rjlimit),] if (method[targetCol]=="norm") { tempData[,targetCol] <- rnorm(rjlimit,xfitted[i],newsigmasq^0.5) } else if (method[targetCol]=="logreg") { tempData[,targetCol] <- rbinom(rjlimit,size=1,xfitted[i]) } else if (method[targetCol]=="poisson") { tempData[,targetCol] <- rpois(rjlimit,xfitted[i]) } else if (method[targetCol]=="latnorm") { tempData[,targetCol] <- rnorm(rjlimit,xfitted[i],newsigmasq[i]^0.5) } #passively impute tempData <- updatePassiveVars(tempData, method, passiveVars) #accept reject uDraw <- runif(rjlimit) if (smtype=="lm") { outmodxb <- model.matrix(as.formula(smformula),tempData) %*% outcomeModBeta deviation <- tempData[,outcomeCol] - outmodxb reject = 1*(log(uDraw) > -(deviation^2) / (2*array(outcomeModResVar,dim=c(rjlimit,1)))) } else if (smtype=="logistic") { outmodxb <- model.matrix(as.formula(smformula),tempData) %*% outcomeModBeta prob = expit(outmodxb) prob = prob*tempData[,outcomeCol] + (1-prob)*(1-tempData[,outcomeCol]) reject = 1*(uDraw>prob) } else if (smtype=="dtsam") { prob <- dtsamOutcomeDens(tempData,extraArgs$timeEffects,outcomeModBeta,nTimePoints ,smformula,timeCol,dCol) reject = 1*(uDraw>prob) } else if (smtype=="poisson") { outmodxb <- model.matrix(as.formula(smformula),tempData) %*% outcomeModBeta prob = dpois(tempData[,outcomeCol], exp(outmodxb)) reject = 1*(uDraw>prob) } else if (smtype=="weibull") { outmodxb <- model.matrix(as.formula(smformula),tempData) %*% outcomeModBeta s_t <- 1-survival::psurvreg(tempData[,timeCol], mean=outmodxb, scale=weibullScale) if (d[i]==1) { prob <- -exp(1)*log(s_t)*s_t #the following line fixes a numerical error which occurs if s_t=0 for any draws prob[is.na(prob)] <- 0 } else { prob <- s_t } reject = 1*(uDraw>prob) } else if ((smtype=="coxph") | (smtype=="casecohort")) { outmodxb <- model.matrix(as.formula(smformula),tempData) outmodxb <- as.matrix(outmodxb[,2:dim(outmodxb)[2]]) %*% as.matrix(outcomeModBeta) s_t = exp(-H0[i]* exp(outmodxb)) prob = exp(1 + outmodxb - (H0[i]* exp(outmodxb)) ) * H0[i] prob = d[i]*prob + (1-d[i])*s_t reject = 1*(uDraw > prob ) } else if (smtype=="nestedcc") { outmodxb <- model.matrix(as.formula(smformula2),tempData) outmodxb <- as.matrix(outmodxb[,2:dim(outmodxb)[2]]) %*% as.matrix(outcomeModBeta) s_t = exp(-H0[i]* exp(outmodxb)) prob = exp(1 + outmodxb - (H0[i]* exp(outmodxb)) ) * H0[i] prob = d[i]*prob + (1-d[i])*s_t reject = 1*(uDraw > prob ) } else if (smtype=="compet") { prob <- rep(1,rjlimit) for (cause in 1:numCauses) { outmodxb <- model.matrix(linpred[[cause]],tempData) outmodxb <- as.matrix(outmodxb[,2:dim(outmodxb)[2]]) %*% as.matrix(outcomeModBeta[[cause]]) prob = prob * exp(-H0[[cause]][i] * exp(outmodxb))* (H0[[cause]][i]*exp(1+outmodxb))^(d[i]==cause) } reject = 1*(uDraw > prob ) } if (sum(reject)0) { warning(paste("Rejection sampling failed ",rjFailCount," times (across all variables, iterations, and imputations). You may want to increase the rejection sampling limit.",sep="")) } # Added smformula and smtype to metadata, and make "smcfcs class" res <- list( impDatasets = imputations, smCoefIter = smCoefIter, smInfo = list("smtype" = smtype, "smformula" = smformula), extraArgs = extraArgs # For plot of dtsam ) class(res) <- "smcfcs" return(res) } updatePassiveVars <- function(data, method, passivecols) { for (i in passivecols) { data[,i] <- with(data, eval(parse(text=method[i]))) } data } expit <- function(x) { exp(x)/(1+exp(x)) } sumna <- function(x) { sum(is.na(x)==FALSE) } #returns first non missing entry of x firstnonna <- function(x) { x[is.na(x)==FALSE][1] } catdraw <- function(prob) { (1:length(prob))[rmultinom(1,size=1,prob=prob)==1] } modPostDraw <- function(modobj) { beta <- modobj$coef varcov <- vcov(modobj) beta + MASS::mvrnorm(1, mu=rep(0,ncol(varcov)), Sigma=varcov) } #a helper function which calculates the substantive model probability value #for each individual for the discrete time survival (logistic) substantive model dtsamOutcomeDens <- function(inputData,timeEffects,outcomeModBeta,nTimePoints,smformula,timeCol,dCol) { inputDataN <- dim(inputData)[1] if (timeEffects=="factor") { #first add in time effects on log odds scale outmodxb <- matrix(outcomeModBeta[1:nTimePoints], nrow=inputDataN, ncol=nTimePoints,byrow=TRUE) #calculate covariate effects covXbEffects <- model.matrix(as.formula(paste("~-1+",strsplit(smformula, "~")[[1]][2],sep="")), inputData) %*% utils::tail(outcomeModBeta,length(outcomeModBeta)-nTimePoints) } else if (timeEffects=="linear") { #linear time #first add in time effects on log odds scale outmodxb <- outcomeModBeta[1] + matrix(outcomeModBeta[2]*((1:nTimePoints)-1), nrow=inputDataN, ncol=nTimePoints,byrow=TRUE) #calculate covariate effects covXbEffects <- model.matrix(as.formula(paste("~-1+",strsplit(smformula, "~")[[1]][2],sep="")), inputData) %*% utils::tail(outcomeModBeta,length(outcomeModBeta)-2) } else { #quadratic time #first add in time effects on log odds scale outmodxb <- outcomeModBeta[1] + matrix(outcomeModBeta[2]*((1:nTimePoints)-1)+outcomeModBeta[3]*(((1:nTimePoints)-1)^2), nrow=inputDataN, ncol=nTimePoints,byrow=TRUE) #calculate covariate effects covXbEffects <- model.matrix(as.formula(paste("~-1+",strsplit(smformula, "~")[[1]][2],sep="")), inputData) %*% utils::tail(outcomeModBeta,length(outcomeModBeta)-3) } #add in covariate effects outmodxb <- outmodxb + matrix(covXbEffects, nrow=inputDataN, ncol=nTimePoints) #prob is matrix of conditional probabilities/hazard of event in each period prob <- expit(outmodxb) logSurvProb <- log(1-prob) logSurvProbCumSum <- cbind(rep(0,inputDataN),t(apply(logSurvProb, 1, cumsum))) #create vector of last time point each person survived to, +1 lastSurvPlusOne <- 1 + inputData[,timeCol] - inputData[,dCol] #create vector of log of probability of survival to time when each person actually survived to logSurvProbIndividual <- logSurvProbCumSum[cbind(1:inputDataN,lastSurvPlusOne)] #return vector of outcome density values exp(logSurvProbIndividual + inputData[,dCol]*log(prob[cbind(1:inputDataN, inputData[,timeCol])])) } smcfcs/R/plot_convergence.R0000644000176200001440000001402714062220333015407 0ustar liggesusers#' Assess convergence of a smcfcs object #' #' Visualises the contents of smCoefIter. Specifically, it plots the parameter #' estimates of the substantive model against the number of iterations from #' the imputation procedure. This is done for each regression coefficient, #' and each line corresponds to an imputed dataset. #' #' Requires loading of ggplot2 plotting library. #' #' @author Edouard F. Bonneville \email{e.f.bonneville@@lumc.nl} #' #' @param x An object of class 'smcfcs' #' @param include Character vector of coefficient names for which to return the #' convergence plot. Default is "all" and returns plots for all coefficients in #' a facetted manner. #' #' Recommendation is to plot first with include = "all", and then select #' coefficient names to zoom in to. #' #' For competing risks, the coefficients are indexed by their cause. E.g. for #' coefficient of a variable x1 in a model for cause 2, will be labelled #' "x1-cause2". #' @param ... Additional parameters to pass on to ggplot2::facet_wrap(), #' eg. nrow = 2 #' #' @return A ggplot2 object, containing the convergence plots, facetted per #' covariate in the substantive model #' @export #' #' @examples #' \dontrun{ #' # Use simulated competing risks example in package #' imps <- smcfcs( #' originaldata = ex_compet, #' smtype = "compet", #' smformula = list( #' "Surv(t, d == 1) ~ x1 + x2", #' "Surv(t, d == 2) ~ x1 + x2" #' ), #' method = c("", "", "norm", "norm") #' ) #' #' plot(imps) #' plot(imps, include = c("x1-cause1", "x2-cause2")) #' } #' #' @importFrom rlang .data plot.smcfcs <- function(x, include = "all", ...) { if (!inherits(x, "smcfcs")) stop("'x' must be a 'smcfcs' object") if (!requireNamespace("ggplot2", quietly = TRUE)) { stop("Package ggplot2 needed for this function to work. Please install it.", call. = FALSE) } # Prepare data df_plot <- prep_iters(x) # Choose plots to include if (length(include) >= 1 & include[1] != "all") { coef_names = unique(df_plot$covar) if (any(!(include %in% coef_names))) { mssg <- paste0( "include should be character vector containing any combination of: '", paste0(coef_names, collapse = "','"), "'; or simply 'all'" ) stop(mssg) } else df_plot <- df_plot[df_plot$covar %in% include, ] } # Make plot p <- ggplot2::ggplot( data = df_plot, ggplot2::aes(x = .data$iters, y = .data$value, col = factor(.data$imp)) ) + ggplot2::geom_line() + ggplot2::theme(legend.position = "none") + ggplot2::labs(x = "Iterations", y = "Coefficient") + ggplot2::facet_wrap(~ covar, ...) return(p) } # Prepare data for plotting prep_iters <- function(x) { # Extract meta data M <- dim(x$smCoefIter)[1] smtype <- x$smInfo$smtype smformula <- x$smInfo$smformula dat <- x$impDatasets[[1]] # for names in model matrix numit <- dim(x$smCoefIter)[3] if (numit < 2) stop("Re-run smcfcs() with numit >= 2 in order to assess convergence") # Check if competing risks coef_names <- if (smtype == "compet") { K <- length(smformula) cause_coef_names <- lapply(X = seq_len(K), FUN = function(k) { names_mod <- get_coef_names(smformula[k], dat, intercept = FALSE) paste0(names_mod, "-cause", as.character(k)) }) unlist(cause_coef_names) } else if (smtype %in% c("weibull", "coxph", "casecohort", "nestedcc")) { get_coef_names(smformula, dat, intercept = FALSE) } else if (smtype == "dtsam"){ get_dtsam_names(smformula, dat, x$extraArgs$timeEffects) } else { get_coef_names(smformula, dat, intercept = TRUE) } # Prepare df for plotting ests_list <- lapply(X = seq_len(M), function(m) { coef_dat <- as.data.frame(t(x$smCoefIter[m, ,])) coef_dat$iters <- seq_len(numit) coef_dat$imp <- m return(coef_dat) }) ests_df <- do.call(rbind.data.frame, ests_list) colnames(ests_df) <- c(coef_names, "iters", "imp") # Make long format ests_long <- stats::reshape( data = ests_df, varying = coef_names, timevar = "covar", v.names = "value", idvar = c("imp", "iters"), direction = "long", times = coef_names ) return(ests_long) } get_dtsam_names <- function(smformula, dat, timeEffects) { # Get sides of formula rhs <- gsub(x = smformula, pattern = ".*~", replacement = "") lhs <- gsub(x = smformula, pattern = "~.*", replacement = "") surv_obj <- with(dat, eval(parse(text = lhs))) time_var <- as.matrix(surv_obj)[, "time"] # Make longdata cutPoints <- seq_len(max(time_var)) # Probably change to unique timepoints later longData <- survival::survSplit(as.formula(smformula), data = dat, cut = cutPoints) # Get model matrix formula smformula_matrix <- if (timeEffects == "factor") { paste0("~ -1 + factor(tstart) + ", rhs) } else if (timeEffects == "linear") { paste0("~ tstart + ", rhs) } else paste0("~ tstart + I(tstart^2) + ", rhs) # Make matrix model_mat <- stats::model.matrix( object = as.formula(smformula_matrix), data = longData ) coef_names <- colnames(model_mat) return(coef_names) } get_coef_names <- function(smformula, dat, intercept) { rhs <- gsub(x = smformula, pattern = ".*~", replacement = "") smformula_matrix <- as.formula(paste0("~ +", rhs)) # Check if there is stratification - if so remove from model matrix # (stratification means different baseline hazards, coefficients still same) if (grepl(x = rhs, pattern = "strata")) { strata_var <- gsub(x = rhs, pattern = ".*\\(|\\).*", replacement = "") rm_strata <- as.formula(paste0("~ . - strata(", strata_var, ")")) smformula_matrix <- update(smformula_matrix, rm_strata) } model_mat <- stats::model.matrix( object = smformula_matrix, data = dat ) # For survival models if (intercept == FALSE) { model_mat <- model_mat[, !(colnames(model_mat) %in% "(Intercept)")] } coef_names <- colnames(model_mat) return(coef_names) } smcfcs/R/smcfcs_parallel.r0000644000176200001440000001332614062656731015265 0ustar liggesusers#' Parallel substantive model compatible imputation #' #' Runs substantive model compatible imputation using parallel cores #' #' This function can be used to call one of the substantive model compatible imputation #' methods using parallel cores, to reduce computation time. You must specify #' the arguments required for the standard smcfcs call, and then specify your #' the arguments for how to use parallel cores. #' #' @author Edouard F. Bonneville \email{e.f.bonneville@@lumc.nl} #' @author Jonathan Bartlett \email{j.w.bartlett@@bath.ac.uk} #' #' @param smcfcs_func Specifies which base smcfcs function to call. Possible values #' are `smcfcs`, `smcfcs.casecohort`, `smcfcs.dtasam`, `smcfcs.nestedcc`. Defaults #' to `smcfcs`. #' @param seed A required seed, set as `set.seed` when `n_cores = 1`, #' or as `parallel::clusterSetRNGStream` when `n_cores > 1`. #' @param m Number of imputed datasets to generate. #' @param n_cores Number of cores over which to split the `m` imputations. If #' `n_cores` is not divisible exactly by `m`, one of the cores will perform #' more/less imputations that the rest such that the final result still contains #' `m` imputed datasets. #' @param cl_type Either "PSOCK" or "FORK". If running on a Windows system #' "PSOCK" is recommended, otherwise for Linux/Mac machines "FORK" tends to #' offer faster computation - see \link[mice]{parlmice}. #' @param outfile Optional character path to location for #' output from the workers. Useful to diagnose rejection sampling warnings. #' File path must be formulated as "path/to/filename.txt". #' @param ... Additional arguments to pass on to \link[smcfcs]{smcfcs}, #' \link[smcfcs]{smcfcs.casecohort}, #' \link[smcfcs]{smcfcs.dtsam}, or #' \link[smcfcs]{smcfcs.nestedcc}. #' #' @return An object of type "smcfcs", as would usually be returned from #' \link[smcfcs]{smcfcs}. #' @export #' #' @examples #' \dontrun{ #' # Detect number of cores #' parallel::detectCores() #' #' imps <- smcfcs.parallel( #' smcfcs_func="smcfcs", #' seed = 2021, #' n_cores = 2, #' originaldata = smcfcs::ex_compet, #' m = 10, #' smtype = "compet", #' smformula = list( #' "Surv(t, d == 1) ~ x1 + x2", #' "Surv(t, d == 2) ~ x1 + x2" #' ), #' method = c("", "", "norm", "norm") #' ) #' } smcfcs.parallel <- function(smcfcs_func = "smcfcs", seed, m = 5, n_cores = parallel::detectCores() - 1, cl_type = "PSOCK", outfile = "", ...) { checkmate::matchArg( x = smcfcs_func, choices = c("smcfcs", "smcfcs.casecohort", "smcfcs.dtsam", "smcfcs.nestedcc") ) # Save chosen function as string and and expression for later use smcfcs_func_string <- paste0("smcfcs::", smcfcs_func) smcfcs_func_expr <- parse(text = smcfcs_func_string) # Check smcfcs arguments args <- list(...) args_smcfcs <- names(formals(eval(smcfcs_func_expr))) check_args <- !(names(args) %in% args_smcfcs) if (any(check_args)) { wrong_args <- paste(names(args)[check_args], collapse = ", ") mssg <- paste0("The following are not valid arguments of", smcfcs_func_string, " : ", wrong_args) stop(mssg) } # Check parallel arguments checkmate::assert_int(x = seed, lower=0) checkmate::assert_int(x = m, lower = 1) #checkmate::assert_int(x = m_per_core, lower = 1, upper = max(1,floor(m / n_cores)), null.ok = TRUE) checkmate::matchArg(x = cl_type, choices = c("PSOCK", "FORK")) checkmate::assert_int(x = n_cores, lower = 1, upper = min(parallel::detectCores(), m)) if (outfile != "") checkmate::assert_path_for_output(x = outfile, overwrite = TRUE) # Standard smcfcs if n_cores = 1 if (n_cores == 1) { if (!is.null(seed)) set.seed(seed) args$m <- m res <- do.call(eval(smcfcs_func_expr), args) } else { # Determine number of imputations per core imp_specs <- determine_imp_specs(n_cores, m) # Set up the cluster cl <- parallel::makeCluster(n_cores, type = cl_type, outfile = outfile) if (!is.null(seed)) parallel::clusterSetRNGStream(cl, seed) # Export necessary objects/functions parallel::clusterCall(cl, assign, "Surv", survival::Surv, envir = .GlobalEnv) parallel::clusterCall(cl, assign, "strata", survival::strata, envir = .GlobalEnv) parallel::clusterExport( cl = cl, varlist = c( "args", "imp_specs", "seed", "m", "n_cores", "cl_type", "smcfcs", "smcfcs.casecohort", "smcfcs.dtsam", "smcfcs.nestedcc", "smcfcs_func_expr" ), envir = environment() ) # Run the imputations imps <- parallel::parLapply(cl = cl, X = seq_along(imp_specs), function(x) { args$m <- imp_specs[x] do.call(eval(smcfcs_func_expr), args) }) parallel::stopCluster(cl) # Combine imputations res <- combine_smcfcs_objects(imps) } return(res) } # Prepare imputations per core determine_imp_specs <- function(n_cores, m) { imp_specs <- rep(floor(m / n_cores), times = n_cores) modul <- m %% n_cores # Add remaining imps to add to m if (modul != 0) imp_specs[length(imp_specs)] <- imp_specs[length(imp_specs)] + modul return(imp_specs) } # Helper to combine smcfcs objects combine_smcfcs_objects <- function(smcfcs_list) { # Combine imputed datasets ls_impdats <- do.call("c", lapply(smcfcs_list, "[[", "impDatasets")) # Combine monitoring of imputations coef_array <- abind::abind(lapply(smcfcs_list, "[[", "smCoefIter"), along = 1) # Polish and return res <- list( impDatasets = ls_impdats, smCoefIter = coef_array, smInfo = list( smtype = smcfcs_list[[1]]$smInfo$smtype, smformula = smcfcs_list[[1]]$smInfo$smformula ) ) class(res) <- "smcfcs" return(res) } smcfcs/MD50000644000176200001440000000531514062674212012050 0ustar liggesusers55b572d38673b565cca8940d3ef47501 *DESCRIPTION 84dc3ef81530e45306c07d22375d8a69 *NAMESPACE e875e6f02ae688e1e2d363e8a24c7fd8 *R/data.r a9328477ca7a1419d32dc2a45177386e *R/plot_convergence.R 853d6df191a2af5c7e7cd8152c0dd3d4 *R/smcfcs.r 5b6894671e11269eea6ef8639c7b4657 *R/smcfcs_parallel.r 602bc8b0d2c779eb5f79845f97006441 *README.md 109fbf03b7bd361215755bf9cb2b97fc *build/partial.rdb 5ec0dcf3bebaef19402b3a5b6f8cc2c3 *build/vignette.rds 349d3292d60dffaa31dc3e5176c40e00 *data/ex_cc.rda 910325991049c4ddfeb88e5bc2c03b4b *data/ex_compet.rda f4ad3c32a4f3159cfd8b89919e2f3029 *data/ex_coxquad.rda f003416ef5187c1045f3cd44933f0b79 *data/ex_dtsam.rda 770dbd5c08d991dfc97a20af88d828f8 *data/ex_lininter.rda 0f0a5efdbb7443f737971f5d1f051a0c *data/ex_linquad.rda 94afec78cacd910ad18d314291edfde4 *data/ex_logisticquad.rda 8da11d1f46cc30decc78135f468648eb *data/ex_ncc.rda 74bbe345dfc46ea273beddf150a982b4 *data/ex_poisson.rda 3c4b33e1b0f89104e953037d36457443 *inst/doc/smcfcs-vignette.R e140de9f18d3479daac6fae04873afcf *inst/doc/smcfcs-vignette.Rmd 3a3d8e6da65c9ad40f3dc1e685d1a6ac *inst/doc/smcfcs-vignette.html cbf1cf077abd91ccb8368783cf80117d *inst/doc/smcfcs_coverror-vignette.R 501d76583c6ca6f34c9983286f624396 *inst/doc/smcfcs_coverror-vignette.Rmd 922ccad787b064452d722a3f4f1826b3 *inst/doc/smcfcs_coverror-vignette.html 87baf6360aeb31a2f1a6a69a7a74ff0a *man/ex_cc.Rd 213d9469951a64275721f5a8df38ddfd *man/ex_compet.Rd f897c23b2c1c39b7f7a4a543fc15b7a1 *man/ex_coxquad.Rd 546bdaa53662f9d295c4cd48fb2bf3c0 *man/ex_dtsam.Rd c1e961eb316fc83d0c09edfde1552187 *man/ex_lininter.Rd 5c30213502cd059e26bd9e75b2771139 *man/ex_linquad.Rd 278041deceb24d58bc7f088900969e13 *man/ex_logisticquad.Rd c0dcabe2915622fd1756baef3f1b5e00 *man/ex_ncc.Rd 25739890e4717faa5c468e4854a5c495 *man/ex_poisson.Rd caa8f3a450b1778a349126223becc13f *man/plot.smcfcs.Rd 25e15a86e3f8e4a37e7603b071576ef2 *man/smcfcs.Rd 7a5b1315e65c026ac570f287bad6995a *man/smcfcs.casecohort.Rd f615499f769b0454437f5055e413e484 *man/smcfcs.dtsam.Rd 6b805e6e1b7f6716ef61d85539ac04ea *man/smcfcs.nestedcc.Rd 09546eddd58847c065242723d35505ad *man/smcfcs.parallel.Rd 9f40147057e571da5ec194999e774073 *tests/testthat/test_casecohort.r 7a5ba60301ebc2950d7fd62cfa78af32 *tests/testthat/test_coxph.r 7be42cac5198d2bac61532b207042e69 *tests/testthat/test_dtsam.r a9be13dfe8cc4a0cdaf0c4cf4033f922 *tests/testthat/test_errorchecks.R 0dba92974fc8136b174204cc84547b96 *tests/testthat/test_measerror.r 3990502a03aeecb62c719ccf8299c191 *tests/testthat/test_nestedcc.R de196b323343630f3e16c209d36f0a0d *tests/testthat/test_parallel.r 11f7bbc5bae5e49841b758741a5ba861 *tests/testthat/test_weibull.r e140de9f18d3479daac6fae04873afcf *vignettes/smcfcs-vignette.Rmd 501d76583c6ca6f34c9983286f624396 *vignettes/smcfcs_coverror-vignette.Rmd smcfcs/inst/0000755000176200001440000000000014062671441012512 5ustar liggesuserssmcfcs/inst/doc/0000755000176200001440000000000014062671441013257 5ustar liggesuserssmcfcs/inst/doc/smcfcs-vignette.Rmd0000644000176200001440000003762113763376371017050 0ustar liggesusers--- title: "smcfcs" author: "Jonathan Bartlett" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{smcfcs} %\VignetteEngine{knitr::rmarkdown} %\usepackage[utf8]{inputenc} --- # Introduction Missing data are a common issue in many fields of empirical research. An popular approach to handling missing data is the method of multiple imputation (MI). Multiple imputation involves replacing missing values by a number of imputations, creating multiple imputed datasets. Each completed dataset is then analysed as usual, and estimates and standard errors are combined across imputations using rules developed by Rubin. The most popular approach to imputation uses parametric models for the missing variables given the observed. Multiple imputation gives valid inferences provided that the missing data satisfy the so called missing at random (MAR) assumption and that the imputation models used are correctly specified. ## Joint model and FCS multiple imputation When multiple variables are affected by missingness, the traditional approach to imputation is to specify a joint (or multivariate model) for the partially observed variables. One of the earliest examples of this was MI using the multivariate normal model. Rather than specifying a joint model directly, a popular alternative is the fully conditional specification (FCS), or chained equations approach. In FCS MI separate conditional models are specified for each partially observed variable. In each of these conditional models, by default all of the variables serve as predictors. For an overview of the FCS MI and an implementation of it in R, see van Buuren and Groothuis-Oudshoorn. ## Imputation model compatibility When missing values are imputed from a misspecified model, in general invalid inferences will result. One way in which misspecification can occur is when the imputation and substantive (analysis) model of interest are incompatible. Loosely speaking, this means there exists no joint model which contains the imputation model and the substantive model as the corresponding conditionals. In this case, as described by Bartlett *et al* (2015), assuming that the substantive model is correctly specified, unless the imputation and substantive models can be made compatible by imposing a restriction on the imputation model, incompatibility implies the imputation model is misspecified. Such incompatibility between the imputation model used to impute a partially observed covariate and the substantive/outcome model can arise for example when the latter includes interactions or non-linear effects of variables. A further example is when the substantive model is a Cox proportional hazards model for a censored time to event outcome. In these cases, it may be difficult or impossible to specify an imputation model for a covariate which is compatible with the model for the outcome (the substantive model) using standard imputation models as available in existing packages. # Substantive Model Compatible Fully Conditional Specification multiple imputation The substantive model compatible modification of FCS MI (SMC-FCS), proposed by Bartlett *et al* (2015), ensures that each partially observed variable is imputed from an imputation model which is compatible with a user specified model for the outcome (which is typically the substantive model of interest, although see below regarding auxiliary variables). As described in further detail in the linked paper, for each partially observed variable, e.g. `x1`, in SMC-FCS a model is specified for the conditional distribution of `x1` given the other partially observed variables `x2,x3,..,xp` and fully observed covariates `z`. This, together with the specified substantive model (a model for the outcome `y`) defines an imputation model for `x1` which is guaranteed to be compatible with this specified substantive model. ## Sampling from the imputation distribution Unfortunately, the resulting imputation model for each partially observed variable generally does not belong to a standard parametric family, complicating the imputation of missing values. To overcome this, `smcfcs` uses the method of rejection sampling, which is more computationally intensive than direct sampling methods. ## Statistical properties SMC-FCS ensures compatibility between each partially observed covariate's imputation model with the substantive model. However, when there is more than one partially observed variable, it does not guarantee that the corresponding different imputation models are mutually compatible. Consequently, as described further by Bartlett *et al* (2015), only in special cases does SMC-FCS generate imputations from a well defined Bayesian joint model. Nonetheless, by ensuring compatibility between each partially observed variable's imputation model and the substantive model, it arguably overcomes (compared to standard FCS MI) the type of model incompatibility which is most likely to adversely affect inferences. ## When SMC-FCS may be preferable to FCS/MICE In certain situations it may be advantageous to use SMC-FCS rather than traditional FCS MI. Important examples, as mentioned previously, include situations where the substantive (outcome) model includes interactions or non-linear effects of some of the covariates, or where the outcome model is itself non-linear, such as a Cox proportional hazards model. See Bartlett *et al* (2015) for simulation results comparing the two approaches in these situations. # The `smcfcs` package The `smcfcs` function in the `smcfcs` package implements the SMC-FCS procedure. Currently linear, logistic and Cox proportional hazards substantive models. Competing risks outcome data can also be accommodated, with a Cox proportional hazards model used to model each cause specific hazard function. Partially observed variables can be imputed using normal linear regression, logistic regression (for binary variables), proportional odds regression (sometimes known as ordinal logistic regression, suitable for ordered categorical variables), multinomial logistic regression (for unordered categorical variables), and Poisson regression (for count variables). In the following we describe some of the important aspects of using `smcfcs` by way of an example data frame. ## Example - linear regression substantive model with quadratic covariate effects To illustrate the package, we use the simple example data frame `ex_linquad`, which is included with the package. This data frame was simulated for `n=1000` independent rows. For each row, variables `y,x,z,v` were intended to be collected, but there are missing values in `x`. The values have been made artificially missing, with the probability of missingness dependent on (the fully observed) `y` variable. Below the first 10 rows of the data frame are shown: ```{r} library(smcfcs) ex_linquad[1:10,] ``` As shown, the `xsq` variable is equal to the square of the `x` variable. Since the latter has missing values, so does the former. We now impute the missing values in `x` and `xsq`, compatibly with a substantive model for the outcome `y` which is specified as a linear regression, with `z`, `x` and `xsq` as covariates: ```{r} set.seed(123) #impute missing values in x, compatibly with quadratic substantive model imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq",method=c("","","norm","x^2","")) ``` As demonstrated here, the minimal arguments to pass to `smcfcs` are the data frame to be used, the substantive model type, the substantive model formula, and a method vector. The substantive model type specifies whether the model for the outcome is linear, logistic or Cox regression, or a competing risks analysis (see documentation). The `smformula` specifies the linear predictor of the substantive/outcome model. Here we specified that the outcome `y` is assumed to follow a linear regression model, with `z`, `x` and `xsq` as predictors. Lastly, we passed a vector of strings as the `method` argument. This specifies, for each column in the data frame, the method to use for imputation. As in the example, empty strings should be passed for those columns which are fully observed and thus are not to be imputed. For `x` we specify `norm`, in order to impute using a normal linear regression model. See the help for `smcfcs` for the syntax for other imputation model types. For `xsq` we specify `"x^2"` as the imputation method. This instructs `smcfcs` to impute `xsq` by simply squaring the imputed values of `x`. Such a specification could also be used with the `mice` package, which implements standard FCS MI. Note however that here, through specifying the substantive model as including an effect of `xsq`, `smcfcs` is imputing the missing values in `x` which allows for a quadratic effect on `y`. Having generated the imputed datasets, we can now fit our substantive model of interest. Here we make use of the `mitools` package to fit our substantive model to each imputed dataset, collect the results, and combine them using Rubin's rules: ```{r} # fit substantive model library(mitools) impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~z+x+xsq)) summary(MIcombine(models)) ``` Here the data were simulated such that the coefficients of `z`, `x` and `xsq` are all 1. The estimates we have obtained are (reassuringly) close to these true parameter values. To illustrate the dangers of imputing a covariate using an imputation model which is not compatible with the substantive model, we now re-impute `x`, but this time imputing compatibly with a model for `y` which does not allow for the quadratic effect: ```{r} #impute missing values in x, compatibly with model for y which omits the quadratic effect imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x",method=c("","","norm","x^2","")) ``` `smcfcs` has issued some warnings about rejection sampling. We discuss this later in this vignette, but here we will continue and proceed to fit a model for `y` which includes both `x` and `xsq` (plus `z`) as covariates: ```{r} # fit substantive model impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~z+x+xsq)) summary(MIcombine(models)) ``` Now we have an estimate of the coefficient of `xsq` of 0.60, which is considerably smaller than the true value 1 used to simulate the data. This bias is due to the imputation model we have just used for `x` being misspecified. In particular, it was misspecified due to the fact it wrongly assumed a linear dependence of `y` on `x`, rather than allowing a quadratic dependence. ## Imputing using auxiliary variables with `smcfcs` One of the strengths of multiple imputation in general is the possibility to use variables in imputation models which are subsequently not involved in the substantive model. This may be useful in order to condition or adjust for variables which are predictive of missingness, but which are not used in the substantive model of interest. Moreover, adjusting for auxiliary variables which are strongly correlated with one or more variables which are being imputed improves efficiency. When using `smcfcs` to impute missing covariates, auxiliary variables `v` can be included by adding them as an additional covariate in the substantive model, as passed using the `smformula` argument. Here we are imputing `x` compatibly with a certain specification of model for the outcome. Our substantive model of interest is then a simpler model which omits `v`. For example, in the quadratic example dataset, we can add the auxiliary variable `v` using: ```{r} #impute, including v as a covariate in the substantive/outcome model imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq+v",method=c("","","norm","x^2","")) # fit substantive model, which omits v impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~z+x+xsq)) summary(MIcombine(models)) ``` For outcome models other than linear regression, this approach is not entirely justifiable due to the lack of collapsibility of non-linear models. For example, if a Cox model is assumed for a failure time given variables `x` and `v`, the hazard function given only `x` (i.e. omitting `v` from the model) is no longer a Cox model. Further research is warranted to explore how this might affect the resulting inferences. It is also possible to include the auxiliary variable `v` without adding it to the outcome model (as given in the `smformula` argument), through specification of the `predictorMatrix` argument. Doing so conditions on `v`, but assumes that the outcome is independent of `v`, conditional on whatever covariates are specified in `smformula`. This should thus only be used when the latter assumption is justified. When it is, inferences will in general be more efficient. To make this assumption when imputing `x` in the `ex_linquad` data, we define a `predictorMatrix` which will specify that `x` be imputed using both `z` and `v`, but we omit `v` from the `smformula` argument: ```{r} predMatrix <- array(0, dim=c(ncol(ex_linquad),ncol(ex_linquad))) predMatrix[3,] <- c(0,1,0,0,1) imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq",method=c("","","norm","x^2",""),predictorMatrix=predMatrix) impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~z+x+xsq)) summary(MIcombine(models)) ``` ## Rejection sampling warnings Sometimes when running `smcfcs` you may receive warnings that the rejection sampling that `smcfcs` uses has failed to draw from the required distribution on a couple of occasions. Upon receiving this warning, it is generally good idea to re-run `smcfcs`, specifying a value for `rjlimit` which is larger than the default, until the warning is no longer issued. Having said that, when only a small number of warnings are issued, it may be fine to ignore the warnings, especially when the dataset is large. ## Assessing convergence Like standard chained equations or FCS imputation, the SMC-FCS algorithm must be run for a sufficient number of iterations for the process to converge to its stationary distribution. The default number of iterations used is 10, but this may not be sufficient in any given dataset and model specification To assess convergence, the object returned by `smcfcs` includes an object called `smCoefIter`. This matrix contains the parameter estimates of the substantive model, and is indexed by imputation number, parameter number, and iteration number. To assess convergence, one can call smcfcs with `m=1` and `numit` suitably chosen (e.g. `numit=100`). The values in the resulting smCoefIter matrix can then be plotted to assess convergence. To illustrate, we re-run the imputation model used previously with the example data, but asking for only `m=1` imputation to be generated, and with 100 iterations. ```{r, fig.width = 6, fig.height = 4} # impute once with a larger number of iterations than the default 10 imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq",method=c("","","norm","x^2",""),predictorMatrix=predMatrix,m=1,numit=100) # plot estimates of the fourth parameter of the substantive model against iteration number plot(imps$smCoefIter[1,4,]) ``` The plot shows that the process appears to converge rapidly, such that the default choice of `numit=10` is probably fine here. Of course we should also examine the corresponding plots for the other parameters of the substantive model, since convergence may require more than 10 iterations for some of these.

References

Bartlett JW, Seaman SR, White IR, Carpenter JR. Multiple imputation of covariates by fully conditional specification: accommodating the substantive model. Statistical Methods in Medical Research, 2015; 24(4):462-487 van Buuren S, Groothuis-Oudshoorn K. mice: Multivariate Imputation by Chained Equations in R. Journal of Statistical Software, 2011; 45(3) smcfcs/inst/doc/smcfcs_coverror-vignette.html0000644000176200001440000020744514062671440021202 0ustar liggesusers smcfcs for covariate measurement error correction

smcfcs for covariate measurement error correction

Jonathan Bartlett

2021-06-17

This short vignette introduces the capabilities of smcfcs to accommodate classical covariate measurement error. We consider the cases where internal validation data and then internal replication data are available.

Validation data

We will simulate a dataset with internal validation data where the true covariate (x) is observed for 10% of the sample, while every subject has an error-prone measurement (w) observed:

set.seed(1234)
n <- 1000
x <- rnorm(n)
w <- x+rnorm(n)
y <- x+rnorm(n)
x[(n*0.1):n] <- NA
simData <- data.frame(x,w,y)

We have generated code where the error-prone measurement w is equal to the true covariate x plus some independent normally distributed measurement error. Since x is observed for some of the subjects in the case of interval validation data, this is a regular missing data problem. The error-prone measurement w serves as an auxiliary variable for the purposes of imputation of x. In particular, we will impute using `smcfcs’ such that w is not in the substantive model. This encodes the so called non-differential error assumption, that says that conditional on x, the error-prone measurement w provides no independent information about the outcome y. An initial attempt to do this is:

library(smcfcs)
imps <- smcfcs(simData, smtype="lm", smformula="y~x",
                     method=c("norm", "", ""),m=5)
## [1] "Outcome variable(s): y"
## [1] "Passive variables: "
## [1] "Partially obs. variables: x"
## [1] "Fully obs. substantive model variables: "
## [1] "Imputation  1"
## [1] "Imputing:  x  using    plus outcome"
## [1] "Imputation  2"
## [1] "Imputation  3"
## [1] "Imputation  4"
## [1] "Imputation  5"
## Warning in smcfcs.core(originaldata, smtype, smformula, method,
## predictorMatrix, : Rejection sampling failed 16 times (across all variables,
## iterations, and imputations). You may want to increase the rejection sampling
## limit.

We see from the output that smcfcs has not mentioned that it is using w anywhere. This is because w is fully observed and is not involved in the substantive model. To force w to be conditioned on when imputing x, we must pass an appropriate predictorMatrix to smcfcs:

predMat <- array(0, dim=c(3,3))
predMat[1,2] <- 1

We have specified that the first variable, x, be imputed using w. Note that we do not need to tell smcfcs to impute x using y, as this will occur automatically by virtue of y being the outcome variable in the substantive model. We can now impute again, passing predMat as the predictorMatrix:

imps <- smcfcs(simData, smtype="lm", smformula="y~x",
                     method=c("norm", "", ""),m=5,
               predictorMatrix=predMat)
## [1] "Outcome variable(s): y"
## [1] "Passive variables: "
## [1] "Partially obs. variables: x"
## [1] "Fully obs. substantive model variables: "
## [1] "Imputation  1"
## [1] "Imputing:  x  using  w  plus outcome"
## [1] "Imputation  2"
## [1] "Imputation  3"
## [1] "Imputation  4"
## [1] "Imputation  5"
## Warning in smcfcs.core(originaldata, smtype, smformula, method,
## predictorMatrix, : Rejection sampling failed 3 times (across all variables,
## iterations, and imputations). You may want to increase the rejection sampling
## limit.

Now we can fit the substantive model to each imputed dataset and use the mitools package to pool the estimates and standard errors using Rubin’s rules:

library(mitools)
impobj <- imputationList(imps$impDatasets)
models <- with(impobj, lm(y~x))
summary(MIcombine(models))
## Multiple imputation results:
##       with(impobj, lm(y ~ x))
##       MIcombine.default(models)
##                results         se     (lower    upper) missInfo
## (Intercept) 0.08850686 0.08171538 -0.1136864 0.2907001     87 %
## x           0.91596526 0.11612856  0.6100080 1.2219226     95 %

We note from the results that the fraction of missing information for the coefficient of x is high. This should not surprise us, given that x was missing for 90% of the sample and the error-prone measurement w is quite a noisy measure of x.

Replication data

We will now demonstrate how smcfcs can be used to impute a covariate x which is not observed for any subjects, but we have for at least a subset of the sample two or more error-prone replicate measurements. We first simulate the dataset:

x <- rnorm(n)
w1 <- x+rnorm(n)
w2 <- x+rnorm(n)
w2[(n*0.1):n] <- NA
y <- x+rnorm(n)
x <- rep(NA,n)
simData <- data.frame(x,w1,w2,y)

Note that now x is missing for every subject. Every subject has an error-prone measurement w1 of x, and 10% of the sample have a replicated measurement w2.

We will now impute x using smcfcs. To do this we specify that x be imputed using the latnorm method. In addition, we pass a matrix to the errorProneMatrix argument of smcfcs, whose role is to specify, for each latent normal variable to be imputed, which variables in the data frame are error-prone measurements. smcfcs then imputes the missing values in x, assuming a normal classical error model for the error-prone replicates.

errMat <- array(0, dim=c(4,4))
errMat[1,c(2,3)] <- 1
imps <- smcfcs(simData, smtype="lm", smformula="y~x",
                     method=c("latnorm", "", "",""),m=5,
               errorProneMatrix=errMat)
## [1] "Outcome variable(s): y"
## [1] "Passive variables: "
## [1] "Partially obs. variables: x"
## [1] "Fully obs. substantive model variables: "
## [1] "Imputation  1"
## [1] "Imputing:  x  using  w1,w2  plus outcome"
## [1] "Imputation  2"
## [1] "Imputation  3"
## [1] "Imputation  4"
## [1] "Imputation  5"

Analysing the imputed datasets, we obtain:

impobj <- imputationList(imps$impDatasets)
models <- with(impobj, lm(y~x))
summary(MIcombine(models))
## Multiple imputation results:
##       with(impobj, lm(y ~ x))
##       MIcombine.default(models)
##                 results         se     (lower      upper) missInfo
## (Intercept) -0.09181376 0.03709867 -0.1653430 -0.01828453     21 %
## x            0.86868846 0.15799531  0.4424182  1.29495872     97 %

If we summarise one of the imputed datasets (below), we will see that smcfcs has not only imputed the missing values in x, but also the ‘missing’ values in w2. We hyphenate missing here because typically a study with replicate error-prone measurements will have intentionally planned to only take a second error-prone measurement on a random subset, so the values were never intended to be measured.

summary(imps$impDatasets[[1]])
##        x                  w1                 w2                 y           
##  Min.   :-3.03077   Min.   :-4.36681   Min.   :-4.78473   Min.   :-4.43675  
##  1st Qu.:-0.82756   1st Qu.:-0.93609   1st Qu.:-1.01688   1st Qu.:-1.02676  
##  Median :-0.02556   Median :-0.01339   Median :-0.02595   Median :-0.13283  
##  Mean   :-0.02280   Mean   :-0.00018   Mean   :-0.06838   Mean   :-0.08455  
##  3rd Qu.: 0.78154   3rd Qu.: 0.94560   3rd Qu.: 0.91115   3rd Qu.: 0.87570  
##  Max.   : 4.12664   Max.   : 5.20210   Max.   : 4.38671   Max.   : 4.25531

One thing to be wary of when imputing covariates measured with error, particularly with replication data, is that convergence may take longer than in the regular missing data setting. To examine this, we re-impute one dataset using 100 iterations, and then plot the estimates against iteration number:

imps <- smcfcs(simData, smtype="lm", smformula="y~x",
                     method=c("latnorm", "", "",""),m=1,numit=100,
               errorProneMatrix=errMat)
## [1] "Outcome variable(s): y"
## [1] "Passive variables: "
## [1] "Partially obs. variables: x"
## [1] "Fully obs. substantive model variables: "
## [1] "Imputation  1"
## [1] "Imputing:  x  using  w1,w2  plus outcome"
## Warning in smcfcs.core(originaldata, smtype, smformula, method,
## predictorMatrix, : Rejection sampling failed 6 times (across all variables,
## iterations, and imputations). You may want to increase the rejection sampling
## limit.
plot(imps$smCoefIter[1,2,])

This plot suggests it would probably be safer to impute using more than 10 iterations per imputation.

Multiple covariates measured with error

smcfcs can impute multiple covariates measured with error when internal replication data are available. It allows for a separate error variance for each such covariate. The following code adds a second covariate which is itself measured by two error-prone measurements, but this time with a smaller error variance. It then defines the errorProneMatrix, imputes and analyses the imputed datasets:

x <- rnorm(n)
x1 <- x+rnorm(n)
x2 <- x+rnorm(n)
w2[(n*0.1):n] <- NA
z <- x+rnorm(n)
z1 <- z+0.1*rnorm(n)
z2 <- z+0.1*rnorm(n)
y <- x-z+rnorm(n)
x <- rep(NA,n)
z <- rep(NA,n)
simData <- data.frame(x,x1,x2,z,z1,z2,y)

errMat <- array(0, dim=c(7,7))
errMat[1,c(2,3)] <- 1
errMat[4,c(5,6)] <- 1
imps <- smcfcs(simData, smtype="lm", smformula="y~x+z",
                     method=c("latnorm", "", "","latnorm", "", "", ""),m=5,
               errorProneMatrix=errMat)
## [1] "Outcome variable(s): y"
## [1] "Passive variables: "
## [1] "Partially obs. variables: x,z"
## [1] "Fully obs. substantive model variables: "
## [1] "Imputation  1"
## [1] "Imputing:  x  using  z,x1,x2  plus outcome"
## [1] "Imputing:  z  using  x,z1,z2  plus outcome"
## [1] "Imputation  2"
## [1] "Imputation  3"
## [1] "Imputation  4"
## [1] "Imputation  5"
## Warning in smcfcs.core(originaldata, smtype, smformula, method,
## predictorMatrix, : Rejection sampling failed 31 times (across all variables,
## iterations, and imputations). You may want to increase the rejection sampling
## limit.

We now analyse the imputed datasets, remembering to add z into the substantive model:

impobj <- imputationList(imps$impDatasets)
models <- with(impobj, lm(y~x+z))
summary(MIcombine(models))
## Multiple imputation results:
##       with(impobj, lm(y ~ x + z))
##       MIcombine.default(models)
##                 results         se     (lower      upper) missInfo
## (Intercept) -0.05742881 0.03822934 -0.1337412  0.01888355     27 %
## x            0.90802422 0.12418803  0.5935915  1.22245696     90 %
## z           -0.90700487 0.05662733 -1.0352990 -0.77871071     73 %

We see that the fraction of missing information is lower for z than for x. This is a consequence of the fact that we generated the error-prone measurements of z to have smaller error variance than for the corresponding error-prone measurements of x.

smcfcs/inst/doc/smcfcs-vignette.R0000644000176200001440000000437114062671411016505 0ustar liggesusers## ----------------------------------------------------------------------------- library(smcfcs) ex_linquad[1:10,] ## ----------------------------------------------------------------------------- set.seed(123) #impute missing values in x, compatibly with quadratic substantive model imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq",method=c("","","norm","x^2","")) ## ----------------------------------------------------------------------------- # fit substantive model library(mitools) impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~z+x+xsq)) summary(MIcombine(models)) ## ----------------------------------------------------------------------------- #impute missing values in x, compatibly with model for y which omits the quadratic effect imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x",method=c("","","norm","x^2","")) ## ----------------------------------------------------------------------------- # fit substantive model impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~z+x+xsq)) summary(MIcombine(models)) ## ----------------------------------------------------------------------------- #impute, including v as a covariate in the substantive/outcome model imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq+v",method=c("","","norm","x^2","")) # fit substantive model, which omits v impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~z+x+xsq)) summary(MIcombine(models)) ## ----------------------------------------------------------------------------- predMatrix <- array(0, dim=c(ncol(ex_linquad),ncol(ex_linquad))) predMatrix[3,] <- c(0,1,0,0,1) imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq",method=c("","","norm","x^2",""),predictorMatrix=predMatrix) impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~z+x+xsq)) summary(MIcombine(models)) ## ---- fig.width = 6, fig.height = 4------------------------------------------- # impute once with a larger number of iterations than the default 10 imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq",method=c("","","norm","x^2",""),predictorMatrix=predMatrix,m=1,numit=100) # plot estimates of the fourth parameter of the substantive model against iteration number plot(imps$smCoefIter[1,4,]) smcfcs/inst/doc/smcfcs-vignette.html0000644000176200001440000023442214062671413017254 0ustar liggesusers smcfcs

smcfcs

Jonathan Bartlett

2021-06-17

Introduction

Missing data are a common issue in many fields of empirical research. An popular approach to handling missing data is the method of multiple imputation (MI). Multiple imputation involves replacing missing values by a number of imputations, creating multiple imputed datasets. Each completed dataset is then analysed as usual, and estimates and standard errors are combined across imputations using rules developed by Rubin.

The most popular approach to imputation uses parametric models for the missing variables given the observed. Multiple imputation gives valid inferences provided that the missing data satisfy the so called missing at random (MAR) assumption and that the imputation models used are correctly specified.

Joint model and FCS multiple imputation

When multiple variables are affected by missingness, the traditional approach to imputation is to specify a joint (or multivariate model) for the partially observed variables. One of the earliest examples of this was MI using the multivariate normal model. Rather than specifying a joint model directly, a popular alternative is the fully conditional specification (FCS), or chained equations approach. In FCS MI separate conditional models are specified for each partially observed variable. In each of these conditional models, by default all of the variables serve as predictors. For an overview of the FCS MI and an implementation of it in R, see van Buuren and Groothuis-Oudshoorn.

Imputation model compatibility

When missing values are imputed from a misspecified model, in general invalid inferences will result. One way in which misspecification can occur is when the imputation and substantive (analysis) model of interest are incompatible. Loosely speaking, this means there exists no joint model which contains the imputation model and the substantive model as the corresponding conditionals. In this case, as described by Bartlett et al (2015), assuming that the substantive model is correctly specified, unless the imputation and substantive models can be made compatible by imposing a restriction on the imputation model, incompatibility implies the imputation model is misspecified.

Such incompatibility between the imputation model used to impute a partially observed covariate and the substantive/outcome model can arise for example when the latter includes interactions or non-linear effects of variables. A further example is when the substantive model is a Cox proportional hazards model for a censored time to event outcome. In these cases, it may be difficult or impossible to specify an imputation model for a covariate which is compatible with the model for the outcome (the substantive model) using standard imputation models as available in existing packages.

Substantive Model Compatible Fully Conditional Specification multiple imputation

The substantive model compatible modification of FCS MI (SMC-FCS), proposed by Bartlett et al (2015), ensures that each partially observed variable is imputed from an imputation model which is compatible with a user specified model for the outcome (which is typically the substantive model of interest, although see below regarding auxiliary variables). As described in further detail in the linked paper, for each partially observed variable, e.g. x1, in SMC-FCS a model is specified for the conditional distribution of x1 given the other partially observed variables x2,x3,..,xp and fully observed covariates z. This, together with the specified substantive model (a model for the outcome y) defines an imputation model for x1 which is guaranteed to be compatible with this specified substantive model.

Sampling from the imputation distribution

Unfortunately, the resulting imputation model for each partially observed variable generally does not belong to a standard parametric family, complicating the imputation of missing values. To overcome this, smcfcs uses the method of rejection sampling, which is more computationally intensive than direct sampling methods.

Statistical properties

SMC-FCS ensures compatibility between each partially observed covariate’s imputation model with the substantive model. However, when there is more than one partially observed variable, it does not guarantee that the corresponding different imputation models are mutually compatible. Consequently, as described further by Bartlett et al (2015), only in special cases does SMC-FCS generate imputations from a well defined Bayesian joint model. Nonetheless, by ensuring compatibility between each partially observed variable’s imputation model and the substantive model, it arguably overcomes (compared to standard FCS MI) the type of model incompatibility which is most likely to adversely affect inferences.

When SMC-FCS may be preferable to FCS/MICE

In certain situations it may be advantageous to use SMC-FCS rather than traditional FCS MI. Important examples, as mentioned previously, include situations where the substantive (outcome) model includes interactions or non-linear effects of some of the covariates, or where the outcome model is itself non-linear, such as a Cox proportional hazards model. See Bartlett et al (2015) for simulation results comparing the two approaches in these situations.

The smcfcs package

The smcfcs function in the smcfcs package implements the SMC-FCS procedure. Currently linear, logistic and Cox proportional hazards substantive models. Competing risks outcome data can also be accommodated, with a Cox proportional hazards model used to model each cause specific hazard function. Partially observed variables can be imputed using normal linear regression, logistic regression (for binary variables), proportional odds regression (sometimes known as ordinal logistic regression, suitable for ordered categorical variables), multinomial logistic regression (for unordered categorical variables), and Poisson regression (for count variables). In the following we describe some of the important aspects of using smcfcs by way of an example data frame.

Example - linear regression substantive model with quadratic covariate effects

To illustrate the package, we use the simple example data frame ex_linquad, which is included with the package. This data frame was simulated for n=1000 independent rows. For each row, variables y,x,z,v were intended to be collected, but there are missing values in x. The values have been made artificially missing, with the probability of missingness dependent on (the fully observed) y variable. Below the first 10 rows of the data frame are shown:

library(smcfcs)
ex_linquad[1:10,]
##             y          z          x        xsq           v
## 1  -0.3404639 -1.2053334 -1.2070657 1.45700772 -2.18088437
## 2   2.1699185  0.3014667  0.2774292 0.07696698  0.17779805
## 3   2.0293128 -1.5391452  1.0844412 1.17601267  0.97370618
## 4   6.6311247  0.6353707 -2.3456977 5.50229771 -1.15350311
## 5   3.9096291  0.7029518  0.4291247 0.18414800 -1.22676124
## 6  -0.5019313 -1.9058829         NA         NA -0.53958740
## 7   0.5816303  0.9389214         NA         NA -2.31497909
## 8   1.0236009 -0.2244921         NA         NA -0.03351108
## 9  -1.2942170 -0.6738168         NA         NA -1.01040885
## 10  1.9041271  0.4457874 -0.8900378 0.79216734 -2.72923160

As shown, the xsq variable is equal to the square of the x variable. Since the latter has missing values, so does the former. We now impute the missing values in x and xsq, compatibly with a substantive model for the outcome y which is specified as a linear regression, with z, x and xsq as covariates:

set.seed(123)
#impute missing values in x, compatibly with quadratic substantive model
imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq",method=c("","","norm","x^2",""))
## [1] "Outcome variable(s): y"
## [1] "Passive variables: xsq"
## [1] "Partially obs. variables: x"
## [1] "Fully obs. substantive model variables: z"
## [1] "Imputation  1"
## [1] "Imputing:  x  using  z  plus outcome"
## [1] "Imputation  2"
## [1] "Imputation  3"
## [1] "Imputation  4"
## [1] "Imputation  5"

As demonstrated here, the minimal arguments to pass to smcfcs are the data frame to be used, the substantive model type, the substantive model formula, and a method vector. The substantive model type specifies whether the model for the outcome is linear, logistic or Cox regression, or a competing risks analysis (see documentation). The smformula specifies the linear predictor of the substantive/outcome model. Here we specified that the outcome y is assumed to follow a linear regression model, with z, x and xsq as predictors.

Lastly, we passed a vector of strings as the method argument. This specifies, for each column in the data frame, the method to use for imputation. As in the example, empty strings should be passed for those columns which are fully observed and thus are not to be imputed. For x we specify norm, in order to impute using a normal linear regression model. See the help for smcfcs for the syntax for other imputation model types. For xsq we specify "x^2" as the imputation method. This instructs smcfcs to impute xsq by simply squaring the imputed values of x. Such a specification could also be used with the mice package, which implements standard FCS MI. Note however that here, through specifying the substantive model as including an effect of xsq, smcfcs is imputing the missing values in x which allows for a quadratic effect on y.

Having generated the imputed datasets, we can now fit our substantive model of interest. Here we make use of the mitools package to fit our substantive model to each imputed dataset, collect the results, and combine them using Rubin’s rules:

# fit substantive model
library(mitools)
impobj <- imputationList(imps$impDatasets)
models <- with(impobj, lm(y~z+x+xsq))
summary(MIcombine(models))
## Multiple imputation results:
##       with(impobj, lm(y ~ z + x + xsq))
##       MIcombine.default(models)
##               results         se    (lower   upper) missInfo
## (Intercept) 0.9334715 0.04630014 0.8403438 1.026599     32 %
## z           1.0052498 0.03733622 0.9308187 1.079681     26 %
## x           0.9849376 0.03375213 0.9183668 1.051508     15 %
## xsq         1.0387792 0.02430037 0.9902690 1.087289     27 %

Here the data were simulated such that the coefficients of z, x and xsq are all 1. The estimates we have obtained are (reassuringly) close to these true parameter values. To illustrate the dangers of imputing a covariate using an imputation model which is not compatible with the substantive model, we now re-impute x, but this time imputing compatibly with a model for y which does not allow for the quadratic effect:

#impute missing values in x, compatibly with model for y which omits the quadratic effect
imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x",method=c("","","norm","x^2",""))
## [1] "Outcome variable(s): y"
## [1] "Passive variables: xsq"
## [1] "Partially obs. variables: x"
## [1] "Fully obs. substantive model variables: z"
## [1] "Imputation  1"
## [1] "Imputing:  x  using  z  plus outcome"
## [1] "Imputation  2"
## [1] "Imputation  3"
## [1] "Imputation  4"
## [1] "Imputation  5"
## Warning in smcfcs.core(originaldata, smtype, smformula, method,
## predictorMatrix, : Rejection sampling failed 3 times (across all variables,
## iterations, and imputations). You may want to increase the rejection sampling
## limit.

smcfcs has issued some warnings about rejection sampling. We discuss this later in this vignette, but here we will continue and proceed to fit a model for y which includes both x and xsq (plus z) as covariates:

# fit substantive model
impobj <- imputationList(imps$impDatasets)
models <- with(impobj, lm(y~z+x+xsq))
summary(MIcombine(models))
## Multiple imputation results:
##       with(impobj, lm(y ~ z + x + xsq))
##       MIcombine.default(models)
##               results         se    (lower    upper) missInfo
## (Intercept) 1.2518297 0.07721520 1.0926282 1.4110313     45 %
## z           1.0923872 0.05635147 0.9799551 1.2048193     26 %
## x           0.9277074 0.06518336 0.7859114 1.0695035     63 %
## xsq         0.6093138 0.05299860 0.4845629 0.7340648     80 %

Now we have an estimate of the coefficient of xsq of 0.60, which is considerably smaller than the true value 1 used to simulate the data. This bias is due to the imputation model we have just used for x being misspecified. In particular, it was misspecified due to the fact it wrongly assumed a linear dependence of y on x, rather than allowing a quadratic dependence.

Imputing using auxiliary variables with smcfcs

One of the strengths of multiple imputation in general is the possibility to use variables in imputation models which are subsequently not involved in the substantive model. This may be useful in order to condition or adjust for variables which are predictive of missingness, but which are not used in the substantive model of interest. Moreover, adjusting for auxiliary variables which are strongly correlated with one or more variables which are being imputed improves efficiency.

When using smcfcs to impute missing covariates, auxiliary variables v can be included by adding them as an additional covariate in the substantive model, as passed using the smformula argument. Here we are imputing x compatibly with a certain specification of model for the outcome. Our substantive model of interest is then a simpler model which omits v. For example, in the quadratic example dataset, we can add the auxiliary variable v using:

#impute, including v as a covariate in the substantive/outcome model
imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq+v",method=c("","","norm","x^2",""))
## [1] "Outcome variable(s): y"
## [1] "Passive variables: xsq"
## [1] "Partially obs. variables: x"
## [1] "Fully obs. substantive model variables: z,v"
## [1] "Imputation  1"
## [1] "Imputing:  x  using  z,v  plus outcome"
## [1] "Imputation  2"
## [1] "Imputation  3"
## [1] "Imputation  4"
## [1] "Imputation  5"
## Warning in smcfcs.core(originaldata, smtype, smformula, method,
## predictorMatrix, : Rejection sampling failed 1 times (across all variables,
## iterations, and imputations). You may want to increase the rejection sampling
## limit.
# fit substantive model, which omits v
impobj <- imputationList(imps$impDatasets)
models <- with(impobj, lm(y~z+x+xsq))
summary(MIcombine(models))
## Multiple imputation results:
##       with(impobj, lm(y ~ z + x + xsq))
##       MIcombine.default(models)
##               results         se    (lower   upper) missInfo
## (Intercept) 0.9295283 0.04234163 0.8457342 1.013322     19 %
## z           1.0209851 0.03536731 0.9511068 1.090863     17 %
## x           0.9762357 0.03556863 0.9054434 1.047028     24 %
## xsq         1.0403799 0.02367377 0.9933561 1.087404     23 %

For outcome models other than linear regression, this approach is not entirely justifiable due to the lack of collapsibility of non-linear models. For example, if a Cox model is assumed for a failure time given variables x and v, the hazard function given only x (i.e. omitting v from the model) is no longer a Cox model. Further research is warranted to explore how this might affect the resulting inferences.

It is also possible to include the auxiliary variable v without adding it to the outcome model (as given in the smformula argument), through specification of the predictorMatrix argument. Doing so conditions on v, but assumes that the outcome is independent of v, conditional on whatever covariates are specified in smformula. This should thus only be used when the latter assumption is justified. When it is, inferences will in general be more efficient. To make this assumption when imputing x in the ex_linquad data, we define a predictorMatrix which will specify that x be imputed using both z and v, but we omit v from the smformula argument:

predMatrix <- array(0, dim=c(ncol(ex_linquad),ncol(ex_linquad)))
predMatrix[3,] <- c(0,1,0,0,1)
imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq",method=c("","","norm","x^2",""),predictorMatrix=predMatrix)
## [1] "Outcome variable(s): y"
## [1] "Passive variables: xsq"
## [1] "Partially obs. variables: x"
## [1] "Fully obs. substantive model variables: z"
## [1] "Imputation  1"
## [1] "Imputing:  x  using  z,v  plus outcome"
## [1] "Imputation  2"
## [1] "Imputation  3"
## [1] "Imputation  4"
## [1] "Imputation  5"
## Warning in smcfcs.core(originaldata, smtype, smformula, method,
## predictorMatrix, : Rejection sampling failed 1 times (across all variables,
## iterations, and imputations). You may want to increase the rejection sampling
## limit.
impobj <- imputationList(imps$impDatasets)
models <- with(impobj, lm(y~z+x+xsq))
summary(MIcombine(models))
## Multiple imputation results:
##       with(impobj, lm(y ~ z + x + xsq))
##       MIcombine.default(models)
##               results         se    (lower   upper) missInfo
## (Intercept) 0.9424871 0.04305650 0.8572108 1.027763     20 %
## z           1.0174988 0.03674626 0.9445484 1.090449     22 %
## x           0.9935095 0.03267809 0.9294032 1.057616      6 %
## xsq         1.0340561 0.02323316 0.9882080 1.079904     16 %

Rejection sampling warnings

Sometimes when running smcfcs you may receive warnings that the rejection sampling that smcfcs uses has failed to draw from the required distribution on a couple of occasions. Upon receiving this warning, it is generally good idea to re-run smcfcs, specifying a value for rjlimit which is larger than the default, until the warning is no longer issued. Having said that, when only a small number of warnings are issued, it may be fine to ignore the warnings, especially when the dataset is large.

Assessing convergence

Like standard chained equations or FCS imputation, the SMC-FCS algorithm must be run for a sufficient number of iterations for the process to converge to its stationary distribution. The default number of iterations used is 10, but this may not be sufficient in any given dataset and model specification To assess convergence, the object returned by smcfcs includes an object called smCoefIter. This matrix contains the parameter estimates of the substantive model, and is indexed by imputation number, parameter number, and iteration number. To assess convergence, one can call smcfcs with m=1 and numit suitably chosen (e.g. numit=100). The values in the resulting smCoefIter matrix can then be plotted to assess convergence. To illustrate, we re-run the imputation model used previously with the example data, but asking for only m=1 imputation to be generated, and with 100 iterations.

# impute once with a larger number of iterations than the default 10
imps <- smcfcs(ex_linquad, smtype="lm", smformula="y~z+x+xsq",method=c("","","norm","x^2",""),predictorMatrix=predMatrix,m=1,numit=100)
## [1] "Outcome variable(s): y"
## [1] "Passive variables: xsq"
## [1] "Partially obs. variables: x"
## [1] "Fully obs. substantive model variables: z"
## [1] "Imputation  1"
## [1] "Imputing:  x  using  z,v  plus outcome"
## Warning in smcfcs.core(originaldata, smtype, smformula, method,
## predictorMatrix, : Rejection sampling failed 3 times (across all variables,
## iterations, and imputations). You may want to increase the rejection sampling
## limit.
# plot estimates of the fourth parameter of the substantive model against iteration number
plot(imps$smCoefIter[1,4,])

The plot shows that the process appears to converge rapidly, such that the default choice of numit=10 is probably fine here. Of course we should also examine the corresponding plots for the other parameters of the substantive model, since convergence may require more than 10 iterations for some of these.

References

Bartlett JW, Seaman SR, White IR, Carpenter JR. Multiple imputation of covariates by fully conditional specification: accommodating the substantive model. Statistical Methods in Medical Research, 2015; 24(4):462-487

van Buuren S, Groothuis-Oudshoorn K. mice: Multivariate Imputation by Chained Equations in R. Journal of Statistical Software, 2011; 45(3)

smcfcs/inst/doc/smcfcs_coverror-vignette.R0000644000176200001440000000531314062671440020425 0ustar liggesusers## ----------------------------------------------------------------------------- set.seed(1234) n <- 1000 x <- rnorm(n) w <- x+rnorm(n) y <- x+rnorm(n) x[(n*0.1):n] <- NA simData <- data.frame(x,w,y) ## ----------------------------------------------------------------------------- library(smcfcs) imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("norm", "", ""),m=5) ## ----------------------------------------------------------------------------- predMat <- array(0, dim=c(3,3)) predMat[1,2] <- 1 ## ----------------------------------------------------------------------------- imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("norm", "", ""),m=5, predictorMatrix=predMat) ## ----------------------------------------------------------------------------- library(mitools) impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~x)) summary(MIcombine(models)) ## ----------------------------------------------------------------------------- x <- rnorm(n) w1 <- x+rnorm(n) w2 <- x+rnorm(n) w2[(n*0.1):n] <- NA y <- x+rnorm(n) x <- rep(NA,n) simData <- data.frame(x,w1,w2,y) ## ----------------------------------------------------------------------------- errMat <- array(0, dim=c(4,4)) errMat[1,c(2,3)] <- 1 imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("latnorm", "", "",""),m=5, errorProneMatrix=errMat) ## ----------------------------------------------------------------------------- impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~x)) summary(MIcombine(models)) ## ----------------------------------------------------------------------------- summary(imps$impDatasets[[1]]) ## ---- fig.width=6------------------------------------------------------------- imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("latnorm", "", "",""),m=1,numit=100, errorProneMatrix=errMat) plot(imps$smCoefIter[1,2,]) ## ----------------------------------------------------------------------------- x <- rnorm(n) x1 <- x+rnorm(n) x2 <- x+rnorm(n) w2[(n*0.1):n] <- NA z <- x+rnorm(n) z1 <- z+0.1*rnorm(n) z2 <- z+0.1*rnorm(n) y <- x-z+rnorm(n) x <- rep(NA,n) z <- rep(NA,n) simData <- data.frame(x,x1,x2,z,z1,z2,y) errMat <- array(0, dim=c(7,7)) errMat[1,c(2,3)] <- 1 errMat[4,c(5,6)] <- 1 imps <- smcfcs(simData, smtype="lm", smformula="y~x+z", method=c("latnorm", "", "","latnorm", "", "", ""),m=5, errorProneMatrix=errMat) ## ----------------------------------------------------------------------------- impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~x+z)) summary(MIcombine(models)) smcfcs/inst/doc/smcfcs_coverror-vignette.Rmd0000644000176200001440000001516413763410505020753 0ustar liggesusers--- title: "smcfcs for covariate measurement error correction" author: "Jonathan Bartlett" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{smcfcs_measerror} %\VignetteEngine{knitr::rmarkdown} %\usepackage[utf8]{inputenc} --- This short vignette introduces the capabilities of `smcfcs` to accommodate classical covariate measurement error. We consider the cases where internal validation data and then internal replication data are available. # Validation data We will simulate a dataset with internal validation data where the true covariate (x) is observed for 10\% of the sample, while every subject has an error-prone measurement (w) observed: ```{r} set.seed(1234) n <- 1000 x <- rnorm(n) w <- x+rnorm(n) y <- x+rnorm(n) x[(n*0.1):n] <- NA simData <- data.frame(x,w,y) ``` We have generated code where the error-prone measurement w is equal to the true covariate x plus some independent normally distributed measurement error. Since x is observed for some of the subjects in the case of interval validation data, this is a regular missing data problem. The error-prone measurement w serves as an auxiliary variable for the purposes of imputation of x. In particular, we will impute using `smcfcs' such that w is not in the substantive model. This encodes the so called non-differential error assumption, that says that conditional on x, the error-prone measurement w provides no independent information about the outcome y. An initial attempt to do this is: ```{r} library(smcfcs) imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("norm", "", ""),m=5) ``` We see from the output that `smcfcs` has not mentioned that it is using w anywhere. This is because w is fully observed and is not involved in the substantive model. To force w to be conditioned on when imputing x, we must pass an appropriate `predictorMatrix` to `smcfcs`: ```{r} predMat <- array(0, dim=c(3,3)) predMat[1,2] <- 1 ``` We have specified that the first variable, x, be imputed using w. Note that we do not need to tell `smcfcs` to impute x using y, as this will occur automatically by virtue of y being the outcome variable in the substantive model. We can now impute again, passing `predMat` as the `predictorMatrix`: ```{r} imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("norm", "", ""),m=5, predictorMatrix=predMat) ``` Now we can fit the substantive model to each imputed dataset and use the `mitools` package to pool the estimates and standard errors using Rubin's rules: ```{r} library(mitools) impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~x)) summary(MIcombine(models)) ``` We note from the results that the fraction of missing information for the coefficient of x is high. This should not surprise us, given that x was missing for 90\% of the sample and the error-prone measurement w is quite a noisy measure of x. # Replication data We will now demonstrate how `smcfcs` can be used to impute a covariate x which is not observed for any subjects, but we have for at least a subset of the sample two or more error-prone replicate measurements. We first simulate the dataset: ```{r} x <- rnorm(n) w1 <- x+rnorm(n) w2 <- x+rnorm(n) w2[(n*0.1):n] <- NA y <- x+rnorm(n) x <- rep(NA,n) simData <- data.frame(x,w1,w2,y) ``` Note that now x is missing for every subject. Every subject has an error-prone measurement w1 of x, and 10\% of the sample have a replicated measurement w2. We will now impute x using `smcfcs`. To do this we specify that x be imputed using the `latnorm` method. In addition, we pass a matrix to the `errorProneMatrix` argument of `smcfcs`, whose role is to specify, for each latent normal variable to be imputed, which variables in the data frame are error-prone measurements. `smcfcs` then imputes the missing values in x, assuming a normal classical error model for the error-prone replicates. ```{r} errMat <- array(0, dim=c(4,4)) errMat[1,c(2,3)] <- 1 imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("latnorm", "", "",""),m=5, errorProneMatrix=errMat) ``` Analysing the imputed datasets, we obtain: ```{r} impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~x)) summary(MIcombine(models)) ``` If we summarise one of the imputed datasets (below), we will see that `smcfcs` has not only imputed the missing values in x, but also the 'missing' values in w2. We hyphenate missing here because typically a study with replicate error-prone measurements will have intentionally planned to only take a second error-prone measurement on a random subset, so the values were never intended to be measured. ```{r} summary(imps$impDatasets[[1]]) ``` One thing to be wary of when imputing covariates measured with error, particularly with replication data, is that convergence may take longer than in the regular missing data setting. To examine this, we re-impute one dataset using 100 iterations, and then plot the estimates against iteration number: ```{r, fig.width=6} imps <- smcfcs(simData, smtype="lm", smformula="y~x", method=c("latnorm", "", "",""),m=1,numit=100, errorProneMatrix=errMat) plot(imps$smCoefIter[1,2,]) ``` This plot suggests it would probably be safer to impute using more than 10 iterations per imputation. ## Multiple covariates measured with error `smcfcs` can impute multiple covariates measured with error when internal replication data are available. It allows for a separate error variance for each such covariate. The following code adds a second covariate which is itself measured by two error-prone measurements, but this time with a smaller error variance. It then defines the `errorProneMatrix`, imputes and analyses the imputed datasets: ```{r} x <- rnorm(n) x1 <- x+rnorm(n) x2 <- x+rnorm(n) w2[(n*0.1):n] <- NA z <- x+rnorm(n) z1 <- z+0.1*rnorm(n) z2 <- z+0.1*rnorm(n) y <- x-z+rnorm(n) x <- rep(NA,n) z <- rep(NA,n) simData <- data.frame(x,x1,x2,z,z1,z2,y) errMat <- array(0, dim=c(7,7)) errMat[1,c(2,3)] <- 1 errMat[4,c(5,6)] <- 1 imps <- smcfcs(simData, smtype="lm", smformula="y~x+z", method=c("latnorm", "", "","latnorm", "", "", ""),m=5, errorProneMatrix=errMat) ``` We now analyse the imputed datasets, remembering to add z into the substantive model: ```{r} impobj <- imputationList(imps$impDatasets) models <- with(impobj, lm(y~x+z)) summary(MIcombine(models)) ``` We see that the fraction of missing information is lower for z than for x. This is a consequence of the fact that we generated the error-prone measurements of z to have smaller error variance than for the corresponding error-prone measurements of x.