From 8d9011f18e1512217835a7aa8717b03d282f501f Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 4 Dec 2023 21:53:28 +0000 Subject: [PATCH] Automated Docs Update --- docs/CONTRIBUTING.doctree | Bin 0 -> 42874 bytes docs/CONTRIBUTING.html | 258 +++++ docs/CONTRIBUTING.rst | 143 +++ docs/README.doctree | Bin 0 -> 139336 bytes docs/README.html | 543 ++++++++++ docs/README.rst | 486 +++++++++ docs/_sources/CONTRIBUTING.rst.txt | 143 +++ docs/_sources/README.rst.txt | 486 +++++++++ docs/_sources/astartes.rst.txt | 16 +- .../astartes.samplers.extrapolation.rst.txt | 61 ++ .../astartes.samplers.interpolation.rst.txt | 37 + docs/_sources/astartes.samplers.rst.txt | 67 +- docs/_sources/astartes.utils.rst.txt | 61 ++ docs/_sources/index.rst.txt | 4 +- docs/_sources/modules.rst.txt | 1 - docs/_sources/sklearn_to_astartes.rst.txt | 180 ++++ docs/_sources/test.functional.rst.txt | 29 + docs/_sources/test.regression.rst.txt | 21 + docs/_sources/test.rst.txt | 20 + docs/_sources/test.unit.rst.txt | 19 + .../test.unit.samplers.extrapolative.rst.txt | 61 ++ .../test.unit.samplers.interpolative.rst.txt | 37 + docs/_sources/test.unit.samplers.rst.txt | 19 + docs/_sources/test.unit.utils.rst.txt | 37 + .../_sphinx_javascript_frameworks_compat.js | 123 +++ docs/_static/sphinx_highlight.js | 154 +++ docs/astartes.doctree | Bin 0 -> 120202 bytes docs/astartes.html | 390 +++++++ docs/astartes.rst | 38 + docs/astartes.samplers.doctree | Bin 0 -> 22764 bytes docs/astartes.samplers.extrapolation.doctree | Bin 0 -> 56132 bytes docs/astartes.samplers.extrapolation.html | 336 ++++++ docs/astartes.samplers.extrapolation.rst | 61 ++ docs/astartes.samplers.html | 274 +++++ docs/astartes.samplers.interpolation.doctree | Bin 0 -> 16496 bytes docs/astartes.samplers.interpolation.html | 183 ++++ docs/astartes.samplers.interpolation.rst | 37 + docs/astartes.samplers.rst | 30 + docs/astartes.utils.doctree | Bin 0 -> 136349 bytes docs/astartes.utils.html | 529 ++++++++++ docs/astartes.utils.rst | 61 ++ docs/environment.pickle | Bin 0 -> 1162056 bytes docs/genindex.html | 969 ++++++++++++++++++ docs/index.doctree | Bin 0 -> 4632 bytes docs/index.html | 186 ++++ docs/modules.doctree | Bin 0 -> 2760 bytes docs/modules.html | 191 ++++ docs/modules.rst | 8 + docs/objects.inv | Bin 0 -> 2220 bytes docs/py-modindex.html | 363 +++++++ docs/search.html | 133 +++ docs/searchindex.js | 1 + docs/sklearn_to_astartes.doctree | Bin 0 -> 32216 bytes docs/sklearn_to_astartes.html | 278 +++++ docs/sklearn_to_astartes.rst | 180 ++++ docs/test.doctree | Bin 0 -> 3563 bytes docs/test.functional.doctree | Bin 0 -> 48688 bytes docs/test.functional.html | 306 ++++++ docs/test.functional.rst | 29 + docs/test.html | 223 ++++ docs/test.regression.doctree | Bin 0 -> 17400 bytes docs/test.regression.html | 189 ++++ docs/test.regression.rst | 21 + docs/test.rst | 20 + docs/test.unit.doctree | Bin 0 -> 3599 bytes docs/test.unit.html | 204 ++++ docs/test.unit.rst | 19 + docs/test.unit.samplers.doctree | Bin 0 -> 3720 bytes docs/test.unit.samplers.extrapolative.doctree | Bin 0 -> 72609 bytes docs/test.unit.samplers.extrapolative.html | 367 +++++++ docs/test.unit.samplers.extrapolative.rst | 61 ++ docs/test.unit.samplers.html | 251 +++++ docs/test.unit.samplers.interpolative.doctree | Bin 0 -> 35460 bytes docs/test.unit.samplers.interpolative.html | 247 +++++ docs/test.unit.samplers.interpolative.rst | 37 + docs/test.unit.samplers.rst | 19 + docs/test.unit.utils.doctree | Bin 0 -> 27792 bytes docs/test.unit.utils.html | 220 ++++ docs/test.unit.utils.rst | 37 + 79 files changed, 9441 insertions(+), 63 deletions(-) create mode 100644 docs/CONTRIBUTING.doctree create mode 100644 docs/CONTRIBUTING.html create mode 100644 docs/CONTRIBUTING.rst create mode 100644 docs/README.doctree create mode 100644 docs/README.html create mode 100644 docs/README.rst create mode 100644 docs/_sources/CONTRIBUTING.rst.txt create mode 100644 docs/_sources/README.rst.txt create mode 100644 docs/_sources/astartes.samplers.extrapolation.rst.txt create mode 100644 docs/_sources/astartes.samplers.interpolation.rst.txt create mode 100644 docs/_sources/astartes.utils.rst.txt create mode 100644 docs/_sources/sklearn_to_astartes.rst.txt create mode 100644 docs/_sources/test.functional.rst.txt create mode 100644 docs/_sources/test.regression.rst.txt create mode 100644 docs/_sources/test.rst.txt create mode 100644 docs/_sources/test.unit.rst.txt create mode 100644 docs/_sources/test.unit.samplers.extrapolative.rst.txt create mode 100644 docs/_sources/test.unit.samplers.interpolative.rst.txt create mode 100644 docs/_sources/test.unit.samplers.rst.txt create mode 100644 docs/_sources/test.unit.utils.rst.txt create mode 100644 docs/_static/_sphinx_javascript_frameworks_compat.js create mode 100644 docs/_static/sphinx_highlight.js create mode 100644 docs/astartes.doctree create mode 100644 docs/astartes.html create mode 100644 docs/astartes.rst create mode 100644 docs/astartes.samplers.doctree create mode 100644 docs/astartes.samplers.extrapolation.doctree create mode 100644 docs/astartes.samplers.extrapolation.html create mode 100644 docs/astartes.samplers.extrapolation.rst create mode 100644 docs/astartes.samplers.html create mode 100644 docs/astartes.samplers.interpolation.doctree create mode 100644 docs/astartes.samplers.interpolation.html create mode 100644 docs/astartes.samplers.interpolation.rst create mode 100644 docs/astartes.samplers.rst create mode 100644 docs/astartes.utils.doctree create mode 100644 docs/astartes.utils.html create mode 100644 docs/astartes.utils.rst create mode 100644 docs/environment.pickle create mode 100644 docs/genindex.html create mode 100644 docs/index.doctree create mode 100644 docs/index.html create mode 100644 docs/modules.doctree create mode 100644 docs/modules.html create mode 100644 docs/modules.rst create mode 100644 docs/objects.inv create mode 100644 docs/py-modindex.html create mode 100644 docs/search.html create mode 100644 docs/searchindex.js create mode 100644 docs/sklearn_to_astartes.doctree create mode 100644 docs/sklearn_to_astartes.html create mode 100644 docs/sklearn_to_astartes.rst create mode 100644 docs/test.doctree create mode 100644 docs/test.functional.doctree create mode 100644 docs/test.functional.html create mode 100644 docs/test.functional.rst create mode 100644 docs/test.html create mode 100644 docs/test.regression.doctree create mode 100644 docs/test.regression.html create mode 100644 docs/test.regression.rst create mode 100644 docs/test.rst create mode 100644 docs/test.unit.doctree create mode 100644 docs/test.unit.html create mode 100644 docs/test.unit.rst create mode 100644 docs/test.unit.samplers.doctree create mode 100644 docs/test.unit.samplers.extrapolative.doctree create mode 100644 docs/test.unit.samplers.extrapolative.html create mode 100644 docs/test.unit.samplers.extrapolative.rst create mode 100644 docs/test.unit.samplers.html create mode 100644 docs/test.unit.samplers.interpolative.doctree create mode 100644 docs/test.unit.samplers.interpolative.html create mode 100644 docs/test.unit.samplers.interpolative.rst create mode 100644 docs/test.unit.samplers.rst create mode 100644 docs/test.unit.utils.doctree create mode 100644 docs/test.unit.utils.html create mode 100644 docs/test.unit.utils.rst diff --git a/docs/CONTRIBUTING.doctree b/docs/CONTRIBUTING.doctree new file mode 100644 index 0000000000000000000000000000000000000000..3e6bccbec2a1ba4f709bd53e9a65eccae9e7aaf9 GIT binary patch literal 42874 zcmeHweT*E(btfruzsco?sJ-|o(M?J;m+PHbinJ`6He*pFB~z4E3Q3972Q%9<)3e>f zneI_{&o0-A5*mpkGVa7cJc*M#>ue;j&(59ia1L?-4hfLp;3P&8Cl}n=K<*GLPIAa0 z2Ly0{;Qlxq?)P4GbyfH5^v(=Pn{py(hcn&PRj*#X_v(Gs>l-6K@BQmd{9m*qXxWZ? zy=Ydeu2;2!PBdQiD($A_hMiA!4u7okMrSsf@Xgi0Yx@2Coj}^K{l_~3=+Tx55W|kWE1D=JbF#NYqw!Q0qpc0cwK|LKvKdX9 zp#TCS(v-J2)d16r#wran2yhYKM_jWhzKvJgE%l>pR<8M0joP%MvCv$mTOE6cz1QAm zKWJ~UABsM(V0%q#!Ed{+R`TegP2D=%)|wCRO*qhVaIUT<4L7|a__wwLj%<@xl(bgPDm+X~B` z8yG;1v1&Cc0BYW_+zJ-gT(+ul^H$5ZDvlXi)%}w%G%Pc)j5hv4+cHet^IAULG?tto zXj{gI>@aKvCl(f#ozQNVi|BOW8K5Na+$Y<E*oc@pwbQkY`KBaf*2nF!&UVtOHt2Q_6%Czi*!Hb}2Lfy~Ary^e zYFiaMJn@EYu3%4b4X0|E1~oKkr>V7*QTOxOlNjES!GK2FZ|bydE4F&^u3$-W+TNTc z(181-4&26KGq+dp;rsgLLv3vnUVIZorFil2At@!pj|6f-Z2kpp&;rq-#-2Pg(ag}A zG0CD?muUU0&aDLaOw=Lrx#uWUv3rUT`(yX6T0$9X zn*KFnGana?RcKwT(j35#3zk`3V@A4QtvJ@|0i$7-!KSPgNye->t`pc$bz(KCVw>(V z_&e~>j~Q}jv1l<_lMjrt7Y0TJj7q92HE?`9z3fy3e`0CAJOsqwzVVrLVE*=vx9&dF zYR!J5KmOE3^pv({Q&L1r8)v7y5baW?%sCg@exo5p$2xZuK)>HVKxATkRW#?lV_M%c zuGH__wCR$kbYK?LB(#>6r17z|gjFZQ4y~#%1=uDbISyGYRA`tFc*Hd-4bNryjpuzB z7l9Lc{+coC6s;mU1YdI#%fPoM1ecQ~aN=cj|6*YIq!cEmP7w{3mR>Usvw6b(J8pnY zfN4+b9tIOSZ#gXk_X&eW!7_@kVh6dpv{W=M*-iikz~ulsJkfW%B^ZL5(o{)HaD32u z)oNL86)LkMb~4ekh6gf~U@ld;V$-TR?Iv4Rm?!~MXtxTjwb1t50>e_kmlY>yn~g#cwyTa;pam^FcI?sPR@r=C zrF!JZ!zX_1LzfGr6$u{G1xwOvS);sIHy%PKW zIk@E;ypNo{BUG;>>dBDmxNj4&gsxz=Zg z1a*W(q3Wn7(f~s&E)y8|w|caGVn`T11kxQ^0ITscpeu9Yci!(BO$ zcIo2Lx`Ac#6=|8gbM~#oE~0Hg*+swpj@*OA;wDZkUYr7H6q*gDtys6kReuc>pc`Fc zv)o)%M3Ux>{w$oGQb`4lvDrf@Ohp%DbfBkmB$~M1Y@7&MCWRly;hKgvxnj}M)k7lL zvuq>3bhYAhb90wXpA^}-xyj3pTlH3<(Y@fUTK+}&h8sd5ea@^r zf6+K?Lg92=ll&BLS;HqX`_aHYELBRQ>b1)a3;tpXQ^4clwS}$>h458qrv}U_ANCV@ zn5CAiZ+8czGQ-;J0ahO;C&eNvzt6wAw*h8wDXudbgudr4>$slMK$n7NEXKZ~sQSMeH4TNb}{`GGrPcTsL0z)K%;+VKw zD#eeNO2XhLCocs|SJ{|m4}a*C9hiV?!g7Csty<$)@$up$S(1dp*s7M0kpEkEVUXd^ zp5%CCDUeCm$O4Z&2%^(M#W>(JDKctE>H9$g(M&g-mA{J`#D^i34J@MqNkl7EXEonz z8luOBQ-+-`kQZMvVt_v=zsw$z!yGz%Al38nWS5bKw30D>+Zq2mAqWvE%w-uehwFcX zCs>Y-3i{Cam2UMAdb_*HNK*K8n!dFD{$HlQ0f77PZ4#*lMb4~#K+#m1mgU^`$i>rd zYklv8zfH&305cpF{GxT11L%$nTS@q)G}6_2Ixsv~=gApxhd5S)C}(bc)B5{{pVfXA z4tWBjKUhCRY(OqJV+gq-7w!14U1%^qH9RhMr=-y1B!#q&yB2C9n!@%0wU>REy0*7@ zNzMr0)UNhQPtYjE=BV0(lladFLg`MmL$@DgCI1R_p^2(xg)syW29?0yzVVBajlX^4 zmkv{~L6`8l99FZ);z8*ZGDSdwPuhZv=#(z9Gu{^pyt$Enpn}-)p4j-ry*Mv-W9NVb z#lJkLD$I=Bmf{MeysTQrob4>zjkP%#ZNl!X#^b5htYui&EhMpt@Ph!E>568cb_GD8 zLKBFUVBd!iKU`~3Bfu;GHES^W66mOhMDvu&r7=s9?grYqNLgyE%_q+rg%ylK64%6x z5jLQNB?^aQhOKsZxH$Q|8;AYj=@QuhGDZi?kg}t&4!TC99YGpBfr}H0i#uTG<|CsRy-?}d{wGEGtr*)NJkSVKbw$VoC`ICmh=mmJ~rN_X;jvd4)sa7 zeM77WTuRSzc}eTzi^D^FU}MJ72FgM2q#|(%>ZqW3?fL&SJfKsgYQ$Wt_1Fc`L^O_6 zKbvS)-+sm=rzgM(&eyv7`XIp7|BzbmttU&rt4oAvU3WpL$g(fIy*&tMthgs|85_y3 z{=n>8@A}U0puVf8`0NkHzEHV!%b-elg39+BL&@&`fZs0phef=k(h0#rxTf_oGyD{O z?0dU+Xp_ici3bq6@7`i0N_KVK(|Vm99yKLK&0XBXluDJIdw=TUeoeJXsf%N@Nv5?# z?NW|%NSaxWa(Mr#YL#@aMQhc#XhNBRqerg7y7$x!&kwW?q%?jcd4iS3Ln)>4KKKS= zV4#-(oIrqM1W@f7RRdWINZw%82I^QDzGf&rrMQvsH_5A{&LEqGvi6IUXHDc{Ad8BB z%FZag(U-XV7g5r!ped4OUBl_QcK1k$4(O zrU>V?U=@jUF0xm_+OSL|@3Z$C?J%pEndG3WVJ%bz2|On@T5N3y1njAf*SL!gl_o}eL%n;@deAh}D4l$}{D zYZUZWhJv*4R^Mvj=QDk5EG1}Ek`h-og9g~H`p3M^Im=Q1BdFX-M%h?Q5mGRWFo9@~ z|HdFIAeDNV_UEIsunBj$U^i0F4Xvlz^PW4AX{pzYB^}MI-$3jCo0($5o8rkEy#KDH3{Kk_%yNrND?v1cvgEC4*D zt_M2D!OA7x4N9~rm4X(6tQ3Tu=RFen+HqGdeml#^bZIE&VvSVr6kK)fhH&CuVXlD7 z(Bch-I*d0S?8XfTu3qF_(kUg=V0R)86DarTf}F#G##WxY;6sP@ngTqb%M1S}`6Vl~ z4HCnvb3iACM~AlXo42Oj1RAsKSr2QHoOWgrs`WXM>2qTSAt;zZyiMQTRnef%!Njp4 z7EdB7$@TAZ*)@pv4v)tNV*f{mcGTXKoo#>Y`DhRJjQ;Kvd;4iqiK!cj2skcdL03#| zR5&n#T^IIU#dP+K7h-L9^CTCdLy z5980>gCwAsDT}WDnCVzAX8P-=V7nn-6$gvxdQI&9Cb+` zD-O8kif6K5_s27jrFkaDsrxXhrWogxjU+s~q^_NkuFS;A+gDo!`o9RsRWFP1QIQHCr(aM5^>0Gm#$lsV2r%+24x<0-Rzw=K8{CLooZ-z&hMw(;ja)h zd+Yxm|Fp~XU&BArs*WL$x%1h?hx%`!?Op1F5n|)mZui6{qAk9++I5}F=)nH<*Sc=0 z{Lg6H#n^?u$i-;JP@H2Xb5X7Aw+J&_sivRAL7Crj63F}?jLdwt{xj+w>8jkc{@?LW z2JcDMYBYfZ%#isYSIM{96$S4

%z{`-1@D?-__Y2Jg-bR>N8`-OzZ}aj(q=hb7qE zHx%^SM}~p^!+?GgPoi2;Pm(7pPhmS(y43$0p>c2hPy4{hpNOV{cbI0&UbUM5XY1cU z!}RjbZm{HM3eO{e(!}{sF7-4MO{gmhX~%~`+7p=GWBnuTC^yZ8_sSVqLWl;)uJRLLoB z{uHWzkefiu>A|Uf)WN#Wnv(Rmk$(*wNohz>m#Giz^>mUr(Vl2~v93d(qA%=3_f53( z(HK645GgIVPRbCpDJXW-Lg_)^@EDug-u!%KxzifRq{6!-nsK=jS|^t?o#Zo4obf>; zv-a`C?JlVXNp?D#va(GX7E4JE&_svVRa>$%3uHEpeQ9RviQ!GgGs{XDM*WF zdHM4xB^I&$NQ*g0i%Z~`rOVDWr-ftuCJbwEFZhx8fkMZSd@yAKXW3Q94lTF1Djz6% z{_+C-T8QOjNwiMR^FLq1(R?c57FY+5p2qi@a~%waFW^CZy6tA!^6|x^hSqf$`wltK z%?5rVWsr{loA?uw3}4ui!oOvD8g2}Vwv$Ch=lq56f+^-9R9^SW;CmEa6A`CXn;Z?0 zJNUoq)M`!zR*^{gYk6?`!TJih6p&V3NTxv|bQdU@u$6G8@y}0ZXkRPx^R@3A)JjqI zNI$fqA?N2Z$mvbI^5AZNBj8N$XXTmRdz2vM0p2c335LZ140Q3*}rZYH{VcbQv>=PWz-C!U{# zcz%=Dxi^Jt8n6)0xm`;Qc!7HzTz4Hk(?)FKx@27WQ%&>_(edDh%4tmWYyD63cLnsh zhSld1C5!Y_QpY$^fgH@5dMfgkAkrxt9(rS3fC4(4=dyn|&V14mB|=1gNbQVOTj7M` zN_DK;$^(Ab@3>HvjIAJJA{CWVqW{f%1X4}F{$*wrHSG>NwK{@^6;%CTemx6gF5M>@&lynK+uUF7xYDTXhtmH35@`TSN%TWR5@9%8P!c(? zP};~Y`Y@ivSyWPSPG2~+xPZeyO+@n-aD%)(p}$~<&Bg-i?SjvW^gU5~pdvs$IrHKR z&z`-4FG;2z=`5tuAU^6eOn;t2A9UZR=0YQ?LBQhV0$-+-9#(7|m(MQ*$(f6!rYH0k z@CiJ}vg)de?PN0dMtJht@@^YV3jj@V`N}&FN0O-TUuSi-N$<%_x;Je}g=F0hp@006 z)IaVyib*sNTH%!D@tJ#>&NDhk2Jbk0Rq!i*M_0yO0Xe%C7Y`xXlkC$H_zsE z!^N*ba6iIeG#+AcVsOeZS7#mL+o@1p*9fV?3zRmV6a3&XICL9I5qXNs);b>*`_Dx< zx~O=2>|)%wp`tyvZ)rv>Kw*z-$rBv*I0v8;7x$HO@CZ;crgYhno1XMBk$n!^S&Q9( z-*oSgVOA_Dx+$v)Hf%{Ao2)(m0fi=E21P_S2c>V*5Ss`6Q#xLT-now|aK zM-MM8U96b3n%Agu0uByP7L9YFlCP}Lo4EHxIbexbav(NwER)MXhMf9?r1=Cs$Hl2d z;RGd!SS95ABmubwI92X~j>s`wGWAxlw{3DC`t0ju-th~0_lQ@}ewNNHUOIc>sZ*!V&Q2QmFZqd-Bgn7$%*9g|p1vrqt(`F3R*{9UaT4z< zaV>G3i!S42!n!vFG>F=qFmSpW9?_G=k>b(E#FGLviWTX1ACK>H3MX)I0`+KpJa7{7>Y|%h*kxv|x%LyYK%K`C5(Odq}=Q!b42|2?TtQlb2BcaVWj@ z8~BJuu(P0$x`zwpkOhNdt5WoB>Je525y)oi6EF)lA@ef({vkBv2G8kIHZDIJSS7gh*O7hTACp1Y)?8;DZHAP;Oz9byJa3~*ar zyg02)FHX}uCEK6K+~{(_?WMsr7hDX?O!WAW$)qN_%;#t)becU70CIBl+xd9E}GN ze8OffEP!n2&v+_U2N>aWS|*#$5@wLCZJM_oQ2fzM-@QeiWHf??H`56Pxmv?4tZF^h zb3%~&^YsJ*c7LM&hUWhK3v8u55r@DbX-TvT+8)xG62(e5DW!Ff{c!ReCpaPpvqgtA zD8G^NsdyKn*OqZ6BK6hn#KvosD8GVypBx8ABX#bdR}`1$ac)Bv<`7YEvIY4D$IPi1 zfUrAdAG8Of3AT87U=qom0E<=6YnIibhP2nOK|yrIkX*o^IQb%8OhdVnDEEe}Dyjx2 z2uqls;@BqTRMk@Sv$x~MOXv(t4lQ?Whsxo0|gcBFWOaQ752l`VurFvZ#| zp&v(PxHusdo@2-y7o!4G@ylV8sIKx)FVH(R*?%lm0JTlrHdX&(LR0-@sMGe*kyO2p zP}iHRG#N;b=-C457yhJ>aPzE z^QbUa`vVlztHgm+1IFbgt&g{d2WVW18Lhhy%sd|CevezVbd)-zl%%OpB zOe)MH$rG%?{D`i?MD`_88PwrZ4xq{<#&#?6s6*_%#_Xf?z7QlcRoj)g%Kf}CdlW^r zkv&u;?9u!qG%nCBu;9@~v^n!AVt3kJdHxkiqj;+Jz4_6g2TdbH{Ddfnut05U0#5{ks0cw2)(0@ow&!h>JeyGth`;DYM|i z=sL@pJ~k#A8kLD=v!30b0}HkZ#F)Vr_T`KK8v|Iz{bS4D?6sH$d&LF-CJS zUw?(Lw6}gaK^6%$yh*{8MY7OMf$Gb>+gYx5oYE;5oR6$z?a}tTCxQlHV;X)5Rq(=#J1!qH@##(W5 za?UuTzs^(i3E9bVR#czi!)f}^u)V4aFnr=TWF^Jg>4u1526np!8Lib-BWE@?#Gn+n z1@BX6bj5Q}GSWiKf+m6YNr}8066Ml^Qv|%Hy=DvZ)L(Q$B0*0pA3>uP|<26?BGSfrr2og;k$+3&#rBky?h(w=%N6-Pw z1d?;pX>c|9@GldR7h7Z6g|{!Cz@^N2Fpmwi!G0w(SUyw6#|;TWmWY#zpR_*nC$PJl z^CZwavplJF`s=p^=rJV{`etrz@a&9+*?4|$kO{D}GC}h`f#zPaB?r*{Wb(%#Xg@91 z6festw~@pa_Ru_1;y3#8J4&PpGE3sG_5VpL6005lcYh|@vi(hlHZ=M|ebuZCm+Uf~ zzM=K^cbWcjxteK>AYhh0-1iQljhBVLKeGD?klkPLxVi92Rp2kUX_^4vy7%`eZHxNM zy$r3Ss(TwqrGD<37{m!7od-V&n%j;iH>yYxtDl1AdXsZBDx_s6+C0a3AKxO*6L}v* z-a@MOex6cAx-{K*+kX{ZC5kQ;9frn$bZ3gRpSkd|F?+^y4~51BD3!>^dzp_?H)@CZ z)o>LDM~~n@mbxCjSKXlVNH`JA`O{>wRjmqDt3ol}*o4Q6<}K6+Lh)XAUf6jq&O8;U z{5Ntw#NoRNRU$`(UBnk;!CGCEgAa{x@Uy9Nxd^ENZWfJA4(4V6qxfE%Ypja8lMUO zN_vm^%pZh+_Ra5OWQe*P|VlYC7gwqIyu zR(2LxGW0KJw1KnGYbsmcakttaz_Xf`K>irl>>O0g<-ni2Mf{tJmJy`ysrE3C>lDVIzeTRYl8Ag>pIR{e3tRKZd+&&pJKBLPZ@mIq->Zidf}Xl zOhUR}hhx0JjnE?QBbIn7bD(bl@Y~6p`^^yeP2v@LiTEqfaPAToG$}#D>C2dwatc|J z8ph=%t&cy=^pQ^rlm?MZa?g5;pmm)C-gJ7cB!H7@0kwYqYIqRG6Dm-|p9M>?@p|b; z(lq%Q%v>@-iugY2?P>{)LJNm6 zK;)c8OAP#c@)pLWr59VsEV2xZ)zOR0@r}cK>8*NZefT8G_pArKhWt&FX&TF=51DiL zedFt+)Zb2FP-Bq4L>L2pKZT^U)w{k zQYs@KobCo4uE7%Ru6bTa+J|=M{N`wT0Ivd+vC?(&8FX-E8ple?izaOpYm+}mqFu;f0Lnr$YzOMIi4(KLOD`6+vA<(S#GQz!dqK7hfGF{Z)0M|s*qF)7reEPxkjm*Q*PMQM< zEwF*22Ikbk+0^(n6EI%I@B1tqXS$zC=lfOE>uZ5bFpR^P9)((2!!&^rrwT%q`tmfD z_%EqT(S7tD?CsTdvsFsy4~XRpd_D=U?4YIF!B?2FIlmye)C#P2)hk_Z5rS3cAndLD4K3rEd*I> zI7$j98qIGTU7<6lCE|?e2jqbaTn>N6-*?1&GL(m71nqRaK9)?1d2r=Yj6=4m>!QF0!=nc3410J zz>7_YLT*JngEeILTrVYO+&aEetUY=#beA{0lj73)JIPsJyEZ40s_mv~;GISZ=Z0WDkOa9I?V_GZ_R=eNgiN~?ZL!>y z4ss2maUo8?zaT{z2z>ahgab~?s2)ayvkO3hv_h^t1~RMB`M+p)>MEHId>Osfk{_eQ zLRG##Mi<5R+4>iurqn-Ay2?xTMSIO&vA<-0q5fat{;mHP`l!)Ig+4xt1LXBp`Z&7< zA5YSUjWcF-i$0d<<0^gpThw%^e~CVd^z*&+;UZPBevLj3(#HY%*bh^;zK=dWM=-oa z9~U8V>M!7<9Ze9FocvAO6T^ASe(9#YcGLdSO$P8519y`FyTw4=Vt{TjFt-?xn+(KF z2H+MCev=2j#e?4B0dKYK{WJt)VH>dU9I()`zhHlkQDA>n%>ODOf#?5C`c?-fkUTXV ztici8ECJ^M9n}0(NBYp?g6Ybrd^UDav2cM%qda&~BG`wKjBSnb|uKYKtdcT z473eFSmT9xC{V+fgklW4?9O(oY>M9>NM$NOv-v75n|8pJF_bt8WKEoU6?ikFkz~i* zDx4!@mrq?-Jh%8XF+AxL=l5!A3wcKVGXaDO>A=0_L3j`uI@DwR75ZSBe1pC*P15^R z1x5EPIVaBy!U|nTtv5iByjha#Vh3cdCD;9@;-1$o3WA zftH6&6a{fhiZlnPZ)2z9>z@Ma)jt8mpT95oc;^B(26!{D#l*x;1M{+* m(e7kt)o(^q$z_&lQ*oIZ$k1gHXQ(uR%|G5JX;s_h;{OL+=vS)% literal 0 HcmV?d00001 diff --git a/docs/CONTRIBUTING.html b/docs/CONTRIBUTING.html new file mode 100644 index 00000000..78580996 --- /dev/null +++ b/docs/CONTRIBUTING.html @@ -0,0 +1,258 @@ + + + + + + + Contributing & Developer Notes — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +

+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Contributing & Developer Notes

+

Pull Requests, Bug Reports, and all Contributions are welcome, encouraged, and appreciated! +Please use the appropriate issue or pull request template when making a contribution to help the maintainers get it merged quickly.

+

We make use of the GitHub Discussions page to go over potential features to add. +Please feel free to stop by if you are looking for something to develop or have an idea for a useful feature!

+

When submitting a PR, please mark your PR with the “PR Ready for Review” label when you are finished making changes so that the GitHub actions bots can work their magic!

+
+

Developer Install

+

To contribute to the astartes source code, start by forking and then cloning the repository (i.e. git clone git@github.com:YourUsername/astartes.git) and then inside the repository run pip install -e .[dev]. This will set you up with all the required dependencies to run astartes and conform to our formatting standards (black and isort), which you can configure to run automatically in VSCode like this.

+
+

Warning +Windows (PowerShell) and MacOS Catalina or newer (zsh) require double quotes around the [] characters (i.e. pip install "astartes[dev]")

+
+
+
+

Version Checking

+

astartes uses pyproject.toml to specify all metadata, but the version is also specified in astartes/__init__.py (via __version__) for backwards compatibility with Python 3.7. +To check which version of astartes you have installed, you can run python -c "import astartes; print(astartes.__version__)" on Python 3.7 or `python -c “from importlib.metadata import version; version(‘astartes’)” on Python 3.8 or newer.

+
+
+

Testing

+

All of the tests in astartes are written using the built-in python unittest module (to allow running without pytest) but we highly recommend using pytest. +To execute the tests from the astartes repository, simply type pytest after running the developer install (or alternately, pytest -v for a more helpful output). +On GitHub, we use actions to run the tests on every Pull Request and on a nightly basis (look in .github/workflows for more information). +These tests include unit tests, functional tests, and regression tests.

+
+
+

Adding New Samplers

+

Adding a new sampler should extend the abstract_sampler.py abstract base class. +Each subclass should override the _sample method with its own algorithm for data partitioning and optionally the _before_sample method to perform any data validation.

+

All samplers in astartes are classified as one of two types: extrapolative or interpolative. +Extrapolative samplers work by clustering data into groups (which are then partitioned into train/validation/test to enforce extrapolation) whereas interpolative samplers provide an exact order in which samples should be moved into the training set.

+

When actually implemented, this means that extrapolative samplers should set the self._samples_clusters attribute and interpolative samplers should set the self._samples_idxs attribute.

+

New samplers can be as simple as a passthrough to another train_test_split, or it can be an original implementation that results in X and y being split into two lists. Take a look at astartes/samplers/interpolation/random_split.py for a basic example!

+

After the sampler has been implemented, add it to __init__.py in in astartes/samplers and it will automatically be unit tested. Additional unit tests to verify that hyperparameters can be properly passed, etc. are also recommended.

+

For historical reasons, and as a guide for any developers who would like add new samplers, below is a running list of samplers which have been considered for addition to asartes but ultimately not added for various reasons.

+
+

Not Implemented Sampling Algorithms

+ + + + + + + + + + + + + + + + + +

Sampler Name

Reasoning

Relevant Link(s)

D-Optimal

Requires a-priori knowledge of the test and train size which does not fit in the astartes framework (samplers are all agnostic to the size of the sets) and it is questionable if the use of the Fischer information matrix is actually meaningful in the context of sampling existing data rather than tuning for ideal data.

The Wikipedia article for optimal design does a good job explaining why this is difficult, and points at some potential alternatives.

Duplex

Requires knowing test and train size before execution, and can only partition data into two sets which would make it incompatible with train_val_test_split.

This implementation in R includes helpful references and a reference implementation.

+
+
+
+

Adding New Featurization Schemes

+

All of the sampling methods implemented in astartes accept arbitrary arrays of numbers and return the sampled groups (with the exception of Scaffold.py). If you have an existing featurization scheme (i.e. take an arbitrary input and turn it into an array of numbers), we would be thrilled to include it in astartes.

+

Adding a new interface should take on this format:

+
from astartes import train_test_split
+
+def train_test_split_INTERFACE(
+    INTERFACE_input,
+    INTERFACE_ARGS,
+    y: np.array = None,
+    labels: np.array = None,
+    test_size: float = 0.25,
+    train_size: float = 0.75,
+    splitter: str = 'random',
+    hopts: dict = {},
+    INTERFACE_hopts: dict = {},
+):
+    # turn the INTERFACE_input into an input X
+    # based on INTERFACE ARGS where INTERFACE_hopts
+    # specifies additional behavior
+    X = []
+
+    # call train test split with this input
+    return train_test_split(
+        X,
+        y=y,
+        labels=labels,
+        test_size=test_size,
+        train_size=train_size,
+        splitter=splitter,
+        hopts=hopts,
+    )
+
+
+

If possible, we would like to also add an example Jupyter Notebook with any new interface to demonstrate to new users how it functions. See our other examples in the examples directory.

+

Contact @JacksonBurns if you need assistance adding an existing workflow to astartes. If this featurization scheme requires additional dependencies to function, we may add it as an additional extra package in the same way that molecules in installed.

+
+
+

The train_val_test_split Function

+

train_val_test_split is the workhorse function of astartes. +It is responsible for instantiating the sampling algorithm, partitioning the data into training, validation, and testing, and then returning the requested results while also keeping an eye on data types. +Under the hood, train_test_split is just calling train_val_test_split with val_size set to 0.0. +For more information on how it works, check out the inline documentation in astartes/main.py.

+
+
+

Development Philosophy

+

The developers of astartes prioritize (1) reproducibility, (2) flexibility, and (3) maintainability.

+
    +
  1. All versions of astartes 1.x should produce the same results across all platforms, so we have thorough unit and regression testing run on a continuous basis.

  2. +
  3. We specify as few dependencies as possible with the loosest possible dependency requirements, which allows integrating astartes with other tools more easily.

    +
      +
    • Dependencies which introduce a lot of requirements and/or specific versions of requirements are shuffled into the extras_require to avoid weighing down the main package.

    • +
    • Compatibility with all versions of modern Python is achieved by not tightly specifying version numbers as well as by regression testing across all versions.

    • +
    +
  4. +
  5. We follow DRY (Don’t Repeat Yourself) principles to avoid code duplication and decrease maintainence burden, have near-perfect test coverage, and enforce consistent formatting style in the source code.

    +
      +
    • Inline comments are critical for maintainability - at the time of writing, astartes has 1 comment line for every 2 lines of source code.

    • +
    +
  6. +
+
+
+
+

JOSS Branch

+

astartes corresponding JOSS paper is stored in this repository on a separate branch. You can find paper.md on the aptly named joss-paper branch.

+

Note for Maintainers: To push changes from the main branch into the joss-paper branch, run the Update JOSS Branch workflow.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/CONTRIBUTING.rst b/docs/CONTRIBUTING.rst new file mode 100644 index 00000000..677944a2 --- /dev/null +++ b/docs/CONTRIBUTING.rst @@ -0,0 +1,143 @@ + +Contributing & Developer Notes +------------------------------ + +Pull Requests, Bug Reports, and all Contributions are welcome, encouraged, and appreciated! +Please use the appropriate `issue `_ or `pull request `_ template when making a contribution to help the maintainers get it merged quickly. + +We make use of `the GitHub Discussions page `_ to go over potential features to add. +Please feel free to stop by if you are looking for something to develop or have an idea for a useful feature! + +When submitting a PR, please mark your PR with the "PR Ready for Review" label when you are finished making changes so that the GitHub actions bots can work their magic! + +Developer Install +^^^^^^^^^^^^^^^^^ + +To contribute to the ``astartes`` source code, start by forking and then cloning the repository (i.e. ``git clone git@github.com:YourUsername/astartes.git``\ ) and then inside the repository run ``pip install -e .[dev]``. This will set you up with all the required dependencies to run ``astartes`` and conform to our formatting standards (\ ``black`` and ``isort``\ ), which you can configure to run automatically in VSCode `like this `_. + +.. + + **Warning** + Windows (PowerShell) and MacOS Catalina or newer (zsh) require double quotes around the ``[]`` characters (i.e. ``pip install "astartes[dev]"``\ ) + + +Version Checking +^^^^^^^^^^^^^^^^ + +``astartes`` uses ``pyproject.toml`` to specify all metadata, but the version is also specified in ``astartes/__init__.py`` (via ``__version__``\ ) for backwards compatibility with Python 3.7. +To check which version of ``astartes`` you have installed, you can run ``python -c "import astartes; print(astartes.__version__)"`` on Python 3.7 or `python -c "from importlib.metadata import version; version('astartes')" on Python 3.8 or newer. + +Testing +^^^^^^^ + +All of the tests in ``astartes`` are written using the built-in python ``unittest`` module (to allow running without ``pytest``\ ) but we *highly* recommend using ``pytest``. +To execute the tests from the ``astartes`` repository, simply type ``pytest`` after running the developer install (or alternately, ``pytest -v`` for a more helpful output). +On GitHub, we use actions to run the tests on every Pull Request and on a nightly basis (look in ``.github/workflows`` for more information). +These tests include unit tests, functional tests, and regression tests. + +Adding New Samplers +^^^^^^^^^^^^^^^^^^^ + +Adding a new sampler should extend the ``abstract_sampler.py`` abstract base class. +Each subclass should override the ``_sample`` method with its own algorithm for data partitioning and optionally the ``_before_sample`` method to perform any data validation. + +All samplers in ``astartes`` are classified as one of two types: extrapolative or interpolative. +Extrapolative samplers work by clustering data into groups (which are then partitioned into train/validation/test to enforce extrapolation) whereas interpolative samplers provide an exact *order* in which samples should be moved into the training set. + +When actually implemented, this means that extrapolative samplers should set the ``self._samples_clusters`` attribute and interpolative samplers should set the ``self._samples_idxs`` attribute. + +New samplers can be as simple as a passthrough to another ``train_test_split``\ , or it can be an original implementation that results in X and y being split into two lists. Take a look at ``astartes/samplers/interpolation/random_split.py`` for a basic example! + +After the sampler has been implemented, add it to ``__init__.py`` in in ``astartes/samplers`` and it will automatically be unit tested. Additional unit tests to verify that hyperparameters can be properly passed, etc. are also recommended. + +For historical reasons, and as a guide for any developers who would like add new samplers, below is a running list of samplers which have been *considered* for addition to ``asartes`` but ultimately not added for various reasons. + +Not Implemented Sampling Algorithms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :header-rows: 1 + + * - Sampler Name + - Reasoning + - Relevant Link(s) + * - D-Optimal + - Requires *a-priori* knowledge of the test and train size which does not fit in the ``astartes`` framework (samplers are all agnostic to the size of the sets) and it is questionable if the use of the Fischer information matrix is actually meaningful in the context of sampling existing data rather than tuning for ideal data. + - The `Wikipedia article for optimal design `_ does a good job explaining why this is difficult, and points at some potential alternatives. + * - Duplex + - Requires knowing test and train size before execution, and can only partition data into two sets which would make it incompatible with ``train_val_test_split``. + - This `implementation in R `_ includes helpful references and a reference implementation. + + +Adding New Featurization Schemes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +All of the sampling methods implemented in ``astartes`` accept arbitrary arrays of numbers and return the sampled groups (with the exception of ``Scaffold.py``\ ). If you have an existing featurization scheme (i.e. take an arbitrary input and turn it into an array of numbers), we would be thrilled to include it in ``astartes``. + +Adding a new interface should take on this format: + +.. code-block:: python + + from astartes import train_test_split + + def train_test_split_INTERFACE( + INTERFACE_input, + INTERFACE_ARGS, + y: np.array = None, + labels: np.array = None, + test_size: float = 0.25, + train_size: float = 0.75, + splitter: str = 'random', + hopts: dict = {}, + INTERFACE_hopts: dict = {}, + ): + # turn the INTERFACE_input into an input X + # based on INTERFACE ARGS where INTERFACE_hopts + # specifies additional behavior + X = [] + + # call train test split with this input + return train_test_split( + X, + y=y, + labels=labels, + test_size=test_size, + train_size=train_size, + splitter=splitter, + hopts=hopts, + ) + +If possible, we would like to also add an example Jupyter Notebook with any new interface to demonstrate to new users how it functions. See our other examples in the ``examples`` directory. + +Contact `@JacksonBurns `_ if you need assistance adding an existing workflow to ``astartes``. If this featurization scheme requires additional dependencies to function, we may add it as an additional *extra* package in the same way that ``molecules`` in installed. + +The ``train_val_test_split`` Function +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``train_val_test_split`` is the workhorse function of ``astartes``. +It is responsible for instantiating the sampling algorithm, partitioning the data into training, validation, and testing, and then returning the requested results while also keeping an eye on data types. +Under the hood, ``train_test_split`` is just calling ``train_val_test_split`` with ``val_size`` set to ``0.0``. +For more information on how it works, check out the inline documentation in ``astartes/main.py``. + +Development Philosophy +^^^^^^^^^^^^^^^^^^^^^^ + +The developers of ``astartes`` prioritize (1) reproducibility, (2) flexibility, and (3) maintainability. + + +#. All versions of ``astartes`` ``1.x`` should produce the same results across all platforms, so we have thorough unit and regression testing run on a continuous basis. +#. We specify as *few dependencies as possible* with the *loosest possible* dependency requirements, which allows integrating ``astartes`` with other tools more easily. + + * Dependencies which introduce a lot of requirements and/or specific versions of requirements are shuffled into the ``extras_require`` to avoid weighing down the main package. + * Compatibility with all versions of modern Python is achieved by not tightly specifying version numbers as well as by regression testing across all versions. + +#. We follow DRY (Don't Repeat Yourself) principles to avoid code duplication and decrease maintainence burden, have near-perfect test coverage, and enforce consistent formatting style in the source code. + + * Inline comments are *critical* for maintainability - at the time of writing, ``astartes`` has 1 comment line for every 2 lines of source code. + +JOSS Branch +----------- + +``astartes`` corresponding JOSS paper is stored in this repository on a separate branch. You can find ``paper.md`` on the aptly named ``joss-paper`` branch. + +*Note for Maintainers*\ : To push changes from the ``main`` branch into the ``joss-paper`` branch, run the ``Update JOSS Branch`` workflow. diff --git a/docs/README.doctree b/docs/README.doctree new file mode 100644 index 0000000000000000000000000000000000000000..dcd545cc6748a3d3987088d4e4f783985ef688a7 GIT binary patch literal 139336 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

%-KCvwaf&EZ=Ybnu~@7W1SretusSDOk8YaDKXF| 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

a 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 literal 0 HcmV?d00001 diff --git a/docs/README.html b/docs/README.html new file mode 100644 index 00000000..3520d85a --- /dev/null +++ b/docs/README.html @@ -0,0 +1,543 @@ + + + + + + + Online Documentation — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +

+ + +
+ +
+
+
+ +
+
+
+
+ +

astartes

+

(as-tar-tees)

+

Train:Validation:Test Algorithmic Sampling for Molecules and Arbitrary Arrays

+
:raw-html-m2r:`<p align=”center”>

<img alt=”astarteslogo” src=”https://raw.githubusercontent.com/JacksonBurns/astartes/main/astartes_logo.png”>

+
+
+

</p>`

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

Status Badges

UsageContinuous IntegrationRelease
PyPI - Python VersionReproduce PaperpyOpenSci approved
PyPI - LicenseTest StatusDOI
PyPI - Total DownloadsPyPI conda-forge version
GitHub Repo StarsProject Status: Active – The project has reached a stable, usable state and is being actively developed.
+
+

Online Documentation

+

Follow this link for a nicely-rendered version of this README along with additional tutorials for moving from train_test_split in sklearn to astartes. +Keep reading for a installation guide and links to tutorials!

+
+
+

Installing astartes

+

We recommend installing astartes within a virtual environment, using either venv or conda (or other tools) to simplify dependency management. Python versions 3.7, 3.8, 3.9, 3.10, 3.11, and 3.12 are supported on all platforms.

+
+

Warning +Windows (PowerShell) and MacOS Catalina or newer (zsh) require double quotes around text using the '[]' characters (i.e. pip install "astartes[molecules]").

+
+
+

pip

+

astartes is available on PyPI and can be installed using pip:

+
    +
  • To include the featurization options for chemical data, use pip install astartes[molecules].

  • +
  • To install only the sampling algorithms, use pip install astartes (this install will have fewer dependencies and may be more readily compatible in environments with existing workflows).

  • +
+
+
+

conda

+

astartes package is also available on conda-forge with this command: conda install -c conda-forge astartes. +To install astartes with support for featurizing molecules, use: conda install -c conda-forge astartes aimsim. +This will download the base astartes package as well as aimsim, which is the backend used for molecular featurization.

+
+
+

Source

+

To install astartes from source for development, see the Contributing & Developer Notes section.

+
+
+
+

Statement of Need

+

Machine learning has sparked an explosion of progress in chemical kinetics, materials science, and many other fields as researchers use data-driven methods to accelerate steps in traditional workflows within some acceptable error tolerance. +To facilitate adoption of these models, there are two important tasks to consider:

+
    +
  1. use a validation set when selecting the optimal hyperparameter for the model and separately use a held-out test set to measure performance on unseen data.

  2. +
  3. evaluate model performance on both interpolative and extrapolative tasks so future users are informed of any potential limitations.

  4. +
+

astartes addresses both of these points by implementing an sklearn-compatible train_val_test_split function. +Additional technical detail is provided below as well as in our companion paper in the Journal of Open Source Software: Machine Learning Validation via Rational Dataset Sampling with astartes. +For a demo-based explainer using machine learning on a fast food menu, see the astartes Reproducible Notebook published at the United States Research Software Engineers Conference at this page.

+
+

Target Audience

+

astartes is generally applicable to machine learning involving both discovery and inference and model validation. +There are specific functions in astartes for applications in cheminformatics (astartes.molecules) but the methods implemented are general to all numerical data.

+
+
+
+

Quick Start

+

astartes is designed as a drop-in replacement for sklearn‘s train_test_split function (see the sklearn documentation). To switch to astartes, change from sklearn.model_selection import train_test_split to from astartes import train_test_split.

+

Like sklearn, astartes accepts any iterable object as X, y, and labels. +Each will be converted to a numpy array for internal operations, and returned as a numpy array with limited exceptions: if X is a pandas DataFrame, y is a Series, or labels is a Series, astartes will cast it back to its original type including its index and column names.

+
+

Note +The developers recommend passing X, y, and labels as numpy arrays and handling the conversion to and from other types explicitly on your own. Behind-the-scenes type casting can lead to unexpected behavior!

+
+

By default, astartes will split data randomly. Additionally, a variety of algorithmic sampling approaches can be used by specifying the sampler argument to the function (see the Table of Implemented Samplers for a complete list of options and their corresponding references):

+
from sklearn.datasets import load_diabetes
+
+X, y = load_diabetes(return_X_y=True)
+
+X_train, X_test, y_train, y_test = train_test_split(
+  X,  # preferably numpy arrays, but astartes will cast it for you
+  y,
+  sampler = 'kennard_stone',  # any of the supported samplers
+)
+
+
+
+

Note +Extrapolation sampling algorithms will return an additional set of arrays (the cluster labels) which will result in a ValueError: too many values to unpack if not called properly. See the ``split_comparisons` Google colab demo <https://colab.research.google.com/github/JacksonBurns/astartes/blob/main/examples/split_comparisons/split_comparisons.ipynb>`_ for a full explanation.

+
+

That’s all you need to get started with astartes! +The next sections include more examples and some demo notebooks you can try in your browser.

+
+

Example Notebooks

+

Click the badges in the table below to be taken to a live, interactive demo of astartes:

+

To execute these notebooks locally, clone this repository (i.e. git clone https://github.com/JacksonBurns/astartes.git), navigate to the astartes directory, run pip install .[demos], then open and run the notebooks in your preferred editor. +You do not need to execute the cells prefixed with %%capture - they are only present for compatibility with Google Colab.

+
+
+

Withhold Testing Data with train_val_test_split

+

For rigorous ML research, it is critical to withhold some data during training to use a test set. +The model should never see this data during training (unlike the validation set) so that we can get an accurate measurement of its performance.

+

With astartes performing this three-way data split is readily available with train_val_test_split:

+
from astartes import train_val_test_split
+
+X_train, X_val, X_test = train_val_test_split(X, sampler = 'sphere_exclusion')
+
+
+

You can now train your model with X_train, optimize your model with X_val, and measure its performance with X_test.

+
+
+

Evaluate the Impact of Splitting Algorithms on Regression Models

+

For data with many features it can be difficult to visualize how different sampling algorithms change the distribution of data into training, validation, and testing like we do in some of the demo notebooks. +To aid in analyzing the impact of the algorithms, astartes provides generate_regression_results_dict. +This function allows users to quickly evaluate the impact of different splitting techniques on any sklearn-compatible model’s performance. +All results are stored in a nested dictionary ({sampler:{metric:{split:score}}}) format and can be displayed in a neatly formatted table using the optional print_results argument.

+
from sklearn.svm import LinearSVR
+
+from astartes.utils import generate_regression_results_dict as grrd
+
+sklearn_model = LinearSVR()
+results_dict = grrd(
+    sklearn_model,
+    X,
+    y,
+    print_results=True,
+)
+
+         Train       Val      Test
+----  --------  --------  --------
+MAE   1.41522   3.13435   2.17091
+RMSE  2.03062   3.73721   2.40041
+R2    0.90745   0.80787   0.78412
+
+
+

Additional metrics can be passed to generate_regression_results_dict via the additional_metrics argument, which should be a dictionary mapping the name of the metric (as a string) to the function itself, like this:

+
from sklearn.metrics import mean_absolute_percentage_error
+
+add_met = {"mape": mean_absolute_percentage_error}
+
+grrd(sklearn_model, X, y, additional_metric=add_met)
+
+
+

See the docstring for generate_regression_results_dict (with help(generate_regression_results_dict)) for more information.

+
+
+

Using astartes with Categorical Data

+

Any of the implemented sampling algorithms whose hyperparameters allow specifying the metric or distance_metric (effectively 1-metric) can be co-opted to work with categorical data. +Simply encode the data in a format compatible with the sklearn metric of choice and then call astartes with that metric specified:

+
from sklearn.metrics import jaccard_score
+
+X_train, X_test, y_train, y_test = train_test_split(
+  X,
+  y,
+  sampler='kennard_stone',
+  hopts={"metric": jaccard_score},
+)
+
+
+

Other samplers which do not allow specifying a categorical distance metric did not provide a method for doing so in their original inception, though it is possible that they can be adapted for this application. +If you are interested in adding support for categorical metrics to an existing sampler, consider opening a Feature Request!

+
+
+

Access Sampling Algorithms Directly

+

The sampling algorithms implemented in astartes can also be directly accessed and run if it is more useful for your applications. +In the below example, we import the Kennard Stone sampler, use it to partition a simple array, and then retrieve a sample.

+
from astartes.samplers.interpolation import KennardStone
+
+kennard_stone = KennardStone([[1, 2], [3, 4], [5, 6]])
+first_2_samples = kennard_stone.get_sample_idxs(2)
+
+
+

All samplers in astartes implement a _sample() method that is called by the constructor (i.e. greedily) and either a get_sampler_idxs or get_cluster_idxs for interpolative and extrapolative samplers, respectively. +For more detail on the implementaiton and design of samplers in astartes, see the Developer Notes section.

+
+
+
+

Theory and Application of astartes

+

This section of the README details some of the theory behind why the algorithms implemented in astartes are important and some motivating examples. +For a comprehensive walkthrough of the theory and implementation of astartes, follow this link to read the companion paper (freely available and hosted here on GitHub).

+
+

Note +We reference open-access publications wherever possible. For articles locked behind a paywall (denoted with :small_blue_diamond:), we instead suggest reading this Wikipedia page and absolutely not attempting to bypass the paywall.

+
+
+

Rational Splitting Algorithms

+

While much machine learning is done with a random choice between training/validation/test data, an alternative is the use of so-called “rational” splitting algorithms. +These approaches use some similarity-based algorithm to divide data into sets. +Some of these algorithms include Kennard-Stone (Kennard & Stone :small_blue_diamond:), Sphere Exclusion (Tropsha et. al :small_blue_diamond:),as well as the OptiSim as discussed in Applied Chemoinformatics: Achievements and Future Opportunities :small_blue_diamond:. +Some clustering-based splitting techniques have also been incorporated, such as DBSCAN.

+

There are two broad categories of sampling algorithms implemented in astartes: extrapolative and interpolative. +The former will force your model to predict on out-of-sample data, which creates a more challenging task than interpolative sampling. +See the table below for all of the sampling approaches currently implemented in astartes, as well as the hyperparameters that each algorithm accepts (which are passed in with hopts) and a helpful reference for understanding how the hyperparameters work. +Note that random_state is defined as a keyword argument in train_test_split itself, even though these algorithms will use the random_state in their own work. +Do not provide a random_state in the hopts dictionary - it will be overwritten by the random_state you provide for train_test_split (or the default if none is provided).

+
+

Implemented Sampling Algorithms

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Sampler Name

Usage String

Type

Hyperparameters

Reference

Notes

Random

‘random’

Interpolative

shuffle

sklearn train_test_split Documentation

This sampler is a direct passthrough to sklearn‘s train_test_split.

Kennard-Stone

‘kennard_stone’

Interpolative

metric

Original Paper by Kennard & Stone :small_blue_diamond:

Euclidian distance is used by default, as described in the original paper.

Sample set Partitioning based on joint X-Y distances (SPXY)

‘spxy’

Interpolative

distance_metric

Saldhana et. al original paper :small_blue_diamond:

Extension of Kennard Stone that also includes the response when sampling distances.

Mahalanobis Distance Kennard Stone (MDKS)

‘spxy’ (MDKS is derived from SPXY)

Interpolative

none, see Notes

Saptoro et. al original paper

MDKS is SPXY using Mahalanobis distance and can be called by using SPXY with distance_metric="mahalanobis"

Scaffold

‘scaffold’

Extrapolative

include_chirality

Bemis-Murcko Scaffold :small_blue_diamond: as implemented in RDKit

This sampler requires SMILES strings as input (use the molecules subpackage)

Sphere Exclusion

‘sphere_exclusion’

Extrapolative

metric, distance_cutoff

custom implementation

Variation on Sphere Exclusion for arbitrary-valued vectors.

Time Based

‘time_based’

Extrapolative

none

Papers using Time based splitting: Chen et al. :small_blue_diamond:, Sheridan, R. P :small_blue_diamond:, Feinberg et al. :small_blue_diamond:, Struble et al.

This sampler requires labels to be an iterable of either date or datetime objects.

Optimizable K-Dissimilarity Selection (OptiSim)

‘optisim’

Extrapolative

n_clusters, max_subsample_size, distance_cutoff

custom implementation

Variation on OptiSim for arbitrary-valued vectors.

K-Means

‘kmeans’

Extrapolative

n_clusters, n_init

``sklearn KMeans` <https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html>`_

Passthrough to sklearn‘s KMeans.

Density-Based Spatial Clustering of Applications with Noise (DBSCAN)

‘dbscan’

Extrapolative

eps, min_samples, algorithm, metric, leaf_size

``sklearn DBSCAN` <https://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html>`_ Documentation

Passthrough to sklearn‘s DBSCAN.

Minimum Test Set Dissimilarity (MTSD)

~

~

upcoming in astartes v1.x

~

~

Restricted Boltzmann Machine (RBM)

~

~

upcoming in astartes v1.x

~

~

Kohonen Self-Organizing Map (SOM)

~

~

upcoming in astartes v1.x

~

~

SPlit Method

~

~

upcoming in astartes v1.x

~

~

+
+
+
+

Domain-Specific Applications

+

Below are some field specific applications of astartes. Interested in adding a new sampling algorithm or featurization approach? See ``CONTRIBUTING.md` <./CONTRIBUTING.md>`_.

+
+

Chemical Data and the astartes.molecules Subpackage

+

Machine Learning is enormously useful in chemistry-related fields due to the high-dimensional feature space of chemical data. +To properly apply ML to chemical data for inference or discovery, it is important to know a model’s accuracy under the two domains. +To simplify the process of partitioning chemical data, astartes implements a pre-built featurizer for common chemistry data formats. +After installing with pip install astartes[molecules] one can import the new train/test splitting function like this: from astartes.molecules import train_test_split_molecules

+

The usage of this function is identical to train_test_split but with the addition of new arguments to control how the molecules are featurized:

+
train_test_split_molecules(
+    molecules=smiles,
+    y=y,
+    test_size=0.2,
+    train_size=0.8,
+    fingerprint="daylight_fingerprint",
+    fprints_hopts={
+        "minPath": 2,
+        "maxPath": 5,
+        "fpSize": 200,
+        "bitsPerHash": 4,
+        "useHs": 1,
+        "tgtDensity": 0.4,
+        "minSize": 64,
+    },
+    sampler="random",
+    random_state=42,
+    hopts={
+        "shuffle": True,
+    },
+)
+
+
+

To see a complete example of using train_test_split_molecules with actual chemical data, take a look in the examples directory and the brief companion paper.

+

Configuration options for the featurization scheme can be found in the documentation for AIMSim though most of the critical configuration options are shown above.

+
+
+
+
+

Reproducibility

+

astartes aims to be completely reproducible across different platforms, Python versions, and dependency configurations - any version of astartes v1.x should result in the exact same splits, always. +To that end, the default behavior of astartes is to use 42 as the random seed and always set it. +Running astartes with the default settings will always produce the exact same results. +We have verified this behavior on Debian Ubuntu, Windows, and Intel Macs from Python versions 3.7 through 3.11 (with appropriate dependencies for each version).

+
+

Known Reproducibility Limitations

+

Inevitably external dependencies of astartes will introduce backwards-incompatible changes. +We continually run regression tests to catch these, and will list all known limitations here:

+
    +
  • sklearn v1.3.0 introduced backwards-incompatible changes in the KMeans sampler that changed how the random initialization affects the results, even given the same random seed. Different version of sklearn will affect the performance of astartes and we recommend including the exact version of scikit-learn and astartes used, when applicable.

  • +
+
+

Note +We are limited in our ability to test on M1 Macs, but from our limited manual testing we achieve perfect reproducbility in all cases except occasionally with KMeans on Apple silicon. +astartes is still consistent between runs on the same platform in all cases, and other samplers are not impacted by this apparent bug.

+
+
+
+
+

How to Cite

+

If you use astartes in your work please follow the link below to our (Open Access!) paper in the Journal of Open Source Software or use the “Cite this repository” button on GitHub.

+

Machine Learning Validation via Rational Dataset Sampling with astartes

+
+
+

Contributing & Developer Notes

+

See CONTRIBUTING.md for instructions on installing astartes for development, making a contribution, and general guidance on the design of astartes.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/README.rst b/docs/README.rst new file mode 100644 index 00000000..cda047e5 --- /dev/null +++ b/docs/README.rst @@ -0,0 +1,486 @@ +.. role:: raw-html-m2r(raw) + :format: html + + +:raw-html-m2r:`

astartes

` + +:raw-html-m2r:`

(as-tar-tees)

` + + +.. raw:: html + +

Train:Validation:Test Algorithmic Sampling for Molecules and Arbitrary Arrays

+ + +:raw-html-m2r:`

+ astarteslogo +

` + + +.. raw:: html + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

Status Badges

UsageContinuous IntegrationRelease
PyPI - Python VersionReproduce PaperpyOpenSci approved
PyPI - LicenseTest StatusDOI
PyPI - Total DownloadsPyPI conda-forge version
GitHub Repo StarsProject Status: Active – The project has reached a stable, usable state and is being actively developed.
+
+ + +Online Documentation +-------------------- + +Follow `this link `_ for a nicely-rendered version of this README along with additional tutorials for `moving from train_test_split in sklearn to astartes `_. +Keep reading for a installation guide and links to tutorials! + +Installing ``astartes`` +--------------------------- + +We recommend installing ``astartes`` within a virtual environment, using either ``venv`` or ``conda`` (or other tools) to simplify dependency management. Python versions 3.7, 3.8, 3.9, 3.10, 3.11, and 3.12 are supported on all platforms. + +.. + + **Warning** + Windows (PowerShell) and MacOS Catalina or newer (zsh) require double quotes around text using the ``'[]'`` characters (i.e. ``pip install "astartes[molecules]"``\ ). + + +``pip`` +^^^^^^^^^^^ + +``astartes`` is available on ``PyPI`` and can be installed using ``pip``\ : + + +* To include the featurization options for chemical data, use ``pip install astartes[molecules]``. +* To install only the sampling algorithms, use ``pip install astartes`` (this install will have fewer dependencies and may be more readily compatible in environments with existing workflows). + +``conda`` +^^^^^^^^^^^^^ + +``astartes`` package is also available on ``conda-forge`` with this command: ``conda install -c conda-forge astartes``. +To install ``astartes`` with support for featurizing molecules, use: ``conda install -c conda-forge astartes aimsim``. +This will download the base ``astartes`` package as well as ``aimsim``\ , which is the backend used for molecular featurization. + +Source +^^^^^^ + +To install ``astartes`` from source for development, see the `Contributing & Developer Notes <#contributing--developer-notes>`_ section. + +Statement of Need +----------------- + +Machine learning has sparked an explosion of progress in chemical kinetics, materials science, and many other fields as researchers use data-driven methods to accelerate steps in traditional workflows within some acceptable error tolerance. +To facilitate adoption of these models, there are two important tasks to consider: + + +#. use a validation set when selecting the optimal hyperparameter for the model and separately use a held-out test set to measure performance on unseen data. +#. evaluate model performance on both interpolative and extrapolative tasks so future users are informed of any potential limitations. + +``astartes`` addresses both of these points by implementing an ``sklearn``\ -compatible ``train_val_test_split`` function. +Additional technical detail is provided below as well as in our companion paper in the Journal of Open Source Software: `Machine Learning Validation via Rational Dataset Sampling with astartes `_. +For a demo-based explainer using machine learning on a fast food menu, see the ``astartes`` Reproducible Notebook published at the United States Research Software Engineers Conference at `this page `_. + +Target Audience +^^^^^^^^^^^^^^^ + +``astartes`` is generally applicable to machine learning involving both discovery and inference *and* model validation. +There are specific functions in ``astartes`` for applications in cheminformatics (\ ``astartes.molecules``\ ) but the methods implemented are general to all numerical data. + +Quick Start +----------- + +``astartes`` is designed as a drop-in replacement for ``sklearn``\ 's ``train_test_split`` function (see the `sklearn documentation `_\ ). To switch to ``astartes``\ , change ``from sklearn.model_selection import train_test_split`` to ``from astartes import train_test_split``. + +Like ``sklearn``\ , ``astartes`` accepts any iterable object as ``X``\ , ``y``\ , and ``labels``. +Each will be converted to a ``numpy`` array for internal operations, and returned as a ``numpy`` array with limited exceptions: if ``X`` is a ``pandas`` ``DataFrame``\ , ``y`` is a ``Series``\ , or ``labels`` is a ``Series``\ , ``astartes`` will cast it back to its original type including its index and column names. + +.. + + **Note** + The developers recommend passing ``X``\ , ``y``\ , and ``labels`` as ``numpy`` arrays and handling the conversion to and from other types explicitly on your own. Behind-the-scenes type casting can lead to unexpected behavior! + + +By default, ``astartes`` will split data randomly. Additionally, a variety of algorithmic sampling approaches can be used by specifying the ``sampler`` argument to the function (see the `Table of Implemented Samplers <#implemented-sampling-algorithms>`_ for a complete list of options and their corresponding references): + +.. code-block:: python + + from sklearn.datasets import load_diabetes + + X, y = load_diabetes(return_X_y=True) + + X_train, X_test, y_train, y_test = train_test_split( + X, # preferably numpy arrays, but astartes will cast it for you + y, + sampler = 'kennard_stone', # any of the supported samplers + ) + +.. + + **Note** + Extrapolation sampling algorithms will return an additional set of arrays (the cluster labels) which will result in a ``ValueError: too many values to unpack`` if not called properly. See the `\ ``split_comparisons`` Google colab demo `_ for a full explanation. + + +That's all you need to get started with ``astartes``\ ! +The next sections include more examples and some demo notebooks you can try in your browser. + +Example Notebooks +^^^^^^^^^^^^^^^^^ + +Click the badges in the table below to be taken to a live, interactive demo of ``astartes``\ : + +.. list-table:: + :header-rows: 1 + + * - Demo + - Topic + - Link + * - Comparing Sampling Algorithms with Fast Food + - Visual representations of how different samplers affect data partitioning + - + .. image:: https://colab.research.google.com/assets/colab-badge.svg + :target: https://colab.research.google.com/github/JacksonBurns/astartes/blob/main/examples/split_comparisons/split_comparisons.ipynb + :alt: Colab + + * - Using ``train_val_test_split`` with the ``sklearn`` example datasets + - Demonstrating how witholding a test set with ``train_val_test_split`` can impact performance + - + .. image:: https://colab.research.google.com/assets/colab-badge.svg + :target: https://colab.research.google.com/github/JacksonBurns/astartes/blob/main/examples/train_val_test_split_sklearn_example/train_val_test_split_example.ipynb + :alt: Colab + + * - Cheminformatics sample set partitioning with ``astartes`` + - Extrapolation vs. Interpolation impact on cheminformatics model accuracy + - + .. image:: https://colab.research.google.com/assets/colab-badge.svg + :target: https://colab.research.google.com/github/JacksonBurns/astartes/blob/main/examples/barrier_prediction_with_RDB7/RDB7_barrier_prediction_example.ipynb + :alt: Colab + + * - Comparing partitioning approaches for alkanes + - Visualizing how sampler impact model performance with simple chemicals + - + .. image:: https://colab.research.google.com/assets/colab-badge.svg + :target: https://colab.research.google.com/github/JacksonBurns/astartes/blob/main/examples/mlpds_2023_astartes_demonstration/mlpds_2023_demo.ipynb + :alt: Colab + + + +To execute these notebooks locally, clone this repository (i.e. ``git clone https://github.com/JacksonBurns/astartes.git``\ ), navigate to the ``astartes`` directory, run ``pip install .[demos]``\ , then open and run the notebooks in your preferred editor. +You do *not* need to execute the cells prefixed with ``%%capture`` - they are only present for compatibility with Google Colab. + +Withhold Testing Data with ``train_val_test_split`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For rigorous ML research, it is critical to withhold some data during training to use a ``test`` set. +The model should *never* see this data during training (unlike the validation set) so that we can get an accurate measurement of its performance. + +With ``astartes`` performing this three-way data split is readily available with ``train_val_test_split``\ : + +.. code-block:: python + + from astartes import train_val_test_split + + X_train, X_val, X_test = train_val_test_split(X, sampler = 'sphere_exclusion') + +You can now train your model with ``X_train``\ , optimize your model with ``X_val``\ , and measure its performance with ``X_test``. + +Evaluate the Impact of Splitting Algorithms on Regression Models +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For data with many features it can be difficult to visualize how different sampling algorithms change the distribution of data into training, validation, and testing like we do in some of the demo notebooks. +To aid in analyzing the impact of the algorithms, ``astartes`` provides ``generate_regression_results_dict``. +This function allows users to quickly evaluate the impact of different splitting techniques on any ``sklearn``\ -compatible model's performance. +All results are stored in a nested dictionary (\ ``{sampler:{metric:{split:score}}}``\ ) format and can be displayed in a neatly formatted table using the optional ``print_results`` argument. + +.. code-block:: python + + from sklearn.svm import LinearSVR + + from astartes.utils import generate_regression_results_dict as grrd + + sklearn_model = LinearSVR() + results_dict = grrd( + sklearn_model, + X, + y, + print_results=True, + ) + + Train Val Test + ---- -------- -------- -------- + MAE 1.41522 3.13435 2.17091 + RMSE 2.03062 3.73721 2.40041 + R2 0.90745 0.80787 0.78412 + +Additional metrics can be passed to ``generate_regression_results_dict`` via the ``additional_metrics`` argument, which should be a dictionary mapping the name of the metric (as a ``string``\ ) to the function itself, like this: + +.. code-block:: python + + from sklearn.metrics import mean_absolute_percentage_error + + add_met = {"mape": mean_absolute_percentage_error} + + grrd(sklearn_model, X, y, additional_metric=add_met) + +See the docstring for ``generate_regression_results_dict`` (with ``help(generate_regression_results_dict)``\ ) for more information. + +Using ``astartes`` with Categorical Data +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Any of the implemented sampling algorithms whose hyperparameters allow specifying the ``metric`` or ``distance_metric`` (effectively ``1-metric``\ ) can be co-opted to work with categorical data. +Simply encode the data in a format compatible with the ``sklearn`` metric of choice and then call ``astartes`` with that metric specified: + +.. code-block:: python + + from sklearn.metrics import jaccard_score + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + sampler='kennard_stone', + hopts={"metric": jaccard_score}, + ) + +Other samplers which do not allow specifying a categorical distance metric did not provide a method for doing so in their original inception, though it is possible that they can be adapted for this application. +If you are interested in adding support for categorical metrics to an existing sampler, consider opening a `Feature Request `_\ ! + +Access Sampling Algorithms Directly +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The sampling algorithms implemented in ``astartes`` can also be directly accessed and run if it is more useful for your applications. +In the below example, we import the Kennard Stone sampler, use it to partition a simple array, and then retrieve a sample. + +.. code-block:: python + + from astartes.samplers.interpolation import KennardStone + + kennard_stone = KennardStone([[1, 2], [3, 4], [5, 6]]) + first_2_samples = kennard_stone.get_sample_idxs(2) + +All samplers in ``astartes`` implement a ``_sample()`` method that is called by the constructor (i.e. greedily) and either a ``get_sampler_idxs`` or ``get_cluster_idxs`` for interpolative and extrapolative samplers, respectively. +For more detail on the implementaiton and design of samplers in ``astartes``\ , see the `Developer Notes <#contributing--developer-notes>`_ section. + +Theory and Application of ``astartes`` +------------------------------------------ + +This section of the README details some of the theory behind why the algorithms implemented in ``astartes`` are important and some motivating examples. +For a comprehensive walkthrough of the theory and implementation of ``astartes``\ , follow `this link `_ to read the companion paper (freely available and hosted here on GitHub). + +.. + + **Note** + We reference open-access publications wherever possible. For articles locked behind a paywall (denoted with :small_blue_diamond:), we instead suggest reading `this Wikipedia page `_ and absolutely **not** attempting to bypass the paywall. + + +Rational Splitting Algorithms +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +While much machine learning is done with a random choice between training/validation/test data, an alternative is the use of so-called "rational" splitting algorithms. +These approaches use some similarity-based algorithm to divide data into sets. +Some of these algorithms include Kennard-Stone (\ `Kennard & Stone `_ :small_blue_diamond:), Sphere Exclusion (\ `Tropsha et. al `_ :small_blue_diamond:),as well as the OptiSim as discussed in `Applied Chemoinformatics: Achievements and Future Opportunities `_ :small_blue_diamond:. +Some clustering-based splitting techniques have also been incorporated, such as `DBSCAN `_. + +There are two broad categories of sampling algorithms implemented in ``astartes``\ : extrapolative and interpolative. +The former will force your model to predict on out-of-sample data, which creates a more challenging task than interpolative sampling. +See the table below for all of the sampling approaches currently implemented in ``astartes``\ , as well as the hyperparameters that each algorithm accepts (which are passed in with ``hopts``\ ) and a helpful reference for understanding how the hyperparameters work. +Note that ``random_state`` is defined as a keyword argument in ``train_test_split`` itself, even though these algorithms will use the ``random_state`` in their own work. +Do not provide a ``random_state`` in the ``hopts`` dictionary - it will be overwritten by the ``random_state`` you provide for ``train_test_split`` (or the default if none is provided). + +Implemented Sampling Algorithms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :header-rows: 1 + + * - Sampler Name + - Usage String + - Type + - Hyperparameters + - Reference + - Notes + * - Random + - 'random' + - Interpolative + - ``shuffle`` + - `sklearn train_test_split `_ Documentation + - This sampler is a direct passthrough to ``sklearn``\ 's ``train_test_split``. + * - Kennard-Stone + - 'kennard_stone' + - Interpolative + - ``metric`` + - Original Paper by `Kennard & Stone `_ :small_blue_diamond: + - Euclidian distance is used by default, as described in the original paper. + * - Sample set Partitioning based on joint X-Y distances (SPXY) + - 'spxy' + - Interpolative + - ``distance_metric`` + - Saldhana et. al `original paper `_ :small_blue_diamond: + - Extension of Kennard Stone that also includes the response when sampling distances. + * - Mahalanobis Distance Kennard Stone (MDKS) + - 'spxy' *(MDKS is derived from SPXY)* + - Interpolative + - *none, see Notes* + - Saptoro et. al `original paper `_ + - MDKS is SPXY using Mahalanobis distance and can be called by using SPXY with ``distance_metric="mahalanobis"`` + * - Scaffold + - 'scaffold' + - Extrapolative + - ``include_chirality`` + - `Bemis-Murcko Scaffold `_ :small_blue_diamond: as implemented in RDKit + - This sampler requires SMILES strings as input (use the ``molecules`` subpackage) + * - Sphere Exclusion + - 'sphere_exclusion' + - Extrapolative + - ``metric``\ , ``distance_cutoff`` + - *custom implementation* + - Variation on Sphere Exclusion for arbitrary-valued vectors. + * - Time Based + - 'time_based' + - Extrapolative + - *none* + - Papers using Time based splitting: `Chen et al. `_ :small_blue_diamond:, `Sheridan, R. P `_ :small_blue_diamond:, `Feinberg et al. `_ :small_blue_diamond:, `Struble et al. `_ + - This sampler requires ``labels`` to be an iterable of either date or datetime objects. + * - Optimizable K-Dissimilarity Selection (OptiSim) + - 'optisim' + - Extrapolative + - ``n_clusters``\ , ``max_subsample_size``\ , ``distance_cutoff`` + - *custom implementation* + - Variation on `OptiSim `_ for arbitrary-valued vectors. + * - K-Means + - 'kmeans' + - Extrapolative + - ``n_clusters``\ , ``n_init`` + - `\ ``sklearn KMeans`` `_ + - Passthrough to ``sklearn``\ 's ``KMeans``. + * - Density-Based Spatial Clustering of Applications with Noise (DBSCAN) + - 'dbscan' + - Extrapolative + - ``eps``\ , ``min_samples``\ , ``algorithm``\ , ``metric``\ , ``leaf_size`` + - `\ ``sklearn DBSCAN`` `_ Documentation + - Passthrough to ``sklearn``\ 's ``DBSCAN``. + * - Minimum Test Set Dissimilarity (MTSD) + - ~ + - ~ + - *upcoming in* ``astartes`` *v1.x* + - ~ + - ~ + * - Restricted Boltzmann Machine (RBM) + - ~ + - ~ + - *upcoming in* ``astartes`` *v1.x* + - ~ + - ~ + * - Kohonen Self-Organizing Map (SOM) + - ~ + - ~ + - *upcoming in* ``astartes`` *v1.x* + - ~ + - ~ + * - SPlit Method + - ~ + - ~ + - *upcoming in* ``astartes`` *v1.x* + - ~ + - ~ + + +Domain-Specific Applications +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Below are some field specific applications of ``astartes``. Interested in adding a new sampling algorithm or featurization approach? See `\ ``CONTRIBUTING.md`` <./CONTRIBUTING.md>`_. + +Chemical Data and the ``astartes.molecules`` Subpackage +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Machine Learning is enormously useful in chemistry-related fields due to the high-dimensional feature space of chemical data. +To properly apply ML to chemical data for inference *or* discovery, it is important to know a model's accuracy under the two domains. +To simplify the process of partitioning chemical data, ``astartes`` implements a pre-built featurizer for common chemistry data formats. +After installing with ``pip install astartes[molecules]`` one can import the new train/test splitting function like this: ``from astartes.molecules import train_test_split_molecules`` + +The usage of this function is identical to ``train_test_split`` but with the addition of new arguments to control how the molecules are featurized: + +.. code-block:: python + + train_test_split_molecules( + molecules=smiles, + y=y, + test_size=0.2, + train_size=0.8, + fingerprint="daylight_fingerprint", + fprints_hopts={ + "minPath": 2, + "maxPath": 5, + "fpSize": 200, + "bitsPerHash": 4, + "useHs": 1, + "tgtDensity": 0.4, + "minSize": 64, + }, + sampler="random", + random_state=42, + hopts={ + "shuffle": True, + }, + ) + +To see a complete example of using ``train_test_split_molecules`` with actual chemical data, take a look in the ``examples`` directory and the brief `companion paper `_. + +Configuration options for the featurization scheme can be found in the documentation for `AIMSim `_ though most of the critical configuration options are shown above. + +Reproducibility +--------------- + +``astartes`` aims to be completely reproducible across different platforms, Python versions, and dependency configurations - any version of ``astartes`` v1.x should result in the *exact* same splits, always. +To that end, the default behavior of ``astartes`` is to use ``42`` as the random seed and *always* set it. +Running ``astartes`` with the default settings will always produce the exact same results. +We have verified this behavior on Debian Ubuntu, Windows, and Intel Macs from Python versions 3.7 through 3.11 (with appropriate dependencies for each version). + +Known Reproducibility Limitations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Inevitably external dependencies of ``astartes`` will introduce backwards-incompatible changes. +We continually run regression tests to catch these, and will list all *known* limitations here: + + +* ``sklearn`` v1.3.0 introduced backwards-incompatible changes in the ``KMeans`` sampler that changed how the random initialization affects the results, even given the same random seed. Different version of ``sklearn`` will affect the performance of ``astartes`` and we recommend including the exact version of ``scikit-learn`` and ``astartes`` used, when applicable. + +.. + + **Note** + We are limited in our ability to test on M1 Macs, but from our limited manual testing we achieve perfect reproducbility in all cases *except occasionally* with ``KMeans`` on Apple silicon. + ``astartes`` is still consistent between runs on the same platform in all cases, and other samplers are not impacted by this apparent bug. + + +How to Cite +----------- + +If you use ``astartes`` in your work please follow the link below to our (Open Access!) paper in the Journal of Open Source Software or use the "Cite this repository" button on GitHub. + +`Machine Learning Validation via Rational Dataset Sampling with astartes `_ + +Contributing & Developer Notes +------------------------------ + +See `CONTRIBUTING.md <./CONTRIBUTING.md>`_ for instructions on installing ``astartes`` for development, making a contribution, and general guidance on the design of ``astartes``. diff --git a/docs/_sources/CONTRIBUTING.rst.txt b/docs/_sources/CONTRIBUTING.rst.txt new file mode 100644 index 00000000..677944a2 --- /dev/null +++ b/docs/_sources/CONTRIBUTING.rst.txt @@ -0,0 +1,143 @@ + +Contributing & Developer Notes +------------------------------ + +Pull Requests, Bug Reports, and all Contributions are welcome, encouraged, and appreciated! +Please use the appropriate `issue `_ or `pull request `_ template when making a contribution to help the maintainers get it merged quickly. + +We make use of `the GitHub Discussions page `_ to go over potential features to add. +Please feel free to stop by if you are looking for something to develop or have an idea for a useful feature! + +When submitting a PR, please mark your PR with the "PR Ready for Review" label when you are finished making changes so that the GitHub actions bots can work their magic! + +Developer Install +^^^^^^^^^^^^^^^^^ + +To contribute to the ``astartes`` source code, start by forking and then cloning the repository (i.e. ``git clone git@github.com:YourUsername/astartes.git``\ ) and then inside the repository run ``pip install -e .[dev]``. This will set you up with all the required dependencies to run ``astartes`` and conform to our formatting standards (\ ``black`` and ``isort``\ ), which you can configure to run automatically in VSCode `like this `_. + +.. + + **Warning** + Windows (PowerShell) and MacOS Catalina or newer (zsh) require double quotes around the ``[]`` characters (i.e. ``pip install "astartes[dev]"``\ ) + + +Version Checking +^^^^^^^^^^^^^^^^ + +``astartes`` uses ``pyproject.toml`` to specify all metadata, but the version is also specified in ``astartes/__init__.py`` (via ``__version__``\ ) for backwards compatibility with Python 3.7. +To check which version of ``astartes`` you have installed, you can run ``python -c "import astartes; print(astartes.__version__)"`` on Python 3.7 or `python -c "from importlib.metadata import version; version('astartes')" on Python 3.8 or newer. + +Testing +^^^^^^^ + +All of the tests in ``astartes`` are written using the built-in python ``unittest`` module (to allow running without ``pytest``\ ) but we *highly* recommend using ``pytest``. +To execute the tests from the ``astartes`` repository, simply type ``pytest`` after running the developer install (or alternately, ``pytest -v`` for a more helpful output). +On GitHub, we use actions to run the tests on every Pull Request and on a nightly basis (look in ``.github/workflows`` for more information). +These tests include unit tests, functional tests, and regression tests. + +Adding New Samplers +^^^^^^^^^^^^^^^^^^^ + +Adding a new sampler should extend the ``abstract_sampler.py`` abstract base class. +Each subclass should override the ``_sample`` method with its own algorithm for data partitioning and optionally the ``_before_sample`` method to perform any data validation. + +All samplers in ``astartes`` are classified as one of two types: extrapolative or interpolative. +Extrapolative samplers work by clustering data into groups (which are then partitioned into train/validation/test to enforce extrapolation) whereas interpolative samplers provide an exact *order* in which samples should be moved into the training set. + +When actually implemented, this means that extrapolative samplers should set the ``self._samples_clusters`` attribute and interpolative samplers should set the ``self._samples_idxs`` attribute. + +New samplers can be as simple as a passthrough to another ``train_test_split``\ , or it can be an original implementation that results in X and y being split into two lists. Take a look at ``astartes/samplers/interpolation/random_split.py`` for a basic example! + +After the sampler has been implemented, add it to ``__init__.py`` in in ``astartes/samplers`` and it will automatically be unit tested. Additional unit tests to verify that hyperparameters can be properly passed, etc. are also recommended. + +For historical reasons, and as a guide for any developers who would like add new samplers, below is a running list of samplers which have been *considered* for addition to ``asartes`` but ultimately not added for various reasons. + +Not Implemented Sampling Algorithms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :header-rows: 1 + + * - Sampler Name + - Reasoning + - Relevant Link(s) + * - D-Optimal + - Requires *a-priori* knowledge of the test and train size which does not fit in the ``astartes`` framework (samplers are all agnostic to the size of the sets) and it is questionable if the use of the Fischer information matrix is actually meaningful in the context of sampling existing data rather than tuning for ideal data. + - The `Wikipedia article for optimal design `_ does a good job explaining why this is difficult, and points at some potential alternatives. + * - Duplex + - Requires knowing test and train size before execution, and can only partition data into two sets which would make it incompatible with ``train_val_test_split``. + - This `implementation in R `_ includes helpful references and a reference implementation. + + +Adding New Featurization Schemes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +All of the sampling methods implemented in ``astartes`` accept arbitrary arrays of numbers and return the sampled groups (with the exception of ``Scaffold.py``\ ). If you have an existing featurization scheme (i.e. take an arbitrary input and turn it into an array of numbers), we would be thrilled to include it in ``astartes``. + +Adding a new interface should take on this format: + +.. code-block:: python + + from astartes import train_test_split + + def train_test_split_INTERFACE( + INTERFACE_input, + INTERFACE_ARGS, + y: np.array = None, + labels: np.array = None, + test_size: float = 0.25, + train_size: float = 0.75, + splitter: str = 'random', + hopts: dict = {}, + INTERFACE_hopts: dict = {}, + ): + # turn the INTERFACE_input into an input X + # based on INTERFACE ARGS where INTERFACE_hopts + # specifies additional behavior + X = [] + + # call train test split with this input + return train_test_split( + X, + y=y, + labels=labels, + test_size=test_size, + train_size=train_size, + splitter=splitter, + hopts=hopts, + ) + +If possible, we would like to also add an example Jupyter Notebook with any new interface to demonstrate to new users how it functions. See our other examples in the ``examples`` directory. + +Contact `@JacksonBurns `_ if you need assistance adding an existing workflow to ``astartes``. If this featurization scheme requires additional dependencies to function, we may add it as an additional *extra* package in the same way that ``molecules`` in installed. + +The ``train_val_test_split`` Function +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``train_val_test_split`` is the workhorse function of ``astartes``. +It is responsible for instantiating the sampling algorithm, partitioning the data into training, validation, and testing, and then returning the requested results while also keeping an eye on data types. +Under the hood, ``train_test_split`` is just calling ``train_val_test_split`` with ``val_size`` set to ``0.0``. +For more information on how it works, check out the inline documentation in ``astartes/main.py``. + +Development Philosophy +^^^^^^^^^^^^^^^^^^^^^^ + +The developers of ``astartes`` prioritize (1) reproducibility, (2) flexibility, and (3) maintainability. + + +#. All versions of ``astartes`` ``1.x`` should produce the same results across all platforms, so we have thorough unit and regression testing run on a continuous basis. +#. We specify as *few dependencies as possible* with the *loosest possible* dependency requirements, which allows integrating ``astartes`` with other tools more easily. + + * Dependencies which introduce a lot of requirements and/or specific versions of requirements are shuffled into the ``extras_require`` to avoid weighing down the main package. + * Compatibility with all versions of modern Python is achieved by not tightly specifying version numbers as well as by regression testing across all versions. + +#. We follow DRY (Don't Repeat Yourself) principles to avoid code duplication and decrease maintainence burden, have near-perfect test coverage, and enforce consistent formatting style in the source code. + + * Inline comments are *critical* for maintainability - at the time of writing, ``astartes`` has 1 comment line for every 2 lines of source code. + +JOSS Branch +----------- + +``astartes`` corresponding JOSS paper is stored in this repository on a separate branch. You can find ``paper.md`` on the aptly named ``joss-paper`` branch. + +*Note for Maintainers*\ : To push changes from the ``main`` branch into the ``joss-paper`` branch, run the ``Update JOSS Branch`` workflow. diff --git a/docs/_sources/README.rst.txt b/docs/_sources/README.rst.txt new file mode 100644 index 00000000..cda047e5 --- /dev/null +++ b/docs/_sources/README.rst.txt @@ -0,0 +1,486 @@ +.. role:: raw-html-m2r(raw) + :format: html + + +:raw-html-m2r:`

astartes

` + +:raw-html-m2r:`

(as-tar-tees)

` + + +.. raw:: html + +

Train:Validation:Test Algorithmic Sampling for Molecules and Arbitrary Arrays

+ + +:raw-html-m2r:`

+ astarteslogo +

` + + +.. raw:: html + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

Status Badges

UsageContinuous IntegrationRelease
PyPI - Python VersionReproduce PaperpyOpenSci approved
PyPI - LicenseTest StatusDOI
PyPI - Total DownloadsPyPI conda-forge version
GitHub Repo StarsProject Status: Active – The project has reached a stable, usable state and is being actively developed.
+
+ + +Online Documentation +-------------------- + +Follow `this link `_ for a nicely-rendered version of this README along with additional tutorials for `moving from train_test_split in sklearn to astartes `_. +Keep reading for a installation guide and links to tutorials! + +Installing ``astartes`` +--------------------------- + +We recommend installing ``astartes`` within a virtual environment, using either ``venv`` or ``conda`` (or other tools) to simplify dependency management. Python versions 3.7, 3.8, 3.9, 3.10, 3.11, and 3.12 are supported on all platforms. + +.. + + **Warning** + Windows (PowerShell) and MacOS Catalina or newer (zsh) require double quotes around text using the ``'[]'`` characters (i.e. ``pip install "astartes[molecules]"``\ ). + + +``pip`` +^^^^^^^^^^^ + +``astartes`` is available on ``PyPI`` and can be installed using ``pip``\ : + + +* To include the featurization options for chemical data, use ``pip install astartes[molecules]``. +* To install only the sampling algorithms, use ``pip install astartes`` (this install will have fewer dependencies and may be more readily compatible in environments with existing workflows). + +``conda`` +^^^^^^^^^^^^^ + +``astartes`` package is also available on ``conda-forge`` with this command: ``conda install -c conda-forge astartes``. +To install ``astartes`` with support for featurizing molecules, use: ``conda install -c conda-forge astartes aimsim``. +This will download the base ``astartes`` package as well as ``aimsim``\ , which is the backend used for molecular featurization. + +Source +^^^^^^ + +To install ``astartes`` from source for development, see the `Contributing & Developer Notes <#contributing--developer-notes>`_ section. + +Statement of Need +----------------- + +Machine learning has sparked an explosion of progress in chemical kinetics, materials science, and many other fields as researchers use data-driven methods to accelerate steps in traditional workflows within some acceptable error tolerance. +To facilitate adoption of these models, there are two important tasks to consider: + + +#. use a validation set when selecting the optimal hyperparameter for the model and separately use a held-out test set to measure performance on unseen data. +#. evaluate model performance on both interpolative and extrapolative tasks so future users are informed of any potential limitations. + +``astartes`` addresses both of these points by implementing an ``sklearn``\ -compatible ``train_val_test_split`` function. +Additional technical detail is provided below as well as in our companion paper in the Journal of Open Source Software: `Machine Learning Validation via Rational Dataset Sampling with astartes `_. +For a demo-based explainer using machine learning on a fast food menu, see the ``astartes`` Reproducible Notebook published at the United States Research Software Engineers Conference at `this page `_. + +Target Audience +^^^^^^^^^^^^^^^ + +``astartes`` is generally applicable to machine learning involving both discovery and inference *and* model validation. +There are specific functions in ``astartes`` for applications in cheminformatics (\ ``astartes.molecules``\ ) but the methods implemented are general to all numerical data. + +Quick Start +----------- + +``astartes`` is designed as a drop-in replacement for ``sklearn``\ 's ``train_test_split`` function (see the `sklearn documentation `_\ ). To switch to ``astartes``\ , change ``from sklearn.model_selection import train_test_split`` to ``from astartes import train_test_split``. + +Like ``sklearn``\ , ``astartes`` accepts any iterable object as ``X``\ , ``y``\ , and ``labels``. +Each will be converted to a ``numpy`` array for internal operations, and returned as a ``numpy`` array with limited exceptions: if ``X`` is a ``pandas`` ``DataFrame``\ , ``y`` is a ``Series``\ , or ``labels`` is a ``Series``\ , ``astartes`` will cast it back to its original type including its index and column names. + +.. + + **Note** + The developers recommend passing ``X``\ , ``y``\ , and ``labels`` as ``numpy`` arrays and handling the conversion to and from other types explicitly on your own. Behind-the-scenes type casting can lead to unexpected behavior! + + +By default, ``astartes`` will split data randomly. Additionally, a variety of algorithmic sampling approaches can be used by specifying the ``sampler`` argument to the function (see the `Table of Implemented Samplers <#implemented-sampling-algorithms>`_ for a complete list of options and their corresponding references): + +.. code-block:: python + + from sklearn.datasets import load_diabetes + + X, y = load_diabetes(return_X_y=True) + + X_train, X_test, y_train, y_test = train_test_split( + X, # preferably numpy arrays, but astartes will cast it for you + y, + sampler = 'kennard_stone', # any of the supported samplers + ) + +.. + + **Note** + Extrapolation sampling algorithms will return an additional set of arrays (the cluster labels) which will result in a ``ValueError: too many values to unpack`` if not called properly. See the `\ ``split_comparisons`` Google colab demo `_ for a full explanation. + + +That's all you need to get started with ``astartes``\ ! +The next sections include more examples and some demo notebooks you can try in your browser. + +Example Notebooks +^^^^^^^^^^^^^^^^^ + +Click the badges in the table below to be taken to a live, interactive demo of ``astartes``\ : + +.. list-table:: + :header-rows: 1 + + * - Demo + - Topic + - Link + * - Comparing Sampling Algorithms with Fast Food + - Visual representations of how different samplers affect data partitioning + - + .. image:: https://colab.research.google.com/assets/colab-badge.svg + :target: https://colab.research.google.com/github/JacksonBurns/astartes/blob/main/examples/split_comparisons/split_comparisons.ipynb + :alt: Colab + + * - Using ``train_val_test_split`` with the ``sklearn`` example datasets + - Demonstrating how witholding a test set with ``train_val_test_split`` can impact performance + - + .. image:: https://colab.research.google.com/assets/colab-badge.svg + :target: https://colab.research.google.com/github/JacksonBurns/astartes/blob/main/examples/train_val_test_split_sklearn_example/train_val_test_split_example.ipynb + :alt: Colab + + * - Cheminformatics sample set partitioning with ``astartes`` + - Extrapolation vs. Interpolation impact on cheminformatics model accuracy + - + .. image:: https://colab.research.google.com/assets/colab-badge.svg + :target: https://colab.research.google.com/github/JacksonBurns/astartes/blob/main/examples/barrier_prediction_with_RDB7/RDB7_barrier_prediction_example.ipynb + :alt: Colab + + * - Comparing partitioning approaches for alkanes + - Visualizing how sampler impact model performance with simple chemicals + - + .. image:: https://colab.research.google.com/assets/colab-badge.svg + :target: https://colab.research.google.com/github/JacksonBurns/astartes/blob/main/examples/mlpds_2023_astartes_demonstration/mlpds_2023_demo.ipynb + :alt: Colab + + + +To execute these notebooks locally, clone this repository (i.e. ``git clone https://github.com/JacksonBurns/astartes.git``\ ), navigate to the ``astartes`` directory, run ``pip install .[demos]``\ , then open and run the notebooks in your preferred editor. +You do *not* need to execute the cells prefixed with ``%%capture`` - they are only present for compatibility with Google Colab. + +Withhold Testing Data with ``train_val_test_split`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For rigorous ML research, it is critical to withhold some data during training to use a ``test`` set. +The model should *never* see this data during training (unlike the validation set) so that we can get an accurate measurement of its performance. + +With ``astartes`` performing this three-way data split is readily available with ``train_val_test_split``\ : + +.. code-block:: python + + from astartes import train_val_test_split + + X_train, X_val, X_test = train_val_test_split(X, sampler = 'sphere_exclusion') + +You can now train your model with ``X_train``\ , optimize your model with ``X_val``\ , and measure its performance with ``X_test``. + +Evaluate the Impact of Splitting Algorithms on Regression Models +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For data with many features it can be difficult to visualize how different sampling algorithms change the distribution of data into training, validation, and testing like we do in some of the demo notebooks. +To aid in analyzing the impact of the algorithms, ``astartes`` provides ``generate_regression_results_dict``. +This function allows users to quickly evaluate the impact of different splitting techniques on any ``sklearn``\ -compatible model's performance. +All results are stored in a nested dictionary (\ ``{sampler:{metric:{split:score}}}``\ ) format and can be displayed in a neatly formatted table using the optional ``print_results`` argument. + +.. code-block:: python + + from sklearn.svm import LinearSVR + + from astartes.utils import generate_regression_results_dict as grrd + + sklearn_model = LinearSVR() + results_dict = grrd( + sklearn_model, + X, + y, + print_results=True, + ) + + Train Val Test + ---- -------- -------- -------- + MAE 1.41522 3.13435 2.17091 + RMSE 2.03062 3.73721 2.40041 + R2 0.90745 0.80787 0.78412 + +Additional metrics can be passed to ``generate_regression_results_dict`` via the ``additional_metrics`` argument, which should be a dictionary mapping the name of the metric (as a ``string``\ ) to the function itself, like this: + +.. code-block:: python + + from sklearn.metrics import mean_absolute_percentage_error + + add_met = {"mape": mean_absolute_percentage_error} + + grrd(sklearn_model, X, y, additional_metric=add_met) + +See the docstring for ``generate_regression_results_dict`` (with ``help(generate_regression_results_dict)``\ ) for more information. + +Using ``astartes`` with Categorical Data +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Any of the implemented sampling algorithms whose hyperparameters allow specifying the ``metric`` or ``distance_metric`` (effectively ``1-metric``\ ) can be co-opted to work with categorical data. +Simply encode the data in a format compatible with the ``sklearn`` metric of choice and then call ``astartes`` with that metric specified: + +.. code-block:: python + + from sklearn.metrics import jaccard_score + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + sampler='kennard_stone', + hopts={"metric": jaccard_score}, + ) + +Other samplers which do not allow specifying a categorical distance metric did not provide a method for doing so in their original inception, though it is possible that they can be adapted for this application. +If you are interested in adding support for categorical metrics to an existing sampler, consider opening a `Feature Request `_\ ! + +Access Sampling Algorithms Directly +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The sampling algorithms implemented in ``astartes`` can also be directly accessed and run if it is more useful for your applications. +In the below example, we import the Kennard Stone sampler, use it to partition a simple array, and then retrieve a sample. + +.. code-block:: python + + from astartes.samplers.interpolation import KennardStone + + kennard_stone = KennardStone([[1, 2], [3, 4], [5, 6]]) + first_2_samples = kennard_stone.get_sample_idxs(2) + +All samplers in ``astartes`` implement a ``_sample()`` method that is called by the constructor (i.e. greedily) and either a ``get_sampler_idxs`` or ``get_cluster_idxs`` for interpolative and extrapolative samplers, respectively. +For more detail on the implementaiton and design of samplers in ``astartes``\ , see the `Developer Notes <#contributing--developer-notes>`_ section. + +Theory and Application of ``astartes`` +------------------------------------------ + +This section of the README details some of the theory behind why the algorithms implemented in ``astartes`` are important and some motivating examples. +For a comprehensive walkthrough of the theory and implementation of ``astartes``\ , follow `this link `_ to read the companion paper (freely available and hosted here on GitHub). + +.. + + **Note** + We reference open-access publications wherever possible. For articles locked behind a paywall (denoted with :small_blue_diamond:), we instead suggest reading `this Wikipedia page `_ and absolutely **not** attempting to bypass the paywall. + + +Rational Splitting Algorithms +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +While much machine learning is done with a random choice between training/validation/test data, an alternative is the use of so-called "rational" splitting algorithms. +These approaches use some similarity-based algorithm to divide data into sets. +Some of these algorithms include Kennard-Stone (\ `Kennard & Stone `_ :small_blue_diamond:), Sphere Exclusion (\ `Tropsha et. al `_ :small_blue_diamond:),as well as the OptiSim as discussed in `Applied Chemoinformatics: Achievements and Future Opportunities `_ :small_blue_diamond:. +Some clustering-based splitting techniques have also been incorporated, such as `DBSCAN `_. + +There are two broad categories of sampling algorithms implemented in ``astartes``\ : extrapolative and interpolative. +The former will force your model to predict on out-of-sample data, which creates a more challenging task than interpolative sampling. +See the table below for all of the sampling approaches currently implemented in ``astartes``\ , as well as the hyperparameters that each algorithm accepts (which are passed in with ``hopts``\ ) and a helpful reference for understanding how the hyperparameters work. +Note that ``random_state`` is defined as a keyword argument in ``train_test_split`` itself, even though these algorithms will use the ``random_state`` in their own work. +Do not provide a ``random_state`` in the ``hopts`` dictionary - it will be overwritten by the ``random_state`` you provide for ``train_test_split`` (or the default if none is provided). + +Implemented Sampling Algorithms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + :header-rows: 1 + + * - Sampler Name + - Usage String + - Type + - Hyperparameters + - Reference + - Notes + * - Random + - 'random' + - Interpolative + - ``shuffle`` + - `sklearn train_test_split `_ Documentation + - This sampler is a direct passthrough to ``sklearn``\ 's ``train_test_split``. + * - Kennard-Stone + - 'kennard_stone' + - Interpolative + - ``metric`` + - Original Paper by `Kennard & Stone `_ :small_blue_diamond: + - Euclidian distance is used by default, as described in the original paper. + * - Sample set Partitioning based on joint X-Y distances (SPXY) + - 'spxy' + - Interpolative + - ``distance_metric`` + - Saldhana et. al `original paper `_ :small_blue_diamond: + - Extension of Kennard Stone that also includes the response when sampling distances. + * - Mahalanobis Distance Kennard Stone (MDKS) + - 'spxy' *(MDKS is derived from SPXY)* + - Interpolative + - *none, see Notes* + - Saptoro et. al `original paper `_ + - MDKS is SPXY using Mahalanobis distance and can be called by using SPXY with ``distance_metric="mahalanobis"`` + * - Scaffold + - 'scaffold' + - Extrapolative + - ``include_chirality`` + - `Bemis-Murcko Scaffold `_ :small_blue_diamond: as implemented in RDKit + - This sampler requires SMILES strings as input (use the ``molecules`` subpackage) + * - Sphere Exclusion + - 'sphere_exclusion' + - Extrapolative + - ``metric``\ , ``distance_cutoff`` + - *custom implementation* + - Variation on Sphere Exclusion for arbitrary-valued vectors. + * - Time Based + - 'time_based' + - Extrapolative + - *none* + - Papers using Time based splitting: `Chen et al. `_ :small_blue_diamond:, `Sheridan, R. P `_ :small_blue_diamond:, `Feinberg et al. `_ :small_blue_diamond:, `Struble et al. `_ + - This sampler requires ``labels`` to be an iterable of either date or datetime objects. + * - Optimizable K-Dissimilarity Selection (OptiSim) + - 'optisim' + - Extrapolative + - ``n_clusters``\ , ``max_subsample_size``\ , ``distance_cutoff`` + - *custom implementation* + - Variation on `OptiSim `_ for arbitrary-valued vectors. + * - K-Means + - 'kmeans' + - Extrapolative + - ``n_clusters``\ , ``n_init`` + - `\ ``sklearn KMeans`` `_ + - Passthrough to ``sklearn``\ 's ``KMeans``. + * - Density-Based Spatial Clustering of Applications with Noise (DBSCAN) + - 'dbscan' + - Extrapolative + - ``eps``\ , ``min_samples``\ , ``algorithm``\ , ``metric``\ , ``leaf_size`` + - `\ ``sklearn DBSCAN`` `_ Documentation + - Passthrough to ``sklearn``\ 's ``DBSCAN``. + * - Minimum Test Set Dissimilarity (MTSD) + - ~ + - ~ + - *upcoming in* ``astartes`` *v1.x* + - ~ + - ~ + * - Restricted Boltzmann Machine (RBM) + - ~ + - ~ + - *upcoming in* ``astartes`` *v1.x* + - ~ + - ~ + * - Kohonen Self-Organizing Map (SOM) + - ~ + - ~ + - *upcoming in* ``astartes`` *v1.x* + - ~ + - ~ + * - SPlit Method + - ~ + - ~ + - *upcoming in* ``astartes`` *v1.x* + - ~ + - ~ + + +Domain-Specific Applications +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Below are some field specific applications of ``astartes``. Interested in adding a new sampling algorithm or featurization approach? See `\ ``CONTRIBUTING.md`` <./CONTRIBUTING.md>`_. + +Chemical Data and the ``astartes.molecules`` Subpackage +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Machine Learning is enormously useful in chemistry-related fields due to the high-dimensional feature space of chemical data. +To properly apply ML to chemical data for inference *or* discovery, it is important to know a model's accuracy under the two domains. +To simplify the process of partitioning chemical data, ``astartes`` implements a pre-built featurizer for common chemistry data formats. +After installing with ``pip install astartes[molecules]`` one can import the new train/test splitting function like this: ``from astartes.molecules import train_test_split_molecules`` + +The usage of this function is identical to ``train_test_split`` but with the addition of new arguments to control how the molecules are featurized: + +.. code-block:: python + + train_test_split_molecules( + molecules=smiles, + y=y, + test_size=0.2, + train_size=0.8, + fingerprint="daylight_fingerprint", + fprints_hopts={ + "minPath": 2, + "maxPath": 5, + "fpSize": 200, + "bitsPerHash": 4, + "useHs": 1, + "tgtDensity": 0.4, + "minSize": 64, + }, + sampler="random", + random_state=42, + hopts={ + "shuffle": True, + }, + ) + +To see a complete example of using ``train_test_split_molecules`` with actual chemical data, take a look in the ``examples`` directory and the brief `companion paper `_. + +Configuration options for the featurization scheme can be found in the documentation for `AIMSim `_ though most of the critical configuration options are shown above. + +Reproducibility +--------------- + +``astartes`` aims to be completely reproducible across different platforms, Python versions, and dependency configurations - any version of ``astartes`` v1.x should result in the *exact* same splits, always. +To that end, the default behavior of ``astartes`` is to use ``42`` as the random seed and *always* set it. +Running ``astartes`` with the default settings will always produce the exact same results. +We have verified this behavior on Debian Ubuntu, Windows, and Intel Macs from Python versions 3.7 through 3.11 (with appropriate dependencies for each version). + +Known Reproducibility Limitations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Inevitably external dependencies of ``astartes`` will introduce backwards-incompatible changes. +We continually run regression tests to catch these, and will list all *known* limitations here: + + +* ``sklearn`` v1.3.0 introduced backwards-incompatible changes in the ``KMeans`` sampler that changed how the random initialization affects the results, even given the same random seed. Different version of ``sklearn`` will affect the performance of ``astartes`` and we recommend including the exact version of ``scikit-learn`` and ``astartes`` used, when applicable. + +.. + + **Note** + We are limited in our ability to test on M1 Macs, but from our limited manual testing we achieve perfect reproducbility in all cases *except occasionally* with ``KMeans`` on Apple silicon. + ``astartes`` is still consistent between runs on the same platform in all cases, and other samplers are not impacted by this apparent bug. + + +How to Cite +----------- + +If you use ``astartes`` in your work please follow the link below to our (Open Access!) paper in the Journal of Open Source Software or use the "Cite this repository" button on GitHub. + +`Machine Learning Validation via Rational Dataset Sampling with astartes `_ + +Contributing & Developer Notes +------------------------------ + +See `CONTRIBUTING.md <./CONTRIBUTING.md>`_ for instructions on installing ``astartes`` for development, making a contribution, and general guidance on the design of ``astartes``. diff --git a/docs/_sources/astartes.rst.txt b/docs/_sources/astartes.rst.txt index 2d827941..4af4818c 100644 --- a/docs/_sources/astartes.rst.txt +++ b/docs/_sources/astartes.rst.txt @@ -7,16 +7,24 @@ Subpackages .. toctree:: :maxdepth: 4 - astartes.interfaces astartes.samplers + astartes.utils Submodules ---------- -astartes.astartes module ------------------------- +astartes.main module +-------------------- -.. automodule:: astartes.astartes +.. automodule:: astartes.main + :members: + :undoc-members: + :show-inheritance: + +astartes.molecules module +------------------------- + +.. automodule:: astartes.molecules :members: :undoc-members: :show-inheritance: diff --git a/docs/_sources/astartes.samplers.extrapolation.rst.txt b/docs/_sources/astartes.samplers.extrapolation.rst.txt new file mode 100644 index 00000000..6fd2f0b8 --- /dev/null +++ b/docs/_sources/astartes.samplers.extrapolation.rst.txt @@ -0,0 +1,61 @@ +astartes.samplers.extrapolation package +======================================= + +Submodules +---------- + +astartes.samplers.extrapolation.dbscan module +--------------------------------------------- + +.. automodule:: astartes.samplers.extrapolation.dbscan + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.extrapolation.kmeans module +--------------------------------------------- + +.. automodule:: astartes.samplers.extrapolation.kmeans + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.extrapolation.optisim module +---------------------------------------------- + +.. automodule:: astartes.samplers.extrapolation.optisim + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.extrapolation.scaffold module +----------------------------------------------- + +.. automodule:: astartes.samplers.extrapolation.scaffold + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.extrapolation.sphere\_exclusion module +-------------------------------------------------------- + +.. automodule:: astartes.samplers.extrapolation.sphere_exclusion + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.extrapolation.time\_based module +-------------------------------------------------- + +.. automodule:: astartes.samplers.extrapolation.time_based + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: astartes.samplers.extrapolation + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_sources/astartes.samplers.interpolation.rst.txt b/docs/_sources/astartes.samplers.interpolation.rst.txt new file mode 100644 index 00000000..91f887d4 --- /dev/null +++ b/docs/_sources/astartes.samplers.interpolation.rst.txt @@ -0,0 +1,37 @@ +astartes.samplers.interpolation package +======================================= + +Submodules +---------- + +astartes.samplers.interpolation.kennardstone module +--------------------------------------------------- + +.. automodule:: astartes.samplers.interpolation.kennardstone + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.interpolation.random\_split module +---------------------------------------------------- + +.. automodule:: astartes.samplers.interpolation.random_split + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.interpolation.spxy module +------------------------------------------- + +.. automodule:: astartes.samplers.interpolation.spxy + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: astartes.samplers.interpolation + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_sources/astartes.samplers.rst.txt b/docs/_sources/astartes.samplers.rst.txt index 1d92b78a..0caaf02a 100644 --- a/docs/_sources/astartes.samplers.rst.txt +++ b/docs/_sources/astartes.samplers.rst.txt @@ -1,69 +1,22 @@ astartes.samplers package ========================= -Submodules ----------- - -astartes.samplers.dbscan module -------------------------------- - -.. automodule:: astartes.samplers.dbscan - :members: - :undoc-members: - :show-inheritance: - -astartes.samplers.doptimal module ---------------------------------- - -.. automodule:: astartes.samplers.doptimal - :members: - :undoc-members: - :show-inheritance: - -astartes.samplers.duplex module -------------------------------- - -.. automodule:: astartes.samplers.duplex - :members: - :undoc-members: - :show-inheritance: - -astartes.samplers.kennard\_stone module ---------------------------------------- +Subpackages +----------- -.. automodule:: astartes.samplers.kennard_stone - :members: - :undoc-members: - :show-inheritance: - -astartes.samplers.optisim module --------------------------------- - -.. automodule:: astartes.samplers.optisim - :members: - :undoc-members: - :show-inheritance: - -astartes.samplers.random module -------------------------------- +.. toctree:: + :maxdepth: 4 -.. automodule:: astartes.samplers.random - :members: - :undoc-members: - :show-inheritance: + astartes.samplers.extrapolation + astartes.samplers.interpolation -astartes.samplers.sampler module --------------------------------- - -.. automodule:: astartes.samplers.sampler - :members: - :undoc-members: - :show-inheritance: +Submodules +---------- -astartes.samplers.sphere\_exclusion module +astartes.samplers.abstract\_sampler module ------------------------------------------ -.. automodule:: astartes.samplers.sphere_exclusion +.. automodule:: astartes.samplers.abstract_sampler :members: :undoc-members: :show-inheritance: diff --git a/docs/_sources/astartes.utils.rst.txt b/docs/_sources/astartes.utils.rst.txt new file mode 100644 index 00000000..729aa702 --- /dev/null +++ b/docs/_sources/astartes.utils.rst.txt @@ -0,0 +1,61 @@ +astartes.utils package +====================== + +Submodules +---------- + +astartes.utils.array\_type\_helpers module +------------------------------------------ + +.. automodule:: astartes.utils.array_type_helpers + :members: + :undoc-members: + :show-inheritance: + +astartes.utils.exceptions module +-------------------------------- + +.. automodule:: astartes.utils.exceptions + :members: + :undoc-members: + :show-inheritance: + +astartes.utils.fast\_kennard\_stone module +------------------------------------------ + +.. automodule:: astartes.utils.fast_kennard_stone + :members: + :undoc-members: + :show-inheritance: + +astartes.utils.sampler\_factory module +-------------------------------------- + +.. automodule:: astartes.utils.sampler_factory + :members: + :undoc-members: + :show-inheritance: + +astartes.utils.user\_utils module +--------------------------------- + +.. automodule:: astartes.utils.user_utils + :members: + :undoc-members: + :show-inheritance: + +astartes.utils.warnings module +------------------------------ + +.. automodule:: astartes.utils.warnings + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: astartes.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_sources/index.rst.txt b/docs/_sources/index.rst.txt index 6b398a99..75ed3a60 100644 --- a/docs/_sources/index.rst.txt +++ b/docs/_sources/index.rst.txt @@ -1,5 +1,5 @@ .. astartes documentation master file, created by - sphinx-quickstart on Fri Jul 9 14:25:42 2021. + sphinx-quickstart on Fri Jul 9 14:25:42 2022. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. @@ -11,6 +11,8 @@ astartes documentation :caption: Contents: README + CONTRIBUTING + sklearn_to_astartes modules diff --git a/docs/_sources/modules.rst.txt b/docs/_sources/modules.rst.txt index 5ec05fd6..831c4b4f 100644 --- a/docs/_sources/modules.rst.txt +++ b/docs/_sources/modules.rst.txt @@ -5,5 +5,4 @@ astartes :maxdepth: 4 astartes - setup test diff --git a/docs/_sources/sklearn_to_astartes.rst.txt b/docs/_sources/sklearn_to_astartes.rst.txt new file mode 100644 index 00000000..fa5248f3 --- /dev/null +++ b/docs/_sources/sklearn_to_astartes.rst.txt @@ -0,0 +1,180 @@ + +Transitioning from ``sklearn`` to ``astartes`` +====================================================== + +Step 1. Installation +-------------------- + +``astartes`` has been designed to rely on (1) as few packages as possible and (2) packages which are already likely to be installed in a Machine Learning (ML) Python workflow (i.e. Numpy and Sklearn). Because of this, ``astartes`` should be compatible with your *existing* workflow such as a conda environment. + +To install ``astartes`` for general ML use (the sampling of arbitrary vectors): **\ ``pip install astartes``\ ** + +For users in cheminformatics, ``astartes`` has an optional add-on that includes featurization as part of the sampling. To install, type **\ ``pip install 'astartes[molecules]'``\ **. With this extra install, ``astartes`` uses `\ ``AIMSim`` `_ to encode SMILES strings as feature vectors. The SMILES strings are parsed into molecular graphs using RDKit and then sampled with a single function call: ``train_test_split_molecules``. + + +* If your workflow already has a featurization scheme in place (i.e. you already have a vector representation of your chemical of interest), you can directly use ``train_test_split`` (though we invite you to explore the many molecular descriptors made available through AIMSim). + +Step 2. Changing the ``import`` Statement +--------------------------------------------- + +In one of the first few lines of your Python script, you have the line ``from sklearn.model_selection import train_test_split``. To switch to using ``astartes`` change this line to ``from astartes import train_test_split``. + +That's it! You are now using ``astartes``. + +If you were just calling ``train_test_split(X, y)``\ , your script should now work in the exact same way as ``sklearn`` with no changes required. + +.. code-block:: python + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + random_state=42, + ) + +*becomes* + +.. code-block:: python + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + random_state=42, + ) + +But we encourage you to try one of our many other samplers (see below)! + +Step 3. Specifying an Algorithmic Sampler +----------------------------------------- + +By default (for interoperability), ``astartes`` will use a random sampler to produce train/test splits - but the real value of ``astartes`` is in the algorithmic sampling algorithms it implements. Check out the `README for a complete list of available algorithms `_ and how to call and customize them. + +If you existing call to ``train_test_split`` looks like this: + +.. code-block:: python + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + ) + +and you want to try out using Kennard-Stone sampling, switch it to this: + +.. code-block:: python + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + sampler="kennard_stone", + ) + +That's it! + +Step 4. Passing Keyword Arguments +--------------------------------- + +All of the arguments to the ``sklearn``\ 's ``train_test_split`` can still be passed to ``astartes``\ ' ``train_test_split``\ : + +.. code-block:: python + + X_train, X_test, y_train, y_test, labels_train, labels_test = train_test_split( + X, + y, + labels, + train_size = 0.75, + test_size = 0.25, + sampler = "kmeans", + hopts = {"n_clusters": 4}, + ) + +Some samplers have tunable hyperparameters that allow you to more finely control their behavior. To do this with Sphere Exclusion, for example, switch your call to this: + +.. code-block:: python + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + sampler="sphere_exclusion", + hopts={"distance_cutoff":0.15}, + ) + +Step 5. Useful ``astartes`` Features +---------------------------------------- + +``return_indices``\ : Improve Code Clarity +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are circumstances where the indices of the train/test data can be useful (for example, if ``y`` or ``labels`` are large, memory-intense objects), and there is no way to directly return these indices in ``sklearn``. ``astartes`` will return the sampling splits themselves by default, but it can also return the indices for the user to manipulate according to their needs: + +.. code-block:: python + + X_train, X_test, y_train, y_test, labels_train, labels_test = train_test_split( + X, + y, + labels, + return_indices = False, + ) + +*could instead be* + +.. code-block:: python + + X_train, X_test, y_train, y_test, labels_train, labels_test, indices_train, indices_test = train_test_split( + X, + y, + labels, + return_indices = True, + ) + +If ``y`` or ``labels`` were large, memory-intense objects it could be beneficial to *not* pass them in to ``train_test_split`` and instead separate the existing lists later using the returned indices. + +``train_val_test_split``\ : More Rigorous ML +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Behind the scenes, ``train_test_split`` is actually just a one-line function that calls the real workhorse of ``astartes`` - ``train_val_test_split``\ : + +.. code-block:: python + + def train_test_split( + X: np.array, + ... + return_indices: bool = False, + ): + return train_val_test_split( + X, y, labels, train_size, 0, test_size, sampler, hopts, return_indices + ) + +The function call to ``train_val_test_split`` is identical to ``train_test_split`` and supports all the same samplers and hyperparameters, except for one additional keyword argument ``val_size``\ : + +.. code-block:: python + + def train_val_test_split( + X: np.array, + y: np.array = None, + labels: np.array = None, + train_size: float = 0.8, + val_size: float = 0.1, + test_size: float = 0.1, + sampler: str = "random", + hopts: dict = {}, + return_indices: bool = False, + ): + +When called, this will return *three* arrays from ``X``\ , ``y``\ , and ``labels`` (or three arrays of indices, if ``return_indices=True``\ ) rather than the usual two, according to the values given for ``train_size``\ , ``val_size``\ , and ``test_size`` in the function call. + +.. code-block:: python + + X_train, X_val, X_test, y_train, y_val, y_test = train_val_test_split( + X, + y, + train_size: float = 0.8, + val_size: float = 0.1, + test_size: float = 0.1, + ) + +For truly rigorous ML modeling, the validation set should be used for hyperparameter tuning and the test set held out until the *very final* change has been made to the model to get a true sense of its performance. For better or for worse, this is *not* the current standard for ML modeling, but the authors believe it should be. + +Custom Warnings: ``ImperfectSplittingWarning`` and ``NormalizationWarning`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the event that your requested train/validation/test split is not mathematically possible given the dimensions of the input data (i.e. you request 50/25/25 but have 101 data points), ``astartes`` will warn you during runtime that it has occurred. ``sklearn`` simply moves on quietly, and while this is fine *most* of the time, the authors felt it prudent to warn the user. +When entering a train/validation/test split, ``astartes`` will check that it is normalized and make it so if not, warning the user during runtime. This will hopefully help prevent head-scratching hours of debugging. diff --git a/docs/_sources/test.functional.rst.txt b/docs/_sources/test.functional.rst.txt new file mode 100644 index 00000000..0c1189a2 --- /dev/null +++ b/docs/_sources/test.functional.rst.txt @@ -0,0 +1,29 @@ +test.functional package +======================= + +Submodules +---------- + +test.functional.test\_astartes module +------------------------------------- + +.. automodule:: test.functional.test_astartes + :members: + :undoc-members: + :show-inheritance: + +test.functional.test\_molecules module +-------------------------------------- + +.. automodule:: test.functional.test_molecules + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: test.functional + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_sources/test.regression.rst.txt b/docs/_sources/test.regression.rst.txt new file mode 100644 index 00000000..c3cb03bb --- /dev/null +++ b/docs/_sources/test.regression.rst.txt @@ -0,0 +1,21 @@ +test.regression package +======================= + +Submodules +---------- + +test.regression.test\_regression module +--------------------------------------- + +.. automodule:: test.regression.test_regression + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: test.regression + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_sources/test.rst.txt b/docs/_sources/test.rst.txt new file mode 100644 index 00000000..9fca9975 --- /dev/null +++ b/docs/_sources/test.rst.txt @@ -0,0 +1,20 @@ +test package +============ + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + test.functional + test.regression + test.unit + +Module contents +--------------- + +.. automodule:: test + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_sources/test.unit.rst.txt b/docs/_sources/test.unit.rst.txt new file mode 100644 index 00000000..d11aa2eb --- /dev/null +++ b/docs/_sources/test.unit.rst.txt @@ -0,0 +1,19 @@ +test.unit package +================= + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + test.unit.samplers + test.unit.utils + +Module contents +--------------- + +.. automodule:: test.unit + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_sources/test.unit.samplers.extrapolative.rst.txt b/docs/_sources/test.unit.samplers.extrapolative.rst.txt new file mode 100644 index 00000000..cd6b17ef --- /dev/null +++ b/docs/_sources/test.unit.samplers.extrapolative.rst.txt @@ -0,0 +1,61 @@ +test.unit.samplers.extrapolative package +======================================== + +Submodules +---------- + +test.unit.samplers.extrapolative.test\_DBSCAN module +---------------------------------------------------- + +.. automodule:: test.unit.samplers.extrapolative.test_DBSCAN + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.extrapolative.test\_Scaffold module +------------------------------------------------------ + +.. automodule:: test.unit.samplers.extrapolative.test_Scaffold + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.extrapolative.test\_kmeans module +---------------------------------------------------- + +.. automodule:: test.unit.samplers.extrapolative.test_kmeans + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.extrapolative.test\_optisim module +----------------------------------------------------- + +.. automodule:: test.unit.samplers.extrapolative.test_optisim + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.extrapolative.test\_sphere\_exclusion module +--------------------------------------------------------------- + +.. automodule:: test.unit.samplers.extrapolative.test_sphere_exclusion + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.extrapolative.test\_time\_based module +--------------------------------------------------------- + +.. automodule:: test.unit.samplers.extrapolative.test_time_based + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: test.unit.samplers.extrapolative + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_sources/test.unit.samplers.interpolative.rst.txt b/docs/_sources/test.unit.samplers.interpolative.rst.txt new file mode 100644 index 00000000..812af5a9 --- /dev/null +++ b/docs/_sources/test.unit.samplers.interpolative.rst.txt @@ -0,0 +1,37 @@ +test.unit.samplers.interpolative package +======================================== + +Submodules +---------- + +test.unit.samplers.interpolative.test\_kennard\_stone module +------------------------------------------------------------ + +.. automodule:: test.unit.samplers.interpolative.test_kennard_stone + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.interpolative.test\_random module +---------------------------------------------------- + +.. automodule:: test.unit.samplers.interpolative.test_random + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.interpolative.test\_spxy module +-------------------------------------------------- + +.. automodule:: test.unit.samplers.interpolative.test_spxy + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: test.unit.samplers.interpolative + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_sources/test.unit.samplers.rst.txt b/docs/_sources/test.unit.samplers.rst.txt new file mode 100644 index 00000000..dc112797 --- /dev/null +++ b/docs/_sources/test.unit.samplers.rst.txt @@ -0,0 +1,19 @@ +test.unit.samplers package +========================== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + test.unit.samplers.extrapolative + test.unit.samplers.interpolative + +Module contents +--------------- + +.. automodule:: test.unit.samplers + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_sources/test.unit.utils.rst.txt b/docs/_sources/test.unit.utils.rst.txt new file mode 100644 index 00000000..d4b96cf4 --- /dev/null +++ b/docs/_sources/test.unit.utils.rst.txt @@ -0,0 +1,37 @@ +test.unit.utils package +======================= + +Submodules +---------- + +test.unit.utils.test\_convert\_to\_array module +----------------------------------------------- + +.. automodule:: test.unit.utils.test_convert_to_array + :members: + :undoc-members: + :show-inheritance: + +test.unit.utils.test\_sampler\_factory module +--------------------------------------------- + +.. automodule:: test.unit.utils.test_sampler_factory + :members: + :undoc-members: + :show-inheritance: + +test.unit.utils.test\_utils module +---------------------------------- + +.. automodule:: test.unit.utils.test_utils + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: test.unit.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_static/_sphinx_javascript_frameworks_compat.js b/docs/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 00000000..81415803 --- /dev/null +++ b/docs/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/docs/_static/sphinx_highlight.js b/docs/_static/sphinx_highlight.js new file mode 100644 index 00000000..8a96c69a --- /dev/null +++ b/docs/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/docs/astartes.doctree b/docs/astartes.doctree new file mode 100644 index 0000000000000000000000000000000000000000..11f048d018231803452eb1295468b678e57540c9 GIT binary patch literal 120202 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 VL^y1o(8*YdEWUi5V!ko`{{h}tFA4wv literal 0 HcmV?d00001 diff --git a/docs/astartes.html b/docs/astartes.html new file mode 100644 index 00000000..69e5943e --- /dev/null +++ b/docs/astartes.html @@ -0,0 +1,390 @@ + + + + + + + astartes package — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

astartes package

+
+

Subpackages

+
+ +
+
+
+

Submodules

+
+
+

astartes.main module

+
+
+astartes.main.train_test_split(X: array, y: array | None = None, labels: array | None = None, train_size: float = 0.75, test_size: float | None = None, sampler: str = 'random', random_state: int | None = None, hopts: dict = {}, return_indices: bool = False)
+

Deterministic train_test_splitting of arbitrary arrays.

+
+
Parameters:
+
    +
  • X (np.array) – Numpy array of feature vectors.

  • +
  • y (np.array, optional) – Targets corresponding to X, must be of same size. Defaults to None.

  • +
  • labels (np.array, optional) – Labels corresponding to X, must be of same size. Defaults to None.

  • +
  • train_size (float, optional) – Fraction of dataset to use in training set. Defaults to 0.75.

  • +
  • test_size (float, optional) – Fraction of dataset to use in test set. Defaults to None.

  • +
  • sampler (str, optional) – Sampler to use, see IMPLEMENTED_INTER/EXTRAPOLATION_SAMPLERS. Defaults to “random”.

  • +
  • random_state (int, optional) – The random seed used throughout astartes.

  • +
  • hopts (dict, optional) – Hyperparameters for the sampler used above. Defaults to {}.

  • +
  • return_indices (bool, optional) – True to return indices of train/test instead of values. Defaults to False.

  • +
+
+
Returns:
+

X, y, and labels train/val/test data, or indices.

+
+
Return type:
+

np.array

+
+
+
+ +
+
+astartes.main.train_val_test_split(X: array | DataFrame, y: array | Series | None = None, labels: array | Series | None = None, train_size: float = 0.8, val_size: float = 0.1, test_size: float = 0.1, sampler: str = 'random', random_state: int | None = None, hopts: dict = {}, return_indices: bool = False)
+

Deterministic train_test_splitting of arbitrary arrays.

+
+
Parameters:
+
    +
  • X (np.array, pd.DataFrame) – Numpy array or pandas DataFrame of feature vectors.

  • +
  • y (np.array, pd.Series, optional) – Targets corresponding to X, must be of same size. Defaults to None.

  • +
  • labels (np.array, pd.Series, optional) – Labels corresponding to X, must be of same size. Defaults to None.

  • +
  • train_size (float, optional) – Fraction of dataset to use in training set. Defaults to 0.8.

  • +
  • val_size (float, optional) – Fraction of dataset to use in validation set. Defaults to 0.1.

  • +
  • test_size (float, optional) – Fraction of dataset to use in test set. Defaults to 0.1.

  • +
  • sampler (str, optional) – Sampler to use, see IMPLEMENTED_INTER/EXTRAPOLATION_SAMPLERS. Defaults to “random”.

  • +
  • random_state (int, optional) – The random seed used throughout astartes.

  • +
  • hopts (dict, optional) – Hyperparameters for the sampler used above. Defaults to {}.

  • +
  • return_indices (bool, optional) – True to return indices of train/test after values. Defaults to False.

  • +
+
+
Returns:
+

X, y, and labels train/val/test data, or indices.

+
+
Return type:
+

np.array(s)

+
+
+
+ +
+
+

astartes.molecules module

+
+
+astartes.molecules.train_test_split_molecules(molecules: array, y: array | None = None, labels: array | None = None, train_size: float = 0.75, test_size: float | None = None, sampler: str = 'random', random_state: int | None = None, hopts: dict = {}, fingerprint: str = 'morgan_fingerprint', fprints_hopts: dict = {}, return_indices: bool = False)
+

Deterministic train/test splitting of molecules (SMILES strings or RDKit objects).

+
+
Parameters:
+
    +
  • molecules (np.array) – List of SMILES strings or RDKit molecule objects representing molecules or reactions.

  • +
  • y (np.array, optional) – Targets corresponding to SMILES, must be of same size. Defaults to None.

  • +
  • labels (np.array, optional) – Labels corresponding to SMILES, must be of same size. Defaults to None.

  • +
  • train_size (float, optional) – Fraction of dataset to use in training (test+train~1). Defaults to 0.75.

  • +
  • test_size (float, optional) – Fraction of dataset to use in test set. Defaults to None.

  • +
  • sampler (str, optional) – Sampler to use, see IMPLEMENTED_INTER/EXTRAPOLATION_SAMPLERS. Defaults to “random”.

  • +
  • random_state (int, optional) – The random seed used throughout astartes. Defaults to None.

  • +
  • hopts (dict, optional) – Hyperparameters for the sampler used above. Defaults to {}.

  • +
  • fingerprint (str, optional) – Molecular fingerprint to be used from AIMSim. Defaults to “morgan_fingerprint”.

  • +
  • fprints_hopts (dict, optional) – Hyperparameters for AIMSim featurization. Defaults to {}.

  • +
  • return_indices (bool, optional) – True to return indices of train/test after the values. Defaults to False.

  • +
+
+
Returns:
+

X, y, and labels train/test data, or indices.

+
+
Return type:
+

np.array

+
+
+
+ +
+
+astartes.molecules.train_val_test_split_molecules(molecules: array, y: array | None = None, labels: array | None = None, train_size: float = 0.8, val_size: float = 0.1, test_size: float = 0.1, sampler: str = 'random', random_state: int | None = None, hopts: dict = {}, fingerprint: str = 'morgan_fingerprint', fprints_hopts: dict = {}, return_indices: bool = False)
+

Deterministic train_test_splitting of molecules (SMILES strings or RDKit objects).

+
+
Parameters:
+
    +
  • molecules (np.array) – List of SMILES strings or RDKit molecule objects representing molecules or reactions.

  • +
  • y (np.array, optional) – Targets corresponding to SMILES, must be of same size. Defaults to None.

  • +
  • labels (np.array, optional) – Labels corresponding to SMILES, must be of same size. Defaults to None.

  • +
  • train_size (float, optional) – Fraction of dataset to use in training set. Defaults to 0.8.

  • +
  • val_size (float, optional) – Fraction of dataset to use in validation set. Defaults to 0.1.

  • +
  • test_size (float, optional) – Fraction of dataset to use in test set. Defaults to 0.1.

  • +
  • sampler (str, optional) – Sampler to use, see IMPLEMENTED_INTER/EXTRAPOLATION_SAMPLERS. Defaults to “random”.

  • +
  • random_state (int, optional) – The random seed used throughout astartes. Defaults to 42.

  • +
  • hopts (dict, optional) – Hyperparameters for the sampler used above. Defaults to {}.

  • +
  • fingerprint (str, optional) – Molecular fingerprint to be used from AIMSim. Defaults to “morgan_fingerprint”.

  • +
  • fprints_hopts (dict, optional) – Hyperparameters for AIMSim featurization. Defaults to {}.

  • +
  • return_indices (bool, optional) – True to return indices of train/test after the values. Defaults to False.

  • +
+
+
Returns:
+

X, y, and labels train/val/test data, or indices.

+
+
Return type:
+

np.array

+
+
+
+ +
+
+

Module contents

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/astartes.rst b/docs/astartes.rst new file mode 100644 index 00000000..4af4818c --- /dev/null +++ b/docs/astartes.rst @@ -0,0 +1,38 @@ +astartes package +================ + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + astartes.samplers + astartes.utils + +Submodules +---------- + +astartes.main module +-------------------- + +.. automodule:: astartes.main + :members: + :undoc-members: + :show-inheritance: + +astartes.molecules module +------------------------- + +.. automodule:: astartes.molecules + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: astartes + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/astartes.samplers.doctree b/docs/astartes.samplers.doctree new file mode 100644 index 0000000000000000000000000000000000000000..cb821af2b870fc96b3f7c23901749b2569bdec43 GIT binary patch literal 22764 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 La+(mXhPD3#pWATU literal 0 HcmV?d00001 diff --git a/docs/astartes.samplers.extrapolation.doctree b/docs/astartes.samplers.extrapolation.doctree new file mode 100644 index 0000000000000000000000000000000000000000..fad02631bf2536c0a7c11038815cb16e6c71fc8c GIT binary patch literal 56132 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

ZGn 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 literal 0 HcmV?d00001 diff --git a/docs/astartes.samplers.extrapolation.html b/docs/astartes.samplers.extrapolation.html new file mode 100644 index 00000000..6dd39674 --- /dev/null +++ b/docs/astartes.samplers.extrapolation.html @@ -0,0 +1,336 @@ + + + + + + + astartes.samplers.extrapolation package — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +

+ + +
+ +
+
+
+ +
+
+
+
+ +
+

astartes.samplers.extrapolation package

+
+

Submodules

+
+
+

astartes.samplers.extrapolation.dbscan module

+
+
+class astartes.samplers.extrapolation.dbscan.DBSCAN(X, y, labels, configs)
+

Bases: AbstractSampler

+
+ +
+
+

astartes.samplers.extrapolation.kmeans module

+
+
+class astartes.samplers.extrapolation.kmeans.KMeans(X, y, labels, configs)
+

Bases: AbstractSampler

+
+ +
+
+

astartes.samplers.extrapolation.optisim module

+

The Optimizable K-Dissimilarity Selection (OptiSim) algorithm, as originally +described by Clark (https://pubs.acs.org/doi/full/10.1021/ci970282v), adapted +to work for arbitrary distance metrics.

+

The original algorithm: +1. Initialization

+
+
    +
  • Take a featurized dataset and select an arbitrary starting data point for +the selection set.

  • +
  • Treat the remaining data as ‘candidates’.

  • +
  • Create an empty ‘recycling bin’.

  • +
  • Create an empty subsample set.

  • +
  • Create an empty selection set.

  • +
+
+
    +
  1. Remove a random point from the candidates.

  2. +
+
+
    +
  • if it has a similarity greater than a given cutoff to any of the members of the selection set,

  • +
+

recycle it (or conversely, if it is within a cutoff distance) +- otherwise, add to subsample set

+
+
    +
  1. Repeat 2 until one of two conditions is met:

  2. +
+
+
    +
  1. The subsample reaches the pre-determined maximum size K or

  2. +
  3. The candidates are exhausted.

  4. +
+
+

4. If Step 3 resulted in condition b, move all data from recycling bin and go +to Step 2.

+

5. If subsample is empty, quit (all remaining candidates are similar, the +most dissimilar data points have already been identified)

+

6. Pick the most dissimilar (relative to data points already in selection set) +point in the subsample and add it to the selection set.

+
    +
  1. Move the remaining points in the subsample to the recycling bin.

  2. +
  3. If size(selection set) is sufficient, quit. Otherwise, go to Step 2.

  4. +
+

As suggested in the original paper, the members of the selection set are then +used as cluster centers, and we assign every element in the dataset to belong +to the cluster containing the selection set member to which it is the most +similar. To implement this step, use scipy.spatial.distance.cdist.

+

This algorithm seems like it might introduce an infinite loop if the subsample +is not filled and all of the remaining candidates are within the cutoff and cannot +be added. Might need a stop condition here? Unless the empyting of the recycling bin +will somehow fix this. Also possible that one would never have a partially filled +subsample after looking at the full dataset since it is more probable that ALL the +points would be rejected and the subsample would be empty.

+

Likely just check for no more points being possible to fit into the subsample, and +exit if that is the case.

+
+
+class astartes.samplers.extrapolation.optisim.OptiSim(X, y, labels, configs)
+

Bases: AbstractSampler

+
+
+get_dist(i, j)
+

Calculates pdist and returns distance between two samples

+
+ +
+
+move_item(item, source_set, destintation_set)
+

Moves item from source_set to destination_set

+
+ +
+
+rchoose(set)
+

Choose a random element from a set with self._rng

+
+ +
+ +
+
+

astartes.samplers.extrapolation.scaffold module

+

This sampler partitions the data based on the Bemis-Murcko scaffold function as implemented in RDKit. +Bemis, G. W.; Murcko, M. A. The Properties of Known Drugs. 1. Molecular Frameworks. J. Med. Chem. 1996, 39, 2887−2893. +Landrum, G. et al. RDKit: Open-Source Cheminformatics; 2006; https://www.rdkit.org.

+

The goal is to cluster molecules that share the same scaffold. +Later, these clusters will be assigned to training, validation, and testing split +to create data splits that will measure extrapolation by testing on scaffolds +that are not in the training set.

+
+
+class astartes.samplers.extrapolation.scaffold.Scaffold(X, y, labels, configs)
+

Bases: AbstractSampler

+
+
+generate_bemis_murcko_scaffold(mol, include_chirality=False)
+

Compute the Bemis-Murcko scaffold for an RDKit molecule.

+
+
Params:

mol: A smiles string or an RDKit molecule. +include_chirality: Whether to include chirality.

+
+
+
+
Returns:
+

Bemis-Murcko scaffold

+
+
+
+ +
+
+scaffold_to_smiles(mols)
+

Computes scaffold for each smiles string and returns a mapping from scaffolds to sets of smiles.

+
+
Params:

mols: A list of smiles strings or RDKit molecules.

+
+
+
+
Returns:
+

A dictionary mapping each unique scaffold to all smiles (or smiles indices) which have that scaffold.

+
+
+
+ +
+
+str_to_mol(string)
+

Converts an InChI or SMILES string to an RDKit molecule.

+
+
Params:

string: The InChI or SMILES string.

+
+
+
+
Returns:
+

An RDKit molecule.

+
+
+
+ +
+ +
+
+

astartes.samplers.extrapolation.sphere_exclusion module

+

The Sphere Exclusion clustering algorithm.

+

This re-implementation draws from this blog post on the RDKit blog, +though abstracted to work for arbitrary feature vectors: +http://rdkit.blogspot.com/2020/11/sphere-exclusion-clustering-with-rdkit.html +As well as this paper: +https://www.daylight.com/cheminformatics/whitepapers/ClusteringWhitePaper.pdf

+

But instead of using tanimoto similarity, which has a domain between zero and +one, it uses euclidian distance to enable processing arbitrary valued +vectors.

+
+
+class astartes.samplers.extrapolation.sphere_exclusion.SphereExclusion(X, y, labels, configs)
+

Bases: AbstractSampler

+
+ +
+
+

astartes.samplers.extrapolation.time_based module

+
+
+class astartes.samplers.extrapolation.time_based.TimeBased(X, y, labels, configs)
+

Bases: AbstractSampler

+
+ +
+
+

Module contents

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/astartes.samplers.extrapolation.rst b/docs/astartes.samplers.extrapolation.rst new file mode 100644 index 00000000..6fd2f0b8 --- /dev/null +++ b/docs/astartes.samplers.extrapolation.rst @@ -0,0 +1,61 @@ +astartes.samplers.extrapolation package +======================================= + +Submodules +---------- + +astartes.samplers.extrapolation.dbscan module +--------------------------------------------- + +.. automodule:: astartes.samplers.extrapolation.dbscan + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.extrapolation.kmeans module +--------------------------------------------- + +.. automodule:: astartes.samplers.extrapolation.kmeans + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.extrapolation.optisim module +---------------------------------------------- + +.. automodule:: astartes.samplers.extrapolation.optisim + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.extrapolation.scaffold module +----------------------------------------------- + +.. automodule:: astartes.samplers.extrapolation.scaffold + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.extrapolation.sphere\_exclusion module +-------------------------------------------------------- + +.. automodule:: astartes.samplers.extrapolation.sphere_exclusion + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.extrapolation.time\_based module +-------------------------------------------------- + +.. automodule:: astartes.samplers.extrapolation.time_based + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: astartes.samplers.extrapolation + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/astartes.samplers.html b/docs/astartes.samplers.html new file mode 100644 index 00000000..d9dd7390 --- /dev/null +++ b/docs/astartes.samplers.html @@ -0,0 +1,274 @@ + + + + + + + astartes.samplers package — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

astartes.samplers package

+
+

Subpackages

+ +
+
+

Submodules

+
+
+

astartes.samplers.abstract_sampler module

+

Abstract Sampling class

+
+
+class astartes.samplers.abstract_sampler.AbstractSampler(X, y, labels, configs)
+

Bases: ABC

+

Abstract Base Class for all samplers.

+
+
+__init__(X, y, labels, configs)
+

Copies X, y, labels, and configs into class attributes and then calls sampler.

+
+ +
+
+get_clusters()
+

Getter for the cluster labels.

+
+
Returns:
+

Cluster labels.

+
+
Return type:
+

np.array

+
+
+
+ +
+
+get_config(key, default=None)
+

Getter to sampler._configs

+
+
Parameters:
+
    +
  • key (str) – String parameter for the sampler.

  • +
  • default (any, optional) – Default to return if key not present. Defaults to None.

  • +
+
+
Returns:
+

value at provided key, or else default.

+
+
Return type:
+

any

+
+
+
+ +
+
+get_sample_idxs(n_samples)
+

Get idxs of samples.

+
+ +
+
+get_sorted_cluster_counter(max_shufflable_size=None)
+

Return a dict containing cluster_id: number of members sorted by number +of members, ascending

+

if max_shufflable_size is not None, clusters below the passed size will be +shuffled into a new order according to random_state in hopts

+
+ +
+ +
+
+

Module contents

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/astartes.samplers.interpolation.doctree b/docs/astartes.samplers.interpolation.doctree new file mode 100644 index 0000000000000000000000000000000000000000..984109cea32a80ebbb2bdd554cf46ec6ae057d84 GIT binary patch literal 16496 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 IWE9=}KWq<(>i_@% literal 0 HcmV?d00001 diff --git a/docs/astartes.samplers.interpolation.html b/docs/astartes.samplers.interpolation.html new file mode 100644 index 00000000..52f18375 --- /dev/null +++ b/docs/astartes.samplers.interpolation.html @@ -0,0 +1,183 @@ + + + + + + + astartes.samplers.interpolation package — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

astartes.samplers.interpolation package

+
+

Submodules

+
+
+

astartes.samplers.interpolation.kennardstone module

+
+
+class astartes.samplers.interpolation.kennardstone.KennardStone(X, y, labels, configs)
+

Bases: AbstractSampler

+
+ +
+
+

astartes.samplers.interpolation.random_split module

+
+
+class astartes.samplers.interpolation.random_split.Random(X, y, labels, configs)
+

Bases: AbstractSampler

+
+ +
+
+

astartes.samplers.interpolation.spxy module

+

Implements the Sample set Partitioning based on join X-Y distances +algorithm as originally described by Saldanha and coworkers in +“A method for calibration and validation subset partitioning” +doi:10.1016/j.talanta.2005.03.025

+

This implementation has been validated against their original source +code implementation, which can be found in the paper linked above. +The corresponding unit tests reflect the expected output from +the original implemenation. The breaking of ties is different +compared to the original, but this is ultimately a minor and +likely inconsequential difference.

+
+
+class astartes.samplers.interpolation.spxy.SPXY(X, y, labels, configs)
+

Bases: AbstractSampler

+
+ +
+
+

Module contents

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/astartes.samplers.interpolation.rst b/docs/astartes.samplers.interpolation.rst new file mode 100644 index 00000000..91f887d4 --- /dev/null +++ b/docs/astartes.samplers.interpolation.rst @@ -0,0 +1,37 @@ +astartes.samplers.interpolation package +======================================= + +Submodules +---------- + +astartes.samplers.interpolation.kennardstone module +--------------------------------------------------- + +.. automodule:: astartes.samplers.interpolation.kennardstone + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.interpolation.random\_split module +---------------------------------------------------- + +.. automodule:: astartes.samplers.interpolation.random_split + :members: + :undoc-members: + :show-inheritance: + +astartes.samplers.interpolation.spxy module +------------------------------------------- + +.. automodule:: astartes.samplers.interpolation.spxy + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: astartes.samplers.interpolation + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/astartes.samplers.rst b/docs/astartes.samplers.rst new file mode 100644 index 00000000..0caaf02a --- /dev/null +++ b/docs/astartes.samplers.rst @@ -0,0 +1,30 @@ +astartes.samplers package +========================= + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + astartes.samplers.extrapolation + astartes.samplers.interpolation + +Submodules +---------- + +astartes.samplers.abstract\_sampler module +------------------------------------------ + +.. automodule:: astartes.samplers.abstract_sampler + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: astartes.samplers + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/astartes.utils.doctree b/docs/astartes.utils.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d03ce6bce1267ebe2d41a0cdb956ecfbdf82b21b GIT binary patch literal 136349 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 + + + + + + astartes.utils package — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

astartes.utils package

+
+

Submodules

+
+
+

astartes.utils.array_type_helpers module

+
+
+astartes.utils.array_type_helpers.convert_to_array(obj: object, name: str)
+

Attempt to convert obj named name to a numpy array, with appropriate warnings and exceptions.

+
+
Parameters:
+
    +
  • obj (object) – The item to attempt to convert.

  • +
  • name (str) – Human-readable name for printing.

  • +
+
+
+
+ +
+
+astartes.utils.array_type_helpers.panda_handla(X, y, labels)
+

Helper function to deal with supporting Pandas data types in astartes

+
+
Parameters:
+
    +
  • X (Dataframe) – Features with column names

  • +
  • y (Series) – Targets

  • +
  • labels (Series) – Labels for data

  • +
+
+
Returns:
+

Empty if no pandas types, metadata-filled otherwise

+
+
Return type:
+

dict

+
+
+
+ +
+
+astartes.utils.array_type_helpers.return_helper(sampler_instance, train_idxs, val_idxs, test_idxs, return_indices, output_is_pandas)
+

Convenience function to return the requested arrays appropriately.

+
+
Parameters:
+
    +
  • sampler_instance (sampler) – The fit sampler instance.

  • +
  • test_size (float) – Fraction of data to use in test.

  • +
  • val_size (float) – Fraction of data to use in val.

  • +
  • train_size (float) – Fraction of data to use in train.

  • +
  • return_indices (bool) – Return indices after the value arrays.

  • +
  • output_is_pandas (dict) – metadata about casting to pandas.

  • +
+
+
Returns:
+

Either many arrays or indices in arrays.

+
+
Return type:
+

np.array

+
+
+

Notes

+

This function copies and pastes a lot of code when it could instead +use some loop over (X, y, labels, sampler_instance.get_clusters()) +but such an implementation is more error prone. This is long and +not the prettiest, but it is definitely doing what we want.

+
+ +
+
+

astartes.utils.exceptions module

+

Exceptions used by astartes

+
+
+exception astartes.utils.exceptions.InvalidConfigurationError(message=None)
+

Bases: RuntimeError

+

Used when user-requested split/data would not work.

+
+
+__init__(message=None)
+
+ +
+ +
+
+exception astartes.utils.exceptions.InvalidModelTypeError(message=None)
+

Bases: RuntimeError

+

Used when user-provided model is invalid.

+
+
+__init__(message=None)
+
+ +
+ +
+
+exception astartes.utils.exceptions.MoleculesNotInstalledError(message=None)
+

Bases: RuntimeError

+

Used when attempting to featurize molecules without install.

+
+
+__init__(message=None)
+
+ +
+ +
+
+exception astartes.utils.exceptions.SamplerNotImplementedError(message=None)
+

Bases: RuntimeError

+

Used when attempting to call a non-existent sampler.

+
+
+__init__(message=None)
+
+ +
+ +
+
+exception astartes.utils.exceptions.UncastableInputError(message=None)
+

Bases: RuntimeError

+

Used when X, y, or labels cannot be cast to a np.array.

+
+
+__init__(message=None)
+
+ +
+ +
+
+

astartes.utils.fast_kennard_stone module

+
+
+astartes.utils.fast_kennard_stone.fast_kennard_stone(ks_distance: ndarray) ndarray
+

Implements the Kennard-Stone algorithm

+
+
Parameters:
+

ks_distance (np.ndarray) – Distance matrix

+
+
Returns:
+

Indices in order of Kennard-Stone selection

+
+
Return type:
+

np.ndarray

+
+
+
+ +
+
+

astartes.utils.sampler_factory module

+
+
+class astartes.utils.sampler_factory.SamplerFactory(sampler)
+

Bases: object

+
+
+__init__(sampler)
+

Initialize SamplerFactory and copy a lowercased ‘sampler’ into an attribute.

+
+
Parameters:
+

sampler (string) – The desired sampler.

+
+
+
+ +
+
+get_sampler(X, y, labels, hopts)
+

Instantiate (which also performs fitting) and return the sampler.

+
+
Parameters:
+
    +
  • X (np.array) – Feature array.

  • +
  • y (np.array) – Target array.

  • +
  • labels (np.array) – Label array.

  • +
  • hopts (dict) – Hyperparameters for the sampler.

  • +
+
+
Raises:
+

SamplerNotImplementedError – Raised when an non-existent or not yet implemented sampler is requested.

+
+
Returns:
+

The fit sampler instance.

+
+
Return type:
+

astartes.sampler

+
+
+
+ +
+ +
+
+

astartes.utils.user_utils module

+
+
+astartes.utils.user_utils.display_results_as_table(error_dict)
+

Helper function to print a dictionary as a neat tabulate

+
+ +
+
+astartes.utils.user_utils.generate_regression_results_dict(sklearn_model, X, y, samplers=['random'], random_state=0, samplers_hopts={}, train_size=0.8, val_size=0.1, test_size=0.1, print_results=False, additional_metrics={})
+

Helper function to train a sklearn model using the provided data +and provided sampler types.

+
+
Parameters:
+
    +
  • X (np.array, pd.DataFrame) – Numpy array or pandas DataFrame of feature vectors.

  • +
  • y (np.array, pd.Series) – Targets corresponding to X, must be of same size.

  • +
  • train_size (float, optional) – Fraction of dataset to use in training set. Defaults to 0.8.

  • +
  • val_size (float, optional) – Fraction of dataset to use in validation set. Defaults to 0.1.

  • +
  • test_size (float, optional) – Fraction of dataset to use in test set. Defaults to 0.1.

  • +
  • random_state (int, optional) – The random seed used throughout astartes.

  • +
  • samplers_hopts (dict, optional) – Should be a dictionary of dictionaries with the keys specifying +the sampler and the values being another dictionary with the +corresponding hyperparameters. Defaults to {}.

  • +
  • print_results (bool, optional) – whether to print the resulting dictionary as a neat table

  • +
  • additional_metrics (dict, optional) – mapping of name (str) to metric (func) for additional metrics +such as those in sklearn.metrics or user-provided functions

  • +
+
+
Returns:
+

+
nested dictionary with the format of
+
{
+
sampler: {
+
‘mae’:{

‘train’: [], +‘val’: [], +‘test’: [],

+
+
+

}, +‘rmse’:{

+
+

’train’: [], +‘val’: [], +‘test’: [],

+
+

}, +‘R2’:{

+
+

’train’: [], +‘val’: [], +‘test’: [],

+
+

},

+
+
+

},

+
+
+

}

+
+
+

+
+
Return type:
+

dict

+
+
+
+ +
+
+

astartes.utils.warnings module

+

Warnings used by astartes

+
+
+exception astartes.utils.warnings.ConversionWarning(message=None)
+

Bases: RuntimeWarning

+

Used when passed data is not a numpy array.

+
+
+__init__(message=None)
+
+ +
+ +
+
+exception astartes.utils.warnings.ImperfectSplittingWarning(message=None)
+

Bases: RuntimeWarning

+

Used when a sampler cannot match requested splits.

+
+
+__init__(message=None)
+
+ +
+ +
+
+exception astartes.utils.warnings.NoMatchingScaffold(message=None)
+

Bases: Warning

+

Used when an RDKit molecule does not match any +Bemis-Murcko scaffold and returns an empty string.

+
+
+__init__(message=None)
+
+ +
+ +
+
+exception astartes.utils.warnings.NormalizationWarning(message=None)
+

Bases: RuntimeWarning

+

Used when a requested split does not add to 1.

+
+
+__init__(message=None)
+
+ +
+ +
+
+

Module contents

+
+
+astartes.utils.generate_regression_results_dict(sklearn_model, X, y, samplers=['random'], random_state=0, samplers_hopts={}, train_size=0.8, val_size=0.1, test_size=0.1, print_results=False, additional_metrics={})
+

Helper function to train a sklearn model using the provided data +and provided sampler types.

+
+
Parameters:
+
    +
  • X (np.array, pd.DataFrame) – Numpy array or pandas DataFrame of feature vectors.

  • +
  • y (np.array, pd.Series) – Targets corresponding to X, must be of same size.

  • +
  • train_size (float, optional) – Fraction of dataset to use in training set. Defaults to 0.8.

  • +
  • val_size (float, optional) – Fraction of dataset to use in validation set. Defaults to 0.1.

  • +
  • test_size (float, optional) – Fraction of dataset to use in test set. Defaults to 0.1.

  • +
  • random_state (int, optional) – The random seed used throughout astartes.

  • +
  • samplers_hopts (dict, optional) – Should be a dictionary of dictionaries with the keys specifying +the sampler and the values being another dictionary with the +corresponding hyperparameters. Defaults to {}.

  • +
  • print_results (bool, optional) – whether to print the resulting dictionary as a neat table

  • +
  • additional_metrics (dict, optional) – mapping of name (str) to metric (func) for additional metrics +such as those in sklearn.metrics or user-provided functions

  • +
+
+
Returns:
+

+
nested dictionary with the format of
+
{
+
sampler: {
+
‘mae’:{

‘train’: [], +‘val’: [], +‘test’: [],

+
+
+

}, +‘rmse’:{

+
+

’train’: [], +‘val’: [], +‘test’: [],

+
+

}, +‘R2’:{

+
+

’train’: [], +‘val’: [], +‘test’: [],

+
+

},

+
+
+

},

+
+
+

}

+
+
+

+
+
Return type:
+

dict

+
+
+
+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/astartes.utils.rst b/docs/astartes.utils.rst new file mode 100644 index 00000000..729aa702 --- /dev/null +++ b/docs/astartes.utils.rst @@ -0,0 +1,61 @@ +astartes.utils package +====================== + +Submodules +---------- + +astartes.utils.array\_type\_helpers module +------------------------------------------ + +.. automodule:: astartes.utils.array_type_helpers + :members: + :undoc-members: + :show-inheritance: + +astartes.utils.exceptions module +-------------------------------- + +.. automodule:: astartes.utils.exceptions + :members: + :undoc-members: + :show-inheritance: + +astartes.utils.fast\_kennard\_stone module +------------------------------------------ + +.. automodule:: astartes.utils.fast_kennard_stone + :members: + :undoc-members: + :show-inheritance: + +astartes.utils.sampler\_factory module +-------------------------------------- + +.. automodule:: astartes.utils.sampler_factory + :members: + :undoc-members: + :show-inheritance: + +astartes.utils.user\_utils module +--------------------------------- + +.. automodule:: astartes.utils.user_utils + :members: + :undoc-members: + :show-inheritance: + +astartes.utils.warnings module +------------------------------ + +.. automodule:: astartes.utils.warnings + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: astartes.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/environment.pickle b/docs/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..483395c40e55ba9da71ea0965d52d1ece55237a6 GIT binary patch literal 1162056 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�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≦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 + + + + + Index — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/index.doctree b/docs/index.doctree new file mode 100644 index 0000000000000000000000000000000000000000..411881fe3f689a70f593b1a99cf7e3039ec1ee23 GIT binary patch literal 4632 zcmds5U5^|`6J0)&E)c;?4&s=9loXN))D6-%?~x^?ST)xGDQd&@s* z{bp-#&HpnyDrY>K9+EiDL`;=6-B?6LN;7Sr+uJ|2Keqd(C&`%-g^Z{*YtV=oPhv?k z`vjBQPG9px9aaW9kw}-;vzGY>QJP3iRZv?enu{z*A*V7J@r2$9B1ws+aWI_q%TpbE zQt)WvR|Zi2j^x4jiX;fW8N7S%_~`4$_l|<2yGKWd{U3@Vh)5QYnB+Rpj4N+4z)A9i zYMRUfErJ=Y5F~uUv+6UrvJC=eQI6YO*sc% zVr>`EeN47A*9mP*nH#nFW$2a|*nR1A>BD_oINZ6}z9(x`5c>}+j z_Z!bgV-Uw zlKY75pP2Te58iwK!w>9d_QY)7|LElLqX*yq{^JKH-}RDfYJwDzS*S%=yTng)QV|yk zjC^LP+2mQ26ft!f?ZUm!9M`B zdv4l{$1(Wj+-z0$=7Mfkq(drcY#*+fzK@m?Su%reA2hYNkRR5&upc@1zRzxXxAx%X z_f}(Jb}COEoJo@BR9dnco^LIO2jQgia4vvwP~+B99IRAF z9$w(|ZY?l-53-m?;8l{vfhI%ebFV3_h*7vwV|bo5wAruxUDnKIPI1p{98R(NMTMSe z^UUXX;~?eQUDK`ivWwgQ>E*ZIH&^^7W?ktRDT2QTZd1C7hCd)uzh6aBQ^~Zk4q&kC zBa~40nWD5<_7~H^NY8RG;JPzyHt?5D^MprS1ITXr45?;+?$@Dmjwx7daS;dR-&SCL z700j_9m6UAx}p5bFH$zJc)o}?V9tIq2V50DicOS9et&IP;GDcKt3yrA! z>w>7TKYyu!{PUvAy(}RA{_+7~e{Gz+8HU&3w9hZvycq_k{I@SselZLSwy8O#W)9OX zv(cJM@Ayjcvqr#u?k;iF9%AQM;{dF2P_f2>r|Q`zr(DQUAcTvKR+VnHZ(h-oWGeB* z80J!pQU1$rqNRlG;V)Pk^mi87dlOdH-$dCb2 z35q8=Hry=&ZS9nvZdhq~E7sgxnOQOM?C8?kn%OSxF3wP|esg(ZWwE*H?f|SQ1{Wp1 z-P}q@HZI7R!s9W>_cB@xa}8a+ka39C1T_ZRxPA!D5MBZ!ToWGQF|dk`W@=g6Y?A^F z&_ZM`bHHmWF48=lLlBPj0*=l`W+ZV2cf7EfbLEOXE>fMcQ>O;fY!jDJNQSZj0ct9>u5irau5QL-Yp-kM^$tnjgG%_a6MYEl1Icc_&$zf4er1WF-!=6Dkim z)g!+L2w=c;nqadY=nYvEySB4yZUU2OI8V>{1;X+{a&E4w86JSsknu4~@bixc;h?{% zQoLZpPYUF + + + + + + astartes documentation — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+
+ + + + \ No newline at end of file diff --git a/docs/modules.doctree b/docs/modules.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d80d509fe2166cd0ca7412d61fcff4874ea6c7b1 GIT binary patch literal 2760 zcmZ8jTWcIQ6n1Ry)w}CUl2S_~P&QKAwevp*L20ld%|fppkJQbHh}88^a{2J0a~wbG~O;=7d)5ao*uw-g_I* z_#kwgaFT6og+8^88VAow2P*r&vt{zVvGXC;adb-xuP*ZAFd%K1d@ppH=&r)P6pFcLR1)CbL6f@HsZLX)QRMsB|(oPGVd&%sDu?YQ(%UwT1n*B@{rS>Y{0Hel< z@4%zZoMD?lHG5wo6aE!|`WnAy_&vw(1%6LLuknKn0g@3_UT0SuIDU)(2ynRgF|sfc zDw95EbAjNH=o$Zs|I9+apv#<pS=U`5NSm^iqQdKT|Omy0|{?eD_4G0+P7$`>HPV+ z7Re4u&RP>2InxzVTe1eVWM>FFdv#5#cu=10ST-HEOye)ZBWI|xk|umeY4pM{TQjZW zw4<^Hq0y-@@yXwVFv+}0JSHt`M=MFq-q5$qIiVJ4$K$rY=0+>WK$y_|gG!H@wGGKR34GI&@?D)y(^ zuSKP0KG$SfBt9LnWvMMAnDU z%sjhiK1tT*zgd|_r_#jNYi2G4bMwjvx_`=DA>nM`=nO5Cr^(z8ryyiO+TLsvAht{l zxeG`3Ryn#PTr9Z659HmKI`MvF3*5NmPmiXy0P112u9rmWjMn!-IL$akJScqKY(Tk! z5T~zw2^Z<^ucmx61aKulBGeolSWShKG$*W|-P03ABCpi6ZpCzMUq^5T_eYNYy+sI| zF$X7)GiY5CR!|`co+)X{R$(7E4-Jr2&g+?W7xtKXm#+WNuV)FG7gQ7~7ibPg@YGl^ z%qCp@#|R44a(KL8e&ZTUvpbw@N$Upz#IQDR7v0oCcuPRuOTzk_zu~WK7$kwaEfL}S z$lu&q{uTbe<|7-%o5iY5k28UiC-<;eOHxm+^y)A-CAA)cM{$dpmTmnj)kpV)t@dEc z;$Y>qI&`vSzj}+MVgC5Ot!4-JIwnSjhYM&C!$GE{1hB{fS4QubM*a!Oe~7<<{dlpV pkMPE_sCVtK9UNQYgH~LX?4WsDfFg@jtzn*KTQdgIZS7|l{{!?=P0RoQ literal 0 HcmV?d00001 diff --git a/docs/modules.html b/docs/modules.html new file mode 100644 index 00000000..2ff34e79 --- /dev/null +++ b/docs/modules.html @@ -0,0 +1,191 @@ + + + + + + + astartes — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+
+ + + + \ No newline at end of file diff --git a/docs/modules.rst b/docs/modules.rst new file mode 100644 index 00000000..831c4b4f --- /dev/null +++ b/docs/modules.rst @@ -0,0 +1,8 @@ +astartes +======== + +.. toctree:: + :maxdepth: 4 + + astartes + test diff --git a/docs/objects.inv b/docs/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..007f435366e209c5c61eb33e03ff8e8fe517f52c GIT binary patch literal 2220 zcmV;d2vheXAX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGkmb97;H zbY*i2BOq2~a&u{KZaN?eBOp|0Wgv28ZDDC{WMy(7Z)PBLXlZjGW@&6?AZc?TV{dJ6 za%FRKWn>_Ab7^j8AbMtESCT|zltk}4C_~j>AYKMRF-oLdCo5am z>xmC6$P=Y-YO@59!@R(V4X9P;4(oR;0Ux=PDUqU>6z_oXrz&C75F{9K-d51YUj`fl zkP+FMK&ybno~GU@o{#_uF1e_iJ|GPxyX+}2iOB<5`WjjtPGzOEZak@7NknCBi%8L{ zq$ntcy045ItyOl03ESn73iN09KKN*Idx%YDt{T?tx< zjAwaJEh>)qtNgz)T%q)+IduO>GcG22gD19}zQ`UgP`(ZwOZJp<6oyQ8o86A$G^k0` zB=M%j=G`cIEYd6pVo)IPi1LhsykyBU1(wRe8nlt3P60x4=UF|KT7y|IMJi`Uff$QD zVhEsDH7JE1MY?41Mkn01$-Uc@$Z}~tkfX32q@jto^5^H8(1SjinkCE}=B=_bl(5S` zBSIicxu68CMihTB51X2GxXB!(bJ!RpDb1T@Q!usKMDch15JVwfydHuoq6p&6w}1XU zPyAA3cwoY%vxem|*^n`K0OC*}ut&HUTyKtj--;d$#cB0T=S!L$H^B zG4uw?kSH0c9+#m?*NX~O<(!6WK;kjKi(!mXPl69)`;xv|3oCr}BS+GG_>z7Y+n4k|NTM_zFfw@>yNI4>o{*x+^-)>=}Auh^zUZ{K-o!xLgP(Vi{^R zG=UvV1Z9UaRPP|w2KHwI+#45960HMx);phoZg#oY67-Tw=yQki1|*it`~u6tt$y2( z1Kk0Zz3~=s7?b)58Og}gIm*`%@wJ|CD8c?VNedmwFyL8sbcB^Y6tNvj#70eJg-r7# z?;x-rxgY2~6vjQd&tX1rXfT>W78nI&fUp&MXX>M5dldwKG@SDAW05i zv%Jhf0x=FpV%bqp2III``g~T`JBds%TFTWMr#W&Rj`?J+*STSBqVdPB*rb`1%@VZl zJeoYW^JwK)V^at$qq~i5xuP!g0?bio(osh$If=7ps8ct<4(BC-&La@`n!QZcAT=`e;z@S@uQb z_z+YMSA=;W>#pOZw;kS4_U+J5U)LLyYaQbqh$IhWw(WrOK6@xr9cEq2JVzv0eN8eYOD;X99FZ}6MEJ6;(mbo< zU-Xt_QIBs$9{+x#wGlkM&1V&!;}`4-W;!?++PMZ{H9hUhFyf9JBKYGz!6}86W8l@i zA$h99vo|W1+FO~qnR1qd?06|Bbhj}~)zL=pDo_}`+H7le4F_|#r7uIhhQZI0U@hD3 z-3kk2+4^#rR=ImaEQCf4(^?kYVXbF+da8F=o%#4y*Cw4kS(;?;-yP`WjToZIH!-n} z+j@QxO*6Q7`WEhpoL-1;%09x>T=!G=fd-n~H)oZqE?vQA_o){-O!{|q2oGw>Uf={UCH|FSJd3&fXOp_LXK~Mx$0WsI+5eMVMA!0FDs2= z_dnwhO@66qkk|gy!zge6?tL`*>4+|`F>@D9V;)iWHh%>o?JgrJdeznS4wwR{Q%%)7 z_48d*tYT@EIKJ7`G6~sL9pJ^`s?IRA?@fOQqTK)w>qV1pc>!>^H=w;Rv#1 zZ&x&Frq0IXe^YH#2g<3T$YJD;Y=g0t>j$2xmQbBcMLyJJBS9NQ^bM94-tn?lWbU?9 zZ>oD;t6QTJ!y5IjceQa^v3OmaPAFc~i-T?B= + + + + + Python Module Index — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Python Module Index

+ +
+ a | + t +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ a
+ astartes +
    + astartes.main +
    + astartes.molecules +
    + astartes.samplers +
    + astartes.samplers.abstract_sampler +
    + astartes.samplers.extrapolation +
    + astartes.samplers.extrapolation.dbscan +
    + astartes.samplers.extrapolation.kmeans +
    + astartes.samplers.extrapolation.optisim +
    + astartes.samplers.extrapolation.scaffold +
    + astartes.samplers.extrapolation.sphere_exclusion +
    + astartes.samplers.extrapolation.time_based +
    + astartes.samplers.interpolation +
    + astartes.samplers.interpolation.kennardstone +
    + astartes.samplers.interpolation.random_split +
    + astartes.samplers.interpolation.spxy +
    + astartes.utils +
    + astartes.utils.array_type_helpers +
    + astartes.utils.exceptions +
    + astartes.utils.fast_kennard_stone +
    + astartes.utils.sampler_factory +
    + astartes.utils.user_utils +
    + astartes.utils.warnings +
 
+ t
+ test +
    + test.functional +
    + test.functional.test_astartes +
    + test.functional.test_molecules +
    + test.regression +
    + test.regression.test_regression +
    + test.unit +
    + test.unit.samplers +
    + test.unit.samplers.extrapolative +
    + test.unit.samplers.extrapolative.test_DBSCAN +
    + test.unit.samplers.extrapolative.test_kmeans +
    + test.unit.samplers.extrapolative.test_optisim +
    + test.unit.samplers.extrapolative.test_Scaffold +
    + test.unit.samplers.extrapolative.test_sphere_exclusion +
    + test.unit.samplers.extrapolative.test_time_based +
    + test.unit.samplers.interpolative +
    + test.unit.samplers.interpolative.test_kennard_stone +
    + test.unit.samplers.interpolative.test_random +
    + test.unit.samplers.interpolative.test_spxy +
    + test.unit.utils +
    + test.unit.utils.test_convert_to_array +
    + test.unit.utils.test_sampler_factory +
    + test.unit.utils.test_utils +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/search.html b/docs/search.html new file mode 100644 index 00000000..b3370440 --- /dev/null +++ b/docs/search.html @@ -0,0 +1,133 @@ + + + + + + Search — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+ +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/docs/searchindex.js b/docs/searchindex.js new file mode 100644 index 00000000..24194195 --- /dev/null +++ b/docs/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["CONTRIBUTING", "README", "astartes", "astartes.samplers", "astartes.samplers.extrapolation", "astartes.samplers.interpolation", "astartes.utils", "index", "modules", "sklearn_to_astartes", "test", "test.functional", "test.regression", "test.unit", "test.unit.samplers", "test.unit.samplers.extrapolative", "test.unit.samplers.interpolative", "test.unit.utils"], "filenames": ["CONTRIBUTING.rst", "README.rst", "astartes.rst", "astartes.samplers.rst", "astartes.samplers.extrapolation.rst", "astartes.samplers.interpolation.rst", "astartes.utils.rst", "index.rst", "modules.rst", "sklearn_to_astartes.rst", "test.rst", "test.functional.rst", "test.regression.rst", "test.unit.rst", "test.unit.samplers.rst", "test.unit.samplers.extrapolative.rst", "test.unit.samplers.interpolative.rst", "test.unit.utils.rst"], "titles": ["Contributing & Developer Notes", "Online Documentation", "astartes package", "astartes.samplers package", "astartes.samplers.extrapolation package", "astartes.samplers.interpolation package", "astartes.utils package", "astartes documentation", "astartes", "Transitioning from sklearn to astartes", "test package", "test.functional package", "test.regression package", "test.unit package", "test.unit.samplers package", "test.unit.samplers.extrapolative package", "test.unit.samplers.interpolative package", "test.unit.utils package"], "terms": {"pull": 0, "request": [0, 1, 6, 9, 11, 16], "bug": [0, 1], "report": 0, "all": [0, 1, 3, 4, 9, 11, 17], "ar": [0, 1, 4, 9], "welcom": 0, "encourag": [0, 9], "appreci": 0, "pleas": [0, 1], "us": [0, 2, 4, 6, 7, 11, 15, 16, 17], "appropri": [0, 1, 6], "issu": 0, "templat": 0, "when": [0, 1, 6, 9, 11, 16, 17], "make": [0, 1, 9], "help": [0, 1, 9, 11], "maintain": 0, "get": [0, 1, 3, 9], "merg": 0, "quickli": [0, 1], "we": [0, 1, 4, 6, 9], "github": [0, 1, 9], "discuss": [0, 1], "page": [0, 1], "go": [0, 4], "over": [0, 6], "potenti": [0, 1], "add": [0, 4, 6, 9], "feel": 0, "free": 0, "stop": [0, 4], "you": [0, 1, 9], "look": [0, 1, 4, 9], "someth": [0, 15], "have": [0, 1, 4, 9], "an": [0, 1, 4, 6, 7, 11], "idea": 0, "submit": 0, "pr": 0, "mark": 0, "your": [0, 1, 9], "readi": 0, "review": 0, "label": [0, 1, 2, 3, 4, 5, 6, 9, 11, 12, 15], "finish": 0, "chang": [0, 1, 7], "so": [0, 1, 9], "action": 0, "bot": 0, "can": [0, 1, 5, 9, 11], "work": [0, 1, 4, 6, 9], "magic": 0, "To": [0, 1, 4, 9], "astart": [0, 11], "sourc": [0, 4, 5, 7], "code": [0, 5, 6], "start": [0, 4, 7, 11], "fork": 0, "clone": [0, 1], "repositori": [0, 1], "i": [0, 1, 3, 4, 5, 6, 9, 11, 16], "e": [0, 1, 9], "git": [0, 1], "com": [0, 1, 4], "yourusernam": 0, "insid": 0, "run": [0, 1], "pip": [0, 7, 9], "dev": 0, "thi": [0, 1, 4, 5, 6, 9], "set": [0, 1, 2, 4, 5, 6, 9, 11], "up": 0, "requir": [0, 1, 9, 16], "depend": [0, 1], "conform": 0, "our": [0, 1, 9], "format": [0, 1, 6], "standard": [0, 9], "black": 0, "isort": 0, "which": [0, 1, 4, 5, 6, 9, 12], "configur": [0, 1], "automat": 0, "vscode": 0, "like": [0, 1, 4, 5, 9], "warn": [0, 1, 2, 8, 11, 15, 17], "window": [0, 1], "powershel": [0, 1], "maco": [0, 1], "catalina": [0, 1], "newer": [0, 1, 12], "zsh": [0, 1], "doubl": [0, 1], "quot": [0, 1], "around": [0, 1], "charact": [0, 1], "pyproject": 0, "toml": 0, "specifi": [0, 1, 6, 7, 11, 15], "metadata": [0, 6], "also": [0, 1, 4, 6, 9], "__init__": [0, 2, 3, 6], "py": [0, 17], "via": [0, 1], "__version__": 0, "backward": [0, 1], "compat": [0, 1, 9, 11], "python": [0, 1, 9], "3": [0, 1, 4, 7, 12], "7": [0, 1], "c": [0, 1], "import": [0, 1, 7], "print": [0, 6], "from": [0, 1, 2, 4, 5, 7, 15], "importlib": 0, "8": [0, 1, 2, 6, 9], "written": 0, "built": [0, 1], "unittest": 0, "modul": [0, 1, 7, 8], "allow": [0, 1, 9], "without": [0, 6], "pytest": 0, "highli": 0, "recommend": [0, 1], "execut": [0, 1], "simpli": [0, 1, 9], "type": [0, 1, 2, 3, 6, 9, 17], "after": [0, 1, 2, 4, 6], "altern": [0, 1], "v": 0, "more": [0, 1, 4, 6], "output": [0, 5], "On": 0, "everi": [0, 4, 11], "nightli": 0, "basi": 0, "workflow": [0, 1, 9], "inform": [0, 1], "These": [0, 1], "includ": [0, 1, 4, 9, 15], "unit": [0, 1, 5, 8, 10], "regress": [0, 7, 8, 10, 17], "should": [0, 1, 6, 9, 11, 15, 16, 17], "extend": 0, "abstract_sampl": [0, 2, 8], "abstract": [0, 3, 4], "base": [0, 1, 3, 4, 5, 6, 11, 12, 15, 16, 17], "class": [0, 3, 4, 5, 6, 11, 12, 15, 16, 17], "each": [0, 1, 4], "subclass": 0, "overrid": 0, "_sampl": [0, 1], "method": [0, 1, 5, 12], "its": [0, 1, 9], "own": [0, 1], "data": [0, 2, 4, 6, 7, 9, 11, 15], "partit": [0, 1, 4, 5], "option": [0, 1, 2, 3, 6, 9, 11], "_before_sampl": 0, "perform": [0, 1, 6, 9], "ani": [0, 1, 3, 4, 6], "valid": [0, 1, 2, 4, 5, 6, 9, 11], "classifi": 0, "one": [0, 1, 4, 9, 16], "two": [0, 1, 4, 9], "extrapol": [0, 1, 2, 3, 11, 12, 13, 14], "interpol": [0, 1, 2, 3, 11, 12, 13, 14], "cluster": [0, 1, 3, 4], "group": 0, "train": [0, 1, 2, 4, 6, 9, 11], "enforc": 0, "wherea": 0, "provid": [0, 1, 3, 6, 16], "exact": [0, 1, 9], "order": [0, 3, 6], "move": [0, 1, 4, 9], "actual": [0, 1, 9], "mean": [0, 1], "self": [0, 1, 4], "_samples_clust": 0, "attribut": [0, 3, 6, 11, 12, 15, 16, 17], "_samples_idx": 0, "simpl": [0, 1, 17], "passthrough": [0, 1], "anoth": [0, 6], "train_test_split": [0, 1, 2, 8, 9, 11, 15, 16], "origin": [0, 1, 4, 5], "result": [0, 1, 4, 6, 11, 12, 15, 16, 17], "x": [0, 1, 2, 3, 4, 5, 6, 9, 11], "y": [0, 1, 2, 3, 4, 5, 6, 9, 11, 16], "being": [0, 4, 6], "split": [0, 2, 4, 6, 7, 9, 11, 12, 16, 17], "list": [0, 1, 2, 4, 9], "take": [0, 1, 4], "random_split": [0, 2, 3], "basic": 0, "exampl": [0, 7, 9], "ha": [0, 1, 4, 5, 9, 12], "been": [0, 1, 4, 5, 9], "addit": [0, 1, 6, 9], "verifi": [0, 1, 15, 16], "hyperparamet": [0, 1, 2, 6, 9, 11], "properli": [0, 1], "pass": [0, 1, 3, 6, 7, 11], "etc": 0, "For": [0, 1, 9], "histor": 0, "reason": 0, "guid": [0, 1], "who": 0, "would": [0, 4, 6, 11], "below": [0, 1, 3, 9], "consid": [0, 1], "asart": 0, "ultim": [0, 5], "variou": [0, 11, 15, 16], "name": [0, 1, 6], "relev": 0, "link": [0, 1, 5], "": [0, 1, 2, 9], "d": 0, "optim": [0, 1], "priori": 0, "knowledg": 0, "size": [0, 2, 3, 4, 6, 11], "doe": [0, 6], "fit": [0, 4, 6], "framework": [0, 4], "agnost": 0, "question": 0, "fischer": 0, "matrix": [0, 6], "meaning": 0, "context": 0, "exist": [0, 1, 6, 9], "rather": [0, 9], "than": [0, 1, 4, 9, 15], "tune": [0, 9], "ideal": 0, "wikipedia": [0, 1], "articl": [0, 1], "design": [0, 1, 9], "good": 0, "job": 0, "explain": [0, 1], "why": [0, 1], "difficult": [0, 1], "point": [0, 1, 4, 9], "some": [0, 1, 6, 9], "duplex": 0, "know": [0, 1], "befor": 0, "onli": [0, 1], "incompat": [0, 1], "r": [0, 1], "refer": [0, 1, 12], "accept": [0, 1], "arbitrari": [0, 1, 2, 4, 9], "arrai": [0, 1, 2, 3, 6, 9, 11, 16, 17], "number": [0, 3, 15], "return": [0, 1, 2, 3, 4, 6, 9, 11, 17], "except": [0, 1, 2, 8, 9, 11], "scaffold": [0, 1, 2, 3, 6, 15], "If": [0, 1, 4, 9, 11], "input": [0, 1, 9, 11, 15, 17], "turn": 0, "thrill": 0, "interfac": [0, 11], "def": [0, 9], "train_test_split_interfac": 0, "interface_input": 0, "interface_arg": 0, "np": [0, 2, 3, 6, 9], "none": [0, 1, 2, 3, 6, 9], "test_siz": [0, 1, 2, 6, 9], "float": [0, 2, 6, 9], "0": [0, 1, 2, 6, 9], "25": [0, 9], "train_siz": [0, 1, 2, 6, 9], "75": [0, 2, 9], "splitter": 0, "str": [0, 2, 3, 6, 9], "random": [0, 1, 2, 3, 4, 5, 6, 9, 16], "hopt": [0, 1, 2, 3, 6, 9, 11], "dict": [0, 2, 3, 6, 9], "interface_hopt": 0, "arg": 0, "where": [0, 9], "behavior": [0, 1, 9], "call": [0, 1, 3, 6, 9, 15, 17], "possibl": [0, 1, 4, 9, 16], "jupyt": 0, "notebook": [0, 7], "demonstr": 0, "user": [0, 1, 6, 9, 11], "how": [0, 7, 9], "see": [0, 1, 2, 9], "other": [0, 1, 9, 15], "directori": [0, 1], "contact": 0, "jacksonburn": [0, 1], "need": [0, 4, 7, 9], "assist": 0, "mai": [0, 1], "extra": [0, 9], "packag": [0, 1, 7, 8, 9], "same": [0, 1, 2, 4, 6, 9], "wai": [0, 1, 9], "molecul": [0, 4, 6, 8, 9, 11, 15], "workhors": [0, 9], "It": 0, "respons": [0, 1], "instanti": [0, 6, 15, 16], "while": [0, 1, 9], "keep": [0, 1], "ey": 0, "under": [0, 1], "hood": 0, "just": [0, 4, 9], "val_siz": [0, 2, 6, 9], "out": [0, 1, 9], "inlin": 0, "document": 0, "main": [0, 1, 8], "priorit": 0, "1": [0, 1, 2, 4, 6, 7], "reproduc": [0, 7], "2": [0, 1, 4, 7, 12], "flexibl": 0, "produc": [0, 1, 9], "across": [0, 1], "platform": [0, 1], "thorough": 0, "continu": [0, 1], "few": [0, 9], "loosest": 0, "integr": [0, 1], "tool": [0, 1], "easili": 0, "introduc": [0, 1, 4], "lot": [0, 6], "specif": [0, 7], "shuffl": [0, 1, 3, 11], "extras_requir": 0, "avoid": 0, "weigh": 0, "down": [0, 11], "modern": 0, "achiev": [0, 1], "tightli": 0, "well": [0, 1, 4, 12], "follow": [0, 1], "dry": 0, "don": 0, "t": [0, 11], "repeat": [0, 4], "yourself": 0, "principl": 0, "duplic": 0, "decreas": 0, "burden": 0, "perfect": [0, 1], "coverag": 0, "consist": [0, 1], "style": 0, "comment": 0, "critic": [0, 1], "time": [0, 1, 9], "write": 0, "line": [0, 9], "correspond": [0, 1, 2, 5, 6], "paper": [0, 1, 4, 5], "store": [0, 1], "separ": [0, 1, 9], "find": 0, "md": [0, 1], "aptli": 0, "push": 0, "updat": 0, "tar": 1, "tee": 1, "raw": 1, "html": [1, 4, 9], "m2r": 1, "p": 1, "align": 1, "center": [1, 4], "img": 1, "alt": 1, "astarteslogo": 1, "src": 1, "http": [1, 4, 9], "githubusercont": 1, "astartes_logo": 1, "png": 1, "statu": 1, "badg": 1, "usag": 1, "releas": 1, "nice": 1, "render": 1, "version": [1, 7], "readm": [1, 9], "along": 1, "tutori": 1, "sklearn": [1, 6, 7, 12], "read": 1, "within": [1, 4, 17], "virtual": 1, "environ": [1, 9], "either": [1, 6], "venv": 1, "simplifi": 1, "manag": 1, "9": 1, "10": [1, 4, 5], "11": [1, 4], "12": 1, "support": [1, 6, 9, 17], "text": 1, "avail": [1, 9], "pypi": 1, "featur": [1, 2, 4, 6, 7, 11], "fewer": 1, "readili": 1, "forg": 1, "command": 1, "aimsim": [1, 2, 9], "download": 1, "backend": 1, "molecular": [1, 2, 4, 9, 11], "section": 1, "machin": [1, 9], "learn": [1, 9], "spark": 1, "explos": 1, "progress": 1, "kinet": 1, "materi": 1, "scienc": 1, "mani": [1, 6, 9], "field": 1, "research": 1, "driven": 1, "acceler": 1, "step": [1, 4, 7, 11], "tradit": 1, "error": [1, 6, 11, 17], "toler": 1, "facilit": 1, "adopt": 1, "task": [1, 17], "select": [1, 4, 6], "held": [1, 9], "measur": [1, 4], "unseen": 1, "both": 1, "futur": 1, "address": 1, "function": [1, 4, 6, 7, 8, 9, 10, 15, 16, 17], "technic": 1, "detail": 1, "companion": 1, "journal": 1, "open": [1, 4], "softwar": 1, "dataset": [1, 2, 4, 6], "demo": 1, "fast": 1, "food": 1, "menu": 1, "publish": 1, "state": 1, "engin": 1, "confer": 1, "gener": [1, 9, 17], "involv": 1, "discoveri": 1, "infer": 1, "There": [1, 9], "cheminformat": [1, 4, 9], "numer": 1, "drop": 1, "replac": 1, "switch": [1, 9], "model_select": [1, 9], "iter": 1, "object": [1, 2, 6, 9, 11, 15], "convert": [1, 4, 6], "numpi": [1, 2, 6, 9], "intern": 1, "oper": 1, "panda": [1, 2, 6], "datafram": [1, 2, 6, 17], "seri": [1, 2, 6, 17], "cast": [1, 6, 17], "back": 1, "index": [1, 7], "column": [1, 6], "The": [1, 2, 4, 5, 6, 7, 9], "handl": [1, 17], "convers": [1, 4], "explicitli": 1, "behind": [1, 9], "scene": [1, 9], "lead": 1, "unexpect": 1, "By": [1, 9], "default": [1, 2, 3, 6, 9], "randomli": 1, "addition": 1, "varieti": 1, "approach": 1, "sampler": [1, 2, 6, 7, 8, 10, 11, 13, 17], "argument": [1, 7], "tabl": [1, 6], "complet": [1, 9], "load_diabet": 1, "return_x_i": 1, "true": [1, 2, 9], "x_train": [1, 9], "x_test": [1, 9], "y_train": [1, 9], "y_test": [1, 9], "prefer": 1, "kennard_ston": [1, 9, 16], "valueerror": [1, 15], "too": 1, "valu": [1, 2, 3, 4, 6, 9, 11], "unpack": 1, "split_comparison": 1, "googl": 1, "colab": 1, "blob": 1, "ipynb": 1, "_": [1, 9], "full": [1, 4], "explan": 1, "That": [1, 9], "next": 1, "try": [1, 9, 11], "browser": 1, "click": 1, "taken": 1, "live": 1, "interact": 1, "local": 1, "navig": 1, "editor": 1, "do": [1, 6, 9, 17], "cell": 1, "prefix": 1, "captur": 1, "thei": 1, "present": [1, 3], "rigor": 1, "ml": 1, "dure": [1, 9], "never": [1, 4], "unlik": 1, "accur": 1, "With": [1, 9], "three": [1, 9], "x_val": [1, 9], "sphere_exclus": [1, 2, 3, 9, 15], "now": [1, 9], "visual": 1, "differ": [1, 5, 11], "distribut": 1, "aid": 1, "analyz": 1, "generate_regression_results_dict": [1, 2, 6], "techniqu": 1, "nest": [1, 6], "dictionari": [1, 4, 6, 17], "metric": [1, 4, 6], "score": 1, "displai": 1, "neatli": 1, "print_result": [1, 6], "svm": 1, "linearsvr": 1, "util": [1, 2, 8, 10, 13], "grrd": 1, "sklearn_model": [1, 6], "results_dict": 1, "val": [1, 2, 6], "mae": [1, 6], "41522": 1, "13435": 1, "17091": 1, "rmse": [1, 6], "03062": 1, "73721": 1, "40041": 1, "r2": [1, 6], "90745": 1, "80787": 1, "78412": 1, "additional_metr": [1, 6], "map": [1, 4, 6, 15], "string": [1, 2, 3, 4, 6, 9], "itself": 1, "mean_absolute_percentage_error": 1, "add_met": 1, "mape": 1, "docstr": [1, 11], "whose": 1, "distance_metr": 1, "effect": 1, "co": 1, "opt": 1, "encod": [1, 9], "choic": 1, "jaccard_scor": 1, "distanc": [1, 4, 5, 6], "did": 1, "incept": 1, "though": [1, 4, 9], "adapt": [1, 4], "interest": [1, 9], "ad": [1, 4, 7], "In": [1, 9], "kennard": [1, 6, 9, 16], "stone": [1, 6, 9, 16], "retriev": 1, "kennardston": [1, 2, 3, 16], "4": [1, 4, 7], "5": [1, 4, 7], "6": [1, 4], "first_2_sampl": 1, "get_sample_idx": [1, 2, 3], "constructor": 1, "greedili": 1, "get_sampler_idx": 1, "get_cluster_idx": 1, "respect": 1, "implementaiton": 1, "motiv": 1, "comprehens": 1, "walkthrough": 1, "freeli": 1, "host": 1, "here": [1, 4], "public": 1, "wherev": 1, "lock": 1, "paywal": 1, "denot": 1, "small_blue_diamond": 1, "instead": [1, 2, 4, 6, 9], "suggest": [1, 4, 11], "absolut": 1, "attempt": [1, 6], "bypass": 1, "much": 1, "done": 1, "between": [1, 4], "similar": [1, 4], "divid": 1, "sphere": [1, 4, 9], "exclus": [1, 4, 9], "tropsha": 1, "et": [1, 4], "al": [1, 4], "optisim": [1, 2, 3, 15], "appli": 1, "chemoinformat": 1, "opportun": 1, "incorpor": 1, "dbscan": [1, 2, 3, 15], "broad": 1, "categori": 1, "former": 1, "forc": 1, "predict": 1, "creat": [1, 4], "challeng": 1, "current": [1, 9], "understand": 1, "random_st": [1, 2, 3, 6, 9, 11], "defin": 1, "keyword": [1, 7], "even": 1, "overwritten": 1, "direct": 1, "euclidian": [1, 4], "describ": [1, 4, 5], "joint": 1, "spxy": [1, 2, 3, 16], "saldhana": 1, "extens": 1, "mahalanobi": 1, "mdk": 1, "deriv": 1, "saptoro": 1, "include_chir": [1, 4], "bemi": [1, 4, 6], "murcko": [1, 4, 6], "rdkit": [1, 2, 4, 6, 9, 11], "smile": [1, 2, 4, 9, 15], "distance_cutoff": [1, 9], "custom": 1, "variat": 1, "vector": [1, 2, 4, 6, 9], "time_bas": [1, 2, 3, 15], "chen": 1, "sheridan": 1, "feinberg": 1, "strubl": 1, "date": [1, 15], "datetim": [1, 15], "optimiz": [1, 4], "k": [1, 4], "dissimilar": [1, 4], "n_cluster": [1, 9], "max_subsample_s": 1, "kmean": [1, 2, 3, 9, 12, 15], "n_init": 1, "scikit": 1, "org": [1, 4], "stabl": 1, "densiti": 1, "spatial": [1, 4], "nois": 1, "ep": 1, "min_sampl": 1, "leaf_siz": 1, "minimum": 1, "mtsd": 1, "upcom": 1, "v1": [1, 12], "restrict": 1, "boltzmann": 1, "rbm": 1, "kohonen": 1, "organ": 1, "som": 1, "new": [1, 3, 7], "enorm": 1, "chemistri": 1, "relat": 1, "due": 1, "high": 1, "dimension": 1, "space": 1, "accuraci": 1, "process": [1, 4], "pre": [1, 4], "common": 1, "train_test_split_molecul": [1, 2, 8, 9], "ident": [1, 9], "control": [1, 9], "fingerprint": [1, 2, 11], "daylight_fingerprint": [1, 11], "fprints_hopt": [1, 2], "minpath": 1, "maxpath": 1, "fpsize": 1, "200": 1, "bitsperhash": 1, "useh": 1, "tgtdensiti": 1, "minsiz": 1, "64": 1, "42": [1, 2, 9], "brief": 1, "scheme": [1, 7, 9], "found": [1, 5], "most": [1, 4, 9], "shown": 1, "abov": [1, 2, 5], "aim": 1, "alwai": 1, "end": 1, "seed": [1, 2, 6], "debian": 1, "ubuntu": 1, "intel": 1, "mac": 1, "through": [1, 9, 11], "inevit": 1, "extern": 1, "catch": 1, "initi": [1, 4, 6], "affect": 1, "given": [1, 4, 9], "abil": [1, 11, 15], "m1": 1, "manual": 1, "reproducbl": 1, "case": [1, 4], "occasion": 1, "appl": 1, "silicon": 1, "still": [1, 9], "appar": 1, "button": 1, "instruct": 1, "guidanc": 1, "abstractsampl": [2, 3, 4, 5], "get_clust": [2, 3, 6], "get_config": [2, 3], "get_sorted_cluster_count": [2, 3], "array_type_help": [2, 8], "convert_to_arrai": [2, 6], "panda_handla": [2, 6], "return_help": [2, 6], "invalidconfigurationerror": [2, 6], "invalidmodeltypeerror": [2, 6], "moleculesnotinstallederror": [2, 6], "samplernotimplementederror": [2, 6], "uncastableinputerror": [2, 6], "fast_kennard_ston": [2, 8], "sampler_factori": [2, 8], "samplerfactori": [2, 6, 17], "get_sampl": [2, 6], "user_util": [2, 8], "display_results_as_t": [2, 6], "conversionwarn": [2, 6], "imperfectsplittingwarn": [2, 6], "nomatchingscaffold": [2, 6], "normalizationwarn": [2, 6], "int": [2, 6], "return_indic": [2, 6], "bool": [2, 6, 9], "fals": [2, 4, 6, 9], "determinist": 2, "paramet": [2, 3, 6], "target": [2, 6, 7], "must": [2, 6], "fraction": [2, 6], "test": [2, 4, 5, 6, 7, 8, 9], "implemented_int": 2, "extrapolation_sampl": 2, "throughout": [2, 6], "indic": [2, 4, 6, 9, 11], "train_val_test_split": [2, 7, 8, 11], "pd": [2, 6], "morgan_fingerprint": 2, "repres": 2, "reaction": 2, "train_val_test_split_molecul": [2, 8, 11], "get_dist": [3, 4], "move_item": [3, 4], "rchoos": [3, 4], "generate_bemis_murcko_scaffold": [3, 4], "scaffold_to_smil": [3, 4], "str_to_mol": [3, 4], "sphereexclus": [3, 4], "timebas": [3, 4, 12, 15], "sampl": [3, 4, 5, 7, 9], "config": [3, 4, 5], "abc": 3, "copi": [3, 6], "getter": 3, "kei": [3, 6], "_config": 3, "els": 3, "n_sampl": 3, "idx": 3, "max_shufflable_s": 3, "contain": [3, 4, 17], "cluster_id": 3, "member": [3, 4], "sort": 3, "ascend": 3, "accord": [3, 9], "algorithm": [4, 5, 6, 7], "clark": 4, "pub": 4, "ac": 4, "doi": [4, 5], "1021": 4, "ci970282v": 4, "treat": 4, "remain": 4, "candid": 4, "empti": [4, 6], "recycl": 4, "bin": 4, "subsampl": 4, "remov": 4, "greater": 4, "cutoff": 4, "otherwis": [4, 6], "until": [4, 9], "condit": 4, "met": 4, "reach": 4, "determin": 4, "maximum": 4, "exhaust": 4, "b": 4, "quit": 4, "alreadi": [4, 9], "identifi": 4, "pick": 4, "rel": [4, 12], "suffici": 4, "As": 4, "assign": 4, "element": 4, "belong": 4, "implement": [4, 5, 6, 9], "scipi": 4, "cdist": 4, "seem": 4, "might": 4, "infinit": 4, "loop": [4, 6], "fill": [4, 6], "cannot": [4, 6, 15], "unless": 4, "empyt": 4, "somehow": 4, "fix": 4, "partial": 4, "sinc": 4, "probabl": 4, "reject": 4, "check": [4, 7, 9, 11, 12], "exit": 4, "j": [4, 5], "calcul": [4, 15], "pdist": 4, "item": [4, 6], "source_set": 4, "destintation_set": 4, "destination_set": 4, "choos": 4, "_rng": 4, "g": 4, "w": 4, "m": 4, "A": [4, 5], "properti": 4, "known": [4, 7], "drug": 4, "med": 4, "chem": 4, "1996": 4, "39": 4, "2887": 4, "2893": 4, "landrum": 4, "2006": 4, "www": 4, "goal": 4, "share": 4, "later": [4, 9, 11, 12, 15, 16], "mol": 4, "comput": 4, "param": 4, "whether": [4, 6], "chiral": [4, 15], "uniqu": 4, "inchi": [4, 15], "re": [4, 16, 17], "draw": 4, "blog": 4, "post": 4, "blogspot": 4, "2020": 4, "daylight": 4, "whitepap": 4, "clusteringwhitepap": 4, "pdf": 4, "But": [4, 9], "tanimoto": 4, "domain": [4, 7], "zero": [4, 11], "enabl": 4, "join": 5, "saldanha": 5, "cowork": 5, "calibr": 5, "subset": 5, "1016": 5, "talanta": 5, "2005": 5, "03": 5, "025": 5, "against": 5, "reflect": 5, "expect": [5, 11], "implemen": 5, "break": 5, "ti": 5, "compar": 5, "minor": 5, "inconsequenti": 5, "obj": 6, "human": 6, "readabl": 6, "helper": 6, "deal": 6, "sampler_inst": 6, "train_idx": 6, "val_idx": 6, "test_idx": 6, "output_is_panda": 6, "conveni": [6, 11, 12, 15, 16], "instanc": 6, "about": 6, "note": [6, 7, 11], "past": 6, "could": [6, 9], "prone": 6, "long": 6, "prettiest": 6, "definit": 6, "what": 6, "want": [6, 9], "messag": 6, "runtimeerror": 6, "model": [6, 7, 9], "invalid": 6, "instal": [6, 7], "non": 6, "ks_distanc": 6, "ndarrai": 6, "lowercas": 6, "desir": 6, "rais": [6, 11, 15, 17], "yet": 6, "error_dict": 6, "neat": 6, "tabul": 6, "samplers_hopt": 6, "func": 6, "those": 6, "runtimewarn": 6, "match": 6, "onlin": 7, "conda": [7, 9], "statement": 7, "audienc": 7, "quick": 7, "withhold": 7, "evalu": 7, "impact": 7, "categor": 7, "access": 7, "directli": [7, 9, 15, 16], "theori": 7, "applic": 7, "ration": 7, "limit": 7, "cite": 7, "contribut": 7, "develop": 7, "philosophi": 7, "joss": 7, "branch": 7, "transit": 7, "subpackag": 8, "submodul": [8, 10, 13, 14], "content": 8, "test_astart": [8, 10], "test_molecul": [8, 10], "test_regress": [8, 10], "reli": 9, "becaus": 9, "part": 9, "vlachosgroup": 9, "io": 9, "pars": 9, "graph": [9, 11], "singl": 9, "place": 9, "represent": 9, "chemic": 9, "invit": 9, "explor": 9, "descriptor": [9, 11], "made": 9, "first": 9, "script": 9, "were": 9, "becom": 9, "interoper": 9, "real": 9, "them": [9, 17], "labels_train": 9, "labels_test": 9, "tunabl": 9, "fine": 9, "15": 9, "circumst": 9, "larg": 9, "memori": 9, "intens": 9, "themselv": 9, "manipul": 9, "indices_train": 9, "indices_test": 9, "benefici": 9, "usual": 9, "y_val": 9, "truli": 9, "veri": 9, "final": 9, "sens": 9, "better": 9, "wors": 9, "author": 9, "believ": 9, "event": [9, 11], "mathemat": [9, 16], "dimens": 9, "50": 9, "101": 9, "runtim": 9, "occur": 9, "quietli": 9, "felt": 9, "prudent": 9, "enter": 9, "normal": 9, "hopefulli": 9, "prevent": 9, "head": 9, "scratch": 9, "hour": 9, "debug": 9, "setupclass": [10, 11, 12, 13, 14, 15, 16, 17], "test_close_mispelling_sampl": [10, 11], "test_extrapolative_shuffl": [10, 11], "test_inconsistent_input_length": [10, 11], "test_insufficient_dataset_test": [10, 11], "test_insufficient_dataset_train": [10, 11], "test_insufficient_dataset_v": [10, 11], "test_not_implemented_sampl": [10, 11], "test_return_indic": [10, 11], "test_return_indices_with_valid": [10, 11], "test_split_valid": [10, 11], "test_train_test_split": [10, 11, 13, 17], "test_train_val_test_split": [10, 11], "test_train_val_test_split_extrpolation_shuffl": [10, 11], "test_fingerprint": [10, 11], "test_fprint_hopt": [10, 11], "test_maximum_cal": [10, 11], "test_molecules_with_rdkit": [10, 11], "test_molecules_with_troublesome_smil": [10, 11], "test_sampler_hopt": [10, 11], "test_validation_split_molecul": [10, 11], "test_extrapolation_regress": [10, 12], "test_interpolation_regress": [10, 12], "test_kmeans_regression_sklearn_v12": [10, 12], "test_kmeans_regression_sklearn_v13": [10, 12], "test_timebased_regress": [10, 12], "test_convert_to_arrai": [10, 13], "test_sampler_factori": [10, 13], "test_util": [10, 13], "methodnam": [11, 12, 15, 16, 17], "runtest": [11, 12, 15, 16, 17], "testcas": [11, 12, 15, 16, 17], "classmethod": [11, 12, 15, 16, 17], "typo": 11, "length": 11, "round": 11, "funat": 11, "imperfect": 11, "inhomogen": 11, "variabl": 11, "save": [12, 16, 17], "static": 12, "earlier": 12, "test_dbscan": [13, 14], "test_scaffold": [13, 14], "test_kmean": [13, 14], "test_optisim": [13, 14], "test_sphere_exclus": [13, 14], "test_time_bas": [13, 14], "test_kennard_ston": [13, 14], "test_random": [13, 14], "test_spxi": [13, 14], "test_bad_type_cast": [13, 17], "test_convertable_input": [13, 17], "test_panda_handla": [13, 17], "test_unconvertable_input": [13, 17], "test_generate_regression_results_dict": [13, 17], "test_dbscan_sampl": [14, 15], "test_include_chir": [14, 15], "test_incorrect_input": [14, 15], "test_mol_from_inchi": [14, 15], "test_no_scaffold_found_warn": [14, 15], "test_remove_atom_map": [14, 15], "test_scaffold_sampl": [14, 15], "test_kmeans_sampling_v12": [14, 15], "test_kmeans_sampling_v13": [14, 15], "test_optisim_sampl": [14, 15], "test_sphereexclus": [14, 15], "test_sphereexclusion_sampl": [14, 15], "test_mising_label": [14, 15], "test_time_based_d": [14, 15], "test_time_based_datetim": [14, 15], "test_time_based_sampl": [14, 15], "test_kennard_stone_sampl": [14, 16], "test_kennard_stone_sample_no_warn": [14, 16], "test_random_sampl": [14, 16], "test_random_sample_no_warn": [14, 16], "test_missing_i": [14, 16], "test_spxy_sampl": [14, 16], "typeerror": 15, "load": 15, "atom": 15, "neither": 15, "nor": 15, "Not": 15, "tt": 16, "complain": 16, "fail": 17, "factori": 17}, "objects": {"": [[2, 0, 0, "-", "astartes"], [10, 0, 0, "-", "test"]], "astartes": [[2, 0, 0, "-", "main"], [2, 0, 0, "-", "molecules"], [3, 0, 0, "-", "samplers"], [6, 0, 0, "-", "utils"]], "astartes.main": [[2, 1, 1, "", "train_test_split"], [2, 1, 1, "", "train_val_test_split"]], "astartes.molecules": [[2, 1, 1, "", "train_test_split_molecules"], [2, 1, 1, "", "train_val_test_split_molecules"]], "astartes.samplers": [[3, 0, 0, "-", "abstract_sampler"], [4, 0, 0, "-", "extrapolation"], [5, 0, 0, "-", "interpolation"]], "astartes.samplers.abstract_sampler": [[3, 2, 1, "", "AbstractSampler"]], "astartes.samplers.abstract_sampler.AbstractSampler": [[3, 3, 1, "", "__init__"], [3, 3, 1, "", "get_clusters"], [3, 3, 1, "", "get_config"], [3, 3, 1, "", "get_sample_idxs"], [3, 3, 1, "", "get_sorted_cluster_counter"]], "astartes.samplers.extrapolation": [[4, 0, 0, "-", "dbscan"], [4, 0, 0, "-", "kmeans"], [4, 0, 0, "-", "optisim"], [4, 0, 0, "-", "scaffold"], [4, 0, 0, "-", "sphere_exclusion"], [4, 0, 0, "-", "time_based"]], "astartes.samplers.extrapolation.dbscan": [[4, 2, 1, "", "DBSCAN"]], "astartes.samplers.extrapolation.kmeans": [[4, 2, 1, "", "KMeans"]], "astartes.samplers.extrapolation.optisim": [[4, 2, 1, "", "OptiSim"]], "astartes.samplers.extrapolation.optisim.OptiSim": [[4, 3, 1, "", "get_dist"], [4, 3, 1, "", "move_item"], [4, 3, 1, "", "rchoose"]], "astartes.samplers.extrapolation.scaffold": [[4, 2, 1, "", "Scaffold"]], "astartes.samplers.extrapolation.scaffold.Scaffold": [[4, 3, 1, "", "generate_bemis_murcko_scaffold"], [4, 3, 1, "", "scaffold_to_smiles"], [4, 3, 1, "", "str_to_mol"]], "astartes.samplers.extrapolation.sphere_exclusion": [[4, 2, 1, "", "SphereExclusion"]], "astartes.samplers.extrapolation.time_based": [[4, 2, 1, "", "TimeBased"]], "astartes.samplers.interpolation": [[5, 0, 0, "-", "kennardstone"], [5, 0, 0, "-", "random_split"], [5, 0, 0, "-", "spxy"]], "astartes.samplers.interpolation.kennardstone": [[5, 2, 1, "", "KennardStone"]], "astartes.samplers.interpolation.random_split": [[5, 2, 1, "", "Random"]], "astartes.samplers.interpolation.spxy": [[5, 2, 1, "", "SPXY"]], "astartes.utils": [[6, 0, 0, "-", "array_type_helpers"], [6, 0, 0, "-", "exceptions"], [6, 0, 0, "-", "fast_kennard_stone"], [6, 1, 1, "", "generate_regression_results_dict"], [6, 0, 0, "-", "sampler_factory"], [6, 0, 0, "-", "user_utils"], [6, 0, 0, "-", "warnings"]], "astartes.utils.array_type_helpers": [[6, 1, 1, "", "convert_to_array"], [6, 1, 1, "", "panda_handla"], [6, 1, 1, "", "return_helper"]], "astartes.utils.exceptions": [[6, 4, 1, "", "InvalidConfigurationError"], [6, 4, 1, "", "InvalidModelTypeError"], [6, 4, 1, "", "MoleculesNotInstalledError"], [6, 4, 1, "", "SamplerNotImplementedError"], [6, 4, 1, "", "UncastableInputError"]], "astartes.utils.exceptions.InvalidConfigurationError": [[6, 3, 1, "", "__init__"]], "astartes.utils.exceptions.InvalidModelTypeError": [[6, 3, 1, "", "__init__"]], "astartes.utils.exceptions.MoleculesNotInstalledError": [[6, 3, 1, "", "__init__"]], "astartes.utils.exceptions.SamplerNotImplementedError": [[6, 3, 1, "", "__init__"]], "astartes.utils.exceptions.UncastableInputError": [[6, 3, 1, "", "__init__"]], "astartes.utils.fast_kennard_stone": [[6, 1, 1, "", "fast_kennard_stone"]], "astartes.utils.sampler_factory": [[6, 2, 1, "", "SamplerFactory"]], "astartes.utils.sampler_factory.SamplerFactory": [[6, 3, 1, "", "__init__"], [6, 3, 1, "", "get_sampler"]], "astartes.utils.user_utils": [[6, 1, 1, "", "display_results_as_table"], [6, 1, 1, "", "generate_regression_results_dict"]], "astartes.utils.warnings": [[6, 4, 1, "", "ConversionWarning"], [6, 4, 1, "", "ImperfectSplittingWarning"], [6, 4, 1, "", "NoMatchingScaffold"], [6, 4, 1, "", "NormalizationWarning"]], "astartes.utils.warnings.ConversionWarning": [[6, 3, 1, "", "__init__"]], "astartes.utils.warnings.ImperfectSplittingWarning": [[6, 3, 1, "", "__init__"]], "astartes.utils.warnings.NoMatchingScaffold": [[6, 3, 1, "", "__init__"]], "astartes.utils.warnings.NormalizationWarning": [[6, 3, 1, "", "__init__"]], "test": [[11, 0, 0, "-", "functional"], [12, 0, 0, "-", "regression"], [13, 0, 0, "-", "unit"]], "test.functional": [[11, 0, 0, "-", "test_astartes"], [11, 0, 0, "-", "test_molecules"]], "test.functional.test_astartes": [[11, 2, 1, "", "Test_astartes"]], "test.functional.test_astartes.Test_astartes": [[11, 3, 1, "", "setUpClass"], [11, 3, 1, "", "test_close_mispelling_sampler"], [11, 3, 1, "", "test_extrapolative_shuffling"], [11, 3, 1, "", "test_inconsistent_input_lengths"], [11, 3, 1, "", "test_insufficient_dataset_test"], [11, 3, 1, "", "test_insufficient_dataset_train"], [11, 3, 1, "", "test_insufficient_dataset_val"], [11, 3, 1, "", "test_not_implemented_sampler"], [11, 3, 1, "", "test_return_indices"], [11, 3, 1, "", "test_return_indices_with_validation"], [11, 3, 1, "", "test_split_validation"], [11, 3, 1, "", "test_train_test_split"], [11, 3, 1, "", "test_train_val_test_split"], [11, 3, 1, "", "test_train_val_test_split_extrpolation_shuffling"]], "test.functional.test_molecules": [[11, 2, 1, "", "Test_molecules"]], "test.functional.test_molecules.Test_molecules": [[11, 3, 1, "", "setUpClass"], [11, 3, 1, "", "test_fingerprints"], [11, 3, 1, "", "test_fprint_hopts"], [11, 3, 1, "", "test_maximum_call"], [11, 3, 1, "", "test_molecules"], [11, 3, 1, "", "test_molecules_with_rdkit"], [11, 3, 1, "", "test_molecules_with_troublesome_smiles"], [11, 3, 1, "", "test_sampler_hopts"], [11, 3, 1, "", "test_validation_split_molecules"]], "test.regression": [[12, 0, 0, "-", "test_regression"]], "test.regression.test_regression": [[12, 2, 1, "", "Test_regression"]], "test.regression.test_regression.Test_regression": [[12, 3, 1, "", "setUpClass"], [12, 3, 1, "", "test_extrapolation_regression"], [12, 3, 1, "", "test_interpolation_regression"], [12, 3, 1, "", "test_kmeans_regression_sklearn_v12"], [12, 3, 1, "", "test_kmeans_regression_sklearn_v13"], [12, 3, 1, "", "test_timebased_regression"]], "test.unit": [[14, 0, 0, "-", "samplers"], [17, 0, 0, "-", "utils"]], "test.unit.samplers": [[15, 0, 0, "-", "extrapolative"], [16, 0, 0, "-", "interpolative"]], "test.unit.samplers.extrapolative": [[15, 0, 0, "-", "test_DBSCAN"], [15, 0, 0, "-", "test_Scaffold"], [15, 0, 0, "-", "test_kmeans"], [15, 0, 0, "-", "test_optisim"], [15, 0, 0, "-", "test_sphere_exclusion"], [15, 0, 0, "-", "test_time_based"]], "test.unit.samplers.extrapolative.test_DBSCAN": [[15, 2, 1, "", "Test_DBSCAN"]], "test.unit.samplers.extrapolative.test_DBSCAN.Test_DBSCAN": [[15, 3, 1, "", "setUpClass"], [15, 3, 1, "", "test_dbscan"], [15, 3, 1, "", "test_dbscan_sampling"]], "test.unit.samplers.extrapolative.test_Scaffold": [[15, 2, 1, "", "Test_scaffold"]], "test.unit.samplers.extrapolative.test_Scaffold.Test_scaffold": [[15, 3, 1, "", "setUpClass"], [15, 3, 1, "", "test_include_chirality"], [15, 3, 1, "", "test_incorrect_input"], [15, 3, 1, "", "test_mol_from_inchi"], [15, 3, 1, "", "test_no_scaffold_found_warning"], [15, 3, 1, "", "test_remove_atom_map"], [15, 3, 1, "", "test_scaffold"], [15, 3, 1, "", "test_scaffold_sampling"]], "test.unit.samplers.extrapolative.test_kmeans": [[15, 2, 1, "", "Test_kmeans"]], "test.unit.samplers.extrapolative.test_kmeans.Test_kmeans": [[15, 3, 1, "", "setUpClass"], [15, 3, 1, "", "test_kmeans"], [15, 3, 1, "", "test_kmeans_sampling_v12"], [15, 3, 1, "", "test_kmeans_sampling_v13"]], "test.unit.samplers.extrapolative.test_optisim": [[15, 2, 1, "", "Test_optisim"]], "test.unit.samplers.extrapolative.test_optisim.Test_optisim": [[15, 3, 1, "", "setUpClass"], [15, 3, 1, "", "test_optisim"], [15, 3, 1, "", "test_optisim_sampling"]], "test.unit.samplers.extrapolative.test_sphere_exclusion": [[15, 2, 1, "", "Test_sphere_exclusion"]], "test.unit.samplers.extrapolative.test_sphere_exclusion.Test_sphere_exclusion": [[15, 3, 1, "", "setUpClass"], [15, 3, 1, "", "test_sphereexclusion"], [15, 3, 1, "", "test_sphereexclusion_sampling"]], "test.unit.samplers.extrapolative.test_time_based": [[15, 2, 1, "", "Test_time_based"]], "test.unit.samplers.extrapolative.test_time_based.Test_time_based": [[15, 3, 1, "", "setUpClass"], [15, 3, 1, "", "test_incorrect_input"], [15, 3, 1, "", "test_mising_labels"], [15, 3, 1, "", "test_time_based_date"], [15, 3, 1, "", "test_time_based_datetime"], [15, 3, 1, "", "test_time_based_sampling"]], "test.unit.samplers.interpolative": [[16, 0, 0, "-", "test_kennard_stone"], [16, 0, 0, "-", "test_random"], [16, 0, 0, "-", "test_spxy"]], "test.unit.samplers.interpolative.test_kennard_stone": [[16, 2, 1, "", "Test_kennard_stone"]], "test.unit.samplers.interpolative.test_kennard_stone.Test_kennard_stone": [[16, 3, 1, "", "setUpClass"], [16, 3, 1, "", "test_kennard_stone"], [16, 3, 1, "", "test_kennard_stone_sample"], [16, 3, 1, "", "test_kennard_stone_sample_no_warning"]], "test.unit.samplers.interpolative.test_random": [[16, 2, 1, "", "Test_random"]], "test.unit.samplers.interpolative.test_random.Test_random": [[16, 3, 1, "", "setUpClass"], [16, 3, 1, "", "test_random"], [16, 3, 1, "", "test_random_sample"], [16, 3, 1, "", "test_random_sample_no_warning"]], "test.unit.samplers.interpolative.test_spxy": [[16, 2, 1, "", "Test_SPXY"]], "test.unit.samplers.interpolative.test_spxy.Test_SPXY": [[16, 3, 1, "", "setUpClass"], [16, 3, 1, "", "test_missing_y"], [16, 3, 1, "", "test_spxy"], [16, 3, 1, "", "test_spxy_sampling"]], "test.unit.utils": [[17, 0, 0, "-", "test_convert_to_array"], [17, 0, 0, "-", "test_sampler_factory"], [17, 0, 0, "-", "test_utils"]], "test.unit.utils.test_convert_to_array": [[17, 2, 1, "", "Test_convert_to_array"]], "test.unit.utils.test_convert_to_array.Test_convert_to_array": [[17, 3, 1, "", "test_bad_type_cast"], [17, 3, 1, "", "test_convertable_input"], [17, 3, 1, "", "test_panda_handla"], [17, 3, 1, "", "test_unconvertable_input"]], "test.unit.utils.test_sampler_factory": [[17, 2, 1, "", "Test_sampler_factory"]], "test.unit.utils.test_sampler_factory.Test_sampler_factory": [[17, 3, 1, "", "setUpClass"], [17, 3, 1, "", "test_train_test_split"]], "test.unit.utils.test_utils": [[17, 2, 1, "", "Test_utils"]], "test.unit.utils.test_utils.Test_utils": [[17, 3, 1, "", "setUpClass"], [17, 3, 1, "", "test_generate_regression_results_dict"]]}, "objtypes": {"0": "py:module", "1": "py:function", "2": "py:class", "3": "py:method", "4": "py:exception"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "function", "Python function"], "2": ["py", "class", "Python class"], "3": ["py", "method", "Python method"], "4": ["py", "exception", "Python exception"]}, "titleterms": {"contribut": [0, 1], "develop": [0, 1], "note": [0, 1], "instal": [0, 1, 9], "version": 0, "check": 0, "test": [0, 1, 10, 11, 12, 13, 14, 15, 16, 17], "ad": 0, "new": 0, "sampler": [0, 3, 4, 5, 9, 14, 15, 16], "Not": 0, "implement": [0, 1], "sampl": [0, 1], "algorithm": [0, 1, 9], "featur": [0, 9], "scheme": 0, "The": 0, "train_val_test_split": [0, 1, 9], "function": [0, 11], "philosophi": 0, "joss": 0, "branch": 0, "onlin": 1, "document": [1, 7], "astart": [1, 2, 3, 4, 5, 6, 7, 8, 9], "pip": 1, "conda": 1, "sourc": 1, "statement": [1, 9], "need": 1, "target": 1, "audienc": 1, "quick": 1, "start": 1, "exampl": 1, "notebook": 1, "withhold": 1, "data": 1, "evalu": 1, "impact": 1, "split": 1, "regress": [1, 12], "model": 1, "us": [1, 9], "categor": 1, "access": 1, "directli": 1, "theori": 1, "applic": 1, "ration": 1, "domain": 1, "specif": 1, "chemic": 1, "molecul": [1, 2], "subpackag": [1, 2, 3, 10, 13, 14], "reproduc": 1, "known": 1, "limit": 1, "how": 1, "cite": 1, "packag": [2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15, 16, 17], "submodul": [2, 3, 4, 5, 6, 11, 12, 15, 16, 17], "main": 2, "modul": [2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15, 16, 17], "content": [2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17], "abstract_sampl": 3, "extrapol": [4, 15], "dbscan": 4, "kmean": 4, "optisim": 4, "scaffold": 4, "sphere_exclus": 4, "time_bas": 4, "interpol": [5, 16], "kennardston": 5, "random_split": 5, "spxy": 5, "util": [6, 17], "array_type_help": 6, "except": 6, "fast_kennard_ston": 6, "sampler_factori": 6, "user_util": 6, "warn": [6, 9], "indic": 7, "tabl": 7, "transit": 9, "from": 9, "sklearn": 9, "step": 9, "1": 9, "2": 9, "chang": 9, "import": 9, "3": 9, "specifi": 9, "an": 9, "4": 9, "pass": 9, "keyword": 9, "argument": 9, "5": 9, "return_indic": 9, "improv": 9, "code": 9, "clariti": 9, "more": 9, "rigor": 9, "ml": 9, "custom": 9, "imperfectsplittingwarn": 9, "normalizationwarn": 9, "test_astart": 11, "test_molecul": 11, "test_regress": 12, "unit": [13, 14, 15, 16, 17], "test_dbscan": 15, "test_scaffold": 15, "test_kmean": 15, "test_optisim": 15, "test_sphere_exclus": 15, "test_time_bas": 15, "test_kennard_ston": 16, "test_random": 16, "test_spxi": 16, "test_convert_to_arrai": 17, "test_sampler_factori": 17, "test_util": 17}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 60}, "alltitles": {"Contributing & Developer Notes": [[0, "contributing-developer-notes"], [1, "id7"]], "Developer Install": [[0, "developer-install"]], "Version Checking": [[0, "version-checking"]], "Testing": [[0, "testing"]], "Adding New Samplers": [[0, "adding-new-samplers"]], "Not Implemented Sampling Algorithms": [[0, "not-implemented-sampling-algorithms"]], "Adding New Featurization Schemes": [[0, "adding-new-featurization-schemes"]], "The train_val_test_split Function": [[0, "the-train-val-test-split-function"]], "Development Philosophy": [[0, "development-philosophy"]], "JOSS Branch": [[0, "joss-branch"]], "Online Documentation": [[1, "online-documentation"]], "Installing astartes": [[1, "installing-astartes"]], "pip": [[1, "pip"]], "conda": [[1, "conda"]], "Source": [[1, "source"]], "Statement of Need": [[1, "statement-of-need"]], "Target Audience": [[1, "target-audience"]], "Quick Start": [[1, "quick-start"]], "Example Notebooks": [[1, "example-notebooks"]], "Withhold Testing Data with train_val_test_split": [[1, "withhold-testing-data-with-train-val-test-split"]], "Evaluate the Impact of Splitting Algorithms on Regression Models": [[1, "evaluate-the-impact-of-splitting-algorithms-on-regression-models"]], "Using astartes with Categorical Data": [[1, "using-astartes-with-categorical-data"]], "Access Sampling Algorithms Directly": [[1, "access-sampling-algorithms-directly"]], "Theory and Application of astartes": [[1, "theory-and-application-of-astartes"]], "Rational Splitting Algorithms": [[1, "rational-splitting-algorithms"]], "Implemented Sampling Algorithms": [[1, "implemented-sampling-algorithms"]], "Domain-Specific Applications": [[1, "domain-specific-applications"]], "Chemical Data and the astartes.molecules Subpackage": [[1, "chemical-data-and-the-astartes-molecules-subpackage"]], "Reproducibility": [[1, "reproducibility"]], "Known Reproducibility Limitations": [[1, "known-reproducibility-limitations"]], "How to Cite": [[1, "how-to-cite"]], "astartes package": [[2, "astartes-package"]], "Subpackages": [[2, "subpackages"], [3, "subpackages"], [10, "subpackages"], [13, "subpackages"], [14, "subpackages"]], "Submodules": [[2, "submodules"], [3, "submodules"], [4, "submodules"], [5, "submodules"], [6, "submodules"], [11, "submodules"], [12, "submodules"], [15, "submodules"], [16, "submodules"], [17, "submodules"]], "astartes.main module": [[2, "module-astartes.main"]], "astartes.molecules module": [[2, "module-astartes.molecules"]], "Module contents": [[2, "module-astartes"], [3, "module-astartes.samplers"], [4, "module-astartes.samplers.extrapolation"], [5, "module-astartes.samplers.interpolation"], [6, "module-astartes.utils"], [10, "module-test"], [11, "module-test.functional"], [12, "module-test.regression"], [13, "module-test.unit"], [14, "module-test.unit.samplers"], [15, "module-test.unit.samplers.extrapolative"], [16, "module-test.unit.samplers.interpolative"], [17, "module-test.unit.utils"]], "astartes.samplers package": [[3, "astartes-samplers-package"]], "astartes.samplers.abstract_sampler module": [[3, "module-astartes.samplers.abstract_sampler"]], "astartes.samplers.extrapolation package": [[4, "astartes-samplers-extrapolation-package"]], "astartes.samplers.extrapolation.dbscan module": [[4, "module-astartes.samplers.extrapolation.dbscan"]], "astartes.samplers.extrapolation.kmeans module": [[4, "module-astartes.samplers.extrapolation.kmeans"]], "astartes.samplers.extrapolation.optisim module": [[4, "module-astartes.samplers.extrapolation.optisim"]], "astartes.samplers.extrapolation.scaffold module": [[4, "module-astartes.samplers.extrapolation.scaffold"]], "astartes.samplers.extrapolation.sphere_exclusion module": [[4, "module-astartes.samplers.extrapolation.sphere_exclusion"]], "astartes.samplers.extrapolation.time_based module": [[4, "module-astartes.samplers.extrapolation.time_based"]], "astartes.samplers.interpolation package": [[5, "astartes-samplers-interpolation-package"]], "astartes.samplers.interpolation.kennardstone module": [[5, "module-astartes.samplers.interpolation.kennardstone"]], "astartes.samplers.interpolation.random_split module": [[5, "module-astartes.samplers.interpolation.random_split"]], "astartes.samplers.interpolation.spxy module": [[5, "module-astartes.samplers.interpolation.spxy"]], "astartes.utils package": [[6, "astartes-utils-package"]], "astartes.utils.array_type_helpers module": [[6, "module-astartes.utils.array_type_helpers"]], "astartes.utils.exceptions module": [[6, "module-astartes.utils.exceptions"]], "astartes.utils.fast_kennard_stone module": [[6, "module-astartes.utils.fast_kennard_stone"]], "astartes.utils.sampler_factory module": [[6, "module-astartes.utils.sampler_factory"]], "astartes.utils.user_utils module": [[6, "module-astartes.utils.user_utils"]], "astartes.utils.warnings module": [[6, "module-astartes.utils.warnings"]], "astartes documentation": [[7, "astartes-documentation"]], "Contents:": [[7, null]], "Indices and tables": [[7, "indices-and-tables"]], "astartes": [[8, "astartes"]], "Transitioning from sklearn to astartes": [[9, "transitioning-from-sklearn-to-astartes"]], "Step 1. Installation": [[9, "step-1-installation"]], "Step 2. Changing the import Statement": [[9, "step-2-changing-the-import-statement"]], "Step 3. Specifying an Algorithmic Sampler": [[9, "step-3-specifying-an-algorithmic-sampler"]], "Step 4. Passing Keyword Arguments": [[9, "step-4-passing-keyword-arguments"]], "Step 5. Useful astartes Features": [[9, "step-5-useful-astartes-features"]], "return_indices: Improve Code Clarity": [[9, "return-indices-improve-code-clarity"]], "train_val_test_split: More Rigorous ML": [[9, "train-val-test-split-more-rigorous-ml"]], "Custom Warnings: ImperfectSplittingWarning and NormalizationWarning": [[9, "custom-warnings-imperfectsplittingwarning-and-normalizationwarning"]], "test package": [[10, "test-package"]], "test.functional package": [[11, "test-functional-package"]], "test.functional.test_astartes module": [[11, "module-test.functional.test_astartes"]], "test.functional.test_molecules module": [[11, "module-test.functional.test_molecules"]], "test.regression package": [[12, "test-regression-package"]], "test.regression.test_regression module": [[12, "module-test.regression.test_regression"]], "test.unit package": [[13, "test-unit-package"]], "test.unit.samplers package": [[14, "test-unit-samplers-package"]], "test.unit.samplers.extrapolative package": [[15, "test-unit-samplers-extrapolative-package"]], "test.unit.samplers.extrapolative.test_DBSCAN module": [[15, "module-test.unit.samplers.extrapolative.test_DBSCAN"]], "test.unit.samplers.extrapolative.test_Scaffold module": [[15, "module-test.unit.samplers.extrapolative.test_Scaffold"]], "test.unit.samplers.extrapolative.test_kmeans module": [[15, "module-test.unit.samplers.extrapolative.test_kmeans"]], "test.unit.samplers.extrapolative.test_optisim module": [[15, "module-test.unit.samplers.extrapolative.test_optisim"]], "test.unit.samplers.extrapolative.test_sphere_exclusion module": [[15, "module-test.unit.samplers.extrapolative.test_sphere_exclusion"]], "test.unit.samplers.extrapolative.test_time_based module": [[15, "module-test.unit.samplers.extrapolative.test_time_based"]], "test.unit.samplers.interpolative package": [[16, "test-unit-samplers-interpolative-package"]], "test.unit.samplers.interpolative.test_kennard_stone module": [[16, "module-test.unit.samplers.interpolative.test_kennard_stone"]], "test.unit.samplers.interpolative.test_random module": [[16, "module-test.unit.samplers.interpolative.test_random"]], "test.unit.samplers.interpolative.test_spxy module": [[16, "module-test.unit.samplers.interpolative.test_spxy"]], "test.unit.utils package": [[17, "test-unit-utils-package"]], "test.unit.utils.test_convert_to_array module": [[17, "module-test.unit.utils.test_convert_to_array"]], "test.unit.utils.test_sampler_factory module": [[17, "module-test.unit.utils.test_sampler_factory"]], "test.unit.utils.test_utils module": [[17, "module-test.unit.utils.test_utils"]]}, "indexentries": {"astartes": [[2, "module-astartes"]], "astartes.main": [[2, "module-astartes.main"]], "astartes.molecules": [[2, "module-astartes.molecules"]], "module": [[2, "module-astartes"], [2, "module-astartes.main"], [2, "module-astartes.molecules"], [3, "module-astartes.samplers"], [3, "module-astartes.samplers.abstract_sampler"], [4, "module-astartes.samplers.extrapolation"], [4, "module-astartes.samplers.extrapolation.dbscan"], [4, "module-astartes.samplers.extrapolation.kmeans"], [4, "module-astartes.samplers.extrapolation.optisim"], [4, "module-astartes.samplers.extrapolation.scaffold"], [4, "module-astartes.samplers.extrapolation.sphere_exclusion"], [4, "module-astartes.samplers.extrapolation.time_based"], [5, "module-astartes.samplers.interpolation"], [5, "module-astartes.samplers.interpolation.kennardstone"], [5, "module-astartes.samplers.interpolation.random_split"], [5, "module-astartes.samplers.interpolation.spxy"], [6, "module-astartes.utils"], [6, "module-astartes.utils.array_type_helpers"], [6, "module-astartes.utils.exceptions"], [6, "module-astartes.utils.fast_kennard_stone"], [6, "module-astartes.utils.sampler_factory"], [6, "module-astartes.utils.user_utils"], [6, "module-astartes.utils.warnings"], [10, "module-test"], [11, "module-test.functional"], [11, "module-test.functional.test_astartes"], [11, "module-test.functional.test_molecules"], [12, "module-test.regression"], [12, "module-test.regression.test_regression"], [13, "module-test.unit"], [14, "module-test.unit.samplers"], [15, "module-test.unit.samplers.extrapolative"], [15, "module-test.unit.samplers.extrapolative.test_DBSCAN"], [15, "module-test.unit.samplers.extrapolative.test_Scaffold"], [15, "module-test.unit.samplers.extrapolative.test_kmeans"], [15, "module-test.unit.samplers.extrapolative.test_optisim"], [15, "module-test.unit.samplers.extrapolative.test_sphere_exclusion"], [15, "module-test.unit.samplers.extrapolative.test_time_based"], [16, "module-test.unit.samplers.interpolative"], [16, "module-test.unit.samplers.interpolative.test_kennard_stone"], [16, "module-test.unit.samplers.interpolative.test_random"], [16, "module-test.unit.samplers.interpolative.test_spxy"], [17, "module-test.unit.utils"], [17, "module-test.unit.utils.test_convert_to_array"], [17, "module-test.unit.utils.test_sampler_factory"], [17, "module-test.unit.utils.test_utils"]], "train_test_split() (in module astartes.main)": [[2, "astartes.main.train_test_split"]], "train_test_split_molecules() (in module astartes.molecules)": [[2, "astartes.molecules.train_test_split_molecules"]], "train_val_test_split() (in module astartes.main)": [[2, "astartes.main.train_val_test_split"]], "train_val_test_split_molecules() (in module astartes.molecules)": [[2, "astartes.molecules.train_val_test_split_molecules"]], "abstractsampler (class in astartes.samplers.abstract_sampler)": [[3, "astartes.samplers.abstract_sampler.AbstractSampler"]], "__init__() (astartes.samplers.abstract_sampler.abstractsampler method)": [[3, "astartes.samplers.abstract_sampler.AbstractSampler.__init__"]], "astartes.samplers": [[3, "module-astartes.samplers"]], "astartes.samplers.abstract_sampler": [[3, "module-astartes.samplers.abstract_sampler"]], "get_clusters() (astartes.samplers.abstract_sampler.abstractsampler method)": [[3, "astartes.samplers.abstract_sampler.AbstractSampler.get_clusters"]], "get_config() (astartes.samplers.abstract_sampler.abstractsampler method)": [[3, "astartes.samplers.abstract_sampler.AbstractSampler.get_config"]], "get_sample_idxs() (astartes.samplers.abstract_sampler.abstractsampler method)": [[3, "astartes.samplers.abstract_sampler.AbstractSampler.get_sample_idxs"]], "get_sorted_cluster_counter() (astartes.samplers.abstract_sampler.abstractsampler method)": [[3, "astartes.samplers.abstract_sampler.AbstractSampler.get_sorted_cluster_counter"]], "dbscan (class in astartes.samplers.extrapolation.dbscan)": [[4, "astartes.samplers.extrapolation.dbscan.DBSCAN"]], "kmeans (class in astartes.samplers.extrapolation.kmeans)": [[4, "astartes.samplers.extrapolation.kmeans.KMeans"]], "optisim (class in astartes.samplers.extrapolation.optisim)": [[4, "astartes.samplers.extrapolation.optisim.OptiSim"]], "scaffold (class in astartes.samplers.extrapolation.scaffold)": [[4, "astartes.samplers.extrapolation.scaffold.Scaffold"]], "sphereexclusion (class in astartes.samplers.extrapolation.sphere_exclusion)": [[4, "astartes.samplers.extrapolation.sphere_exclusion.SphereExclusion"]], "timebased (class in astartes.samplers.extrapolation.time_based)": [[4, "astartes.samplers.extrapolation.time_based.TimeBased"]], "astartes.samplers.extrapolation": [[4, "module-astartes.samplers.extrapolation"]], "astartes.samplers.extrapolation.dbscan": [[4, "module-astartes.samplers.extrapolation.dbscan"]], "astartes.samplers.extrapolation.kmeans": [[4, "module-astartes.samplers.extrapolation.kmeans"]], "astartes.samplers.extrapolation.optisim": [[4, "module-astartes.samplers.extrapolation.optisim"]], "astartes.samplers.extrapolation.scaffold": [[4, "module-astartes.samplers.extrapolation.scaffold"]], "astartes.samplers.extrapolation.sphere_exclusion": [[4, "module-astartes.samplers.extrapolation.sphere_exclusion"]], "astartes.samplers.extrapolation.time_based": [[4, "module-astartes.samplers.extrapolation.time_based"]], "generate_bemis_murcko_scaffold() (astartes.samplers.extrapolation.scaffold.scaffold method)": [[4, "astartes.samplers.extrapolation.scaffold.Scaffold.generate_bemis_murcko_scaffold"]], "get_dist() (astartes.samplers.extrapolation.optisim.optisim method)": [[4, "astartes.samplers.extrapolation.optisim.OptiSim.get_dist"]], "move_item() (astartes.samplers.extrapolation.optisim.optisim method)": [[4, "astartes.samplers.extrapolation.optisim.OptiSim.move_item"]], "rchoose() (astartes.samplers.extrapolation.optisim.optisim method)": [[4, "astartes.samplers.extrapolation.optisim.OptiSim.rchoose"]], "scaffold_to_smiles() (astartes.samplers.extrapolation.scaffold.scaffold method)": [[4, "astartes.samplers.extrapolation.scaffold.Scaffold.scaffold_to_smiles"]], "str_to_mol() (astartes.samplers.extrapolation.scaffold.scaffold method)": [[4, "astartes.samplers.extrapolation.scaffold.Scaffold.str_to_mol"]], "kennardstone (class in astartes.samplers.interpolation.kennardstone)": [[5, "astartes.samplers.interpolation.kennardstone.KennardStone"]], "random (class in astartes.samplers.interpolation.random_split)": [[5, "astartes.samplers.interpolation.random_split.Random"]], "spxy (class in astartes.samplers.interpolation.spxy)": [[5, "astartes.samplers.interpolation.spxy.SPXY"]], "astartes.samplers.interpolation": [[5, "module-astartes.samplers.interpolation"]], "astartes.samplers.interpolation.kennardstone": [[5, "module-astartes.samplers.interpolation.kennardstone"]], "astartes.samplers.interpolation.random_split": [[5, "module-astartes.samplers.interpolation.random_split"]], "astartes.samplers.interpolation.spxy": [[5, "module-astartes.samplers.interpolation.spxy"]], "conversionwarning": [[6, "astartes.utils.warnings.ConversionWarning"]], "imperfectsplittingwarning": [[6, "astartes.utils.warnings.ImperfectSplittingWarning"]], "invalidconfigurationerror": [[6, "astartes.utils.exceptions.InvalidConfigurationError"]], "invalidmodeltypeerror": [[6, "astartes.utils.exceptions.InvalidModelTypeError"]], "moleculesnotinstallederror": [[6, "astartes.utils.exceptions.MoleculesNotInstalledError"]], "nomatchingscaffold": [[6, "astartes.utils.warnings.NoMatchingScaffold"]], "normalizationwarning": [[6, "astartes.utils.warnings.NormalizationWarning"]], "samplerfactory (class in astartes.utils.sampler_factory)": [[6, "astartes.utils.sampler_factory.SamplerFactory"]], "samplernotimplementederror": [[6, "astartes.utils.exceptions.SamplerNotImplementedError"]], "uncastableinputerror": [[6, "astartes.utils.exceptions.UncastableInputError"]], "__init__() (astartes.utils.exceptions.invalidconfigurationerror method)": [[6, "astartes.utils.exceptions.InvalidConfigurationError.__init__"]], "__init__() (astartes.utils.exceptions.invalidmodeltypeerror method)": [[6, "astartes.utils.exceptions.InvalidModelTypeError.__init__"]], "__init__() (astartes.utils.exceptions.moleculesnotinstallederror method)": [[6, "astartes.utils.exceptions.MoleculesNotInstalledError.__init__"]], "__init__() (astartes.utils.exceptions.samplernotimplementederror method)": [[6, "astartes.utils.exceptions.SamplerNotImplementedError.__init__"]], "__init__() (astartes.utils.exceptions.uncastableinputerror method)": [[6, "astartes.utils.exceptions.UncastableInputError.__init__"]], "__init__() (astartes.utils.sampler_factory.samplerfactory method)": [[6, "astartes.utils.sampler_factory.SamplerFactory.__init__"]], "__init__() (astartes.utils.warnings.conversionwarning method)": [[6, "astartes.utils.warnings.ConversionWarning.__init__"]], "__init__() (astartes.utils.warnings.imperfectsplittingwarning method)": [[6, "astartes.utils.warnings.ImperfectSplittingWarning.__init__"]], "__init__() (astartes.utils.warnings.nomatchingscaffold method)": [[6, "astartes.utils.warnings.NoMatchingScaffold.__init__"]], "__init__() (astartes.utils.warnings.normalizationwarning method)": [[6, "astartes.utils.warnings.NormalizationWarning.__init__"]], "astartes.utils": [[6, "module-astartes.utils"]], "astartes.utils.array_type_helpers": [[6, "module-astartes.utils.array_type_helpers"]], "astartes.utils.exceptions": [[6, "module-astartes.utils.exceptions"]], "astartes.utils.fast_kennard_stone": [[6, "module-astartes.utils.fast_kennard_stone"]], "astartes.utils.sampler_factory": [[6, "module-astartes.utils.sampler_factory"]], "astartes.utils.user_utils": [[6, "module-astartes.utils.user_utils"]], "astartes.utils.warnings": [[6, "module-astartes.utils.warnings"]], "convert_to_array() (in module astartes.utils.array_type_helpers)": [[6, "astartes.utils.array_type_helpers.convert_to_array"]], "display_results_as_table() (in module astartes.utils.user_utils)": [[6, "astartes.utils.user_utils.display_results_as_table"]], "fast_kennard_stone() (in module astartes.utils.fast_kennard_stone)": [[6, "astartes.utils.fast_kennard_stone.fast_kennard_stone"]], "generate_regression_results_dict() (in module astartes.utils)": [[6, "astartes.utils.generate_regression_results_dict"]], "generate_regression_results_dict() (in module astartes.utils.user_utils)": [[6, "astartes.utils.user_utils.generate_regression_results_dict"]], "get_sampler() (astartes.utils.sampler_factory.samplerfactory method)": [[6, "astartes.utils.sampler_factory.SamplerFactory.get_sampler"]], "panda_handla() (in module astartes.utils.array_type_helpers)": [[6, "astartes.utils.array_type_helpers.panda_handla"]], "return_helper() (in module astartes.utils.array_type_helpers)": [[6, "astartes.utils.array_type_helpers.return_helper"]], "test": [[10, "module-test"]], "test_astartes (class in test.functional.test_astartes)": [[11, "test.functional.test_astartes.Test_astartes"]], "test_molecules (class in test.functional.test_molecules)": [[11, "test.functional.test_molecules.Test_molecules"]], "setupclass() (test.functional.test_astartes.test_astartes class method)": [[11, "test.functional.test_astartes.Test_astartes.setUpClass"]], "setupclass() (test.functional.test_molecules.test_molecules class method)": [[11, "test.functional.test_molecules.Test_molecules.setUpClass"]], "test.functional": [[11, "module-test.functional"]], "test.functional.test_astartes": [[11, "module-test.functional.test_astartes"]], "test.functional.test_molecules": [[11, "module-test.functional.test_molecules"]], "test_close_mispelling_sampler() (test.functional.test_astartes.test_astartes method)": [[11, "test.functional.test_astartes.Test_astartes.test_close_mispelling_sampler"]], "test_extrapolative_shuffling() (test.functional.test_astartes.test_astartes method)": [[11, "test.functional.test_astartes.Test_astartes.test_extrapolative_shuffling"]], "test_fingerprints() (test.functional.test_molecules.test_molecules method)": [[11, "test.functional.test_molecules.Test_molecules.test_fingerprints"]], "test_fprint_hopts() (test.functional.test_molecules.test_molecules method)": [[11, "test.functional.test_molecules.Test_molecules.test_fprint_hopts"]], "test_inconsistent_input_lengths() (test.functional.test_astartes.test_astartes method)": [[11, "test.functional.test_astartes.Test_astartes.test_inconsistent_input_lengths"]], "test_insufficient_dataset_test() (test.functional.test_astartes.test_astartes method)": [[11, "test.functional.test_astartes.Test_astartes.test_insufficient_dataset_test"]], "test_insufficient_dataset_train() (test.functional.test_astartes.test_astartes method)": [[11, "test.functional.test_astartes.Test_astartes.test_insufficient_dataset_train"]], "test_insufficient_dataset_val() (test.functional.test_astartes.test_astartes method)": [[11, "test.functional.test_astartes.Test_astartes.test_insufficient_dataset_val"]], "test_maximum_call() (test.functional.test_molecules.test_molecules method)": [[11, "test.functional.test_molecules.Test_molecules.test_maximum_call"]], "test_molecules() (test.functional.test_molecules.test_molecules method)": [[11, "test.functional.test_molecules.Test_molecules.test_molecules"]], "test_molecules_with_rdkit() (test.functional.test_molecules.test_molecules method)": [[11, "test.functional.test_molecules.Test_molecules.test_molecules_with_rdkit"]], "test_molecules_with_troublesome_smiles() (test.functional.test_molecules.test_molecules method)": [[11, "test.functional.test_molecules.Test_molecules.test_molecules_with_troublesome_smiles"]], "test_not_implemented_sampler() (test.functional.test_astartes.test_astartes method)": [[11, "test.functional.test_astartes.Test_astartes.test_not_implemented_sampler"]], "test_return_indices() (test.functional.test_astartes.test_astartes method)": [[11, "test.functional.test_astartes.Test_astartes.test_return_indices"]], "test_return_indices_with_validation() (test.functional.test_astartes.test_astartes method)": [[11, "test.functional.test_astartes.Test_astartes.test_return_indices_with_validation"]], "test_sampler_hopts() (test.functional.test_molecules.test_molecules method)": [[11, "test.functional.test_molecules.Test_molecules.test_sampler_hopts"]], "test_split_validation() (test.functional.test_astartes.test_astartes method)": [[11, "test.functional.test_astartes.Test_astartes.test_split_validation"]], "test_train_test_split() (test.functional.test_astartes.test_astartes method)": [[11, "test.functional.test_astartes.Test_astartes.test_train_test_split"]], "test_train_val_test_split() (test.functional.test_astartes.test_astartes method)": [[11, "test.functional.test_astartes.Test_astartes.test_train_val_test_split"]], "test_train_val_test_split_extrpolation_shuffling() (test.functional.test_astartes.test_astartes method)": [[11, "test.functional.test_astartes.Test_astartes.test_train_val_test_split_extrpolation_shuffling"]], "test_validation_split_molecules() (test.functional.test_molecules.test_molecules method)": [[11, "test.functional.test_molecules.Test_molecules.test_validation_split_molecules"]], "test_regression (class in test.regression.test_regression)": [[12, "test.regression.test_regression.Test_regression"]], "setupclass() (test.regression.test_regression.test_regression class method)": [[12, "test.regression.test_regression.Test_regression.setUpClass"]], "test.regression": [[12, "module-test.regression"]], "test.regression.test_regression": [[12, "module-test.regression.test_regression"]], "test_extrapolation_regression() (test.regression.test_regression.test_regression method)": [[12, "test.regression.test_regression.Test_regression.test_extrapolation_regression"]], "test_interpolation_regression() (test.regression.test_regression.test_regression method)": [[12, "test.regression.test_regression.Test_regression.test_interpolation_regression"]], "test_kmeans_regression_sklearn_v12() (test.regression.test_regression.test_regression method)": [[12, "test.regression.test_regression.Test_regression.test_kmeans_regression_sklearn_v12"]], "test_kmeans_regression_sklearn_v13() (test.regression.test_regression.test_regression method)": [[12, "test.regression.test_regression.Test_regression.test_kmeans_regression_sklearn_v13"]], "test_timebased_regression() (test.regression.test_regression.test_regression method)": [[12, "test.regression.test_regression.Test_regression.test_timebased_regression"]], "test.unit": [[13, "module-test.unit"]], "test.unit.samplers": [[14, "module-test.unit.samplers"]], "test_dbscan (class in test.unit.samplers.extrapolative.test_dbscan)": [[15, "test.unit.samplers.extrapolative.test_DBSCAN.Test_DBSCAN"]], "test_kmeans (class in test.unit.samplers.extrapolative.test_kmeans)": [[15, "test.unit.samplers.extrapolative.test_kmeans.Test_kmeans"]], "test_optisim (class in test.unit.samplers.extrapolative.test_optisim)": [[15, "test.unit.samplers.extrapolative.test_optisim.Test_optisim"]], "test_scaffold (class in test.unit.samplers.extrapolative.test_scaffold)": [[15, "test.unit.samplers.extrapolative.test_Scaffold.Test_scaffold"]], "test_sphere_exclusion (class in test.unit.samplers.extrapolative.test_sphere_exclusion)": [[15, "test.unit.samplers.extrapolative.test_sphere_exclusion.Test_sphere_exclusion"]], "test_time_based (class in test.unit.samplers.extrapolative.test_time_based)": [[15, "test.unit.samplers.extrapolative.test_time_based.Test_time_based"]], "setupclass() (test.unit.samplers.extrapolative.test_dbscan.test_dbscan class method)": [[15, "test.unit.samplers.extrapolative.test_DBSCAN.Test_DBSCAN.setUpClass"]], "setupclass() (test.unit.samplers.extrapolative.test_scaffold.test_scaffold class method)": [[15, "test.unit.samplers.extrapolative.test_Scaffold.Test_scaffold.setUpClass"]], "setupclass() (test.unit.samplers.extrapolative.test_kmeans.test_kmeans class method)": [[15, "test.unit.samplers.extrapolative.test_kmeans.Test_kmeans.setUpClass"]], "setupclass() (test.unit.samplers.extrapolative.test_optisim.test_optisim class method)": [[15, "test.unit.samplers.extrapolative.test_optisim.Test_optisim.setUpClass"]], "setupclass() (test.unit.samplers.extrapolative.test_sphere_exclusion.test_sphere_exclusion class method)": [[15, "test.unit.samplers.extrapolative.test_sphere_exclusion.Test_sphere_exclusion.setUpClass"]], "setupclass() (test.unit.samplers.extrapolative.test_time_based.test_time_based class method)": [[15, "test.unit.samplers.extrapolative.test_time_based.Test_time_based.setUpClass"]], "test.unit.samplers.extrapolative": [[15, "module-test.unit.samplers.extrapolative"]], "test.unit.samplers.extrapolative.test_dbscan": [[15, "module-test.unit.samplers.extrapolative.test_DBSCAN"]], "test.unit.samplers.extrapolative.test_scaffold": [[15, "module-test.unit.samplers.extrapolative.test_Scaffold"]], "test.unit.samplers.extrapolative.test_kmeans": [[15, "module-test.unit.samplers.extrapolative.test_kmeans"]], "test.unit.samplers.extrapolative.test_optisim": [[15, "module-test.unit.samplers.extrapolative.test_optisim"]], "test.unit.samplers.extrapolative.test_sphere_exclusion": [[15, "module-test.unit.samplers.extrapolative.test_sphere_exclusion"]], "test.unit.samplers.extrapolative.test_time_based": [[15, "module-test.unit.samplers.extrapolative.test_time_based"]], "test_dbscan() (test.unit.samplers.extrapolative.test_dbscan.test_dbscan method)": [[15, "test.unit.samplers.extrapolative.test_DBSCAN.Test_DBSCAN.test_dbscan"]], "test_dbscan_sampling() (test.unit.samplers.extrapolative.test_dbscan.test_dbscan method)": [[15, "test.unit.samplers.extrapolative.test_DBSCAN.Test_DBSCAN.test_dbscan_sampling"]], "test_include_chirality() (test.unit.samplers.extrapolative.test_scaffold.test_scaffold method)": [[15, "test.unit.samplers.extrapolative.test_Scaffold.Test_scaffold.test_include_chirality"]], "test_incorrect_input() (test.unit.samplers.extrapolative.test_scaffold.test_scaffold method)": [[15, "test.unit.samplers.extrapolative.test_Scaffold.Test_scaffold.test_incorrect_input"]], "test_incorrect_input() (test.unit.samplers.extrapolative.test_time_based.test_time_based method)": [[15, "test.unit.samplers.extrapolative.test_time_based.Test_time_based.test_incorrect_input"]], "test_kmeans() (test.unit.samplers.extrapolative.test_kmeans.test_kmeans method)": [[15, "test.unit.samplers.extrapolative.test_kmeans.Test_kmeans.test_kmeans"]], "test_kmeans_sampling_v12() (test.unit.samplers.extrapolative.test_kmeans.test_kmeans method)": [[15, "test.unit.samplers.extrapolative.test_kmeans.Test_kmeans.test_kmeans_sampling_v12"]], "test_kmeans_sampling_v13() (test.unit.samplers.extrapolative.test_kmeans.test_kmeans method)": [[15, "test.unit.samplers.extrapolative.test_kmeans.Test_kmeans.test_kmeans_sampling_v13"]], "test_mising_labels() (test.unit.samplers.extrapolative.test_time_based.test_time_based method)": [[15, "test.unit.samplers.extrapolative.test_time_based.Test_time_based.test_mising_labels"]], "test_mol_from_inchi() (test.unit.samplers.extrapolative.test_scaffold.test_scaffold method)": [[15, "test.unit.samplers.extrapolative.test_Scaffold.Test_scaffold.test_mol_from_inchi"]], "test_no_scaffold_found_warning() (test.unit.samplers.extrapolative.test_scaffold.test_scaffold method)": [[15, "test.unit.samplers.extrapolative.test_Scaffold.Test_scaffold.test_no_scaffold_found_warning"]], "test_optisim() (test.unit.samplers.extrapolative.test_optisim.test_optisim method)": [[15, "test.unit.samplers.extrapolative.test_optisim.Test_optisim.test_optisim"]], "test_optisim_sampling() (test.unit.samplers.extrapolative.test_optisim.test_optisim method)": [[15, "test.unit.samplers.extrapolative.test_optisim.Test_optisim.test_optisim_sampling"]], "test_remove_atom_map() (test.unit.samplers.extrapolative.test_scaffold.test_scaffold method)": [[15, "test.unit.samplers.extrapolative.test_Scaffold.Test_scaffold.test_remove_atom_map"]], "test_scaffold() (test.unit.samplers.extrapolative.test_scaffold.test_scaffold method)": [[15, "test.unit.samplers.extrapolative.test_Scaffold.Test_scaffold.test_scaffold"]], "test_scaffold_sampling() (test.unit.samplers.extrapolative.test_scaffold.test_scaffold method)": [[15, "test.unit.samplers.extrapolative.test_Scaffold.Test_scaffold.test_scaffold_sampling"]], "test_sphereexclusion() (test.unit.samplers.extrapolative.test_sphere_exclusion.test_sphere_exclusion method)": [[15, "test.unit.samplers.extrapolative.test_sphere_exclusion.Test_sphere_exclusion.test_sphereexclusion"]], "test_sphereexclusion_sampling() (test.unit.samplers.extrapolative.test_sphere_exclusion.test_sphere_exclusion method)": [[15, "test.unit.samplers.extrapolative.test_sphere_exclusion.Test_sphere_exclusion.test_sphereexclusion_sampling"]], "test_time_based_date() (test.unit.samplers.extrapolative.test_time_based.test_time_based method)": [[15, "test.unit.samplers.extrapolative.test_time_based.Test_time_based.test_time_based_date"]], "test_time_based_datetime() (test.unit.samplers.extrapolative.test_time_based.test_time_based method)": [[15, "test.unit.samplers.extrapolative.test_time_based.Test_time_based.test_time_based_datetime"]], "test_time_based_sampling() (test.unit.samplers.extrapolative.test_time_based.test_time_based method)": [[15, "test.unit.samplers.extrapolative.test_time_based.Test_time_based.test_time_based_sampling"]], "test_spxy (class in test.unit.samplers.interpolative.test_spxy)": [[16, "test.unit.samplers.interpolative.test_spxy.Test_SPXY"]], "test_kennard_stone (class in test.unit.samplers.interpolative.test_kennard_stone)": [[16, "test.unit.samplers.interpolative.test_kennard_stone.Test_kennard_stone"]], "test_random (class in test.unit.samplers.interpolative.test_random)": [[16, "test.unit.samplers.interpolative.test_random.Test_random"]], "setupclass() (test.unit.samplers.interpolative.test_kennard_stone.test_kennard_stone class method)": [[16, "test.unit.samplers.interpolative.test_kennard_stone.Test_kennard_stone.setUpClass"]], "setupclass() (test.unit.samplers.interpolative.test_random.test_random class method)": [[16, "test.unit.samplers.interpolative.test_random.Test_random.setUpClass"]], "setupclass() (test.unit.samplers.interpolative.test_spxy.test_spxy class method)": [[16, "test.unit.samplers.interpolative.test_spxy.Test_SPXY.setUpClass"]], "test.unit.samplers.interpolative": [[16, "module-test.unit.samplers.interpolative"]], "test.unit.samplers.interpolative.test_kennard_stone": [[16, "module-test.unit.samplers.interpolative.test_kennard_stone"]], "test.unit.samplers.interpolative.test_random": [[16, "module-test.unit.samplers.interpolative.test_random"]], "test.unit.samplers.interpolative.test_spxy": [[16, "module-test.unit.samplers.interpolative.test_spxy"]], "test_kennard_stone() (test.unit.samplers.interpolative.test_kennard_stone.test_kennard_stone method)": [[16, "test.unit.samplers.interpolative.test_kennard_stone.Test_kennard_stone.test_kennard_stone"]], "test_kennard_stone_sample() (test.unit.samplers.interpolative.test_kennard_stone.test_kennard_stone method)": [[16, "test.unit.samplers.interpolative.test_kennard_stone.Test_kennard_stone.test_kennard_stone_sample"]], "test_kennard_stone_sample_no_warning() (test.unit.samplers.interpolative.test_kennard_stone.test_kennard_stone method)": [[16, "test.unit.samplers.interpolative.test_kennard_stone.Test_kennard_stone.test_kennard_stone_sample_no_warning"]], "test_missing_y() (test.unit.samplers.interpolative.test_spxy.test_spxy method)": [[16, "test.unit.samplers.interpolative.test_spxy.Test_SPXY.test_missing_y"]], "test_random() (test.unit.samplers.interpolative.test_random.test_random method)": [[16, "test.unit.samplers.interpolative.test_random.Test_random.test_random"]], "test_random_sample() (test.unit.samplers.interpolative.test_random.test_random method)": [[16, "test.unit.samplers.interpolative.test_random.Test_random.test_random_sample"]], "test_random_sample_no_warning() (test.unit.samplers.interpolative.test_random.test_random method)": [[16, "test.unit.samplers.interpolative.test_random.Test_random.test_random_sample_no_warning"]], "test_spxy() (test.unit.samplers.interpolative.test_spxy.test_spxy method)": [[16, "test.unit.samplers.interpolative.test_spxy.Test_SPXY.test_spxy"]], "test_spxy_sampling() (test.unit.samplers.interpolative.test_spxy.test_spxy method)": [[16, "test.unit.samplers.interpolative.test_spxy.Test_SPXY.test_spxy_sampling"]], "test_convert_to_array (class in test.unit.utils.test_convert_to_array)": [[17, "test.unit.utils.test_convert_to_array.Test_convert_to_array"]], "test_sampler_factory (class in test.unit.utils.test_sampler_factory)": [[17, "test.unit.utils.test_sampler_factory.Test_sampler_factory"]], "test_utils (class in test.unit.utils.test_utils)": [[17, "test.unit.utils.test_utils.Test_utils"]], "setupclass() (test.unit.utils.test_sampler_factory.test_sampler_factory class method)": [[17, "test.unit.utils.test_sampler_factory.Test_sampler_factory.setUpClass"]], "setupclass() (test.unit.utils.test_utils.test_utils class method)": [[17, "test.unit.utils.test_utils.Test_utils.setUpClass"]], "test.unit.utils": [[17, "module-test.unit.utils"]], "test.unit.utils.test_convert_to_array": [[17, "module-test.unit.utils.test_convert_to_array"]], "test.unit.utils.test_sampler_factory": [[17, "module-test.unit.utils.test_sampler_factory"]], "test.unit.utils.test_utils": [[17, "module-test.unit.utils.test_utils"]], "test_bad_type_cast() (test.unit.utils.test_convert_to_array.test_convert_to_array method)": [[17, "test.unit.utils.test_convert_to_array.Test_convert_to_array.test_bad_type_cast"]], "test_convertable_input() (test.unit.utils.test_convert_to_array.test_convert_to_array method)": [[17, "test.unit.utils.test_convert_to_array.Test_convert_to_array.test_convertable_input"]], "test_generate_regression_results_dict() (test.unit.utils.test_utils.test_utils method)": [[17, "test.unit.utils.test_utils.Test_utils.test_generate_regression_results_dict"]], "test_panda_handla() (test.unit.utils.test_convert_to_array.test_convert_to_array method)": [[17, "test.unit.utils.test_convert_to_array.Test_convert_to_array.test_panda_handla"]], "test_train_test_split() (test.unit.utils.test_sampler_factory.test_sampler_factory method)": [[17, "test.unit.utils.test_sampler_factory.Test_sampler_factory.test_train_test_split"]], "test_unconvertable_input() (test.unit.utils.test_convert_to_array.test_convert_to_array method)": [[17, "test.unit.utils.test_convert_to_array.Test_convert_to_array.test_unconvertable_input"]]}}) \ No newline at end of file diff --git a/docs/sklearn_to_astartes.doctree b/docs/sklearn_to_astartes.doctree new file mode 100644 index 0000000000000000000000000000000000000000..f249addcf2b01a14fb7d829247fbb788125400e1 GIT binary patch literal 32216 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 nM28Y + + + + + + Transitioning from sklearn to astartes — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Transitioning from sklearn to astartes

+
+

Step 1. Installation

+

astartes has been designed to rely on (1) as few packages as possible and (2) packages which are already likely to be installed in a Machine Learning (ML) Python workflow (i.e. Numpy and Sklearn). Because of this, astartes should be compatible with your existing workflow such as a conda environment.

+

To install astartes for general ML use (the sampling of arbitrary vectors): **pip install astartes**

+

For users in cheminformatics, astartes has an optional add-on that includes featurization as part of the sampling. To install, type **pip install 'astartes[molecules]'**. With this extra install, astartes uses ``AIMSim` <https://vlachosgroup.github.io/AIMSim/README.html>`_ to encode SMILES strings as feature vectors. The SMILES strings are parsed into molecular graphs using RDKit and then sampled with a single function call: train_test_split_molecules.

+
    +
  • If your workflow already has a featurization scheme in place (i.e. you already have a vector representation of your chemical of interest), you can directly use train_test_split (though we invite you to explore the many molecular descriptors made available through AIMSim).

  • +
+
+
+

Step 2. Changing the import Statement

+

In one of the first few lines of your Python script, you have the line from sklearn.model_selection import train_test_split. To switch to using astartes change this line to from astartes import train_test_split.

+

That’s it! You are now using astartes.

+

If you were just calling train_test_split(X, y), your script should now work in the exact same way as sklearn with no changes required.

+
X_train, X_test, y_train, y_test = train_test_split(
+    X,
+    y,
+    random_state=42,
+)
+
+
+

becomes

+
X_train, X_test, y_train, y_test = train_test_split(
+    X,
+    y,
+    random_state=42,
+)
+
+
+

But we encourage you to try one of our many other samplers (see below)!

+
+
+

Step 3. Specifying an Algorithmic Sampler

+

By default (for interoperability), astartes will use a random sampler to produce train/test splits - but the real value of astartes is in the algorithmic sampling algorithms it implements. Check out the README for a complete list of available algorithms and how to call and customize them.

+

If you existing call to train_test_split looks like this:

+
X_train, X_test, y_train, y_test = train_test_split(
+    X,
+    y,
+)
+
+
+

and you want to try out using Kennard-Stone sampling, switch it to this:

+
X_train, X_test, y_train, y_test = train_test_split(
+    X,
+    y,
+    sampler="kennard_stone",
+)
+
+
+

That’s it!

+
+
+

Step 4. Passing Keyword Arguments

+

All of the arguments to the sklearn‘s train_test_split can still be passed to astartestrain_test_split:

+
X_train, X_test, y_train, y_test, labels_train, labels_test = train_test_split(
+    X,
+    y,
+    labels,
+    train_size = 0.75,
+    test_size = 0.25,
+    sampler = "kmeans",
+    hopts = {"n_clusters": 4},
+)
+
+
+

Some samplers have tunable hyperparameters that allow you to more finely control their behavior. To do this with Sphere Exclusion, for example, switch your call to this:

+
X_train, X_test, y_train, y_test = train_test_split(
+    X,
+    y,
+    sampler="sphere_exclusion",
+    hopts={"distance_cutoff":0.15},
+)
+
+
+
+
+

Step 5. Useful astartes Features

+
+

return_indices: Improve Code Clarity

+

There are circumstances where the indices of the train/test data can be useful (for example, if y or labels are large, memory-intense objects), and there is no way to directly return these indices in sklearn. astartes will return the sampling splits themselves by default, but it can also return the indices for the user to manipulate according to their needs:

+
X_train, X_test, y_train, y_test, labels_train, labels_test = train_test_split(
+    X,
+    y,
+    labels,
+    return_indices = False,
+)
+
+
+

could instead be

+
X_train, X_test, y_train, y_test, labels_train, labels_test, indices_train, indices_test = train_test_split(
+    X,
+    y,
+    labels,
+    return_indices = True,
+)
+
+
+

If y or labels were large, memory-intense objects it could be beneficial to not pass them in to train_test_split and instead separate the existing lists later using the returned indices.

+
+
+

train_val_test_split: More Rigorous ML

+

Behind the scenes, train_test_split is actually just a one-line function that calls the real workhorse of astartes - train_val_test_split:

+
def train_test_split(
+    X: np.array,
+    ...
+    return_indices: bool = False,
+):
+    return train_val_test_split(
+        X, y, labels, train_size, 0, test_size, sampler, hopts, return_indices
+    )
+
+
+

The function call to train_val_test_split is identical to train_test_split and supports all the same samplers and hyperparameters, except for one additional keyword argument val_size:

+
def train_val_test_split(
+    X: np.array,
+    y: np.array = None,
+    labels: np.array = None,
+    train_size: float = 0.8,
+    val_size: float = 0.1,
+    test_size: float = 0.1,
+    sampler: str = "random",
+    hopts: dict = {},
+    return_indices: bool = False,
+):
+
+
+

When called, this will return three arrays from X, y, and labels (or three arrays of indices, if return_indices=True) rather than the usual two, according to the values given for train_size, val_size, and test_size in the function call.

+
X_train, X_val, X_test, y_train, y_val, y_test = train_val_test_split(
+    X,
+    y,
+    train_size: float = 0.8,
+    val_size: float = 0.1,
+    test_size: float = 0.1,
+)
+
+
+

For truly rigorous ML modeling, the validation set should be used for hyperparameter tuning and the test set held out until the very final change has been made to the model to get a true sense of its performance. For better or for worse, this is not the current standard for ML modeling, but the authors believe it should be.

+
+
+

Custom Warnings: ImperfectSplittingWarning and NormalizationWarning

+

In the event that your requested train/validation/test split is not mathematically possible given the dimensions of the input data (i.e. you request 50/25/25 but have 101 data points), astartes will warn you during runtime that it has occurred. sklearn simply moves on quietly, and while this is fine most of the time, the authors felt it prudent to warn the user. +When entering a train/validation/test split, astartes will check that it is normalized and make it so if not, warning the user during runtime. This will hopefully help prevent head-scratching hours of debugging.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/sklearn_to_astartes.rst b/docs/sklearn_to_astartes.rst new file mode 100644 index 00000000..fa5248f3 --- /dev/null +++ b/docs/sklearn_to_astartes.rst @@ -0,0 +1,180 @@ + +Transitioning from ``sklearn`` to ``astartes`` +====================================================== + +Step 1. Installation +-------------------- + +``astartes`` has been designed to rely on (1) as few packages as possible and (2) packages which are already likely to be installed in a Machine Learning (ML) Python workflow (i.e. Numpy and Sklearn). Because of this, ``astartes`` should be compatible with your *existing* workflow such as a conda environment. + +To install ``astartes`` for general ML use (the sampling of arbitrary vectors): **\ ``pip install astartes``\ ** + +For users in cheminformatics, ``astartes`` has an optional add-on that includes featurization as part of the sampling. To install, type **\ ``pip install 'astartes[molecules]'``\ **. With this extra install, ``astartes`` uses `\ ``AIMSim`` `_ to encode SMILES strings as feature vectors. The SMILES strings are parsed into molecular graphs using RDKit and then sampled with a single function call: ``train_test_split_molecules``. + + +* If your workflow already has a featurization scheme in place (i.e. you already have a vector representation of your chemical of interest), you can directly use ``train_test_split`` (though we invite you to explore the many molecular descriptors made available through AIMSim). + +Step 2. Changing the ``import`` Statement +--------------------------------------------- + +In one of the first few lines of your Python script, you have the line ``from sklearn.model_selection import train_test_split``. To switch to using ``astartes`` change this line to ``from astartes import train_test_split``. + +That's it! You are now using ``astartes``. + +If you were just calling ``train_test_split(X, y)``\ , your script should now work in the exact same way as ``sklearn`` with no changes required. + +.. code-block:: python + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + random_state=42, + ) + +*becomes* + +.. code-block:: python + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + random_state=42, + ) + +But we encourage you to try one of our many other samplers (see below)! + +Step 3. Specifying an Algorithmic Sampler +----------------------------------------- + +By default (for interoperability), ``astartes`` will use a random sampler to produce train/test splits - but the real value of ``astartes`` is in the algorithmic sampling algorithms it implements. Check out the `README for a complete list of available algorithms `_ and how to call and customize them. + +If you existing call to ``train_test_split`` looks like this: + +.. code-block:: python + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + ) + +and you want to try out using Kennard-Stone sampling, switch it to this: + +.. code-block:: python + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + sampler="kennard_stone", + ) + +That's it! + +Step 4. Passing Keyword Arguments +--------------------------------- + +All of the arguments to the ``sklearn``\ 's ``train_test_split`` can still be passed to ``astartes``\ ' ``train_test_split``\ : + +.. code-block:: python + + X_train, X_test, y_train, y_test, labels_train, labels_test = train_test_split( + X, + y, + labels, + train_size = 0.75, + test_size = 0.25, + sampler = "kmeans", + hopts = {"n_clusters": 4}, + ) + +Some samplers have tunable hyperparameters that allow you to more finely control their behavior. To do this with Sphere Exclusion, for example, switch your call to this: + +.. code-block:: python + + X_train, X_test, y_train, y_test = train_test_split( + X, + y, + sampler="sphere_exclusion", + hopts={"distance_cutoff":0.15}, + ) + +Step 5. Useful ``astartes`` Features +---------------------------------------- + +``return_indices``\ : Improve Code Clarity +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are circumstances where the indices of the train/test data can be useful (for example, if ``y`` or ``labels`` are large, memory-intense objects), and there is no way to directly return these indices in ``sklearn``. ``astartes`` will return the sampling splits themselves by default, but it can also return the indices for the user to manipulate according to their needs: + +.. code-block:: python + + X_train, X_test, y_train, y_test, labels_train, labels_test = train_test_split( + X, + y, + labels, + return_indices = False, + ) + +*could instead be* + +.. code-block:: python + + X_train, X_test, y_train, y_test, labels_train, labels_test, indices_train, indices_test = train_test_split( + X, + y, + labels, + return_indices = True, + ) + +If ``y`` or ``labels`` were large, memory-intense objects it could be beneficial to *not* pass them in to ``train_test_split`` and instead separate the existing lists later using the returned indices. + +``train_val_test_split``\ : More Rigorous ML +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Behind the scenes, ``train_test_split`` is actually just a one-line function that calls the real workhorse of ``astartes`` - ``train_val_test_split``\ : + +.. code-block:: python + + def train_test_split( + X: np.array, + ... + return_indices: bool = False, + ): + return train_val_test_split( + X, y, labels, train_size, 0, test_size, sampler, hopts, return_indices + ) + +The function call to ``train_val_test_split`` is identical to ``train_test_split`` and supports all the same samplers and hyperparameters, except for one additional keyword argument ``val_size``\ : + +.. code-block:: python + + def train_val_test_split( + X: np.array, + y: np.array = None, + labels: np.array = None, + train_size: float = 0.8, + val_size: float = 0.1, + test_size: float = 0.1, + sampler: str = "random", + hopts: dict = {}, + return_indices: bool = False, + ): + +When called, this will return *three* arrays from ``X``\ , ``y``\ , and ``labels`` (or three arrays of indices, if ``return_indices=True``\ ) rather than the usual two, according to the values given for ``train_size``\ , ``val_size``\ , and ``test_size`` in the function call. + +.. code-block:: python + + X_train, X_val, X_test, y_train, y_val, y_test = train_val_test_split( + X, + y, + train_size: float = 0.8, + val_size: float = 0.1, + test_size: float = 0.1, + ) + +For truly rigorous ML modeling, the validation set should be used for hyperparameter tuning and the test set held out until the *very final* change has been made to the model to get a true sense of its performance. For better or for worse, this is *not* the current standard for ML modeling, but the authors believe it should be. + +Custom Warnings: ``ImperfectSplittingWarning`` and ``NormalizationWarning`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the event that your requested train/validation/test split is not mathematically possible given the dimensions of the input data (i.e. you request 50/25/25 but have 101 data points), ``astartes`` will warn you during runtime that it has occurred. ``sklearn`` simply moves on quietly, and while this is fine *most* of the time, the authors felt it prudent to warn the user. +When entering a train/validation/test split, ``astartes`` will check that it is normalized and make it so if not, warning the user during runtime. This will hopefully help prevent head-scratching hours of debugging. diff --git a/docs/test.doctree b/docs/test.doctree new file mode 100644 index 0000000000000000000000000000000000000000..fb5d912aca5d0ed91dbe9da22e610f104e72b685 GIT binary patch literal 3563 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 literal 0 HcmV?d00001 diff --git a/docs/test.functional.html b/docs/test.functional.html new file mode 100644 index 00000000..6d932449 --- /dev/null +++ b/docs/test.functional.html @@ -0,0 +1,306 @@ + + + + + + + test.functional package — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

test.functional package

+
+

Submodules

+
+
+

test.functional.test_astartes module

+
+
+class test.functional.test_astartes.Test_astartes(methodName='runTest')
+

Bases: TestCase

+

Test the various functionalities of astartes.

+
+
+classmethod setUpClass()
+

Convenience attributes for later tests.

+
+ +
+
+test_close_mispelling_sampler()
+

Astartes should be helpful in the event of a typo.

+
+ +
+
+test_extrapolative_shuffling()
+

extrapolative samplers should split data differently with different random_state

+
+ +
+
+test_inconsistent_input_lengths()
+

Different length X, y, and labels should raise an exception at start.

+
+ +
+
+test_insufficient_dataset_test()
+

If the user requests a split that would result in rounding down the size of the +test set to zero, a helpful exception should be raised.

+
+ +
+
+test_insufficient_dataset_train()
+

If the user requests a split that would result in rounding down the size of the +test set to zero, a helpful exception should be raised.

+
+ +
+
+test_insufficient_dataset_val()
+

If the user requests a split that would result in rounding down the size of the +test set to zero, a helpful exception should be raised.

+
+ +
+
+test_not_implemented_sampler()
+

Astartes should suggest checking the docstring.

+
+ +
+
+test_return_indices()
+

Test the ability to return the indices and the values.

+
+ +
+
+test_return_indices_with_validation()
+

Test the ability to return indices in train_val_test_split

+
+ +
+
+test_split_validation()
+

Tests of the input split validation.

+
+ +
+
+test_train_test_split()
+

Funational test of train_test_split with imperfect splitting.

+
+ +
+
+test_train_val_test_split()
+

Split data into training, validation, and test sets.

+
+ +
+
+test_train_val_test_split_extrpolation_shuffling()
+

Split data into training, validation, and test sets with shuffling.

+
+ +
+ +
+
+

test.functional.test_molecules module

+
+
+class test.functional.test_molecules.Test_molecules(methodName='runTest')
+

Bases: TestCase

+

Test the various functionalities of molecules.

+

Note: daylight_fingerprint is not compatible – inhomogenous arrays +(variable length descriptor)

+
+
+classmethod setUpClass()
+

Convenience attributes for later tests.

+
+ +
+
+test_fingerprints()
+

Test using different fingerprints with the molecular featurization.

+
+ +
+
+test_fprint_hopts()
+

Test specifying hyperparameters for the molecular featurization step.

+
+ +
+
+test_maximum_call()
+

Specify ALL the optional hyperparameters!

+
+ +
+
+test_molecules()
+

Try train_test_split molecules with every interpolative sampler.

+
+ +
+
+test_molecules_with_rdkit()
+

Try train_test_split molecules, every sampler, passing rdkit objects.

+
+ +
+
+test_molecules_with_troublesome_smiles()
+

Helpful errors when rdkit graphs can’t be featurized.

+
+ +
+
+test_sampler_hopts()
+

Test ability to pass through sampler hopts with molecules interface, expecting no warnings.

+
+ +
+
+test_validation_split_molecules()
+

Try train_val_test_split_molecule with every extrapolative sampler.

+
+ +
+ +
+
+

Module contents

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/test.functional.rst b/docs/test.functional.rst new file mode 100644 index 00000000..0c1189a2 --- /dev/null +++ b/docs/test.functional.rst @@ -0,0 +1,29 @@ +test.functional package +======================= + +Submodules +---------- + +test.functional.test\_astartes module +------------------------------------- + +.. automodule:: test.functional.test_astartes + :members: + :undoc-members: + :show-inheritance: + +test.functional.test\_molecules module +-------------------------------------- + +.. automodule:: test.functional.test_molecules + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: test.functional + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/test.html b/docs/test.html new file mode 100644 index 00000000..711a9a07 --- /dev/null +++ b/docs/test.html @@ -0,0 +1,223 @@ + + + + + + + test package — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

test package

+
+

Subpackages

+
+ +
+
+
+

Module contents

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/test.regression.doctree b/docs/test.regression.doctree new file mode 100644 index 0000000000000000000000000000000000000000..b2442a3ff6b77792c5c023e0bb6f8e40913f8e8d GIT binary patch literal 17400 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 literal 0 HcmV?d00001 diff --git a/docs/test.regression.html b/docs/test.regression.html new file mode 100644 index 00000000..d58d57ce --- /dev/null +++ b/docs/test.regression.html @@ -0,0 +1,189 @@ + + + + + + + test.regression package — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

test.regression package

+
+

Submodules

+
+
+

test.regression.test_regression module

+
+
+class test.regression.test_regression.Test_regression(methodName='runTest')
+

Bases: TestCase

+

Test for regression relative to saved reference splits.

+
+
+classmethod setUpClass()
+

Convenience attributes for later tests.

+
+ +
+
+test_extrapolation_regression()
+

Regression testing of extrapolative methods relative to static results.

+
+ +
+
+test_interpolation_regression()
+

Regression testing of interpolative methods relative to static results.

+
+ +
+
+test_kmeans_regression_sklearn_v12()
+

Regression testing of KMeans in sklearn v1.2 or earlier.

+
+ +
+
+test_kmeans_regression_sklearn_v13()
+

Regression testing of KMeans in sklearn v1.3 or newer.

+
+ +
+
+test_timebased_regression()
+

Regression test TimeBased, which has labels to check as well.

+
+ +
+ +
+
+

Module contents

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/test.regression.rst b/docs/test.regression.rst new file mode 100644 index 00000000..c3cb03bb --- /dev/null +++ b/docs/test.regression.rst @@ -0,0 +1,21 @@ +test.regression package +======================= + +Submodules +---------- + +test.regression.test\_regression module +--------------------------------------- + +.. automodule:: test.regression.test_regression + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: test.regression + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/test.rst b/docs/test.rst new file mode 100644 index 00000000..9fca9975 --- /dev/null +++ b/docs/test.rst @@ -0,0 +1,20 @@ +test package +============ + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + test.functional + test.regression + test.unit + +Module contents +--------------- + +.. automodule:: test + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/test.unit.doctree b/docs/test.unit.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d21cd75c23774f0b28dd004946e3e27d251539af GIT binary patch literal 3599 zcmb7HU2h||74@zy+46^EJK3PXuG0;IBn}cwc?g0c1&RWBTtsM_qHh5~%}^p^4msh+ zT7C$SJfw&L0{gIRUIOI*^k4OGI2y^?Y|$DJFueS_JonslufOm8Yj3#I{DqONxlqe7 zElZ_KW@9)gb>S_u3SPVN@QE(wk!&Lk_hGAOngtX&!|Gs5~ z6IylKd5`z`{@3x64?@ogC)vhSICIRpu~))9t!Z&h7c8d5SiARkwoFd^){-A%_N-r1 z_~9Zy3j@+Q&UZt<^>-Tfq);qQ{fve~>YNcXk1LyZ?TXT-H|!UZS_>n-dx}>1>!9@Y zdN6}?hRxF&ANCzxq^Zb9{4qb~Pxvms2%k;3uGqwQrI?xAXmdTG)=`7&)*o=vPP#Xb zjfL}XKYQqB{3xTnhU;`?2uEM}S&NR%@Vs^3*5UzYKFQ8Z`P=Eq{P&0-e+PKJi{E?r zeSqJGcmw~a@%<_<=O4p~9-J5;y1J^hSLH^Oasc@b9#*k%OVxz}C9ABRErTtJOz z8PNcIISuFC%-GVZmdx1r&o~XEwY}jMj4T`rRY+g5xsZ83|11BBg@cMNOIAA`pY0)% zv~I|UxG$uh#k0StuV&1!GCtc0hYdBYR`M2W4?+30s|l?y_(g-# zK0yBSHni|K19Np_Xk9ZC={DMb!oCf(5gpb=Cmh+00Mk{lw#^%{J6!Xwi`{=A(CABD zddZ#^S~)zcBhf4NHIdB!M)d*IT#l2c#}@+E%}M(x%P2i9TTPOTxLo4K-$H=ejYIV;pv60xh5 zh^>S88w&Tz(YqVyK?`1=x1F%@kHeeJP-P`egeSGp3&U&{ww}|D%FOC^O+#{@AbJpn zg*QnyNhgxWD@zv3aA28pLM>1a&N_jgn}$7Q4E=vl>5+t8h3ISVYVYEdkEUU;U=Tp+ zv_UElN}A$??8e|IUr2DvHHL@n&>M--2~vn8nN72}xR>(pHiq-L)=p{1HYT4v2q&q| zAc4tpu1ytT8Cpn7O`uJL{|;QPt_Ny3cLhH$D%s3H(gt`;taQAT>>lwNa63>RB7TSxGJhhaW+?Z9g5 zllv1}JHu&u0ElKe@R4{>3@4JRg-5jp+$F{jp|If%!wPLm0y$>LeN`l(pN2lNZH_kr z4pD-rQ1E5s{V=57X|gtjhXUL>DScIwj(==)+$b=@zaOg?9jI63qcq@J3 z63a}Jh)ku^O2qpJH3V_WL-6w~B^PL;7GR+im2mOP(+|S1W;FpQC`77g06R{W8HMjD zGs5qs!aQ8f&wd#PBGsY#hK!;uvZu(hV&d>{su7@+t5fnt8Exe6p;M ze}8p6GL z5-t{8;s^5XNu79qY%6p{VoD1A1(?`;SU0zlMN_05MuYWuW?0c zKAW=LiU4XnEJDq}ft4zpC!Iif-C8HAL|&W1(L%Nw1W!IG@l?+@$~_v>2dkp)XFi;4Qm(<^q!1u( z0ui`mOH!8Ax(xQFC9gvWK+$TZWyj)X>6=@|ZuQ{aiG$Ux&8G8v=Qmw{DoKyF&uVAT zZbJ78wAmnc3`d2Q67;|uQ26%0Xzec%xgX=-ki+;l2Wo(SOe|QNFYM&+p82RVH^e(? WTV4=-kvMl)CWUUrEcG0IHvSL0Rec@+ literal 0 HcmV?d00001 diff --git a/docs/test.unit.html b/docs/test.unit.html new file mode 100644 index 00000000..9bf8b511 --- /dev/null +++ b/docs/test.unit.html @@ -0,0 +1,204 @@ + + + + + + + test.unit package — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+ + +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/test.unit.rst b/docs/test.unit.rst new file mode 100644 index 00000000..d11aa2eb --- /dev/null +++ b/docs/test.unit.rst @@ -0,0 +1,19 @@ +test.unit package +================= + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + test.unit.samplers + test.unit.utils + +Module contents +--------------- + +.. automodule:: test.unit + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/test.unit.samplers.doctree b/docs/test.unit.samplers.doctree new file mode 100644 index 0000000000000000000000000000000000000000..485bbee4bcc9ddca3f272bac20d2952ceee62cc0 GIT binary patch literal 3720 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 NxYiQO5^nr={eSpx|K9)r literal 0 HcmV?d00001 diff --git a/docs/test.unit.samplers.extrapolative.html b/docs/test.unit.samplers.extrapolative.html new file mode 100644 index 00000000..9a05fa1e --- /dev/null +++ b/docs/test.unit.samplers.extrapolative.html @@ -0,0 +1,367 @@ + + + + + + + test.unit.samplers.extrapolative package — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

test.unit.samplers.extrapolative package

+
+

Submodules

+
+
+

test.unit.samplers.extrapolative.test_DBSCAN module

+
+
+class test.unit.samplers.extrapolative.test_DBSCAN.Test_DBSCAN(methodName='runTest')
+

Bases: TestCase

+

Test the various functionalities of dbscan.

+
+
+classmethod setUpClass()
+

Convenience attributes for later tests.

+
+ +
+
+test_dbscan()
+

Directly instantiate and test DBSCAN.

+
+ +
+
+test_dbscan_sampling()
+

Use dbscan in the train_test_split and verify results.

+
+ +
+ +
+
+

test.unit.samplers.extrapolative.test_Scaffold module

+
+
+class test.unit.samplers.extrapolative.test_Scaffold.Test_scaffold(methodName='runTest')
+

Bases: TestCase

+

Test the various functionalities of Scaffold.

+
+
+classmethod setUpClass()
+

Convenience attributes for later tests.

+
+ +
+
+test_include_chirality()
+

Include chirality in scaffold calculation

+
+ +
+
+test_incorrect_input()
+

Calling with something other than SMILES should raise TypeError

+
+ +
+
+test_mol_from_inchi()
+

Ability to load data from InChi inputs

+
+ +
+
+test_no_scaffold_found_warning()
+

Molecules that cannot be scaffolded should raise a warning

+
+ +
+
+test_remove_atom_map()
+

Scaffolds should not include atom map numbers

+
+ +
+
+test_scaffold()
+

Directly instantiate and test Scaffold.

+
+ +
+
+test_scaffold_sampling()
+

Use Scaffold in the train_test_split and verify results.

+
+ +
+ +
+
+

test.unit.samplers.extrapolative.test_kmeans module

+
+
+class test.unit.samplers.extrapolative.test_kmeans.Test_kmeans(methodName='runTest')
+

Bases: TestCase

+

Test the various functionalities of kmeans.

+
+
+classmethod setUpClass()
+

Convenience attributes for later tests.

+
+ +
+
+test_kmeans()
+

Directly instantiate and test KMeans.

+
+ +
+
+test_kmeans_sampling_v12()
+

Use kmeans in the train_test_split and verify results.

+
+ +
+
+test_kmeans_sampling_v13()
+

Use kmeans in the train_test_split and verify results.

+
+ +
+ +
+
+

test.unit.samplers.extrapolative.test_optisim module

+
+
+class test.unit.samplers.extrapolative.test_optisim.Test_optisim(methodName='runTest')
+

Bases: TestCase

+

Test the various functionalities of optisim.

+
+
+classmethod setUpClass()
+

Convenience attributes for later tests.

+
+ +
+
+test_optisim()
+

Directly instantiate and test OptiSim

+
+ +
+
+test_optisim_sampling()
+

Use kmeans in the train_test_split and verify results.

+
+ +
+ +
+
+

test.unit.samplers.extrapolative.test_sphere_exclusion module

+
+
+class test.unit.samplers.extrapolative.test_sphere_exclusion.Test_sphere_exclusion(methodName='runTest')
+

Bases: TestCase

+

Test the various functionalities of sphere_exclusion.

+
+
+classmethod setUpClass()
+

Convenience attributes for later tests.

+
+ +
+
+test_sphereexclusion()
+

Directly instantiate and test KMeans.

+
+ +
+
+test_sphereexclusion_sampling()
+

Use kmeans in the train_test_split and verify results.

+
+ +
+ +
+
+

test.unit.samplers.extrapolative.test_time_based module

+
+
+class test.unit.samplers.extrapolative.test_time_based.Test_time_based(methodName='runTest')
+

Bases: TestCase

+

Test the various functionalities of TimeBased.

+
+
+classmethod setUpClass()
+

Convenience attributes for later tests.

+
+ +
+
+test_incorrect_input()
+

Specifying labels as neither date nor datetime object should raise TypeError

+
+ +
+
+test_mising_labels()
+

Not specifying labels should raise ValueError

+
+ +
+
+test_time_based_date()
+

Directly instantiate and test TimeBased.

+
+ +
+
+test_time_based_datetime()
+

Directly instantiate and test TimeBased.

+
+ +
+
+test_time_based_sampling()
+

Use time_based in the train_test_split and verify results.

+
+ +
+ +
+
+

Module contents

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/test.unit.samplers.extrapolative.rst b/docs/test.unit.samplers.extrapolative.rst new file mode 100644 index 00000000..cd6b17ef --- /dev/null +++ b/docs/test.unit.samplers.extrapolative.rst @@ -0,0 +1,61 @@ +test.unit.samplers.extrapolative package +======================================== + +Submodules +---------- + +test.unit.samplers.extrapolative.test\_DBSCAN module +---------------------------------------------------- + +.. automodule:: test.unit.samplers.extrapolative.test_DBSCAN + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.extrapolative.test\_Scaffold module +------------------------------------------------------ + +.. automodule:: test.unit.samplers.extrapolative.test_Scaffold + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.extrapolative.test\_kmeans module +---------------------------------------------------- + +.. automodule:: test.unit.samplers.extrapolative.test_kmeans + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.extrapolative.test\_optisim module +----------------------------------------------------- + +.. automodule:: test.unit.samplers.extrapolative.test_optisim + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.extrapolative.test\_sphere\_exclusion module +--------------------------------------------------------------- + +.. automodule:: test.unit.samplers.extrapolative.test_sphere_exclusion + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.extrapolative.test\_time\_based module +--------------------------------------------------------- + +.. automodule:: test.unit.samplers.extrapolative.test_time_based + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: test.unit.samplers.extrapolative + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/test.unit.samplers.html b/docs/test.unit.samplers.html new file mode 100644 index 00000000..f89c0b10 --- /dev/null +++ b/docs/test.unit.samplers.html @@ -0,0 +1,251 @@ + + + + + + + test.unit.samplers package — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

test.unit.samplers package

+
+

Subpackages

+
+ +
+
+
+

Module contents

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/test.unit.samplers.interpolative.doctree b/docs/test.unit.samplers.interpolative.doctree new file mode 100644 index 0000000000000000000000000000000000000000..e54d79a502c36efbcae985e603cf9f90be908ff5 GIT binary patch literal 35460 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 + + + + + + test.unit.samplers.interpolative package — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

test.unit.samplers.interpolative package

+
+

Submodules

+
+
+

test.unit.samplers.interpolative.test_kennard_stone module

+
+
+class test.unit.samplers.interpolative.test_kennard_stone.Test_kennard_stone(methodName='runTest')
+

Bases: TestCase

+

Test the various functionalities of kennard_stone.

+
+
+classmethod setUpClass()
+

Save re-used arrays as class attributes.

+
+ +
+
+test_kennard_stone()
+

Directly instantiate and test KennardStone.

+
+ +
+
+test_kennard_stone_sample()
+

Use kennard stone in tts and verify results

+
+ +
+
+test_kennard_stone_sample_no_warning()
+

Use kennard stone with a mathematically possible split requested

+
+ +
+ +
+
+

test.unit.samplers.interpolative.test_random module

+
+
+class test.unit.samplers.interpolative.test_random.Test_random(methodName='runTest')
+

Bases: TestCase

+

Test the various functionalities of Random.

+
+
+classmethod setUpClass()
+

Save re-used arrays as class attributes.

+
+ +
+
+test_random()
+

Directly instantiate and test random.

+
+ +
+
+test_random_sample()
+

Use kennard stone in tts and verify results

+
+ +
+
+test_random_sample_no_warning()
+

Use random with a mathematically possible split requested

+
+ +
+ +
+
+

test.unit.samplers.interpolative.test_spxy module

+
+
+class test.unit.samplers.interpolative.test_spxy.Test_SPXY(methodName='runTest')
+

Bases: TestCase

+

Test the various functionalities of SPXY.

+
+
+classmethod setUpClass()
+

Convenience attributes for later tests.

+
+ +
+
+test_missing_y()
+

SPXY requires a y array and should complain when one is not provided.

+
+ +
+
+test_spxy()
+

Directly instantiate and test SPXY

+
+ +
+
+test_spxy_sampling()
+

Use spxy in the train_test_split and verify results.

+
+ +
+ +
+
+

Module contents

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/test.unit.samplers.interpolative.rst b/docs/test.unit.samplers.interpolative.rst new file mode 100644 index 00000000..812af5a9 --- /dev/null +++ b/docs/test.unit.samplers.interpolative.rst @@ -0,0 +1,37 @@ +test.unit.samplers.interpolative package +======================================== + +Submodules +---------- + +test.unit.samplers.interpolative.test\_kennard\_stone module +------------------------------------------------------------ + +.. automodule:: test.unit.samplers.interpolative.test_kennard_stone + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.interpolative.test\_random module +---------------------------------------------------- + +.. automodule:: test.unit.samplers.interpolative.test_random + :members: + :undoc-members: + :show-inheritance: + +test.unit.samplers.interpolative.test\_spxy module +-------------------------------------------------- + +.. automodule:: test.unit.samplers.interpolative.test_spxy + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: test.unit.samplers.interpolative + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/test.unit.samplers.rst b/docs/test.unit.samplers.rst new file mode 100644 index 00000000..dc112797 --- /dev/null +++ b/docs/test.unit.samplers.rst @@ -0,0 +1,19 @@ +test.unit.samplers package +========================== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + test.unit.samplers.extrapolative + test.unit.samplers.interpolative + +Module contents +--------------- + +.. automodule:: test.unit.samplers + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/test.unit.utils.doctree b/docs/test.unit.utils.doctree new file mode 100644 index 0000000000000000000000000000000000000000..72e0d0349a13c5f0434924870b78b391eac3308f GIT binary patch literal 27792 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 literal 0 HcmV?d00001 diff --git a/docs/test.unit.utils.html b/docs/test.unit.utils.html new file mode 100644 index 00000000..f72f5bb8 --- /dev/null +++ b/docs/test.unit.utils.html @@ -0,0 +1,220 @@ + + + + + + + test.unit.utils package — astartes astartes.__version__ documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

test.unit.utils package

+
+

Submodules

+
+
+

test.unit.utils.test_convert_to_array module

+
+
+class test.unit.utils.test_convert_to_array.Test_convert_to_array(methodName='runTest')
+

Bases: TestCase

+

Test array type handling.

+
+
+test_bad_type_cast()
+

Raise error when casting arrays that do not contain supported types.

+
+ +
+
+test_convertable_input()
+

Raise warning when casting.

+
+ +
+
+test_panda_handla()
+

Splitting Dataframes and series should return them as such.

+
+ +
+
+test_unconvertable_input()
+

Raise error when casting fails.

+
+ +
+ +
+
+

test.unit.utils.test_sampler_factory module

+
+
+class test.unit.utils.test_sampler_factory.Test_sampler_factory(methodName='runTest')
+

Bases: TestCase

+

Test SamplerFactory functions on all samplers.

+
+
+classmethod setUpClass()
+

Save re-used arrays as class attributes.

+
+ +
+
+test_train_test_split()
+

Call sampler factory on all inputs.

+
+ +
+ +
+
+

test.unit.utils.test_utils module

+
+
+class test.unit.utils.test_utils.Test_utils(methodName='runTest')
+

Bases: TestCase

+

Test functions within utils.py.

+
+
+classmethod setUpClass()
+

Save re-used arrays as class attributes.

+
+ +
+
+test_generate_regression_results_dict()
+

Generate results dictionary for simple regression task.

+
+ +
+ +
+
+

Module contents

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/docs/test.unit.utils.rst b/docs/test.unit.utils.rst new file mode 100644 index 00000000..d4b96cf4 --- /dev/null +++ b/docs/test.unit.utils.rst @@ -0,0 +1,37 @@ +test.unit.utils package +======================= + +Submodules +---------- + +test.unit.utils.test\_convert\_to\_array module +----------------------------------------------- + +.. automodule:: test.unit.utils.test_convert_to_array + :members: + :undoc-members: + :show-inheritance: + +test.unit.utils.test\_sampler\_factory module +--------------------------------------------- + +.. automodule:: test.unit.utils.test_sampler_factory + :members: + :undoc-members: + :show-inheritance: + +test.unit.utils.test\_utils module +---------------------------------- + +.. automodule:: test.unit.utils.test_utils + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: test.unit.utils + :members: + :undoc-members: + :show-inheritance:
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Index

+ +
+ _ + | A + | C + | D + | F + | G + | I + | K + | M + | N + | O + | P + | R + | S + | T + | U + +
+

_

+ + +
+ +

A

+ + + +
    +
  • AbstractSampler (class in astartes.samplers.abstract_sampler) +
  • +
  • + astartes + +
  • +
  • + astartes.main + +
  • +
  • + astartes.molecules + +
  • +
  • + astartes.samplers + +
  • +
  • + astartes.samplers.abstract_sampler + +
  • +
  • + astartes.samplers.extrapolation + +
  • +
  • + astartes.samplers.extrapolation.dbscan + +
  • +
  • + astartes.samplers.extrapolation.kmeans + +
  • +
  • + astartes.samplers.extrapolation.optisim + +
  • +
  • + astartes.samplers.extrapolation.scaffold + +
  • +
  • + astartes.samplers.extrapolation.sphere_exclusion + +
  • +
    +
  • + astartes.samplers.extrapolation.time_based + +
  • +
  • + astartes.samplers.interpolation + +
  • +
  • + astartes.samplers.interpolation.kennardstone + +
  • +
  • + astartes.samplers.interpolation.random_split + +
  • +
  • + astartes.samplers.interpolation.spxy + +
  • +
  • + astartes.utils + +
  • +
  • + astartes.utils.array_type_helpers + +
  • +
  • + astartes.utils.exceptions + +
  • +
  • + astartes.utils.fast_kennard_stone + +
  • +
  • + astartes.utils.sampler_factory + +
  • +
  • + astartes.utils.user_utils + +
  • +
  • + astartes.utils.warnings + +
  • +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

F

+ + +
+ +

G

+ + + +
+ +

I

+ + + +
+ +

K

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + +
+ +

P

+ + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + +
+ + + +
+
+ +
+
+
+