From 8787033ba2384e52616c017f4442bcc4614410c5 Mon Sep 17 00:00:00 2001 From: rasbt Date: Sun, 6 May 2018 16:14:35 -0400 Subject: [PATCH] update efs --- docs/sources/CHANGELOG.md | 6 +- .../SequentialFeatureSelector_55_0.png | Bin 0 -> 17311 bytes .../SequentialFeatureSelector_82_1.png | Bin 0 -> 14185 bytes .../exhaustive_feature_selector.py | 120 +++++++++++++++--- .../tests/test_exhaustive_feature_selector.py | 41 ++++-- 5 files changed, 135 insertions(+), 32 deletions(-) create mode 100644 docs/sources/user_guide/feature_selection/SequentialFeatureSelector_files/SequentialFeatureSelector_55_0.png create mode 100644 docs/sources/user_guide/feature_selection/SequentialFeatureSelector_files/SequentialFeatureSelector_82_1.png diff --git a/docs/sources/CHANGELOG.md b/docs/sources/CHANGELOG.md index f8ac2adce..1722e42fd 100755 --- a/docs/sources/CHANGELOG.md +++ b/docs/sources/CHANGELOG.md @@ -20,12 +20,14 @@ The CHANGELOG for the current development version is available at - The `SequentialFeatureSelector` now accepts custom feature names via the `fit` method for more interpretable feature subset reports. ([#379](https://github.com/rasbt/mlxtend/pull/379)) - The `SequentialFeatureSelector` is now also compatible with Pandas DataFrames and uses DataFrame column-names for more interpretable feature subset reports. ([#379](https://github.com/rasbt/mlxtend/pull/379)) - `ColumnSelector` now works with Pandas DataFrames columns. ([#378](https://github.com/rasbt/mlxtend/pull/378) by [Manuel Garrido](https://github.com/manugarri)) +- The `ExhaustiveFeatureSelector` estimator in `mlxtend.feature_selection` now is safely stoppable mid-process by control+c. ([#380](https://github.com/rasbt/mlxtend/pull/380)) ##### Changes +- For concistency, the `best_idx_` attribute of the `ExhaustiveFeatureSelector` was renamed to `k_feature_idx_`, which is used by the `SequentialFeatureSelector`. Likewise, `best_score_` was renamed to `k_score_`. ([#380](https://github.com/rasbt/mlxtend/pull/380)) + -- - ##### Bug Fixes @@ -303,7 +305,7 @@ Note that this didn't cause any difference in performance on any of the test sce - The `StackingClassifier` has a new parameter `average_probas` that is set to `True` by default to maintain the current behavior. A deprecation warning was added though, and it will default to `False` in future releases (0.6.0); `average_probas=False` will result in stacking of the level-1 predicted probabilities rather than averaging these. - New `StackingCVClassifier` estimator in 'mlxtend.classifier' for implementing a stacking ensemble that uses cross-validation techniques for training the meta-estimator to avoid overfitting ([Reiichiro Nakano](https://github.com/reiinakano)) - New `OnehotTransactions` encoder class added to the `preprocessing` submodule for transforming transaction data into a one-hot encoded array -- The `SequentialFeatureSelector` estimator in `mlxtend.feature_selection` now is safely stoppable mid-process by control+c, and deprecated print_progress in favor of a more tunable verbose parameter ([Will McGinnis](https://github.com/wdm0006)) +- The `SequentialFeatureSelector` estimator in `mlxtend.feature_selection` now is safely stoppable mid-process by control+c, and deprecated `print_progress` in favor of a more tunable `verbose` parameter ([Will McGinnis](https://github.com/wdm0006)) - New `apriori` function in `association` to extract frequent itemsets from transaction data for association rule mining - New `checkerboard_plot` function in `plotting` to plot checkerboard tables / heat maps - New `mcnemar_table` and `mcnemar` functions in `evaluate` to compute 2x2 contingency tables and McNemar's test diff --git a/docs/sources/user_guide/feature_selection/SequentialFeatureSelector_files/SequentialFeatureSelector_55_0.png b/docs/sources/user_guide/feature_selection/SequentialFeatureSelector_files/SequentialFeatureSelector_55_0.png new file mode 100644 index 0000000000000000000000000000000000000000..9d5a1d050a95abe2d9f8bbe3d265d6681e404637 GIT binary patch literal 17311 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 CvJL_O literal 0 HcmV?d00001 diff --git a/docs/sources/user_guide/feature_selection/SequentialFeatureSelector_files/SequentialFeatureSelector_82_1.png b/docs/sources/user_guide/feature_selection/SequentialFeatureSelector_files/SequentialFeatureSelector_82_1.png new file mode 100644 index 0000000000000000000000000000000000000000..e324748a440fd2780e88187e4d04c3d4a552dc9f GIT binary patch literal 14185 zcma*O2UJr**Deg9cOtz*M37EIkPd1P>7az(s~{!x-dm6+(v>EiP^Ak90i;P2F!U-Q zy-OFo2jB0%t?O2taEZ^X3w6zpZ)ATbD}lX70HMhiLtP-$dsPLUSMHi#{geq zLVV!P3aQU2@Pq62L`jza@66qKuXN^r|Pjxb=C%*~ZK?4?WU>P+`#B=*Ph#kJEFp9(3pt5^*Nm7CntPyD8by8c`i_ zS9z~4vcK;0OUp~wW3tLncdrxN{pWZUo&YzYaxJb>gFp-wtak6uD!^{EU?$XwwhF6td5)9FK9bQ9 zQH*^)v?u+W_VKr$SLk=p22;>rLSQ9c8woq)WpEY97TXqNN|Tt)+b|AD!~iFuMP0g? z_0qQ(k^j+rngE)IJfLc#-+*ISP|Z{u);qa?Bt_r0KHqm1JFp+URvWd~HVje+Lex6i*Keu~Kzn@tAy&TX>X)5u;a%7A?$OIQZI6-mN6WM19(trthB%$I(HJxJZ9!N|U3vJhw$@Ny=NVoC2fXDj9WgJU= zA64=28*Uw>2sOMN3deR|dDe6~gP6tWCj32wd04og2pKhL3T&4{g}$k*b8lxn^YyVmk*rxqIbtLlVRiu3O&NiyU-oaaR;bFmrA z>Vki{_ZW zUrAT}MW~mlg+M++PxX}s_lASoSgI?R>RHM<5aM;#fk-4O8Gp=Kmt#Oe!=zuHoxk`g6AUyw;anPS;f zTa|Yc+M#t++@ta_-~PxGgoQ9&f9UtKnh(z0PI8k8&3hR^m5`{;g-jT?)hV@B$?8a2 z8PxxF^2mxn<9*y%yaRqYPos^WspFFFS z`BnKmCTHb$ei7Su8plGMIa>a~f~5;=Kl~$y`7Cpd9tGT)G4&xG?5mJ>XMYg1n#skv zI`g`yH*|PmPuTlD%j!>Zf1sFMy~Ga9)vCb-bFfm~fpV}WfD@GFTPBn}S_%x4ncB0L z=hG$y&Hnsmjbi%S``wfC&bMgptDWh)tw*l0?1YW=^*p_-`-&kQ>*sjb#|g)Fjx38} z`qfhufHa6@3!#KZXEsx9k7De-L)9PksWMMe^igD&bWyn*@@};$OBG}R#$WC*8PA5> zbkoKcmbsoZaAh?oOt~t<|-~UZ+vN$HLYuVMk@-44> zd8*TeJ2J$4crMs}BuEqPNwHeS%Fnn`)sya$JQP(5S(sw+6p@G)XA$Uc4iaGexLWIxga}p{E27D(v}@b& znIFZsb?5s~ffD7LJtiLI!fF!G`Q90U{Y3l|18V9bkD{`hE60vbRl-WP>K3`)2^sxM z5y4OCfX6(<#4>|9*23qt@B(v3-G4|&m;}Rq2qYuBUuj5@(cx00u6I-gC7MmYh$2Xn zA|)jhvB9rvd}_MbcWpbQbF(T^PeR*xEv)Yv*EOh**)Kc{3%)6js!}$5(9!x-a>HJ2 z!U`0DM>1Xqf?qxmoISOg0;^d&DsgQ%vE{gfhRrtJn=(%5kG@XI}MD# zc|I_VJH9Kc)KyLEC#kS?J|1p$+wF5t5i&N_`9JS(;S%eI_304o7NLHx1II|Y}ZbL~-IyaR*!yC2T_nq?uv^>>GU#Jd|;aXJRiK8$Ex zuk~Xe*>1t_TlN15{V0%CGPAWgdbBtAp5>sA%CF3Iu-{^vsZ(R0sF!0x_Jcf3;)*$E zpt8?xw8cnLa(lk>(&ZY^Q4FtpgE;dT=85g=8q|3CZPzk#nx{5L4zo$-x+X90JwO4=LX9i;u2PtpphK_zb)qW5$#=HyriTr z%WxmFXL{H4l0CBVp0pN>8cwG-HK2e|hQ~aWkpnPS#LGa+*pX*U-BMt+&di)K6!q@7 z^WyKde%d^a&t)yE^3>47?6NR7eeavk0U_q|wJs)8lwHT2llxn&GW+pgmwK2w_e%6s zC4QC!<8fauk0{CZ=1_j07xB^X?>>?^pMFZT_eHAz=@+6S3G+SaoWGaT%xP^SYb6&+ zjr=IoySO5;URe49gQrM+(H$}=x1rF8(wJ5{^}mCw(x;?NJN>_i@;37h^H6zW&+T#1Xl_PeRI_y>lGjeFf^;kto#oxrPt5 z9Xf0>>u-CJdK)$?ZpDl}dELccV{Z+@9CR0}l2ysa%Z;vwCw0!ct;2&lbOcH|kGC!7 zS|0WX$hmk2sKid_tc9u=3AS{uIj;M1avf&aAevw2))o8|&DxX9b_kx0EtB^Uj`+Hu znhmUIO{H9uOa?N^)xwfoRri6lsEF`G;c`PN6DT$4=}5AfF#D|n0X+`BH=cDq3kaw- zzi#7u3&}ZoTs&L=J3<&TC3V+hax($uS%TBZgf7a z>%?i@bf1%arESmMC!aQt{jQ6eSB>i#3jp*LD`Iub3fPwngBKzbyOZXd5_g;FMVj)j zze;?6FWT2O_OvD{h{C#5gmy?sUl!qqVK0X#1*l8++uFq8JS{wu@ILf{PEnca5UoXS~dBlZKhMbm2-^Y*IS`+snnl|&k=45Ui>pQt?jYf7vx)wKew zXR6WG1M97?;yKJEnM|G{G(|1y+vWT2lga>zSg8~q7Jhp?CG!^GTIBtx_pY74?+}O# z3(q8DLQBWrfVz~H+eK_dZOlrN_q*5v*(?L7wE4(mwrSyuE| zBr?I7Zd7|5wMz$^t$&rnaTa#Ow#6X=3cQ%@mq}?7o~Ox`VNv(mMIE_M9$LM$9eT{O z%Ffv5^V|AprysULdgm9bvc#dwbXaJZ$kk?rj6_UFMOd;fYn*?k-cwn2;b~?WN6a2v=UqYAM`gRtuA;7ozR*sHNtmVdh)nQ8wu94w3qw`++!ZCG)41?LR z6+a8ji1mr?ru9nBv-#a>$JeCb!XMpx<|>=+VCx2PtM${ zxJqD~6k@v*Zi$5>K`}|P@yaD#uHuV%4M8z)AE`9>VNbE6eI+F`fOI<>BZ)&%i$8vT z5>~PEGCT_wBQyN=9dvX>=aq zj7yEH?%Ug;R^L)ZF2u?8@tu>?pwkZ?w*J*^MJ39paTy?IDVnQ$!`k3wv1 zvOWsD+jVc>Wiz8@pUJ+nH0UPh8Fc!Hg9fnB=~lU^?(y+#`{vRjsyH%)hGut%xvgn@ zh=2N-EGtDXll@`Tdh@|R&b_8}^(Z)n_-ak(vf{asXT-poZu4N)BOl#^_lc2SqC*=_ zAIk(V-$kOiKuk;7R>U12<+f{Tg*1YOS?(}5&-TdWyx>7q|H=?Qo7+4X_ha^SNEn@` zLaY%Sx1L=KI!jcX@_EC%Tqp(R@HI8_dPx#G-d-{8mJq8$GB+{&B1Z3{Jw!zbNNCl* z{p0rm)6!B`$6+teEFc9*^(5qYRZi4<#_w0NTbKj?zDT$CJycjGUT|C7Oq?6>B@N8| zZEGBw$7gDe7z{XAZQK8Jpi{cNnjRhzVWGvc$sy;$5ecge#O0Y2bV$%ip|CQ(bY%_D z_c}#z0623MaSGDGHO!jxgWZA zCNbw``;ME9A}D3pzpR&ARs#J_#aOcC^si{x{c(O!ZBgCmPtH!BEJ&CKs_V);n7-L@ zHE?Ayqfu8Sw5_C} zXplObT0;AZ2wd{Ii~5+zfAA1hqlc5xLTYf&3E0W~HQ?V25${zXPSNprJaLd)={K~mNku!Q=EqsB7+*xXJ<>lmB(}uC&?k<5B zGp3q1eH)K?EXC%T#%#EHqUIaqTh;LKwAt~iW((rSoa^|ja|r1Ix$RGnYJ~`NIp&r5 zxxNwvS&+Fv1o!OUPh|X}+_rzOiK69)agzHpHBnCCN^?L4v^@ewoq|aIXu^ZoA?rAc zSh9?c10`EL7<<$F>FG2k=JX2DMcW^ls*r>0Ai49pJ6ECMBXz^HHYasrs?Cwlw3uO% z2FyhY2?PM;#+oF-Czz^rO23iZkJRO^WFxh4;x)>kCP;x%Yoee!cWewil(>FQU>=6R zkE>2pmlWUu4Dv810zrZ|Vcnpm=8e-Xv<7M_JCdfP#(EN~Vsj>t#LpwY`u8cP%Kq~g zyh_Zm8hbe*nTo?F8DohSIvQS2fBkm0f`Z4?{RjD~m)*VnibBwKsPdL?Akr=F;EtSWR%cmciTXb5~X)x6ki1B3N>x z&{30_Quf~_0ny6OL7nW&qvP2>H!`v&?rAA}+CUX#KG8h%?=JMu)zk8#<_|Eb1?O-;wu2H+I?dWjofNB&0v-xx@jZIRY!a4D~@__4yJ9SU(>n zMCJpXU1z_>m<9;$F6)j;x4dydrZe+1cFt8T|NfPHc1CSi z!k$1e-pacx?xeH6RheePm&`KxNezsq(2UV;{FdgPg%JvBIeJ=c=^P+CQ~g>|W_Jf= zQ$2;ttm7U;Uj5md06tG@gv}1wMW>*eTV64tE^Cm|piE*?B3i1)w~2UKaf_o|nz*jn zdc1JUHlUU1YFTyO3Zp+xX=kP>>w}G#cemtBJtO=yqnB%Z5`Y!7HGFrMJmZOC3|_Pi zji*uy1+UFf$*-zTDzraXBJ|+RGVfAXw-mDPp;;6PA59i6l24h)Y97!xqW=@h&=}&l7-jkw(vj6DA>B0AF+{@M*1aOsmI0)->lClx9ug7Q!>4s!hfycr z6FuMCql%$LttdPa_z7%v9If10TH9E%B?>XD>4`KUxXZ8R$|YL5&T`OKBVXz3(~0hy_nS6c29M|>qOM2^4u(Yg;txp<@Lv) z7J-zdsc9Ma2EDh!HhDGFYaVsALIW{|r{CuT&6NJuFzETTcNyQ>jxLeKCq(t-weFh4 z-zN!HDXv7nWO72v6(t#LhkuAQZ`X-^rFT2vSMZ_o4$zHEz0Q1Q@EkjEa+mz}B%86R=#jH7 zWw+awm~Xh1e3|ZVdewqx$aTEjbsFQc*{UC{yi@%ue)OH(cV@g{<6FAYw@?KZ??5z= zAWM!7mk|9)UHo9STT8Ssbtm6e8I55ZaRY)hvmd}N6E7d50fz0(-vi{i=`)EnKV^GV zU1|BZ%yfgu;rD2hw5ZN23^ox97p$hAdAg*8=KdqV&f*VhSEfddM-$c-H$cDCcH65lSw>cyX<1%NB&ZIvF;8Vn zsHoWZvn1dKuHlB%JYt&AOqVH)10tF@EoUtB-c-iNo`${Qx2ii=Q&sI8D$Ulf%*3Z| zA4csk^wrw3k9?dLXtiF@wo$XIl{b%NNHNy`p}BB8-Nvn=tHoL}P>HyhcY`|Jcrt3* z49OkvXsjyS*E?wO2TCEXZg%UHqh}V*tDhT;Jb@k`N3Og zktDyKb_UyhLr?PL9r7(>R@sL0pV#}L-~42+^%Hb%M<~T6p@lctvMW-)>UXI4GQgrP zF~9PiA*E`9JS<#A z*4?FZj^}q>v4AGMrF~~5Kk8LENRgtFuq9Wp^()h{Xn9dMvsvgeo)Dx>PJh2D@PRH*!i zHN=CShq-UUB9L{+zE2p3K^U|Zt@SBKZWSO}Bti@`cqwNf$+7r24SGw)7YepqU>}Nu zht-hgpf^bVGMldV@Q>)x5@XE)s^6+a;@7G{eJlEt0Q#;{8v>goxG8~gU%=v2Q+T;3 z4V+`tc)>3*gOIzy{^YFsYt`qFg!5`vlzfWk0OjjgJIxe)5)HVQZv8zfG+;@@fyZUI z*8z81azStlLOVWHtACHg)I*NU*##lT3afvy+AA$u-oN;WP88{R(%K*fWY6Tr^;up4 zk_Ie>8IG}bdMWrZBUs#65=*^krzJOxy>=~Q1sWW@AGOUlEVXzqg|%5=`||gccLcO3 z1WwJb?I90uFGtzJ|NH6HQ`R?$cY%0xPaRh4@UY=V$7*s4C*2L}5^?bz}RW`Yc? zoNjM~`$d2h?TX#2z3n|Rcb$8h5K7TTn#7KF+o6DNE0t}Zp1gVPHG0ho*4O_f;j%P~ zzJ~@aJ%!YmP5p=JXy7}6+Q2ei#0T&t{?3q-syELytes0`0V~x0-qP9OlI+DV2sHsy z8920d(vPEgcO%~yp<0N&v^}^H&okCDiCRlgLS^=>O)O3RQ?ew%@X_69wl z4ZSbucf_*>Zk9CSp(XxXu2Hp%d!wTg?uNrBoAzpVYPDB-((!fdstI9MPRsE~X7c2+ zDG?^``i+~SjZYQ;5qZ|QNZ^j_`$3!&gEZoUlqp!9G&s)k`rgF|>i}!HKG{1}2NkoR zr4A39?RxFTWT~28`cTiG;k*#}=Q%78_YZT^$3ZvcEQu(BbRn#L%EaPeFRUtTlZX)o zxU&u>0@aMT{Jpuh@DvlPvs9An^*Idb+R=TtmrtAF=YDO)=bxtr;Gr%PFA)S@FtQFu7q#UCp2p>8Je^bIwR>F=2fyttqN|i7ph%64 zaX(Z(y4U*0V;8_Ksjrfd_wjbvGsRluVZ(g2fB%K~C$M*DIQlI$2jqbojM%XWyXju@ zmpe`O8K3WC3%+4}Ee@yu_C)Masm^*8#k~d*t8?mCj%sL=tLmYVnb- zBhWeThOx>090QBi&f`t{*JTD*u~3^C4u>;Ea9F>qsk*lZdYN_g0QpdDqjecexQxZ9DtvDb^a_~!RxfF8< zra5HKblU!EQSi^8aCxr{q_Cs~AZ3Iv1F>>ZITgxf@8yGr?FB)E3QbS?FHO5@y`Jih&3-2U{O|xU{WVA??(|sL!f@eu)5)<)=NJ&&2rlVyN`P^C zF2X}CzQt$>onMeS*bt)f|1G!1<8jE|mu{@rLqGnUH;YU(N7#8BWF~BjLb2)>dWzP4 zB4(!f|o08N2K_9fNjCfjYmqBYj)$f=RD9lckcS$@b^p7ln+xm7-^8u-?S!(p$b) zF4U#X!7&IK0Ttu0;W4(ck9rR@%eGu93f+3_+{Z6ZC9X0PJAkC8!mjtC0!bF!-@*#0Z z>H|wwK*g^BP0Z%;e@dE2eSjBlW_t0%ZTRGVit5A(XiUrm2qRAbn5=r!cSg8vO}8Ft zV349CnhtPc(+rRz*7oGrsXqp>8m2h{pJlc$f%LQV8C4v#2nBS?Mi75@P}Udt|70z`#|l%qtOOg#*P;(*3Ii*0kLtfc^KlqWl4FDl9D8 z=G(IXV^yD>2`a&fi&XLYgt=4!TMqYbg-DCKGSbZZ4we_&7kRC`-P8btLHoinvrh%6 zidUK`)VF@NjObL7tzA#v3nkXJtIFjY0B}ZY+6=rFep!mj)(bm*n5<09jNN+JeDFJo zNcPOO(Drd@BzA$Q^-G&L=uqiSh9(?mi2txXGSHG>ALb1q=@L{Lybw;73rr928md95vGom0Wg(}L&$8o1sd|OBK!dz7 zvqL(#qe56|9U6?@Gd`HAqVoSUGq(1Uq-s*D<23^Suc(LHJ0q}F&866lkG*h@*C+4c zra%mGEIr~rSJaX4HrYHXrHt1ld@?g}Ypr?;SsRceMf3`qAXpB>N|kt~TWfxztrU_U zy0Atb#mtB}D!mKnc?u6Rx|OUZ{|eA^`B+tpDgN+%BQ<27`_kj3VSCYX6Josh=Gku= zZbLRpbQIj)i)?EusTu;U3m@kj+JL|`$D5T+#Wb;77a*5CtIf-U(7vs#^;w0Jq{Y6A zXO{mc;ApG~z=zJJzC#4E9M>skFNm_KT~ZB|qfEj~^SctUvGZcs-*D3mTyiIdNZ_As zx>{y;!#E3367cIhq|xK_)2G27;3s?U>#8Gp1rWIA7eAu>sQ8=F-3<2{R*iCoQ#n5o zSH1uaC?uv_eY;{>dI-KqLydvY2Oi(@sW`ME%!+Cm-fjD)frSI25#0w^*xU;O%EZ?S zR`tm81t8{QKZGXtU(x(S+-!DM-Qjk`Z^06ve1Or>PfLaNJZx5;RF-Ck=zhBiP!p`* zKd_)+1GQD5+=9KZ<=(u=bH@IK+A2k#pc51d+@{>LFdyI^A5nstvH_QY4|kV-3wnvK zRLIWD&@C@<4S&&PI!tv)xCJ#bxfF7x%(h1K&t z)M0GD2BN{x?0+dTkgdJC3!T>bwB8C;s-4_=0a5xA-P?0z>Vyf0@gC#Xnia0k(HZ zPKmXS6GZeItR5p{S5l7|X1arcu!s7J5Qofsf>cUHfnRR zGHsGFDNQ2shmerMSRX~n7mj~}*FO;E1;PuvIzm^H8&f5^n_bk^#pM1ph z@B!y;R6kR%*>(QWRK$55929ROp(Y7%37bJu@lAnS-1mkjD)%UH-Nt^APs!Vnm)O;B zg*A;pe;hG}KZ5b`J5kU*0UJ z4tB=ZPbSLIBq)89+x0WX_>QH&0Z`WXd7CfTSn%qOSd8Udu>SQ3m1(gajPS%%~e@W~5c&aOcw|vkR3Vp*BBj z%%H>=MC;G;Mjv;NgfGsy%6>DUfN-~eyrB!CTS-Y&D=LHn&(N7#e|Qpf2SaI2bHGp#2;l)vb`9F%h1 z`SuB@hv$nvmKJ-q;A$D0fyJ*!T5H)-efjBV?Ip(`0cPChA{Q_RAj>yr^<{rdnXJJ~ zm>V*d+8}t}a`3BdhebLNr)t-6`Ni#a1WV*o^agLuCn*ds1`-f(P-dD8$hw?7eT)6B zQjC^^xMm%BeL}42Z%0yqf8KfpG~ZG@n|DCHrNHYmutgd?KEmAM&l?PKWX?6QGeA^L5D?`%)HQfDZT@Z>99p6X2Cr5yV=&;GMVAH8a%^pX6V z+oaQ(%?~36BtORg@mOgTBR}kaPaH>R5~CDWdB8q8umyPCZsdj!6KwUTeZ%~5Q>dL z1Wvk`OwE3#XOjHYD=;3!;2$QG(i-i1A{L#eICIIlaq6fe*b+_L~2J zh$L0fuA0^*7*%;xRi%5+{|_4xJn_uesq z+v89wdpSc_?u~{2mUvTJz#4_}g&f(L-J>LM(!zK^T&b!J;Az-71UETIBgLtq-%vQ* z3`p*<%L$~HUZMyYFSiaBnVdAm9Eq#$SGIEi2VRm*($mgB|7AHB&%K?T0!iou ze_+aV*}l7-*%)O9IdacCmO{^F=W|vHx{7D&^eqR&fgp_9>U6!*U-yfUmP0E6XAlAO zx<^7wL#$F_aO?iAHD+2IBP1KV<7xopP^I9-5SPlw{DZL*fN=Y0 z2#~RkJKa*S{((>hyg%%@<42DHeL+cRQ#4-z{QNo(h~d&CwAQOKITP9-ZYQ=BsLfH0 zh#7;#ZJ?khp+RB$ z>Q&Rfq`beY^8`b0$*&jt4E{Lxp4~R!zCEGc_m52EZDRoVxu+fX@4BYaw81qS+M`NK z%m3`7JundcOTd@IxjOTR_!9%?`yuJudzMgt&2j^(lGun>P*G`Fc1y+}9!Ha;W81OEmNN8yuz^&t?zj}^cdFQRw<8p5*U z0|U7sEpHkw6lPQ5wOL`es<2c>864dON8>Ew3*w4lYasg`z>Q6(6ya5TGk-vJ6(puu%l|(S|KZeLJpQH=8j_HzCwBYP|=w)V9m90ii!*yf&YJc9x35n8`0>#Px2H8fQ-H{ zPMY~_{7js3wwt-bcSw?P$uW$t4^WKpg>QRl!8KsAWaYR&(Llak>CjJo?Ujmq8Pz~wh-C;Pl~H_D6+uF`wS_6$o+kzR;)NVpJ(QK^ zGSmk0=pud++8%n#Z#8DX^8Pm$&aY+vQFAoOE+_=hFN*sBYDZ?%T&%X5pVNK@ot@YO?_AM$N%Fz`03}*3uL*_ z8LWx;<#Lv%qEDn4KavSY&zM{OM<%|1=egA`%{U;9$UYsgzG1HzGZ%y+rq2yhqYk^N zQ{M%4{Z=4Hsz2h}OBAK@8ou7fkk3^nj>wtAH^_2uVzEMjpu~Yffgx;Eh(L8?T#xS8t8)EtFUw^XDmIMD>`!*SVY z+nOM?8HRTdV5XEcyM&#ii&+V&4FM8>P|3Qx1esMRXKZ!sRAk?@$14JK4rm0kIo0*$ zC0wI)g}OfoOQ&SZ1#MW;wVsD!${SgtUUE0XYHFF-rA(Yg+lE8{_-SrlU$*rE^ zSjWtbWd2DI-u1f@?yKGqdEc+|!mu91{U{5wAwI z;r|h+22X)@bT9;4-;?XnK9C1+m_djab`<6#3tkjziW1um_SY zM)_@x;=@n!D<3=VgUQ4*S0qs z0LwU(V2+)nKy~=vw)ow2LCE~*E^VjW;QH%neE65g@b!`{>CV0QDDC=Ri_F-t0yUT< zabrjfVGEo6Gq@>%2~DD9eiSXv_Uq|Lb6Hqcb1sA_q*kFo^s+@?HH+&BvX5i5-7SQ# zWPiPew27-ZfDAF>&BhL05Sns;t%{j}Z%^Q3o5C?cr7j}F*s{ds(LE$sH&Lhs(-qG_ z+(34SOQ+BsuM&IX;>wBXkLdYjiD=vdOSrLCl&3#_ljs)6m*L!-Wk&wTqacn0?h|p@ zV3aHu#0%7ZZ|BtK&1FSin+mK5BzV9BpVyBGOO>?6Uc}v_Ow^#n|3MLZ<>H9f2)tt9 zTFwM;;{X125Y;X!Fim1RU-Mr)@Mo7yldCJp(aoWE#e?1p`DEznvU$P?RpMZEY-K-= z_q7k?X!-E zyM<7Qi?Kco4w z*Bczf+Z@DJeZRQ^&8E=EvNVbQy>UYjVwgAkAw>Hl*~yJebZLndkwnQBEBJ!L zeEEZFgofXf{JJ5?(H+g_)?e`N?~yk@1xkZ>U>^qYcwvek{R+AQ#^K!S(g#hbo3^iq z!&t0Z7{^hl^SyF~!=wkh{z_e{?cIV9)spjwjX=h96>rdAZmG0>`6O+Z58NHcVq!kCDwU^S`=whjo3^NRK0Df0+r#=WvV^ZVDEU-r+DlUcyHXoN))gOg_W`v!E01@b_EQT&F|9Iqbd)17lwYAkT#%lzJ! zV1dz;?}|iKxLBtk7KM=@Jn?(JrcqE|`x7#>d-RrX4Dv378~L16Toum7#Sg=f)v+!4 zL8*d`_0w&Rz0k!mdw=DYSiwG-)u#uq7B72iLJkT7?;j|^hi;45y;OlrS=EhNMcRcZ zCvYNDa1>Gdr^PB1!F%3IA)=~+?6~;9#0Z`PmQIIaHe~!u@AeT;Hd6YjIQg-_(pk8% z(`%xtKIM7|Hjn!2e55-#o2pGg{MnK7s3qu+b48GZ?n}i~51`1Wsy{&n(C+_+Sp47k c$K_w_PZrv>I1~=RYjIdg3hJ=RCuX7l1FX X.shape[1] or self.max_features < 1)): raise AttributeError('max_features must be' @@ -167,12 +228,10 @@ def fit(self, X, y, **fit_params): if self.max_features < self.min_features: raise AttributeError('min_features must be <= max_features') - candidates = chain(*((combinations(range(X.shape[1]), r=i)) + candidates = chain(*((combinations(range(X_.shape[1]), r=i)) for i in range(self.min_features, self.max_features + 1))) - self.subsets_ = {} - def ncr(n, r): """Return the number of combinations of length r from n items. @@ -196,26 +255,39 @@ def ncr(n, r): denom = reduce(op.mul, range(1, r+1)) return numer//denom - all_comb = np.sum([ncr(n=X.shape[1], r=i) + all_comb = np.sum([ncr(n=X_.shape[1], r=i) for i in range(self.min_features, self.max_features + 1)]) n_jobs = min(self.n_jobs, all_comb) parallel = Parallel(n_jobs=n_jobs, pre_dispatch=self.pre_dispatch) work = enumerate(parallel(delayed(_calc_score) - (self, X, y, c, **fit_params) + (self, X_, y, c, **fit_params) for c in candidates)) - for iteration, (c, cv_scores) in work: + try: + for iteration, (c, cv_scores) in work: + + self.subsets_[iteration] = {'feature_idx': c, + 'cv_scores': cv_scores, + 'avg_score': np.mean(cv_scores)} - self.subsets_[iteration] = {'feature_idx': c, - 'cv_scores': cv_scores, - 'avg_score': np.mean(cv_scores)} + if self.print_progress: + sys.stderr.write('\rFeatures: %d/%d' % ( + iteration + 1, all_comb)) + sys.stderr.flush() - if self.print_progress: - sys.stderr.write('\rFeatures: %d/%d' % ( - iteration + 1, all_comb)) - sys.stderr.flush() + if self._TESTING_INTERRUPT_MODE: + self.subsets_, self.k_feature_names_ = \ + _get_featurenames(self.subsets_, + self.k_feature_idx_, + custom_feature_names, + X) + raise KeyboardInterrupt + + except KeyboardInterrupt as e: + self.interrupted_ = True + sys.stderr.write('\nSTOPPING EARLY DUE TO KEYBOARD INTERRUPT...') max_score = float('-inf') for c in self.subsets_: @@ -225,10 +297,14 @@ def ncr(n, r): score = max_score idx = self.subsets_[best_subset]['feature_idx'] - self.best_idx_ = idx - self.best_score_ = score - self.subsets_plus_ = dict() + self.k_feature_idx_ = idx + self.k_score_ = score self.fitted = True + self.subsets_, self.k_feature_names_ = \ + _get_featurenames(self.subsets_, + self.k_feature_idx_, + custom_feature_names, + X) return self def transform(self, X): @@ -246,7 +322,11 @@ def transform(self, X): """ self._check_fitted() - return X[:, self.best_idx_] + if hasattr(X, 'loc'): + X_ = X.values + else: + X_ = X + return X_[:, self.k_feature_idx_] def fit_transform(self, X, y, **fit_params): """Fit to training data and return the best selected features from X. diff --git a/mlxtend/feature_selection/tests/test_exhaustive_feature_selector.py b/mlxtend/feature_selection/tests/test_exhaustive_feature_selector.py index 0dfc269b8..800dda6f6 100644 --- a/mlxtend/feature_selection/tests/test_exhaustive_feature_selector.py +++ b/mlxtend/feature_selection/tests/test_exhaustive_feature_selector.py @@ -20,9 +20,12 @@ def dict_compare_utility(d1, d2): assert d1.keys() == d2.keys(), "%s != %s" % (d1, d2) for i in d1: - err_msg = ("d1[%s]['feature_idx']" - " != d2[%s]['feature_idx']" % (i, i)) - assert d1[i]['feature_idx'] == d1[i]["feature_idx"], err_msg + err_msg1 = ("d1[%s]['feature_idx']" + " != d2[%s]['feature_idx']" % (i, i)) + err_msg2 = ("d1[%s]['feature_names']" + " != d2[%s]['feature_names']" % (i, i)) + assert d1[i]['feature_idx'] == d2[i]["feature_idx"], err_msg1 + assert d1[i]['feature_names'] == d2[i]["feature_names"], err_msg2 assert_almost_equal(d1[i]['avg_score'], d2[i]['avg_score'], decimal=3, @@ -99,33 +102,43 @@ def test_knn_wo_cv(): print_progress=False) efs1 = efs1.fit(X, y) expect = {0: {'feature_idx': (0, 1), + 'feature_names': ('0', '1'), 'avg_score': 0.82666666666666666, 'cv_scores': np.array([0.82666667])}, 1: {'feature_idx': (0, 2), + 'feature_names': ('0', '2'), 'avg_score': 0.95999999999999996, 'cv_scores': np.array([0.96])}, 2: {'feature_idx': (0, 3), + 'feature_names': ('0', '3'), 'avg_score': 0.96666666666666667, 'cv_scores': np.array([0.96666667])}, 3: {'feature_idx': (1, 2), + 'feature_names': ('1', '2'), 'avg_score': 0.95999999999999996, 'cv_scores': np.array([0.96])}, 4: {'feature_idx': (1, 3), + 'feature_names': ('1', '3'), 'avg_score': 0.95999999999999996, 'cv_scores': np.array([0.96])}, 5: {'feature_idx': (2, 3), + 'feature_names': ('2', '3'), 'avg_score': 0.97333333333333338, 'cv_scores': np.array([0.97333333])}, 6: {'feature_idx': (0, 1, 2), + 'feature_names': ('0', '1', '2'), 'avg_score': 0.95999999999999996, 'cv_scores': np.array([0.96])}, 7: {'feature_idx': (0, 1, 3), + 'feature_names': ('0', '1', '3'), 'avg_score': 0.96666666666666667, 'cv_scores': np.array([0.96666667])}, 8: {'feature_idx': (0, 2, 3), + 'feature_names': ('0', '2', '3'), 'avg_score': 0.96666666666666667, 'cv_scores': np.array([0.96666667])}, 9: {'feature_idx': (1, 2, 3), + 'feature_names': ('1', '2', '3'), 'avg_score': 0.97333333333333338, 'cv_scores': np.array([0.97333333])}} dict_compare_utility(d1=expect, d2=efs1.subsets_) @@ -145,23 +158,27 @@ def test_knn_cv3(): efs1 = efs1.fit(X, y) expect = {0: {'avg_score': 0.9391025641025641, 'feature_idx': (0, 1, 2), + 'feature_names': ('0', '1', '2'), 'cv_scores': np.array([0.97435897, 0.94871795, 0.88888889, 0.94444444])}, 1: {'avg_score': 0.94017094017094016, 'feature_idx': (0, 1, 3), + 'feature_names': ('0', '1', '3'), 'cv_scores': np.array([0.92307692, 0.94871795, 0.91666667, 0.97222222])}, 2: {'avg_score': 0.95299145299145294, 'feature_idx': (0, 2, 3), + 'feature_names': ('0', '2', '3'), 'cv_scores': np.array([0.97435897, 0.94871795, 0.91666667, 0.97222222])}, 3: {'avg_score': 0.97275641025641035, 'feature_idx': (1, 2, 3), + 'feature_names': ('1', '2', '3'), 'cv_scores': np.array([0.97435897, 1., 0.94444444, 0.97222222])}} dict_compare_utility(d1=expect, d2=efs1.subsets_) - assert efs1.best_idx_ == (1, 2, 3) - assert round(efs1.best_score_, 4) == 0.9728 + assert efs1.k_feature_idx_ == (1, 2, 3) + assert round(efs1.k_score_, 4) == 0.9728 def test_fit_params(): @@ -178,24 +195,28 @@ def test_fit_params(): print_progress=False) efs1 = efs1.fit(X, y, sample_weight=sample_weight) expect = {0: {'feature_idx': (0, 1, 2), + 'feature_names': ('0', '1', '2'), 'cv_scores': np.array([0.94871795, 0.92307692, 0.91666667, 0.97222222]), 'avg_score': 0.9401709401709402}, 1: {'feature_idx': (0, 1, 3), + 'feature_names': ('0', '1', '3'), 'cv_scores': np.array([0.92307692, 0.92307692, 0.88888889, 1.]), 'avg_score': 0.9337606837606838}, 2: {'feature_idx': (0, 2, 3), + 'feature_names': ('0', '2', '3'), 'cv_scores': np.array([0.97435897, 0.94871795, 0.94444444, 0.97222222]), 'avg_score': 0.9599358974358974}, 3: {'feature_idx': (1, 2, 3), + 'feature_names': ('1', '2', '3'), 'cv_scores': np.array([0.97435897, 0.94871795, 0.91666667, 1.]), 'avg_score': 0.9599358974358974}} dict_compare_utility(d1=expect, d2=efs1.subsets_) - assert efs1.best_idx_ == (0, 2, 3) - assert round(efs1.best_score_, 4) == 0.9599 + assert efs1.k_feature_idx_ == (0, 2, 3) + assert round(efs1.k_score_, 4) == 0.9599 def test_regression(): @@ -209,8 +230,8 @@ def test_regression(): cv=10, print_progress=False) efs_r = efs_r.fit(X, y) - assert efs_r.best_idx_ == (0, 2, 4) - assert round(efs_r.best_score_, 4) == -40.8777 + assert efs_r.k_feature_idx_ == (0, 2, 4) + assert round(efs_r.k_score_, 4) == -40.8777 def test_clone_params_fail(): @@ -305,7 +326,7 @@ def test_clone_params_pass(): print_progress=False, n_jobs=1) efs1 = efs1.fit(X, y) - assert(efs1.best_idx_ == (1, 3)) + assert(efs1.k_feature_idx_ == (1, 3)) def test_transform_not_fitted():