%23%20%2F%2F%2F%20script%0A%23%20requires-python%20%3D%20%22%3E%3D3.11%22%0A%23%20dependencies%20%3D%20%5B%22marimo%3E%3D0.23.9%22%2C%20%22numpy%3E%3D2.0%22%2C%20%22matplotlib%3E%3D3.9%22%2C%20%22urllib3%3E%3D2.2%22%5D%0A%23%20%2F%2F%2F%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.25.2%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Select%20data%20vectors%20by%20similarity%20using%20a%20metric%20score%0A%0A%20%20%20%20%3E%20Marcos%20Duarte%2C%20Renato%20Naville%20Watanabe%3Cbr%3E%0A%20%20%20%20%3E%20%5BLaboratory%20of%20Biomechanics%20and%20Motor%20Control%5D(https%3A%2F%2Fbmclab.pesquisa.ufabc.edu.br%2F)%3Cbr%3E%0A%20%20%20%20%3E%20Federal%20University%20of%20ABC%2C%20Brazil%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20How%20to%20use%20this%20notebook%0A%0A%20%20%20%20Treat%20each%20column%20as%20a%20trial%20and%20each%20row%20as%20a%20common%20time%20sample.%20Predict%20which%20trials%20will%20receive%20large%20scores%2C%20then%20compare%20repeated%20selection%20with%20one-pass%20selection.%20Keep%20the%20selected%20and%20excluded%20indices%20so%20that%20every%20decision%20can%20be%20traced%20back%20to%20the%20original%20trial.%0A%0A%20%20%20%20%23%23%20Opening%20challenge%0A%0A%20%20%20%20Ten%20trajectories%20mostly%20agree%2C%20but%20two%20differ.%20Are%20those%20two%20corrupt%20measurements%2C%20or%20valid%20movements%20from%20a%20second%20condition%3F%20A%20similarity%20rule%20can%20flag%20differences%3B%20it%20cannot%20decide%20their%20cause.%20This%20guide%20makes%20that%20distinction%20explicit%20while%20showing%20how%20the%20algorithm%20works.%0A%0A%20%20%20%20%23%23%20Setup%0A%0A%20%20%20%20NumPy%20and%20Matplotlib%20support%20the%20simulation%20and%20plots.%20The%20example%20retains%20the%20%60simila%60%20algorithm%20and%20its%20documentation%20below%2C%20uses%20seed%200%2C%20and%20needs%20no%20external%20dataset.%20Rows%20must%20already%20represent%20corresponding%20times%20or%20phases%3A%20similarity%20does%20not%20perform%20time%20alignment.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20np.set_printoptions(precision%3D3)%0A%20%20%20%20return%20np%2C%20plt%0A%0A%0A%40app.cell%0Adef%20_(similarity)%3A%0A%20%20%20%20help(similarity)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mse)%3A%0A%20%20%20%20help(mse)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Define%20a%20score%20before%20defining%20an%20exclusion%0A%0A%20%20%20%20For%20%24n%24%20matched%20samples%2C%20the%20unnormalized%20mean%20squared%20error%20is%20%24s_j%3Dn%5E%7B-1%7D%5Csum_i(y_%7Bij%7D-r_i)%5E2%24.%20It%20has%20squared%20signal%20units%20and%20is%20squared%20Euclidean%20distance%20**divided%20by%20%24n%24**%20for%20complete%20vectors%20of%20equal%20length.%20MSE%20does%20not%20satisfy%20the%20triangle%20inequality%2C%20so%20%E2%80%9Cmetric%E2%80%9D%20here%20means%20a%20score%20function%2C%20not%20a%20mathematical%20distance%20metric.%0A%0A%20%20%20%20The%20default%20reference%20is%20the%20pointwise%20median%20across%20trials.%20Dividing%20by%20the%20median%20of%20the%20trial%20scores%20produces%20a%20relative%2C%20dimensionless%20score%20when%20that%20scale%20is%20positive.%20With%20an%20exactly%20zero%20scale%2C%20the%20revised%20implementation%20assigns%20zero%20to%20exact%20matches%20and%20infinity%20to%20nonzero%20error%3B%20missing%20trials%20remain%20NaN.%20Use%20%60normalization%3DNone%60%20when%20an%20absolute%2C%20unit-bearing%20threshold%20is%20more%20appropriate.%0A%0A%20%20%20%20**Exercise%201%20%E2%80%94%20calculate%20the%20score.**%20Reference%20samples%20are%20%24(1%2C2%2C3)%24%20and%20a%20trial%20is%20%24(2%2C2%2C5)%24.%20Find%20squared%20Euclidean%20distance%20and%20MSE.%20If%20the%20median%20trial%20MSE%20is%200.5%2C%20find%20the%20normalized%20score.%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Worked%20solution%20%E2%80%94%20Exercise%201%0A%0A%20%20%20%20The%20squared%20differences%20are%20%24(1%2C0%2C4)%24%2C%20whose%20sum%20is%205.%20MSE%20is%20%245%2F3%24.%20Dividing%20by%200.5%20gives%20%2410%2F3%24.%20All%20three%20values%20answer%20different%20questions%3B%20specify%20both%20normalization%20and%20sample%20correspondence%20when%20comparing%20them.%0A%0A%20%20%20%20%2F%2F%2F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%23%20Example%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20plt%2C%20similarity)%3A%0A%20%20%20%20_rng%20%3D%20np.random.default_rng(0)%0A%20%20%20%20_t%2C%20_n%20%3D%20100%2C%2010%0A%20%20%20%20y%20%3D%20_rng.random((_t%2C%20_n))%20%2F%202%0A%20%20%20%20y%20%2B%3D%20%20np.atleast_2d(2*np.sin(2*np.pi*np.linspace(0%2C%201%2C%20_t))).T%0A%20%20%20%20for%20_i%20in%20range(0%2C%20_n%2C%202)%3A%0A%20%20%20%20%20%20%20_j%20%3D%20_rng.integers(_t-20)%0A%20%20%20%20%20%20%20_p%20%3D%20_rng.integers(20)%0A%20%20%20%20%20%20%20y%5B_j%3A_j%2B_p%2C%20_i%5D%20%3D%20y%5B_j%3A_j%2B_p%2C%20_i%5D%20%2B%20_rng.integers(10)%20-%205%0A%20%20%20%20%20%20%20y%5B%3A%2C%20_i%5D%20%2B%3D%20_rng.integers(4)%20-%202%0A%20%20%20%20_ysr%2C%20_ikeptr%2C%20_inotkeptr%2C%20_scoresr%20%3D%20similarity(y)%0A%20%20%20%20_ysn%2C%20_ikeptn%2C%20_inotkeptn%2C%20_scoresn%20%3D%20similarity(y%2C%20repeat%3DFalse)%0A%20%20%20%20_fig%2C%20_axs%20%3D%20plt.subplots(3%2C%201%2C%20sharex%3DTrue%2C%20figsize%3D(7%2C%207))%0A%20%20%20%20_axs%5B0%5D.plot(y%2C%20label%3Dlist(range(_n)))%0A%20%20%20%20_axs%5B0%5D.legend(loc%3D(1.01%2C%200)%2C%20ncol%3D2)%0A%20%20%20%20_axs%5B0%5D.set_title(f'Original%20vectors%20(n%3D%7B_n%7D)')%0A%20%20%20%20_axs%5B1%5D.plot(_ysr%2C%20label%3D%20_ikeptr.tolist())%0A%20%20%20%20_axs%5B1%5D.set_title(f'Vectors%20maintained%20with%20repeat%20selection%20(n%3D%7Blen(_ikeptr)%7D)')%0A%20%20%20%20_axs%5B1%5D.legend(loc%3D(1.01%2C%200))%0A%20%20%20%20_axs%5B2%5D.plot(_ysn%2C%20label%3D%20_ikeptn.tolist())%0A%20%20%20%20_axs%5B2%5D.set_title(f'Vectors%20maintained%20without%20repeat%20selection%20(n%3D%7Blen(_ikeptn)%7D)')%0A%20%20%20%20_axs%5B2%5D.legend(loc%3D(1.01%2C%200))%0A%20%20%20%20plt.show()%0A%20%20%20%20return%20(y%2C)%0A%0A%0A%40app.cell%0Adef%20_(mse%2C%20np%2C%20similarity%2C%20y)%3A%0A%20%20%20%20ys%2C%20ikept%2C%20inotkept%2C%20scores%20%3D%20similarity(y%2C%20threshold%3D0%2C%20nmin%3D3%2C%20repeat%3DTrue%2C%20metric%3Dmse%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20msg%3D1%2C%20central%3Dnp.nanmedian%2C%20normalization%3Dnp.nanmedian)%0A%20%20%20%20return%20ikept%2C%20inotkept%2C%20scores%2C%20ys%0A%0A%0A%40app.cell%0Adef%20_(ys)%3A%0A%20%20%20%20ys.shape%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(ikept)%3A%0A%20%20%20%20ikept%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(inotkept)%3A%0A%20%20%20%20inotkept%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(scores)%3A%0A%20%20%20%20scores%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mse%2C%20np%2C%20similarity%2C%20y)%3A%0A%20%20%20%20(ys_1%2C%20ikept_1%2C%20inotkept_1%2C%20scores_1)%20%3D%20similarity(y%2C%20threshold%3D0%2C%20nmin%3D3%2C%20repeat%3DTrue%2C%20metric%3Dmse%2C%20drop%3DFalse%2C%20msg%3DTrue%2C%20central%3Dnp.nanmedian%2C%20normalization%3Dnp.nanmedian)%0A%20%20%20%20return%20(ys_1%2C)%0A%0A%0A%40app.cell%0Adef%20_(ys_1)%3A%0A%20%20%20%20ys_1.shape%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mse%2C%20np%2C%20similarity%2C%20y)%3A%0A%20%20%20%20(ys_2%2C%20ikept_2%2C%20inotkept_2%2C%20scores_2)%20%3D%20similarity(y%2C%20threshold%3D0%2C%20nmin%3D3%2C%20repeat%3DFalse%2C%20metric%3Dmse%2C%20msg%3DTrue%2C%20central%3Dnp.nanmedian%2C%20normalization%3Dnp.nanmedian)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20**Exercise%202%20%E2%80%94%20retention%20and%20iteration.**%20Five%20trial%20scores%20are%20(0.5%2C0.7%2C1%2C2%2C8)%2C%20the%20threshold%20is%203%2C%20and%20at%20least%20three%20trials%20must%20be%20retained.%20Which%20trial%20is%20removed%20in%20one%20pass%3F%20Why%20could%20repeated%20selection%20lead%20to%20another%20decision%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Worked%20solution%20%E2%80%94%20Exercise%202%20%E2%80%94%20retention%20and%20iteration%0A%0A%20%20%20%20The%20fifth%20trial%20exceeds%203%20and%20is%20removed%2C%20leaving%20four.%20Repeated%20selection%20recomputes%20the%20reference%20and%20normalized%20scores%20after%20each%20removal%2C%20so%20the%20remaining%20values%20need%20not%20stay%20(0.5%2C0.7%2C1%2C2).%20The%20minimum-count%20rule%20limits%20how%20many%20may%20be%20excluded%3B%20it%20does%20not%20certify%20the%20quality%20of%20the%20retained%20trials.%0A%0A%20%20%20%20%2F%2F%2F%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Function%20profiling%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(similarity%2C%20y)%3A%0A%20%20%20%20(ys_3%2C%20ikept_3%2C%20inotkept_3%2C%20score_all)%20%3D%20similarity(y%2C%20repeat%3DTrue%2C%20msg%3DFalse)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(similarity%2C%20y)%3A%0A%20%20%20%20(ys_4%2C%20ikept_4%2C%20inotkept_4%2C%20score_all_1)%20%3D%20similarity(y%2C%20repeat%3DFalse%2C%20msg%3DFalse)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20The%20original%20profiling%20run%20attributed%2086%25%20of%20runtime%20to%20the%20score%20calculation.%20That%20is%20a%20historical%20measurement%2C%20not%20a%20performance%20guarantee.%20Compare%20the%20actual%20functions%20on%20the%20current%20100-by-10%20example%20below.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mse%2C%20np%2C%20y)%3A%0A%20%20%20%20%23%20magic%20command%20not%20supported%20in%20marimo%3B%20please%20file%20an%20issue%20to%20add%20support%0A%20%20%20%20%23%20%25%25timeit%0A%20%20%20%20score%20%3D%20mse(y%2C%20central%3Dnp.nanmedian%2C%20normalization%3Dnp.nanmedian)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mse%2C%20np%2C%20y)%3A%0A%20%20%20%20score_1%20%3D%20mse(y%2C%20central%3Dnp.nanmean%2C%20normalization%3Dnp.nanmean)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20The%20original%20run%20reported%20a%20roughly%20fourfold%20median%2Fmean%20timing%20difference.%20The%20ratio%20depends%20on%20data%20shape%2C%20missingness%2C%20versions%20and%20hardware%3B%20measure%20it%20again.%20Mean%20and%20median%20also%20estimate%20different%20centres%2C%20so%20speed%20alone%20does%20not%20decide%20which%20is%20suitable.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mse%2C%20np%2C%20y)%3A%0A%20%20%20%20from%20timeit%20import%20repeat%0A%20%20%20%20_median_s%20%3D%20min(repeat(lambda%3A%20mse(y%2C%20central%3Dnp.nanmedian%2C%20normalization%3Dnp.nanmedian)%2C%20number%3D20%2C%20repeat%3D3))%20%2F%2020%0A%20%20%20%20_mean_s%20%3D%20min(repeat(lambda%3A%20mse(y%2C%20central%3Dnp.nanmean%2C%20normalization%3Dnp.nanmean)%2C%20number%3D20%2C%20repeat%3D3))%20%2F%2020%0A%20%20%20%20print(f%22100%20%C3%97%2010%20data%3A%20median%20%7B_median_s%3A.6g%7D%20s%2Fcall%3B%20mean%20%7B_mean_s%3A.6g%7D%20s%2Fcall%3B%20ratio%20%7B_median_s%2F_mean_s%3A.2f%7D%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Function%20%60similarity%60%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np)%3A%0A%20%20%20%20%22%22%22Select%20vectors%20in%20array%20by%20their%20similarity%20using%20a%20metric%20score.%0A%20%20%20%20%22%22%22%0A%0A%20%20%20%20import%20logging%0A%20%20%20%20from%20typing%20import%20Callable%0A%0A%20%20%20%20__author__%20%3D%20'Marcos%20Duarte%2C%20https%3A%2F%2Fgithub.com%2Fdemotu%2FBMC'%0A%20%20%20%20__version__%20%3D%20'simila.py%20v.1.0.0%2020123%2F07%2F31'%0A%20%20%20%20__license__%20%3D%20%22MIT%22%0A%0A%20%20%20%20%23%20set%20logger%20and%20configure%20it%20not%20to%20confuse%20with%20matplotlib%20debug%20messages%0A%20%20%20%20logger%20%3D%20logging.getLogger(__name__)%0A%20%20%20%20logger.setLevel(20)%20%20%23%200%3A%20NOTSET%2C%2010%3A%20DEBUG%2C%2020%3A%20INFO%2C%2030%3A%20WARNING%2C%2040%3A%20ERROR%2C%2050%3A%20CRITICAL%0A%20%20%20%20ch%20%3D%20logging.StreamHandler()%0A%20%20%20%20formatter%20%3D%20logging.Formatter('%7Bname%7D%3A%20%7Blevelname%7D%3A%20%7Bmessage%7D'%2C%20style%3D'%7B')%0A%20%20%20%20ch.setFormatter(formatter)%0A%20%20%20%20logger.addHandler(ch)%0A%0A%0A%20%20%20%20def%20mse(y%3A%20np.ndarray%2C%20target%3A%20np.ndarray%20%7C%20None%20%3D%20None%2C%20axis1%3A%20int%20%3D%200%2C%20axis2%3A%20int%20%3D%201%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20central%3A%20Callable%20%3D%20np.nanmedian%2C%20normalization%3A%20Callable%20%3D%20np.nanmedian%0A%20%20%20%20%20%20%20%20%20%20%20%20)%20-%3E%20np.ndarray%3A%0A%20%20%20%20%20%20%20%20%22%22%22Mean%20Squared%20Error%20of%20%60y%60%20w.r.t.%20%60target%60%20or%20%60central%60%20along%20%60axis2%60%20at%20%60axis1%60.%0A%0A%20%20%20%20%20%20%20%20Parameters%0A%20%20%20%20%20%20%20%20----------%0A%20%20%20%20%20%20%20%20y%20%3A%20numpy.ndarray%0A%20%20%20%20%20%20%20%20%20%20%20%20At%20least%20a%202-D%20numpy.ndarray%20of%20data%20for%20the%20calculation%20of%20mean%20squared%0A%20%20%20%20%20%20%20%20%20%20%20%20error%20w.r.t.%20a%20%60target%60%20or%20a%20%60central%60%20statistics%20of%20the%20data.%0A%20%20%20%20%20%20%20%20target%20%3A%201-D%20numpy.ndarray%20of%20length%20%60axis1%60%2C%20optional%2C%20default%20%3D%20None%0A%20%20%20%20%20%20%20%20%20%20%20%20Reference%20value%20to%20calculate%20the%20mean%20squared%20error%20of%20%60y%60%20w.r.t.%20this%0A%20%20%20%20%20%20%20%20%20%20%20%20vector.%20If%20it%20is%20None%2C%20the%20mse%20value%20will%20be%20calculated%20w.r.t.%20a%20%60central%60%0A%20%20%20%20%20%20%20%20%20%20%20%20calculated%20along%20%60axis2%60%20of%20%60y%60.%0A%20%20%20%20%20%20%20%20axis1%20%3A%20integer%2C%20optional%2C%20default%20%3D%200%0A%20%20%20%20%20%20%20%20%20%20%20%20Axis%20of%20%60y%60%20for%20which%20the%20mse%20will%20be%20calculated%20at%20each%20value.%0A%20%20%20%20%20%20%20%20axis2%20%3A%20integer%2C%20optional%2C%20default%20%3D%201%0A%20%20%20%20%20%20%20%20%20%20%20%20Axis%20of%20%60y%60%20along%20which%20the%20%60central%60%20statistics%20might%20be%20calculated%20or%0A%20%20%20%20%20%20%20%20%20%20%20%20along%20which%20the%20target%20will%20be%20subtracted.%0A%20%20%20%20%20%20%20%20central%20%3A%20Python%20function%2C%20optional%2C%20default%20%3D%20np.nanmedian%0A%20%20%20%20%20%20%20%20%20%20%20%20Function%20to%20calculate%20statistics%20on%20%60y%60%20w.r.t.%20mse%20is%20computed.%0A%20%20%20%20%20%20%20%20normalization%20%3A%20Python%20function%2C%20optional%2C%20default%20%3D%20np.nanmedian%0A%20%20%20%20%20%20%20%20%20%20%20%20Function%20to%20normalize%20the%20calculated%20mse%20values.%20With%20a%20zero%20scale%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20exact%20matches%20have%20score%20zero%20and%20positive%20errors%20have%20score%20infinity.%0A%0A%20%20%20%20%20%20%20%20Returns%0A%20%20%20%20%20%20%20%20-------%0A%20%20%20%20%20%20%20%20score%20%3A%20numpy.ndarray%0A%20%20%20%20%20%20%20%20%20%20%20%20Mean%20Squared%20Error%20values%0A%0A%20%20%20%20%20%20%20%20References%0A%20%20%20%20%20%20%20%20----------%0A%20%20%20%20%20%20%20%20..%20%5B1%5D%20similarity.py%0A%0A%20%20%20%20%20%20%20%20Examples%0A%20%20%20%20%20%20%20%20--------%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20%20%20%20%20%3E%3E%3E%20rng%20%3D%20np.random.default_rng()%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20y%20%3D%20rng.random((100%2C%2010))%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20y%20%3D%20y%20%2B%20np.atleast_2d(np.sin(2*np.pi*np.linspace(0%2C%201%2C%20100))).T%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20mse(y%2C%20axis1%3D0%2C%20axis2%3D1%2C%20central%3Dnp.nanmedian%2C%20normalization%3Dnp.nanmedian)%0A%0A%20%20%20%20%20%20%20%20Version%20history%0A%20%20%20%20%20%20%20%20---------------%0A%20%20%20%20%20%20%20%20'1.0.0'%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20First%20release%20version%0A%20%20%20%20%20%20%20%20%22%22%22%0A%0A%20%20%20%20%20%20%20%20logger.debug('mse...')%0A%0A%20%20%20%20%20%20%20%20score%3A%20np.ndarray%20%3D%20np.empty((y.shape%5Baxis2%5D)%2C%20dtype%3Dfloat)%0A%20%20%20%20%20%20%20%20score.fill(np.nan)%0A%20%20%20%20%20%20%20%20idx%3A%20np.ndarray%20%3D%20np.where(~np.all(np.isnan(y)%2C%20axis%3Daxis1))%5B0%5D%0A%20%20%20%20%20%20%20%20y%20%3D%20y.swapaxes(0%2C%20axis2)%5Bidx%2C%20...%5D.swapaxes(0%2C%20axis2)%20%20%23%20faster%20than%20.take%0A%20%20%20%20%20%20%20%20if%20target%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20logger.debug('target%20shape%3A%20%25s'%2C%20target.shape)%0A%20%20%20%20%20%20%20%20%20%20%20%20reference%20%3D%20np.asarray(target)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20reference.ndim%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20shape%20%3D%20%5B1%5D%20*%20y.ndim%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20shape%5Baxis1%5D%20%3D%20reference.size%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20reference%20%3D%20reference.reshape(shape)%0A%20%20%20%20%20%20%20%20%20%20%20%20score%5Bidx%5D%20%3D%20np.nanmean((y%20-%20reference)**2%2C%20axis%3Daxis1)%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20score%5Bidx%5D%20%3D%20np.nanmean((y%20-%20central(y%2C%20axis%3Daxis2%2C%20keepdims%3DTrue))**2%2C%20axis%3Daxis1)%0A%0A%20%20%20%20%20%20%20%20if%20normalization%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20scale%20%3D%20normalization(score)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20scale%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20score%20%3D%20np.where(score%20%3E%200%2C%20np.inf%2C%20score)%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20score%20%3D%20score%2Fscale%0A%20%20%20%20%20%20%20%20logger.debug('idx%3A%20%25s%2C%20score%3A%20%25s'%2C%20idx%2C%20score)%0A%0A%20%20%20%20%20%20%20%20return%20score%0A%0A%0A%20%20%20%20def%20similarity(y%3A%20np.ndarray%2C%20axis1%3A%20int%20%3D%200%2C%20axis2%3A%20int%20%3D%201%2C%20threshold%3A%20float%20%3D%200%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nmin%3A%20int%20%3D%203%2C%20repeat%3A%20bool%20%3D%20True%2C%20metric%3A%20Callable%20%3D%20mse%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20drop%3DTrue%2C%20msg%3A%20bool%20%3D%20True%2C%20**kwargs%3A%20Callable%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%20-%3E%20tuple%5Bnp.ndarray%2C%20np.ndarray%2C%20np.ndarray%2C%20np.ndarray%5D%3A%0A%0A%20%20%20%20%20%20%20%20%22%22%22Select%20vectors%20in%20array%20by%20their%20similarity%20using%20a%20metric%20score.%0A%0A%20%20%20%20%20%20%20%20For%20example%2C%20if%20%60y%60%20is%20a%202-D%20numpy.ndarray%2C%20with%20shape%20(n%2C%20m)%2C%20%60axis1%60%3D0%0A%20%20%20%20%20%20%20%20(n%20is%20the%20number%20of%20rows)%20and%20%60axis2%60%3D1%20(m%20is%20the%20number%20of%20columns)%2C%20this%0A%20%20%20%20%20%20%20%20function%20will%20select%20the%20vectors%20along%20the%20columns%2C%20that%20are%20more%20similar%0A%20%20%20%20%20%20%20%20to%20a%20%60central%60%20statistics%20of%20%60y%60%20or%20to%20a%20%60target%60%2C%20using%20a%20%60metric%60%20score.%0A%20%20%20%20%20%20%20%20The%20metric%20score%20can%20be%20calculated%20repeatedly%20until%20all%20selected%20vectors%0A%20%20%20%20%20%20%20%20have%20a%20%60metric%60%20score%20not%20greater%20than%20a%20%60threshold%60%2C%20but%20the%20minimum%0A%20%20%20%20%20%20%20%20number%20of%20vectors%20to%20keep%20or%20the%20maximum%20number%20of%20vectors%20to%20discard%0A%20%20%20%20%20%20%20%20can%20be%20specified%20with%20parameter%20%60nmin%60.%0A%0A%20%20%20%20%20%20%20%20The%20default%20%60metric%60%20and%20target%20are%20the%20mean%20squared%20error%20(%60mse%60)%20of%20%60y%60%0A%20%20%20%20%20%20%20%20w.r.t.%20the%20median%20of%20%60y%60%20along%20%60axis2%60.%20The%20%60mse%60%20metric%20is%20equal%0A%20%20%20%20%20%20%20%20to%20squared%20Euclidean%20distance%20divided%20by%20the%20sample%20count%20and%20it%20is%20preferred%20because%20it%0A%20%20%20%20%20%20%20%20penalizes%20largest%20differences%20more%20than%20the%20Euclidean%20distance.%20But%20any%0A%20%20%20%20%20%20%20%20other%20%60metric%60%20that%20can%20be%20calculated%20with%20a%20function%20can%20be%20used.%0A%0A%20%20%20%20%20%20%20%20A%20possible%20use%20of%20this%20function%20is%20to%20discard%20the%20time-series%20data%20from%20bad%0A%20%20%20%20%20%20%20%20trials%20(treated%20as%20outliers)%20stored%20in%20a%202-D%20array%20(each%20trial%20as%20a%20column%0A%20%20%20%20%20%20%20%20and%20instants%20as%20rows)%20where%20the%20criterion%20is%20the%20similarity%20of%20the%20trial%0A%20%20%20%20%20%20%20%20w.r.t.%20the%20median%20trial%20(the%20median%20statistics%20is%20more%20robust%20to%20remove%0A%20%20%20%20%20%20%20%20outliers%20than%20the%20mean%20in%20case%20there%20are%20very%20bad%20trials).%20After%20the%20bad%0A%20%20%20%20%20%20%20%20trials%20are%20discarded%2C%20the%20mean%20of%20all%20trials%20could%20then%20be%20calculated%20more%0A%20%20%20%20%20%20%20%20reliably.%0A%0A%20%20%20%20%20%20%20%20Parameters%0A%20%20%20%20%20%20%20%20----------%0A%20%20%20%20%20%20%20%20y%20%3A%20numpy.ndarray%0A%20%20%20%20%20%20%20%20%20%20%20%20Array%20for%20the%20calculation%20of%20similarity%20(defined%20by%20a%20%60metric%60)%20of%20its%0A%20%20%20%20%20%20%20%20%20%20%20%20vectors%20w.r.t.%20a%20%60target%60%20or%20a%20%60central%60%20statistics%20of%20%60y%60.%0A%20%20%20%20%20%20%20%20axis1%20%3A%20integer%2C%20optional%2C%20default%20%3D%200%0A%20%20%20%20%20%20%20%20%20%20%20%20Axis%20of%20%60y%60%20for%20which%20the%20%60metric%60%20will%20be%20calculated%20at%20each%20value%20and%0A%20%20%20%20%20%20%20%20%20%20%20%20possibly%20averaged%20in%20the%20%60metric%60%20calculation.%0A%20%20%20%20%20%20%20%20axis2%20%3A%20integer%2C%20optional%2C%20default%20%3D%201%0A%20%20%20%20%20%20%20%20%20%20%20%20Axis%20of%20%60y%60%20along%20which%20the%20different%20vectors%20are%20going%20to%20be%20compared%0A%20%20%20%20%20%20%20%20%20%20%20%20with%20the%20%60threshold%60%20for%20their%20similarity%20(using%20their%20%60metric%60%20score).%0A%20%20%20%20%20%20%20%20threshold%20%3A%20float%2C%20optional%2C%20default%20%3D%200%0A%20%20%20%20%20%20%20%20%20%20%20%20If%20greater%20than%200%2C%20vector%20with%20%60metric%60%20score%20above%20this%20value%20will%20be%0A%20%20%20%20%20%20%20%20%20%20%20%20discarded.%20If%200%2C%20threshold%20will%20be%20automatically%20calculated%20as%20the%0A%20%20%20%20%20%20%20%20%20%20%20%20minimum%20of%20%5Bqs%5B2%5D%20%2B%201.5*(qs%5B2%5D-qs%5B0%5D)%2C%20score%5B-2%5D%2C%203%5D%2C%20where%20qs%20are%20the%0A%20%20%20%20%20%20%20%20%20%20%20%20quantiles%20and%20score%5B-2%5D%20is%20the%20before-last%20largest%20score%20of%20%60metric%60%0A%20%20%20%20%20%20%20%20%20%20%20%20among%20vectors%20calculated%20at%20the%20first%20time%2C%20not%20updated%20by%20the%20%60repeat%60%0A%20%20%20%20%20%20%20%20%20%20%20%20option.%0A%20%20%20%20%20%20%20%20nmin%20%3A%20integer%2C%20optional%2C%20default%20%3D%203%0A%20%20%20%20%20%20%20%20%20%20%20%20If%20greater%20than%200%2C%20minumum%20number%20of%20vectors%20to%20keep.%0A%20%20%20%20%20%20%20%20%20%20%20%20If%20lower%20than%200%2C%20maximum%20number%20of%20vectors%20to%20discard.%0A%20%20%20%20%20%20%20%20repeat%20%3A%20bool%2C%20optional%2C%20default%20%3D%20True%0A%20%20%20%20%20%20%20%20%20%20%20%20Whether%20to%20calculate%20similarity%20%60metric%60%20repeatedly%2C%20updating%20the%0A%20%20%20%20%20%20%20%20%20%20%20%20score%20calculation%20each%20time%20a%20vector%20is%20discarded.%0A%20%20%20%20%20%20%20%20%20%20%20%20With%20%60repeat%60%20True%2C%20the%20output%20%60scores%60%20will%20contain%20at%20each%20row%0A%20%20%20%20%20%20%20%20%20%20%20%20the%20updated%20score%20values%20for%20the%20used%20%60metric%60%20for%20each%20data%20vector.%0A%20%20%20%20%20%20%20%20%20%20%20%20The%20first%20row%20will%20contain%20the%20calculated%20original%20scores%20before%20any%0A%20%20%20%20%20%20%20%20%20%20%20%20vector%20was%20discarded.%20On%20the%20next%20equent%20rows%2C%20the%20vectors%20discarded%0A%20%20%20%20%20%20%20%20%20%20%20%20are%20represented%20by%20NaN%20values%20and%20the%20kept%20vectors%20by%20their%20updated%0A%20%20%20%20%20%20%20%20%20%20%20%20scores.%0A%20%20%20%20%20%20%20%20%20%20%20%20The%20last%20row%20will%20contain%20the%20updated%20scores%20of%20the%20final%20vectors%20kept.%0A%20%20%20%20%20%20%20%20%20%20%20%20With%20the%20%60repeat%60%20False%2C%20the%20comparison%20of%20score%20values%20with%0A%20%20%20%20%20%20%20%20%20%20%20%20%60threshold%60%20are%20made%20only%20once%20and%20vectors%20are%20discarded%20accordingly%20at%0A%20%20%20%20%20%20%20%20%20%20%20%20once.%20In%20this%20case%2C%20the%20output%20%60scores%60%20will%20contain%20only%20two%20rows%2C%20the%0A%20%20%20%20%20%20%20%20%20%20%20%20first%20row%20will%20contain%20the%20calculated%20original%20scores%20before%20any%0A%20%20%20%20%20%20%20%20%20%20%20%20vectors%20were%20discarded.%20At%20the%20second%20row%2C%20the%20vectors%20discarded%20are%0A%20%20%20%20%20%20%20%20%20%20%20%20represented%20with%20NaN%20values%20and%20the%20kept%20vectors%20by%20their%20updated%0A%20%20%20%20%20%20%20%20%20%20%20%20scores.%0A%20%20%20%20%20%20%20%20metric%20%3A%20optional%2C%20default%3Dmse%0A%20%20%20%20%20%20%20%20%20%20%20%20Function%20to%20use%20as%20metric%20to%20compute%20similarity.%0A%20%20%20%20%20%20%20%20drop%20%3A%20bool%2C%20optional%2C%20default%20%3D%20True%0A%20%20%20%20%20%20%20%20%20%20%20%20Whether%20to%20drop%20(delete)%20the%20discarded%20vectors%20from%20%60y%60%20in%20the%20output.%0A%20%20%20%20%20%20%20%20%20%20%20%20If%20False%2C%20the%20values%20of%20the%20vectors%20discarded%20will%20be%20replaced%20by%20nans%0A%20%20%20%20%20%20%20%20%20%20%20%20and%20the%20returned%20array%20will%20have%20the%20same%20dimensions%20as%20the%20original%0A%20%20%20%20%20%20%20%20%20%20%20%20array.%0A%20%20%20%20%20%20%20%20msg%20%3A%20bool%2C%20optional%2C%20default%20%3D%20True%0A%20%20%20%20%20%20%20%20%20%20%20%20Whether%20to%20print%20some%20messages.%0A%20%20%20%20%20%20%20%20kwargs%20%3A%20optional%0A%20%20%20%20%20%20%20%20%20%20%20%20Options%20for%20the%20metric%20function%20(e.g.%2C%20see%20%60mse%60%20function).%0A%0A%20%20%20%20%20%20%20%20Returns%0A%20%20%20%20%20%20%20%20-------%0A%20%20%20%20%20%20%20%20y%20%3A%20numpy.ndarray%0A%20%20%20%20%20%20%20%20%20%20%20%20Array%20similar%20to%20input%20%60y%60%20but%20with%20vectors%20discarded%20(deleted)%20if%0A%20%20%20%20%20%20%20%20%20%20%20%20option%20%60drop%60%20is%20True%20or%20with%20all%20values%20of%20vectors%20discarded%20replaced%0A%20%20%20%20%20%20%20%20%20%20%20%20by%20nans%20if%20option%20%60drop%60%20is%20False.%0A%20%20%20%20%20%20%20%20ikept%20%3A%20numpy.ndarray%0A%20%20%20%20%20%20%20%20%20%20%20%20Indexes%20of%20kept%20vectors.%0A%20%20%20%20%20%20%20%20inotkept%20%3A%20numpy.ndarray%0A%20%20%20%20%20%20%20%20%20%20%20%20Indexes%20of%20not%20kept%20(discarded%20or%20replaced%20by%20nan)%20vectors.%0A%20%20%20%20%20%20%20%20scores%20%3A%202-D%20numpy.ndarray%0A%20%20%20%20%20%20%20%20%20%20%20%20Metric%20score%20values%20of%20each%20vector%20(as%20columns)%20for%20each%20round%20of%0A%20%20%20%20%20%20%20%20%20%20%20%20vector%20selection%20(one%20row%20per%20round%20plus%20the%20final%20values).%0A%0A%20%20%20%20%20%20%20%20References%0A%20%20%20%20%20%20%20%20----------%0A%20%20%20%20%20%20%20%20..%20%5B1%5D%20similarity.py%0A%0A%20%20%20%20%20%20%20%20Examples%0A%20%20%20%20%20%20%20%20--------%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20import%20matplotlib.pyplot%20as%20plt%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20rng%20%3D%20np.random.default_rng()%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20t%2C%20n%20%3D%20100%2C%2010%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20y%20%3D%20rng.random((t%2C%20n))%20%2F%202%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20y%20%3D%20y%20%2B%20np.atleast_2d(2*np.sin(2*np.pi*np.linspace(0%2C%201%2C%20t))).T%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20for%20i%20in%20range(0%2C%20n%2C%202)%3A%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20%20%20%20j%20%3D%20rng.integers(t-20)%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20%20%20%20p%20%3D%20rng.integers(20)%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20%20%20%20y%5Bj%3Aj%2Bp%2C%20i%5D%20%3D%20y%5Bj%3Aj%2Bp%2C%20i%5D%20%2B%20rng.integers(10)%20-%205%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20%20%20%20y%5B%3A%2C%20i%5D%20%2B%3D%20rng.integers(4)%20-%202%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20ysr%2C%20ikeptr%2C%20inotkeptr%2C%20scoresr%20%3D%20similarity(y)%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20ysn%2C%20ikeptn%2C%20inotkeptn%2C%20scoresn%20%3D%20similarity(y%2C%20repeat%3DFalse)%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20fig%2C%20axs%20%3D%20plt.subplots(3%2C%201%2C%20sharex%3DTrue%2C%20figsize%3D(8%2C%208))%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20axs%5B0%5D.plot(y%2C%20label%3Dlist(range(n)))%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20axs%5B0%5D.legend(loc%3D(1.01%2C%200)%2C%20ncol%3D2)%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20axs%5B0%5D.set_title(f'Original%20vectors%20(n%3D%7Bn%7D)')%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20axs%5B1%5D.plot(ysr%2C%20label%3D%20ikeptr.tolist())%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20axs%5B1%5D.set_title(f'Vectors%20maintained%20with%20repeat%20selection%20(n%3D%7Blen(ikeptr)%7D)')%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20axs%5B1%5D.legend(loc%3D(1.01%2C%200))%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20axs%5B2%5D.plot(ysn%2C%20label%3D%20ikeptn.tolist())%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20axs%5B2%5D.set_title(f'Vectors%20maintained%20without%20repeat%20selection%20(n%3D%7Blen(ikeptn)%7D)')%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20axs%5B2%5D.legend(loc%3D(1.01%2C%200))%0A%20%20%20%20%20%20%20%20%3E%3E%3E%20plt.show()%0A%0A%20%20%20%20%20%20%20%20Version%20history%0A%20%20%20%20%20%20%20%20---------------%0A%20%20%20%20%20%20%20%20'1.0.0'%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20First%20release%20version%0A%20%20%20%20%20%20%20%20%22%22%22%0A%0A%20%20%20%20%20%20%20%20logger.debug('Similarity...')%0A%0A%20%20%20%20%20%20%20%20if%20y.ndim%20%3C%202%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError('The%20input%20array%20must%20be%20at%20least%20a%202-D%20array.')%0A%20%20%20%20%20%20%20%20y%20%3D%20y.copy()%0A%20%20%20%20%20%20%20%20score%3A%20np.ndarray%20%3D%20metric(y%2C%20axis1%3Daxis1%2C%20axis2%3Daxis2%2C%20**kwargs)%0A%20%20%20%20%20%20%20%20scores%3A%20np.ndarray%20%3D%20np.atleast_2d(score)%0A%20%20%20%20%20%20%20%20ikept%3A%20np.ndarray%20%3D%20np.where(~np.isnan(score))%5B0%5D%20%20%23%20indexes%20of%20kept%20vectors%0A%20%20%20%20%20%20%20%20inotkept%3A%20np.ndarray%20%3D%20np.where(np.isnan(score))%5B0%5D%20%20%23%20indexes%20of%20discarded%20vectors%0A%20%20%20%20%20%20%20%20idx%3A%20np.ndarray%20%3D%20np.argsort(score)%0A%20%20%20%20%20%20%20%20score%20%3D%20score%5Bidx%5D%0A%20%20%20%20%20%20%20%20nkept%3A%20int%20%3D%20np.count_nonzero(~np.isnan(score))%20%20%23%20number%20of%20kept%20vectors%0A%20%20%20%20%20%20%20%20if%20nkept%20%3C%203%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20logger.debug('nkept%3A%20%25s'%2C%20nkept)%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20ValueError('The%20input%20array%20must%20have%20at%20least%203%20valid%20vectors.')%0A%20%20%20%20%20%20%20%20if%20nmin%20%3C%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20nmin%20%3D%20np.max(%5B3%2C%20nkept%20%2B%20nmin%5D)%0A%20%20%20%20%20%20%20%20if%20threshold%20%3D%3D%200%3A%20%20%23%20automatic%20threshold%20calculation%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Infinite%20scores%20denote%20nonzero%20error%20against%20an%20exactly%20zero%20baseline.%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20Keep%20them%20eligible%20for%20rejection%20without%20interpolating%200%20and%20infinity.%0A%20%20%20%20%20%20%20%20%20%20%20%20qs%3A%20np.ndarray%20%3D%20np.quantile(a%3Dscore%5Bnp.isfinite(score)%5D%2C%20q%3D%5B.25%2C%20.50%2C%20.75%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20threshold%20%3D%20np.min(%5Bqs%5B2%5D%20%2B%201.5*(qs%5B2%5D-qs%5B0%5D)%2C%20score%5B-2%5D%2C%203.%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20msg%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print(f'Calculated%20threshold%3A%20%7Bthreshold%7D')%0A%0A%20%20%20%20%20%20%20%20if%20not%20repeat%3A%20%20%23%20discard%20all%20vectors%20at%20once%0A%20%20%20%20%20%20%20%20%20%20%20%20idx2%3A%20np.ndarray%20%3D%20np.nonzero(score%20%3E%20threshold)%5B0%5D%20%20%23%20vectors%20to%20discard%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20len(idx2)%20%3E%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20nkept%20%3E%20nmin%3A%20%20%23%20keep%20at%20least%20nmin%20vectors%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20inotkept%20%3D%20np.r_%5Binotkept%2C%20idx%5Bidx2%5B-(y.shape%5Baxis2%5D%20-%20nmin)%3A%5D%5D%5B%3A%3A-1%5D%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y.swapaxes(0%2C%20axis2)%5Binotkept%2C%20...%5D%20%3D%20np.nan%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20score%20%3D%20metric(y%2C%20axis1%3Daxis1%2C%20axis2%3Daxis2%2C%20**kwargs)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20scores%20%3D%20np.vstack((scores%2C%20score))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20logger.debug('not%20repeat%20-%20score%3A%20%25s'%2C%20score)%0A%20%20%20%20%20%20%20%20else%3A%20%20%23%20discard%20vector%20with%20largest%20updated%20score%20one%20by%20one%0A%20%20%20%20%20%20%20%20%20%20%20%20while%20nkept%20%3E%20nmin%20and%20score%5Bnkept-1%5D%20%3E%20threshold%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20inotkept%20%3D%20np.r_%5Binotkept%2C%20idx%5Bnkept-1%5D%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y.swapaxes(0%2C%20axis2)%5Binotkept%5B-1%5D%2C%20...%5D%20%3D%20np.nan%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20score%20%3D%20metric(y%2C%20axis1%3Daxis1%2C%20axis2%3Daxis2%2C%20**kwargs)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20scores%20%3D%20np.vstack((scores%2C%20score))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20idx%20%3D%20np.argsort(score)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20score%20%3D%20score%5Bidx%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20nkept%20%3D%20nkept%20-%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20logger.debug('repeat%20-%20nkept%3A%20%25s%2C%20score%3A%20%25s'%2C%20nkept%2C%20score)%0A%0A%20%20%20%20%20%20%20%20if%20len(inotkept)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20ikept%20%3D%20np.setdiff1d(ikept%2C%20inotkept)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20drop%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%20%3D%20y.swapaxes(0%2C%20axis2)%5Bikept%2C%20...%5D.swapaxes(0%2C%20axis2)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20msg%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f'Vectors%20discarded%20(dimension%20%7Baxis2%7D%2C%20n%3D%7Blen(inotkept)%7D)%3A%20%7Binotkept%7D')%0A%0A%20%20%20%20%20%20%20%20return%20y%2C%20ikept%2C%20inotkept%2C%20scores%0A%0A%20%20%20%20return%20mse%2C%20similarity%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20**Exercise%203%20%E2%80%94%20keep%20the%20audit%20trail.**%20A%20100-by-10%20array%20loses%20trials%20with%20indices%202%20and%207.%20Compare%20the%20shapes%20and%20interpretation%20with%20%60drop%3DTrue%60%20and%20%60drop%3DFalse%60.%20Then%20explain%20why%20two%20valid%20experimental%20conditions%20should%20not%20be%20pooled%20and%20filtered%20solely%20for%20agreement.%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Worked%20solution%20%E2%80%94%20Exercise%203%0A%0A%20%20%20%20Dropping%20columns%20returns%20shape%20(100%2C8)%3B%20the%20kept%20indices%20map%20those%20columns%20back%20to%20the%20input.%20Keeping%20shape%20returns%20(100%2C10)%20with%20columns%202%20and%207%20set%20to%20NaN.%20Preserve%20both%20original%20data%20and%20exclusions.%20A%20genuine%20condition%20effect%20can%20make%20an%20entire%20subgroup%20dissimilar%2C%20so%20analyse%20experimental%20labels%20and%20measurement%20quality%20before%20treating%20difference%20as%20corruption.%0A%0A%20%20%20%20%2F%2F%2F%0A%0A%20%20%20%20%23%23%20Checkpoint%20questions%0A%0A%20%20%20%20-%20Does%20a%20low%20score%20prove%20that%20a%20trial%20is%20physiologically%20correct%3F%0A%20%20%20%20-%20Why%20can%20the%20final%20scores%20change%20after%20removing%20just%20one%20trial%3F%0A%20%20%20%20-%20Which%20threshold%20has%20squared%20signal%20units%2C%20and%20which%20is%20dimensionless%3F%0A%20%20%20%20-%20Does%20profiling%20establish%20that%20the%20faster%20reference%20estimator%20is%20scientifically%20preferable%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Checkpoint%20answers%0A%0A%20%20%20%20No.%20Common%20artefacts%20may%20affect%20all%20trials%20and%20valid%20subgroups%20may%20differ.%20Reference%20and%20normalization%20are%20recomputed%20during%20repeated%20selection.%20Unnormalized%20MSE%20has%20squared%20signal%20units%3B%20normalization%20by%20a%20positive%20score%20scale%20is%20dimensionless.%20Timing%20measures%20cost%20for%20the%20stated%20input%2C%20while%20estimator%20choice%20depends%20on%20the%20scientific%20question%20and%20robustness%20needed.%0A%0A%20%20%20%20%2F%2F%2F%0A%0A%20%20%20%20%23%23%20Problems%0A%0A%20%20%20%201.%20For%20trial%20%24(1%2C3)%24%20and%20reference%20%24(1%2C1)%24%2C%20report%20unnormalized%20MSE%20and%20squared%20Euclidean%20distance.%0A%20%20%20%202.%20Scores%20before%20normalization%20are%20%24(1%2C2%2C4%2C8%2C16)%24.%20Report%20median-normalized%20scores%20and%20the%20trial%20indices%20exceeding%20threshold%203%20(zero-based%20indexing).%0A%20%20%20%203.%20With%2020%20samples%20and%20six%20trials%2C%20two%20trials%20are%20excluded.%20Give%20the%20output%20shape%20for%20both%20%60drop%60%20choices.%0A%20%20%20%204.%20Four%20trajectories%20are%20identical%20and%20a%20fifth%20differs%3B%20the%20median%20unnormalized%20error%20is%20zero.%20State%20the%20revised%20normalized%20scores%20for%20the%20exact%20matches%20and%20the%20different%20trial.%0A%20%20%20%205.%20Are%20retained%20indices%20sufficient%20to%20claim%20that%20excluded%20trials%20are%20measurement%20failures%3F%0A%0A%20%20%20%20%2F%2F%2F%20details%20%7C%20Final%20answers%20to%20the%20problems%0A%0A%20%20%20%201.%202%20and%204.%0A%20%20%20%202.%20%24(0.25%2C0.5%2C1%2C2%2C4)%24%3B%20index%204.%0A%20%20%20%203.%20%60(20%2C4)%60%20for%20%60drop%3DTrue%60%3B%20%60(20%2C6)%60%20for%20%60drop%3DFalse%60.%0A%20%20%20%204.%20Zero%20for%20each%20exact%20match%3B%20positive%20infinity%20for%20the%20different%20trial.%0A%20%20%20%205.%20No%3B%20exclusion%20needs%20interpretation%20using%20acquisition%20and%20experimental%20context.%0A%0A%20%20%20%20%2F%2F%2F%0A%0A%20%20%20%20%23%23%20Go%20deeper%0A%0A%20%20%20%20Use%20an%20independently%20defined%20target%20trajectory%20and%20compare%20the%20retained%20set%20with%20a%20pointwise-median%20reference.%20Vary%20the%20threshold%20and%20report%20selection%20stability.%20Check%20time%20alignment%20and%20missing-data%20coverage%3A%20%60nanmean%60%20can%20compare%20trials%20using%20different%20numbers%20of%20valid%20samples%2C%20which%20changes%20their%20comparability.%0A%0A%20%20%20%20%23%23%23%20Video%20lectures%20on%20the%20Internet%0A%0A%20%20%20%20-%20%5BMIT%2018.06SC%3A%20projection%20matrices%20and%20least%20squares%5D(https%3A%2F%2Focw.mit.edu%2Fcourses%2F18-06sc-linear-algebra-fall-2011%2Fpages%2Fleast-squares-determinants-and-eigenvalues%2Fprojection-matrices-and-least-squares%2F)%20%E2%80%94%20review%20squared%20residuals%20and%20geometric%20distance%2C%20then%20distinguish%20that%20fixed-target%20calculation%20from%20the%20changing%20median%20reference%20here.%0A%0A%20%20%20%20%23%23%20References%0A%0A%20%20%20%20-%20%5BBMC%20%60simila.py%60%5D(https%3A%2F%2Fgithub.com%2FBMClab%2FBMC%2Fblob%2Fmaster%2Ffunctions%2Fsimila.py)%20%E2%80%94%20algorithm%2C%20parameters%20and%20original%20attribution.%0A%0A%20%20%20%20-%20%5BNumPy%20%60nanmean%60%5D(https%3A%2F%2Fnumpy.org%2Fdoc%2Fstable%2Freference%2Fgenerated%2Fnumpy.nanmean.html)%20%E2%80%94%20averaging%20with%20missing%20values.%0A%0A%20%20%20%20-%20%5BNumPy%20%60nanmedian%60%5D(https%3A%2F%2Fnumpy.org%2Fdoc%2Fstable%2Freference%2Fgenerated%2Fnumpy.nanmedian.html)%20%E2%80%94%20the%20default%20centre%20and%20score%20normalization.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
8d4930c0df35d491758bf5176bed2956