From a30cd8a40c2078feb0f5edc5a98da19e3885c746 Mon Sep 17 00:00:00 2001 From: Oceane <oceane.fourquet@outlook.fr> Date: Tue, 7 Feb 2023 16:47:48 +0100 Subject: [PATCH] Mise au propre --- .../cost_matrix_uncertainty.cpython-39.pyc | Bin 4824 -> 4793 bytes .../dynamic_preselection.cpython-39.pyc | Bin 10739 -> 8692 bytes ...onic_regression_uncertainty.cpython-39.pyc | Bin 12839 -> 12781 bytes .../optimal_k_aggregations.cpython-39.pyc | Bin 4703 -> 4321 bytes .../__pycache__/show_results.cpython-39.pyc | Bin 5682 -> 8815 bytes Module/__pycache__/stages.cpython-39.pyc | Bin 2902 -> 2039 bytes Module/__pycache__/tools.cpython-39.pyc | Bin 4356 -> 4371 bytes Module/cost_matrix_uncertainty.py | 2 +- Module/dynamic_preselection.py | 60 +--- Module/monotonic_regression_uncertainty.py | 9 +- Module/optimal_k_aggregations.py | 28 +- Module/preselection.py | 59 ---- ...show_results_4cases.py => show_results.py} | 271 +++++------------- Module/stages.py | 46 +-- Module/tools.py | 7 +- README.md | 40 +-- run_mem.py | 99 +++++++ 17 files changed, 222 insertions(+), 399 deletions(-) delete mode 100644 Module/preselection.py rename Module/{show_results_4cases.py => show_results.py} (58%) create mode 100644 run_mem.py diff --git a/Module/__pycache__/cost_matrix_uncertainty.cpython-39.pyc b/Module/__pycache__/cost_matrix_uncertainty.cpython-39.pyc index a39af419af09ac84330c78ad6a8a94e5580258a5..eaa56ea6a45882d764e09782f1633c6338042275 100644 GIT binary patch delta 1020 zcmZ9K&rcIU6vw+iy3m&LLnX0_B1*v`w1N^f2BT6@L4#2sW=v?d+iBg{-C5sm2|W?G z7_ZL7t9lVm8cs(40Z(4ZTuium@PF{VB@yE$`<XZM-n^OlzPFeElF!)LY&wBo-_!li znWmPXD=mi{!jh<q7QAfnQdu}HkNZ(r^0-$C+R=02?|#+lS{E~GuH9fp1d~io7(b3N z19(Fj)c^=prU$@euUXcLyUS)<OCQH`uHX+jxtE+Oo*?ri!5|C}P7zKM1_@^fLxi*P zsx>%2OlF=iLKr2SClnAYDOyn_fHATyPt<rbWF2^=3I~933Y#F80hNHsch-V7wfo!J z(KRODrgpTPROta(Nmp~{C^SpxCeXDVGAQD8nqE*pn0lFe9VIlkbtb=MCP&C6Vi!WC zTE4>}vR(fdJ+Pp|HS$f%qh0>Sbuw=dZX(ck8wZ5~djFhE`L^(f966H@78hq%3I@#4 z(hOl1feVzE>D4w&(|jlvRp}yBR)a^}UsJjlF!PZRO=UVFXtT~@jq`v^Na7Zy2Q`)| z+mSs7w#N^(SEkz(4qTSS?BL22MH-&H&a5XKTplVTj6j(_Zc&yae8-MhXCx|hN}{wS zD8{+{KpDR6!zG$o_(HM9nQlj5;R2H%vU#k)_w1&2OD=R@$i(WC8gNH$c5i8`((KtU zlgx$GVSgy|1#gG(?GLXTXFO=Bixl69ZGh*v>p)4F9P1s{Cgo!9W6hE8dq2*^LTVJL zF#{ipW$4ElR1w=cJi`I6UaS9Cl1~(qldt+FN9j$lLipRSn1s_tR2t=p+o&dg_Kj~e zaJA5{tcRl3YI4wNSKQmw9V+R!JS@i&*;ZitH9Ld_3b{)wX5^xzDL2A~!ZL<nl4~Bp mdc0OMasv<!4@1{)z<qM{5J-QZvcYO1(U|~;%!Yh(WbO}d_Vuy= delta 1051 zcmZ9LyKfUg5XN&4Ut$|O0YQN<gjWKA5EBHUAV5T{h(}%o2#CfypV!F=`}UYUM{xv- z2sG5&LQhhGQXv{@3TV-kNEDPv`~mEDDT1)%-_7jI&h36P_i^C+K;ADDa$V+E`ttBY zzG+oN`GFFo%CaHb^t3I?6&bW!B1%+wZpEk2kB(0IQ6Q+iAXK}VsOmfkC7L2gLK#)( z{gBl58>?aMVYeRoOY9^x%DU)$+s_UO<JV#WYHS-r|8^?Y#qBY-W91H+V_Y_WD(R1z z3nPbN9swMnA2<pe1C9eHfRn(0KIrw|J_YkMFa(?d&H}>*k2A8JRAV}4Z1!5RE}DwF z&5^2th|VKz6d{MIG3yQQjy1mh)!VWy)}8E@RnnhwB|VX=9UMez0Vo1Eb^rqzuX8ty z+1PPs^EbOM8FSNS{Wd>3h>%P}2Apj}#>5Y!U%23qO%=o@^q+jRJ_Yj@FufC-H4g~b z`sdB4w}G4zf|=>Lxyi*LhZeAO6PPnF3#iL>twR&=kENorEfsr9A`#IF+pU=0c`2Lh z1~Tq&&q!T}7$#-Xy>Xqh6+iK($Zv^V?b!{RGN9|ax6r>hj!dWJud;VfP$(2TDj{|w zvxU7tMuDGjPa>-g6k+Q=T}*37F*}hT(KUFUxuIMUZ2Jj$SkSKu1EvF8g%{S09xk5E zr|Lrux~pr&4NK{t#UB;OJe1v?4|bo3j!I9zd)&0*&Pa_RzsHP$c~7`XD9SqDchb6| z&-X1@Yx-s1yQ`^?7BVe%%tcL$4j7L*2Aej;*yKd@#(yn&kDQWT-aC2<ccNwBIDmOI zMV^}nls59DWAsda-aEX$j^F|IW@NqH6l7yVI@_2I&P45&X-5OL7yD7&SM(Su_p#z8 zp^-EjCT5^a8x^?-Jwm9rWxmodCK(8&!f1&W5$Xk?KcQ`;y1IJ0XbtANR{N&@0)#OT A@&Et; diff --git a/Module/__pycache__/dynamic_preselection.cpython-39.pyc b/Module/__pycache__/dynamic_preselection.cpython-39.pyc index 6e7a5d749d3ae53b8cb678e579961c50add26f61..114f2d5e86efdad995af1333c3fbf2261be7052f 100644 GIT binary patch delta 3214 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 literal 10739 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 AKmY&$ diff --git a/Module/__pycache__/monotonic_regression_uncertainty.cpython-39.pyc b/Module/__pycache__/monotonic_regression_uncertainty.cpython-39.pyc index 261caf75a92252ad4805cf09d5d7d5d480095b10..df45ec257726d79ba4d83283b4c71ef2b3ac62b7 100644 GIT binary patch delta 2735 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 NdP@_t^E)k@{sT4)AV~lK delta 2873 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 diff --git a/Module/__pycache__/optimal_k_aggregations.cpython-39.pyc b/Module/__pycache__/optimal_k_aggregations.cpython-39.pyc index 278c9521ba1737d10a989dc280157324a77ae69f..0795f9292d3c7fd7fb975537ea5cd593c57a13a3 100644 GIT binary patch delta 884 zcmZuv&1(}u6rVS{+1>0{cGIs!3u@a#Ba~V{q30C5C_;-^X{a%iwrSHOootoDEGeYY z^dJQ0;?3mZUHnTtcyKR%AU*g8=+!q`kfO89Z{K_Sd+#^z&3>Bsa>Xxuo=tFlu6(Wh z4Bq-7g(Z2JUa)toyX&okXsg+HSD{lz$5gDdHIDBzZVh+44}>sa^oT@6q=dn=3DTuS z(uEU<NCX0{E)+>0N_S&3q60c4u_eg1CQL>cc|kX5p2TTE2D&geVF<A;?CliO@kza; zKq6ycc7!cJP@xU=*uj7$oFSZ`Ak%gz{}H8oWMB`KC_N^}SdtmcJhCwA42e2S><X7z zd9n$y7r9t1Ej(4Pn_8o>A7?~{rFS%b+5@KL$-s+zk!E(D2tS9}!wvvxSW$*KU9^<! z9TKO`cU;<vgR}m^C_o9PM?`=kde>Of;%qz;kDf`7{43oD{<H@o_>VX$-uNrthdq67 z<`_1Bxj1&~{2{Q@F)_AG3f_JB-F`K}4ZNh40!?(ro2|sGHCpv@r79OQMd`S+@K`=@ z3bN$hmhauI={+QKAE6NPd1YTiNc5<-TTS#@y;<Q8Wyf3blT?e>8WEpT)Nz@3vj%J@ zG+K~>ziO<h%tx~6PcPm?lW4hA7A%?t7knCMwq{Wma$swtV8JA{sHNd|jEqtneV<NJ z-j=8SAkS4LM}hkPxU0ZJIFPS1SC=Zvom0RN3Y7n*EBg;UQkKd|(#;n3P_D1<JV&>! zW<u~ZIpF)!4?X~s--04=SqSGLmaE~#u|s4O@`-V;$@c42PSNF0<ViRQCHW@2j&u7M iUYdEP!fFV-s9;$^Tfx49Lj|T>a7N^Oc22ux8NUEPSj1HT delta 1285 zcmah{&2Jk;6rVTiwb%P)$8lP_MC!IwD6S}hUXYOBKpjp{BGLmNDbZ?Yoo@WG?(77R zGusGU6z5PWXt;2*ufPRy<=;R;3lieUg};F}#E23hvDW-%-t&9E-<vn@w`;%N@I%kD z34VX{ZbUydzVlZoFcr`%owq*<c@mC-JK-pb`Q|%ub~q5(-Zqc3co0V-Nk@CzVZyWT zyYzbb*wQ4+uZ4RRmw_w0NeK~z!5pNqfGGfBlo^kSpsXazQ`#j{I0Zq4A@MYYE;)ny zzvPxE%}WcCSA{7n%$(BPmiD~N%E)6aV1YbnR~7_!a$p@xixEaXr#;#xxg*KEDy@AC z%U$Un*sOv->j?!SoH=?VNQ&i@a_<6t^=V>^^`y6eQzA`f_vsn%*M&bL^V&ieO;5-P z>M@78kB=>M*B3<JCikV!yf)c~ye3vq%#k%MH#K)@Ue8zL3iJC0lHHyGv)g3e5UbK* zwKkFU7Ut^`Mi%z0uDhkBUnaRJs5H;}b^pt}vFy&OXd=HiBge9V5~XQ**T|dsT7GFM zy!M~MU(Y}`{!jQqXI8NBOIf+vA`AL-r_PSy;hPr{8gn?WQdTkiUoZCXg%jujTg5rB z{<#-+?y|hRLpsg7lXgECCRsEHvn=T)QK-i)cqKT>?Fg1rrZ=1|Qo^;Pp0_{S`dtrP z0pY~m#)NnzFg~#Fb!bsyJRKL6WHcUxQ9QX6rI`qZq2S3UL6i>1hazTy&C8gte(<`g z>TE!$q}@@wW>qog)@zgJ?(q1$jA1OoVann`&`WvH4_?(W$p|qE>`8NL#Deis|8KAQ z!g=t<r^wEIgw9%Fj(IW?MHv}%8JqgA7ZHk*NQQAyO2_f2FhAyrhzm0sq#62>K^pOQ z)w+AH!mn$ZmU`rF_{JdJFW{h{;-vz5>Rb1{@`sx4edT!1-n)xO0zPe;4Y0t5I${G{ z^wbR-ZOgC?o4U{f+i0S_PAzH~K1Q{mNzZK?u7HbY9n+%xNImf8?TOZKG*mRW8a#wk zb<MxIb)d~#8u|zw%Kr-2=ksu>PdcZlrenNvIN0l-pqc3>AXr}uc&^U;AEB>$wJuE5 zH?>W8qJFMDvo^zsPP-_-m9oP@%=HZLedW~G@yRyow_#U(P``Thk#_4g@vep)4M!Ss O4KwvseaqOg%6|fLgf(LT diff --git a/Module/__pycache__/show_results.cpython-39.pyc b/Module/__pycache__/show_results.cpython-39.pyc index 2a77523ab471eb02977f182b7253a9182f0e5c99..2dd8754d800151e48f662369dc523fc144bf777a 100644 GIT binary patch literal 8815 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 B!5aVo literal 5682 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 M`epx8a5Z@IUyEo6<^TWy diff --git a/Module/__pycache__/stages.cpython-39.pyc b/Module/__pycache__/stages.cpython-39.pyc index 8619cd1ba1731d59207ef468dfe6812fdfd0bbfc..b8af48a39981829c186d7e93d4c7b8b26babe952 100644 GIT binary patch literal 2039 zcmZ`)OOG5i5N`K-o;#0yWRnO5$bsRtun`v&AtZ7o5(->eK`n2$XVRH|#r8y5$$eUo zxbPo##3@&Pj*oESFL2_sXR{;`^r-F6E>}%ex$0{=8ucAKzg2%^>&S8bG>g|C7mKg) zieE6~PEJavB8f{3c7eUbx7Y&?lF(uwI7%Xm1K>F6SsViQlYzxiIZQ^d5tZX=FPU8J zO_OOJ=e?htWR~~y0p@u=%tx5_^Krh1`5=!TIg80(@WxpXeUvpqrWKXEc#&@EjB!be zTAo96*tD{!Xqm24x>|9zqOxde0m+@JsT<kUMV4ZlGa(>&OFNKFQ<}qb!Ah1H)s&X2 zh8OZlh3)<PyrvZ_w9tQb;$h|)zpkDTvw6S4E8fE(olByeE$KWUS9!`&t|D9ivD^7w zpn^xvOY(5xX+Lj8napTerdd-ji`9njd`||~E~KZ6P`mk3hxJ+3ZiFUP67EiG@|_M^ zT5$2w;d}VszrQ&7K`<^(nq{-$&o=DjL6dDNR!ebGu_|rP<&&m9`L@Y7B|8z4u9*0= zJ=dXypBWRv1mciB*(ZDol%ZCxA5%d+yf)B}0d|2ZqI?yq06}`&sEcgS(Uu_Gxa+A{ zMN9XQ!(%8QXs=n*WPhDjg%DXuaVN_nvtcK_>ziEkx%o5gWu-`hs;JX7Ci)^>^MTn9 zghZ-zutX_H9j#NwdBb(EPGKSmu);|b&u*9)oybO+etv|-RhWllO!y6~-w5*-Hm<|G zOH7y-Z@f$YvEM}|xUMgWbd_^KF31Dt$KShwa-Mo>fP!~^c9-t4(+!n#>8rttpdLnQ z^fbr`e(tYmEg4=$YGl(FZ2fMGb*#oXw<mj-eMrV?4@pIGx8Y;2n{?A|2FU=Dp_*bp z*ak@QyxUjN<xpZb_l_MkzX5-?ggB~yIaK==#XweSS3Rue20i-#n&aHxnkb?Ra?9xs z<lf~(^>J<9*6R+jnyNz;Z{6+)c!vG{)`d4Wy5sJqI)LnG>7iAFhu<$;lr(Qz9Tjz3 z(v0a)Qodr6BZ<ypuKltQxHV4e71LhH>clU~CgaBt>w#%7nHF`<Uf|-ZjUL)tz3O^B zu@vyCWKiaOX4EE2XrT8iCTZ2=tW0iaoKeYAihXo#USwd7S5h6)wq<p$J$fc|kTsiH z@&JaC9^GWA$QsU)xoxnVfoI^4Wc)cTlR0Ybs$LlkHxP)$EnBC24g=g2RuUU4%c5kq zQ2Buo>|@ZO4Mrs4c`Esanb|m(L}qTzs3rw^V<QtkU#6!zsxd)D`zCDdRnHk88#}(C zhQznJ!A{eoS%!EvnRc^6hb28@Xq(UqMKZdk%e0l^f4buI9oQCkF*xM5J0UYNBxB5d z?<P5P4?zfHGW2F<bZ3O0;#_8_!f4<zU1=KJQp0_KYijV6kJ=6`DTJu)NP6f82ZRwB z!axn1+P1x<dMf;vDgu57cKEwyFsy2?o4*gV7`&DBw{p!tG{-+OgJCI~H~xu1|4j+^ zzJyE|_Z@<e$xXuV0WS`9xZ_H0zK%P0JcCT(aUTQjg>P*6aFY$~3d#**a>E}wY*B(# zXt&LiDZX88*~qdu1LYco3);<ITT1OV!V<2fBb#6A!)qQ}-z}5H_fhDe@UKi;3BzAQ RT-Vjlje+7Ij^il4{SW?l2~Ge2 literal 2902 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 P&m(X~PS6Mfe4qRmyH^3x diff --git a/Module/__pycache__/tools.cpython-39.pyc b/Module/__pycache__/tools.cpython-39.pyc index 3335ebb09460a99f00dcbc32116d144a20c70a59..cff49bba8b77852765176cdb3db435a582510586 100644 GIT binary patch delta 861 zcmY+C%TE(Q7{EK*-9EP6zJLNf2ow-kgpDaG!U0W@Xh<N@;9)Lxx-)&qzL?z_+SGV4 z98mNyM-x*{#-rgM(34)gdD?g|{so>rIfG4%GnwCf`+f7hX7+iRl{KVkYJ`tpt)J%i z51J0<SByQMP~UJHZigOph_UIK9h*3TZ`j1HdEKDpI%hrbJ_;b4QyO4~y-<!g3$Y5< zY{ej$XQ#1Gpv=tp%c(^k+>DA8!;$5Cg0CuH{xQoWe(WCwsmJMlq94ZzoW$yh3?f2< z6)ZQUAyYVwwZE2uh5^nrrBfiz4Kn|IWpQ?>&*9uq%H#YX85H_yTwt~2<l+b(J>kB6 z36G6Oo@RKi(SBwyhKqRoRKgQ@@<ig+^n-|AVy}}At5C&=?z<E@P0~x=->puY9r}dm zQmB}&<x;3vs7@>>H!14&q@^WYqE~o(Fln_N;s;%euv_Y*-Cn{#9dp^kjh<u}zkvaj zpxtZ*I)JHq-94<e9kWGzy%<W42V>|wAr&`BF9?(c#yG;L-?1V4q8b{MJ<AQCd}y_~ zMoz61!#E|Lg-oJn>74MG6&~zPsthi&R%%@hrRu#<c92cjyVMj|WuH?E#R4dS44*2W zWsn95Py}@2OiJg$w7~;F**~BGUFD*l45Pe{^SDsjxe8fDTUILEa?BdqEU573A3b}k z86YkmnRmy&WxQwqs+T+*CO1)lwkR(GDv0uXqbnjytkG_EC<!Is;Z2eN##;mhHuC5- zZl>1-ZV22ISmV%D80*$3K~~6jj}i<u({&m(8wIsS+ah#99K9rdbE*qmW?!>w;0;UU z)(hJr0@%?<LdEIWUY8ndFE>>ZwS=<ia)rc2821UPyVRj~*{j?{X-0&Z7dU^M4IzpC O={EbAyB(cN<o^Jj=-hMw delta 915 zcmY+D&2Q5%6u|4WX_vO?+I_H(15EAE7GNugiNkh)t=%L(#HMY4lpTr}yCow{vX^A6 zQ^h1eNJ#AD6G%wgkt5oT8y7Ahap7cfK;jSJz(0W9RzleF&-Q!I@A<trtoWj+V_i?j zMEm;Xf%Wl&ZlLN$`CdRFD0_7;g58LgtDY4#sT&66)jbS0b|)&>wJ4O=X%IPKP+J2U zP={Kf?YXrzY(sFmh2F;zXR2C9Mdqk41^=j5g=8veqAB()`3aR+HTC-3jEHT;<qdi* zCuU8IiWotg{Z9Qn+z&H5*>+z$Mf!+F(j-H&L_bQQn3NNhBpOPOIbqR%l#rTZogk8L zC?}}1%l)_OCxxCoPX>Cc0vSBk!hv>{3_VxcI#I`Bf{C$M@g&|g*%>6m<jhgm;ZVEd zx}DvK86)hec7N+YnVI2fg5j|T*lkeg6Db^M>#LOsD}p_`VyIkmY?lUM%b{GgJjVl5 zah`D1!Q0d^Q<h`<HP7V<7w@$U1uhE*P!?b#>4($CFjrikCvn%itQ?$`C`k+p@OTh4 zIs2S0>pbB*UdR*sjx8igW==P9a9$ct3YhFpriiAQmsyxJmC8-XNKFT_{#?V6RSPT+ zXkBcBYwUYwYG@RVqnzkz(TgZ62+OC1YynNo$uo&y7eZJPOG7i`!a+BZa`y^nOZu!j zFEp=Mq?geA=^MR*Qn#e3coM&I{^7qA6rXUdibK2txGAcH0dNZzWQ1hhZbU%261XB$ z8k(s`6o*ah!*!vC8xo5W^6fxXz(||PRt+e2<m>|_rfzv|z1GBGt!_IM3~72n{sM4O z;u8DOKabwBk^I8#P3ZyMH3qrrMoqs3ojeQTtgNkLZ_oOzPL-40xqHim<q1<ooHbJc j#oHdZu+HA)N5_jYz?4Mi+bzqLtO{(hZ~4V|sju)CnuPN7 diff --git a/Module/cost_matrix_uncertainty.py b/Module/cost_matrix_uncertainty.py index a04024b..ae05749 100755 --- a/Module/cost_matrix_uncertainty.py +++ b/Module/cost_matrix_uncertainty.py @@ -10,7 +10,7 @@ from itertools import chain import copy -import multiprocess as mp +import multiprocessing as mp ### Useful functions for parallele diff --git a/Module/dynamic_preselection.py b/Module/dynamic_preselection.py index 6c71fd6..9fdeeca 100644 --- a/Module/dynamic_preselection.py +++ b/Module/dynamic_preselection.py @@ -28,9 +28,7 @@ def H_df(df, cls, nbcpus): pool = mp.Pool(nbcpus) vals = [(c, df) for c in cls] res = pool.starmap(monotonic_model_RE, vals, max(1,len(vals)//nbcpus)) - #f = open('logs_H_df.txt', 'a') - #f.write('H d_f {} \n'.format(res)) - #f.close() + return sorted(res) @@ -108,11 +106,11 @@ def deleteNode(array, num): if num == array[i][0]: break - #print('array 1', array) + array[i], array[size - 1] = array[size - 1], array[i] - #print('array 2', array) + array.remove(array[size - 1]) - #print('array 3', array) + for i in range((len(array) // 2) - 1, -1, -1): heapify(array, len(array), i) @@ -263,19 +261,15 @@ def check_disjoint_pairs(Q, param): if len(dis_p) >= param: flag = True break - print('Pairs with {} genes'.format(len(genes))) return flag ### Preselection based on the number of genes -def algorithm_1(cls, df, k, nbcpus, logs): +def algorithm_1(cls, df, k, nbcpus): t0 = time.time() H = H_df(df, cls, nbcpus) t1 = time.time() - f = open(logs, 'a') - f.write('H computed in {} en len(H) = {}\n\n'.format(t1 - t0, len(H))) - f.close() Hd = H_dict(H) @@ -305,10 +299,6 @@ def algorithm_1(cls, df, k, nbcpus, logs): break - f = open(logs, 'a') - f.write('Old G {}\n\n'.format(G.keys())) - f.close() - a = max(Q.keys()) G_ = deepcopy(G) del G_[a] @@ -319,9 +309,6 @@ def algorithm_1(cls, df, k, nbcpus, logs): G_ = deepcopy(G) del G_[a] - f = open(logs, 'a') - f.write('New G {}\n\n'.format(G.keys())) - f.close() @@ -330,22 +317,9 @@ def algorithm_1(cls, df, k, nbcpus, logs): Hd = supp_H_below_a(Hd, h_key) - t3 = time.time() - f = open(logs, 'a') - f.write('S1 computed in {} and size pairs={}\n\n'.format(t3 - t2, Hd.keys())) - f.close() - f = open(logs, 'a') - f.write('G {}\n\n'.format(G.keys())) - f.close() - - - t4 = time.time() for h_key in sorted(Hd.keys()): - f = open(logs, 'a') - f.write('H_key {}\n\n'.format(h_key)) - f.close() a = max(Q.keys()) if h_key <= a: @@ -364,9 +338,6 @@ def algorithm_1(cls, df, k, nbcpus, logs): G = update_dict(G, Gd) Q = update_dict(Q, Qd) - f = open(logs, 'a') - f.write('Old G {}\n\n'.format(G.keys())) - f.close() G_ = deepcopy(G) del G_[a] @@ -377,19 +348,11 @@ def algorithm_1(cls, df, k, nbcpus, logs): G_ = deepcopy(G) del G_[a] - f = open(logs, 'a') - f.write('New G {}\n\n'.format(G.keys())) - f.close() pairs = list() for key in Q.keys(): pairs += Q[key] - t5 = time.time() - f = open(logs, 'a') - f.write('S2 computed in {} and size pairs={}\n\n'.format(t5 - t4, len(pairs))) - f.close() - return Q, pairs @@ -397,15 +360,12 @@ def algorithm_1(cls, df, k, nbcpus, logs): ## Preselection based on the number of pairs -def algorithm_2(cls, df, m, nbcpus, logs): +def algorithm_2(cls, df, m, nbcpus): t0 = time.process_time() H = H_df(df, cls, nbcpus) t1 = time.process_time() - f = open(logs, 'a') - f.write('H computed in {} en len(H) = {}\n\n'.format(t1 - t0, len(H))) - f.close() Hd = H_dict(H) @@ -438,9 +398,7 @@ def algorithm_2(cls, df, m, nbcpus, logs): t3 = time.process_time() - f = open(logs, 'a') - f.write('S1 computed in {}, H size pairs={}, Q size pairs = {}\n\n'.format(t3 - t2, Hd.keys(), Q.keys())) - f.close() + t4 = time.process_time() @@ -472,9 +430,7 @@ def algorithm_2(cls, df, m, nbcpus, logs): pairs += Q[key] t5 = time.process_time() - f = open(logs, 'a') - f.write('S2 computed in {} and size pairs={}\n\n'.format(t5 - t4, len(pairs))) - f.close() + return Q, pairs diff --git a/Module/monotonic_regression_uncertainty.py b/Module/monotonic_regression_uncertainty.py index 48cb10f..88b43b6 100755 --- a/Module/monotonic_regression_uncertainty.py +++ b/Module/monotonic_regression_uncertainty.py @@ -56,7 +56,6 @@ def Z_(H, A, ind_leaves): for i in range(1,len(H)+1): v_i = ind_leaves[i] Z.append(int(compute_Z(A,v_i))) - print('Z', Z) return Z def is_A_balanced(A): @@ -176,7 +175,7 @@ def step1(ind_cg, A, nb_leaves, ind_leaves, err1, S, H): else: A[ind_leaves[ind_cg]-1] = mini + err1 degenerate_interval(A, ind_leaves[ind_cg], ind_leaves) - #print('Step1', time.process_time() - t0) + @@ -241,7 +240,7 @@ def step2(A, v, err0, err1): #add the error in left and right intervals update_all_right(v, A, err0) update_all_left(v, A, err1) - #print('Step2', time.process_time() - t0) + @@ -615,13 +614,13 @@ def compute_recursion(data, case = None): models[4] = (reg_err, bpr, bpb, r_p, b_p) else: - #print('case {}'.format(case)) + rev, up = case[0], case[1] X, H, A, ind_leaves = initialization(data, rev) S = list() labs = [x[2] for x in X] nb_leaves = len(H) - #print(X) + for i in range(len(X)): #((r,c), w, label) x = X[i] xy, w, lab = x diff --git a/Module/optimal_k_aggregations.py b/Module/optimal_k_aggregations.py index a0ca582..20b7218 100755 --- a/Module/optimal_k_aggregations.py +++ b/Module/optimal_k_aggregations.py @@ -63,19 +63,17 @@ def create_and_predict_metamodel(df_, out, pairs, nbcpus, funct): ##Big loop to compute the average error for ensemble contaning k classifiers -def k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k, log): - print('k misclassification : {}\n'.format(funct)) +def k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k): - k_mis = {k : list() for k in range(min_k, max_k)} #Store for each value of k, whereas patients were misclassified or not with an ensemble of k classifiers + + k_mis = {k : list() for k in range(min_k, max_k+1)} #Store for each value of k, whereas patients were misclassified or not with an ensemble of k classifiers #pairs_err = {cl : list() for cl in cls} #For each classifiers we are going to store the average misclassification error (computed with LOOCV) made with each patients for j in range(len(df)): t1 = time.time() - f = open(log, 'a') - f.write('Patient {} \n'.format(j)) - f.close() + out = df.iloc[j, :] df_2 = df.drop([j]) df_2.reset_index(drop=True, inplace=True) @@ -83,11 +81,6 @@ def k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k, log): ndf_err = cmu.error_matrix(df_2, cls, nbcpus,funct) - f = open(log, 'a') - f.write('cost matrix computed \n') - f.close() - - cost = cmu.cost_classifiers(ndf_err) @@ -107,7 +100,7 @@ def k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k, log): min_k +=1 #k > 1: ensemble classifiers - for k in range(min_k, max_k): + for k in range(min_k, max_k+1): t0 = time.time() mve, pairs, algo = find_k_metamodel(df_2, ndf_err, cost, k, nbcpus, strat) pred, proba = create_and_predict_metamodel(df_2, out, pairs, nbcpus, funct) @@ -117,16 +110,7 @@ def k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k, log): else: #case of proba = -1 means that all the classifiers in the metamodel predicted the point as uncertain print('case of unknown point in oka') - f = open(log, 'a') - f.write('Creation metamodel for k = {} in {}s \n'.format(k, time.time()-t0)) - f.close() - - f = open(log, 'a') - f.write('End patient in {}s \n'.format(time.time() - t1)) - f.close() - - - k_error = {k : np.mean(k_mis[k]) for k in range(min_k, max_k)} + k_error = {k : np.mean(k_mis[k]) for k in range(min_k, max_k+1)} return k_error diff --git a/Module/preselection.py b/Module/preselection.py deleted file mode 100644 index caffa4d..0000000 --- a/Module/preselection.py +++ /dev/null @@ -1,59 +0,0 @@ -from Module import cost_matrix_uncertainty as cmu -from Module import optimal_k_aggregations as oka -from Module import monotonic_regression_uncertainty as mru -from Module import tools -from Module import selection_algorithm as sa - -import multiprocessing as mp - -import pandas as pd -import matplotlib.pyplot as plt -import os - - -def all_configurations(df): - transcripts = list(df.columns) - transcripts.remove('target') - - configurations = list() - for i in range(len(transcripts)): - for j in range(i+1, len(transcripts)): - for key in range(1,5): - configurations.append('/'.join([transcripts[i], transcripts[j], str(key)])) - return configurations - - -def single_score(cl, df): - p1, p2, key = cl.split('/') - key = int(key) - rev, up = tools.equiv_key_case(key) - - diag = df['target'].to_list() - tr1, tr2 = df[p1].to_list(), df[p2].to_list() - data = [((tr1[i], tr2[i]), 1, diag[i]) for i in range(len(diag))] - - - X, m = mru.compute_recursion(data, (rev, up, key)) - reg_err, bpr, bpb, r_p, b_p = m[key] - - return (cl, reg_err) - -def regression_error_score(df, cls, nbcpus): - pool = mp.Pool(nbcpus) - - vals = [(cl, df) for cl in cls] - res = pool.starmap(single_score, vals, max(1, len(vals)//nbcpus)) - - dico = {r[0] : r[1] for r in res} - s = pd.Series(dico) - s.name = 'regression error' - return s - -def regression_error_matrix(df, nbcpus): - config = all_configurations(df) - reg = regression_error_score(df, config, nbcpus) - return reg - - -def preselection_reg_err(reg_err_mat, threshold): - return reg_err_mat[reg_err_mat<threshold] diff --git a/Module/show_results_4cases.py b/Module/show_results.py similarity index 58% rename from Module/show_results_4cases.py rename to Module/show_results.py index 25d9795..335ba85 100755 --- a/Module/show_results_4cases.py +++ b/Module/show_results.py @@ -131,10 +131,9 @@ def print_model(data, models, p1, p2, df1, pathname = None, cm=None): -def print_model_log(data, models, p1, p2, df1, pathname = None): - #print the monotonic space with the 3 areas - data = [((log(d[0][0]), log([0][1])), d[1], d[2]) for d in data] +def print_model_out(data, out, models, p1, p2, df1, pathname = None): + #print the monotonic space with the 3 areas if '.1.1' in p1: p1 = p1[:-2] @@ -152,8 +151,8 @@ def print_model_log(data, models, p1, p2, df1, pathname = None): for key in models.keys(): key = int(key) - #print('Key', key) - plt.figure(figsize=(3,3)) + print('Key', key) + plt.figure(figsize=(5,5)) ax = plt.axes() ax.set_facecolor("lightgray") @@ -199,8 +198,8 @@ def print_model_log(data, models, p1, p2, df1, pathname = None): ax.add_artist(patches.Rectangle((x, 0), 1000, y, facecolor = 'lightcoral', zorder = 1)) - #plt.scatter(x_r, y_r, c = 'blue', marker='.', zorder = 2) - #plt.scatter(x_b, y_b, c = 'red', marker='.', zorder = 2) + #plt.scatter(x_r, y_r, c = 'blue', zorder = 2) + #plt.scatter(x_b, y_b, c = 'red', zorder = 2) random.shuffle(data) @@ -209,6 +208,7 @@ def print_model_log(data, models, p1, p2, df1, pathname = None): plt.scatter(d[0][0], d[0][1], c = 'blue', marker='.', zorder = 2) elif d[2] == 1: plt.scatter(d[0][0], d[0][1], c = 'red', marker='.', zorder = 2) + plt.scatter(out[0], out[1], c = 'g', zorder = 2) plt.xlabel(g1) plt.ylabel(g2) @@ -224,29 +224,18 @@ def print_model_log(data, models, p1, p2, df1, pathname = None): -def print_model_out(data, out, models, p1, p2, df1, pathname = None): - #print the monotonic space with the 3 areas - if '.1.1' in p1: - p1 = p1[:-2] - if '.1.1' in p2: - p2 = p2[:-2] - try: - g1 = df1[df1['Probeset_ID'] == p1]['Gene.Symbol'].values.tolist()[0] - except: - g1 = p1 - try: - g2 = df1[df1['Probeset_ID'] == p2]['Gene.Symbol'].values.tolist()[0] - except: - g2 = p2 + +def print_model_positive(data, models, p1, p2, pathname, cm): + for key in models.keys(): key = int(key) - print('Key', key) - plt.figure(figsize=(5,5)) + #print('Key', key) + plt.figure(figsize=(3,3)) ax = plt.axes() - ax.set_facecolor("lightgray") + ax.set_facecolor("lightcoral") x_r = list() y_r = list() @@ -264,169 +253,57 @@ def print_model_out(data, out, models, p1, p2, df1, pathname = None): reg_err, bpr, bpb, r_p, b_p = models[key] - for bp in bpb: - x, y = bp - if key == 1: - ax.add_artist(patches.Rectangle((0.0, 0.0), x, y, facecolor = 'lightskyblue', zorder = 1)) - elif key == 2: - ax.add_artist(patches.Rectangle((x, 0), 1000, y, facecolor = 'lightskyblue', zorder = 1)) - elif key == 3: - ax.add_artist(patches.Rectangle((x, y), 1000, 1000, facecolor = 'lightskyblue', zorder = 1)) - else: - ax.add_artist(patches.Rectangle((0, y ), x, 1000, facecolor = 'lightskyblue', zorder = 1)) + min_x = min(min(x_r), min(x_b))-0.05 + min_y = min(min(y_r), min(y_b))-0.05 + max_x = max(max(x_r), max(x_b))+0.05 + max_y = max(max(y_r), max(y_b))+0.05 - for bp in bpr: + for bp in bpb: x, y = bp - - if key == 1: - ax.add_artist(patches.Rectangle((x, y), 1000, 1000, facecolor ='lightcoral', zorder = 1)) + ax.add_artist(patches.Rectangle((min_x, min_y), abs(x-min_x), abs(y-min_y), facecolor = 'lightsteelblue', zorder = 1)) elif key == 2: - ax.add_artist(patches.Rectangle((0, y ), x, 1000, facecolor = 'lightcoral', zorder = 1)) + ax.add_artist(patches.Rectangle((x, min_y), max_x+abs(x), abs(y-min_y), facecolor = 'lightsteelblue', zorder = 1)) elif key == 3: - ax.add_artist(patches.Rectangle((0.0, 0.0), x, y, facecolor = 'lightcoral', zorder = 1)) + ax.add_artist(patches.Rectangle((x, y), max_x+abs(x), max_y+abs(y), facecolor = 'lightsteelblue', zorder = 1)) else: - ax.add_artist(patches.Rectangle((x, 0), 1000, y, facecolor = 'lightcoral', zorder = 1)) + ax.add_artist(patches.Rectangle((min_x, y ), abs(x-min_x), max_y+abs(y), facecolor = 'lightsteelblue', zorder = 1)) + - #plt.scatter(x_r, y_r, c = 'blue', zorder = 2) - #plt.scatter(x_b, y_b, c = 'red', zorder = 2) random.shuffle(data) for d in data: if d[2] == 0: - plt.scatter(d[0][0], d[0][1], c = 'blue', marker='.', zorder = 2) + plt.scatter(d[0][0], d[0][1], c = 'royalblue', marker='.', zorder = 2) elif d[2] == 1: - plt.scatter(d[0][0], d[0][1], c = 'red', marker='.', zorder = 2) - plt.scatter(out[0], out[1], c = 'g', zorder = 2) - plt.xlabel(g1) - plt.ylabel(g2) - - if pathname is not None: - plt.savefig(pathname + g1 + '_' + g2 + '.png') - - f = open(pathname + 'gene.txt', 'a') - f.write('{} : {}\n'.format(g1, p1)) - f.write('{} : {}\n'.format(g2, p2)) - f.close() - else: - plt.show() - - - -def rank_h(x, D, rev): - h = [d[0] for d in D] - h = sorted(h, reverse=rev) - r = h.index(x) - - if rev: - return len(D) - r + 1 - else: - return r+1 - -def rank_v(x, D, up): - h = [d[1] for d in D] - h.sort() - r = h.index(x) - #if up: - return r+1 - #else: - # return len(D) - r + 1 - - - - - - - -def print_model_RS(data, models, p1, p2, df1, pathname = None, cm=None): - D_hat = [x[0] for x in data] - - - plt.figure(figsize=(3,3)) - ax = plt.axes() - ax.set_facecolor("lightgray") - plt.xlabel(p1) - plt.ylabel(p2) - - for key in models.keys(): - key = int(key) - - rev, up = tools.equiv_key_case(key) - - reg, bpr, bpb, rps, bps = models[key] - - - - for bp in bpb: - x, y = bp - rxd = rank_h(x, D_hat, rev) - ryd = rank_v(y, D_hat, up) - - if key == 1: - ax.add_artist(patches.Rectangle((0.0, 0.0), rxd, ryd, facecolor = 'lightskyblue', zorder = 1)) - elif key == 2: - ax.add_artist(patches.Rectangle((rxd, 0), 1000, ryd, facecolor = 'lightskyblue', zorder = 1)) - elif key == 3: - ax.add_artist(patches.Rectangle((rxd, ryd), 1000, 1000, facecolor = 'lightskyblue', zorder = 1)) - else: - ax.add_artist(patches.Rectangle((0, ryd ), rxd, 1000, facecolor = 'lightskyblue', zorder = 1)) - - - for bp in bpr: - x, y = bp - rxd = rank_h(x, D_hat, rev) - ryd = rank_v(y, D_hat, up) - - if key == 1: - ax.add_artist(patches.Rectangle((rxd, ryd), 1000, 1000, facecolor ='lightcoral', zorder = 1)) - elif key == 2: - ax.add_artist(patches.Rectangle((0, ryd ), rxd, 1000, facecolor = 'lightcoral', zorder = 1)) - elif key == 3: - ax.add_artist(patches.Rectangle((0.0, 0.0), rxd, ryd, facecolor = 'lightcoral', zorder = 1)) - else: - ax.add_artist(patches.Rectangle((rxd, 0), 1000, ryd, facecolor = 'lightcoral', zorder = 1)) + plt.scatter(d[0][0], d[0][1], c = 'firebrick', marker='.', zorder = 2) + plt.xlabel(p1) + plt.ylabel(p2) - random.shuffle(data) - for d in data: - rxd = rank_h(d[0][0], D_hat, rev) - ryd = rank_v(d[0][1], D_hat, up) - if d[2] == 1: - plt.scatter(rxd, ryd, c='red', marker='.', zorder=2) - elif d[2] == 0: - plt.scatter(rxd, ryd, c='blue', marker='.', zorder=2) if cm is not None: pair = '/'.join([p1, p2, str(key)]) error = cm.at['LOOCV', pair] - plt.title('Ranking Space \n LOOCV Error {}'.format(round(error,3))) - - plt.show() - -def print_severe(data, models, p1, p2, df1, pathname = None): - #print the monotonic space with the 3 areas + plt.title('RE = {} & LOOCVE = {}'.format(round(reg_err/len(data),3),round(error,3))) + else: + plt.title('RE = {}'.format(round(reg_err/len(data),3))) - if '.1.1' in p1: - p1 = p1[:-2] - if '.1.1' in p2: - p2 = p2[:-2] + if pathname is not None: + name = pathname + '/' + str(p1) + '_' + str(p2) + '.pdf' + plt.savefig(name.replace('//', '/'), bbox_inches='tight') + else: + plt.show() - try: - g1 = df1[df1['Probeset_ID'] == p1]['Gene.Symbol'].values.tolist()[0] - except: - g1 = p1 - try: - g2 = df1[df1['Probeset_ID'] == p2]['Gene.Symbol'].values.tolist()[0] - except: - g2 = p2 +def print_model_negative(data, models, p1, p2, pathname, cm): for key in models.keys(): key = int(key) - print('Key', key) - plt.figure(figsize=(5,5)) + #print('Key', key) + plt.figure(figsize=(3,3)) ax = plt.axes() - ax.set_facecolor("lightcoral") + ax.set_facecolor("lightsteelblue") x_r = list() y_r = list() @@ -444,55 +321,63 @@ def print_severe(data, models, p1, p2, df1, pathname = None): reg_err, bpr, bpb, r_p, b_p = models[key] - for bp in bpb: + + min_x = min(min(x_r), min(x_b))-0.1 + min_y = min(min(y_r), min(y_b))-0.1 + max_x = max(max(x_r), max(x_b))+0.1 + max_y = max(max(y_r), max(y_b))+0.1 + + + for bp in bpr: x, y = bp + + if key == 1: - ax.add_artist(patches.Rectangle((0.0, 0.0), x, y, facecolor = 'lightskyblue', zorder = 1)) + ax.add_artist(patches.Rectangle((x, y), max_x+abs(x), max_y+abs(y), facecolor ='lightcoral', zorder = 1)) elif key == 2: - ax.add_artist(patches.Rectangle((x, 0), 1000, y, facecolor = 'lightskyblue', zorder = 1)) + ax.add_artist(patches.Rectangle((min_x, y ), abs(x-min_x), max_y+abs(y), facecolor = 'lightcoral', zorder = 1)) elif key == 3: - ax.add_artist(patches.Rectangle((x, y), 1000, 1000, facecolor = 'lightskyblue', zorder = 1)) + ax.add_artist(patches.Rectangle((min_x, min_y), abs(x-min_x), abs(y-min_y), facecolor = 'lightcoral', zorder = 1)) else: - ax.add_artist(patches.Rectangle((0, y ), x, 1000, facecolor = 'lightskyblue', zorder = 1)) - - - #for bp in bpr: - # x, y = bp - - - # if key == 1: - # ax.add_artist(patches.Rectangle((x, y), 1000, 1000, facecolor ='lightcoral', zorder = 1)) - # elif key == 2: - # ax.add_artist(patches.Rectangle((0, y ), x, 1000, facecolor = 'lightcoral', zorder = 1)) - # elif key == 3: - # ax.add_artist(patches.Rectangle((0.0, 0.0), x, y, facecolor = 'lightcoral', zorder = 1)) - # else: - # ax.add_artist(patches.Rectangle((x, 0), 1000, y, facecolor = 'lightcoral', zorder = 1)) + ax.add_artist(patches.Rectangle((x, min_y), max_x+abs(x), abs(y-min_y), facecolor = 'lightcoral', zorder = 1)) random.shuffle(data) for d in data: if d[2] == 0: - plt.scatter(d[0][0], d[0][1], c = 'blue', marker='.', zorder = 2) + plt.scatter(d[0][0], d[0][1], c = 'royalblue', marker='.', zorder = 2) elif d[2] == 1: - plt.scatter(d[0][0], d[0][1], c = 'red', marker='.', zorder = 2) - plt.xlabel(g1) - plt.ylabel(g2) + plt.scatter(d[0][0], d[0][1], c = 'firebrick', marker='.', zorder = 2) + plt.xlabel(p1) + plt.ylabel(p2) - if pathname is not None: - plt.savefig(pathname + g1 + '_' + g2 + '.png') + if cm is not None: + pair = '/'.join([p1, p2, str(key)]) + error = cm.at['LOOCV', pair] + plt.title('RE = {} & LOOCVE = {}'.format(round(reg_err/len(data),3),round(error,3))) + else: + plt.title('RE = {}'.format(round(reg_err/len(data),3))) - f = open(pathname + 'gene.txt', 'a') - f.write('{} : {}\n'.format(g1, p1)) - f.write('{} : {}\n'.format(g2, p2)) - f.close() + if pathname is not None: + name = pathname + '/' + str(p1) + '_' + str(p2) + '.pdf' + plt.savefig(name.replace('//', '/'), bbox_inches='tight') else: plt.show() +def show_results_pos(df, pairs, nbcpus, pathname, cm): + pool = mp.Pool(nbcpus) + vals = [(p, df) for p in pairs] + + res = pool.starmap(cr_models, vals, max(1,len(vals)//nbcpus) ) + + for r in res: + p1, p2, models, data = r + print_model_positive(data, models, p1, p2, pathname, cm) + -def show_results(df, probs_df, pairs, nbcpus, pathname, cm): +def show_results_neg(df, pairs, nbcpus, pathname, cm): pool = mp.Pool(nbcpus) vals = [(p, df) for p in pairs] @@ -500,7 +385,7 @@ def show_results(df, probs_df, pairs, nbcpus, pathname, cm): for r in res: p1, p2, models, data = r - print_model(data, models, p1, p2, probs_df, pathname, cm) + print_model_negative(data, models, p1, p2, pathname, cm) def show_results_RS(df, probs_df, pairs, nbcpus, pathname, cm): pool = mp.Pool(nbcpus) diff --git a/Module/stages.py b/Module/stages.py index 1fc8350..71222ee 100755 --- a/Module/stages.py +++ b/Module/stages.py @@ -3,8 +3,6 @@ from Module import optimal_k_aggregations as oka from Module import monotonic_regression_uncertainty as mru from Module import tools from Module import selection_algorithm as sa -from Module import preselection as psl - from Module import dynamic_preselection as dpsl import pandas as pd @@ -12,56 +10,38 @@ import matplotlib.pyplot as plt import os -from sklearn.metrics import roc_auc_score, confusion_matrix, matthews_corrcoef - - -def stage0_old(df, nbcpus, threshold): - reg = psl.regression_error_matrix(df, nbcpus) - if threshold is not None: - reg = psl.preselection_reg_err(reg, threshold) - return reg -def stage0(df, nbcpus, m, log): +def stage0(df, nbcpus, m): config = dpsl.all_configurations(df) - Q, pairs = dpsl.algorithm_2(config, df, m, nbcpus, log) + Q, pairs = dpsl.algorithm_2(config, df, m, nbcpus) return pairs -def stage_1(df, cls, min_k, max_k, nbcpus, strat, funct, log): - k_error = oka.k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k, log) +def stage_1(df, cls, min_k, max_k, nbcpus, strat, funct): + k_error = oka.k_missclassification(df, cls, nbcpus, funct, strat, min_k, max_k) k_opt, err_k = oka.optimal_k(k_error) return k_opt, k_error -def stage_2(df, cls, k_opt, auc_file, conf_mat_file, nbcpus, funct, strat, logs): +def stage_2(df, cls, k_opt, auc_file, nbcpus, funct, strat): errors, y_true, y_pred, y_proba = list(), list(), list(), list() for i in range(len(df)): out = df.iloc[i, :] df_2 = df.drop([i]) df_2.reset_index(drop=True, inplace=True) - f = open(logs, 'a') - f.write('Patient {} \n'.format(i)) - f.close() ndf_err = cmu.error_matrix(df_2, cls, nbcpus,funct) cost = cmu.cost_classifiers(ndf_err) - f = open(logs, 'a') - f.write('Matrix computed \n') - f.close() mve, pairs, algo = oka.find_k_metamodel(df_2, ndf_err, cost, k_opt, nbcpus, strat) pred, proba = oka.create_and_predict_metamodel(df_2, out, pairs, nbcpus, funct) - f = open(logs, 'a') - f.write('Pred={}, Proba={} \n'.format(pred, proba)) - f.close() - errors.append(abs(out['target']-pred)) y_proba.append(proba) y_true.append(out['target']) @@ -70,21 +50,13 @@ def stage_2(df, cls, k_opt, auc_file, conf_mat_file, nbcpus, funct, strat, logs) acc = errors.count(0)/len(errors) auc = tools.auc_score(y_proba, y_true, auc_file) - auc2 = roc_auc_score(y_true, y_proba) - CI = tools.confidence_interval(auc, y_true) - conf_mat = confusion_matrix(y_true, y_pred) - mcc = matthews_corrcoef(y_true, y_pred) - - f = open(logs, 'a') - f.write('acc={}, auc={}, CI = {}, aucsk = {}, confusion_matrix = {}, mcc = {} \n'.format(acc, auc, CI, auc2, conf_mat, mcc)) - f.close() + ci = tools.confidence_interval(auc, y_true) labels, probas, uncertain_pts = tools.unclassified_points(y_true, y_proba) - return acc, auc, CI, conf_mat + return acc, auc, ci -def stage_3(df, cls, k_opt, cost_mat, nbcpus, funct, strat): +def stage_3(df, cls, k_opt, nbcpus, funct, strat): ndf_err = cmu.error_matrix(df, cls, nbcpus,funct) - ndf_err.to_csv(cost_mat) cost = cmu.cost_classifiers(ndf_err) mve, pairs, algo = oka.find_k_metamodel(df, ndf_err, cost, k_opt, nbcpus, strat) - return pairs, mve + return pairs, ndf_err diff --git a/Module/tools.py b/Module/tools.py index 273b80d..02401a4 100755 --- a/Module/tools.py +++ b/Module/tools.py @@ -122,15 +122,16 @@ def auc_score(probas, labels, auc_file=None): CI = confidence_interval(auc3, labels) if auc_file is not None: - plt.plot(tpr_array, fpr_array, linestyle='--', color='darkorange', lw = 2, label='ROC curve', clip_on=False) - plt.plot([0, 1], [0, 1], color='navy', linestyle='--') + plt.plot(tpr_array, fpr_array, color='darkorange', label='ROC curve') + plt.plot([0, 1], [0, 1], color='gray', linestyle='--') plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.0]) plt.xlabel('False Positive Rate') plt.ylabel('True Positive Rate') plt.title('AUC={}, CI=[{};{}] '.format(round(auc3,3), CI[0], CI[1])) plt.legend(loc="lower right") - plt.savefig(auc_file) + name = auc_file + '/auc.pdf' + plt.savefig(name.replace('//', '/'), bbox_inches='tight') return auc3 diff --git a/README.md b/README.md index 9bc3c91..0f31271 100644 --- a/README.md +++ b/README.md @@ -5,36 +5,22 @@ Author: Océane FOURQUET This project aims to construct an ensemble model of bidimensional monotonic classifiers[1](https://link.springer.com/article/10.1007/s00453-012-9628-4). In addition to reimplementing an established approach[2](https://academic.oup.com/jid/article/217/11/1690/4911472?login=true) in python, it integrates a preselection of the pairs of features, reducing drastically the running time of the approach. ## Python and librairies versions -- Python 3.9.1 -- Pandas 1.2.3 -- Numpy 1.19.2 -- Matplotlib 3.3.4 +- python 3.9.1 +- pandas 1.2.3 +- numpy 1.19.2 +- matplotlib 3.3.4 +- multiprocessing + +This code uses the multiprocessing library to parallelise calculations. By default, the number of CPUs is set to 1, but it is possible to change this configuration with the parameters. ## Run the code ### Data -Data should be presented in csv format, in the form of samples per row and features per column, with a 'target' column for classes. +Data should be presented in csv format, in the form of samples per row and features per column, with a labels column for classes. For the moment, this code only allows to work on data with two classes. ### Code -The code is split in 3 stages. Stage 1: determine the optimal number of classifiers to construct the metamodel. Stage 2: compute an estimate of the AUC score of a metamodel constructed with k_opt classifiers. Stage 3: construct the final metamodel from the whole dataset. The three stages are coded in the py file stages.py, available in the Module. - -To run the whole project, you can run full\_project.py with as follow: - -python3 full\_project.py <dataset> <probeset> <outpath> - -ex : python3 full\_project.py dengue/dengue.csv dengue/probeset_annotations.txt Result/ > log.txt - -To run only one stage, you can use the relevant py file among stage1.py, stage2.py and stage3.py. - -Note that by default, this code uses the 3-classes classification (severe, non severe and uncertain). If you want to compute the metamodel by favoring severe or non severe (2-classes classification), you must change the parameter in the file full\_project.py. - - -## Files in Module -- cost\_matrix\_uncertainty.py -- measures.py -- monotonic\_regression\_uncertainty.py -- optimal\_k\_aggregations.py -- selection\_algorithm.py -- show\_results.py -- stages.py -- tools.py +To run the approach with the default parameters, just run the following command in your shell : +```python +python3 run_mem.py <dataset> +``` +There are some optional parameters such as the number of cpus to use for calculations, the maximum number of pairs for the ensemble model, the name of the label column in the dataset file, ... diff --git a/run_mem.py b/run_mem.py new file mode 100644 index 0000000..c23dbc4 --- /dev/null +++ b/run_mem.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python + +from Module import stages as st +from Module import tools +from Module import monotonic_regression_uncertainty as mru +from Module import selection_algorithm as sa +from Module import optimal_k_aggregations as oka +from Module import show_results as sr + + +import numpy as np +import pandas as pd +import sys +import argparse + +def parse_args(): + parser=argparse.ArgumentParser(description="Monotonic Ensemble Model approach") + parser.add_argument("dataset", help="dataset in csv format") + parser.add_argument("--target", help="name of the column of the classes", default='target') + parser.add_argument("--nbcpus", help="number of cpus to use to do calculation", type=int, default=1) + parser.add_argument("--m", help="number of minimum disjoint pairs for preselection", type=int, default=30) + parser.add_argument("--favoring", help="class to favor in the model between 0 (control case) and 1 (cohort study)", default = 1, type=int, choices=[0,1]) + parser.add_argument("--outdir", help="directory for out files", default='./') + #parser.add_argument("--selection", help="selection strategy to use for the ensemble") + args=parser.parse_args() + return args + + +def verify_nb_classes_dataset(df, target): + if target in df.columns: + tt = set(df[target]) + if len(tt) != 2: + print('Expected number of classes: 2. There are {} classes in the dataset.\n'.format(len(tt))) + return False + else: + return True + else: + print("Can't find the class labels column. Configure the name of the labels column with argument --target.\n") + + +def modify_label_classes_dataset(df, target): + if not set(df[target]) == {0,1}: + tt = list(set(df[target])) + df[target] = df[target].map({tt[0]:0,tt[1]:1}) + df.rename({target:'target'}, axis=1, inplace=True) + return df + + +def main(): + inputs=parse_args() + + strat = [sa.NB] + if inputs.favoring == 1: + funct= mru.predict_severe + else: + funct= mru.predict_non_severe + + try: + df = pd.read_csv(inputs.dataset,index_col=0, low_memory=False) + df.reset_index(drop=True, inplace=True) + except: + print("Can't open the file {}. Check the format.\n".format(inputs.dataset)) + + if not verify_nb_classes_dataset(df, inputs.target): + sys.exit() + + df = modify_label_classes_dataset(df, inputs.target) + + + cls = st.stage0(df, inputs.nbcpus, inputs.m) + + k_opt, k_error = st.stage_1(df, cls, 2, inputs.m, inputs.nbcpus, strat, funct) + + print('Between 2 and {}, the minimal optimal number of classifiers for the ensemble model is {}. \n'.format(inputs.m, k_opt)) + + acc, auc, ci = st.stage_2(df, cls, k_opt, inputs.outdir, inputs.nbcpus, funct, strat) + + print('The estimated performance of the monotonic ensemble model is AUC = {} +/- {}. \n'.format(auc, ci)) + + pairs, cm = st.stage_3(df, cls, k_opt, inputs.nbcpus, funct, strat) + + print('The ensemble model is made of the following pairs : ') + for pair in pairs: + print('- {} \n'.format(pair[:-2])) + + if inputs.favoring == 1: + sr.show_results_pos(df, pairs, inputs.nbcpus, inputs.outdir, cm) + else: + sr.show_results_neg(df, pairs, inputs.nbcpus, inputs.outdir, cm) + + + + + + + + +if __name__ == "__main__": + main() -- GitLab