%23%20%2F%2F%2F%20script%0A%23%20requires-python%20%3D%20%22%3E%3D3.9%22%0A%23%20dependencies%20%3D%20%5B%0A%23%20%20%20%20%20%22detecta%22%2C%0A%23%20%20%20%20%20%22marimo%22%2C%0A%23%20%20%20%20%20%22matplotlib%22%2C%0A%23%20%20%20%20%20%22numpy%22%2C%0A%23%20%20%20%20%20%22pyversions%22%2C%0A%23%20%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(width%3D%22medium%22)%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%20detect_cusum.py%0A%0A%20%20%20%20A%20function%20from%20%5Bdetecta%5D(https%3A%2F%2Fpypi.org%2Fproject%2Fdetecta%2F)%20-%20Python%20module%20to%20detect%20events%20in%20data.%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%5BChange%20detection%5D(http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FChange_detection)%20refers%20to%20procedures%20to%20identify%20abrupt%20changes%20in%20a%20phenomenon%20(Basseville%20and%20Nikiforov%201993%2C%20Gustafsson%202000).%20By%20abrupt%20change%20it%20is%20meant%20any%20difference%20in%20relation%20to%20previous%20known%20data%20faster%20than%20expected%20of%20some%20characteristic%20of%20the%20data%20such%20as%20amplitude%2C%20mean%2C%20variance%2C%20frequency%2C%20etc.%0A%0A%20%20%20%20The%20%5BCumulative%20sum%20(CUSUM)%5D(http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FCUSUM)%20algorithm%20is%20a%20classical%20technique%20for%20monitoring%20change%20detection.%20One%20form%20of%20implementing%20the%20CUSUM%20algorithm%20involves%20the%20calculation%20of%20the%20cumulative%20sum%20of%20positive%20and%20negative%20changes%20(%24g_t%5E%2B%24%20and%20%24g_t%5E-%24)%20in%20the%20data%20(%24x%24)%20and%20comparison%20to%20a%20%24threshold%24.%20When%20this%20threshold%20is%20exceeded%20a%20change%20is%20detected%20(%24t_%7Btalarm%7D%24)%20and%20the%20cumulative%20sum%20restarts%20from%20zero.%20To%20avoid%20the%20detection%20of%20a%20change%20in%20absence%20of%20an%20actual%20change%20or%20a%20slow%20drift%2C%20this%20algorithm%20also%20depends%20on%20a%20parameter%20%24drift%24%20for%20drift%20correction.%20This%20form%20of%20the%20CUSUM%20algorithm%20is%20given%20by%3A%0A%0A%20%20%20%20%24%24%20%5Cbegin%7Barray%7D%7Bl%20l%7D%0A%20%20%20%20%5Cleft%5C%7B%20%5Cbegin%7Barray%7D%7Bl%20l%7D%0A%20%20%20%20s%5Bt%5D%20%3D%20x%5Bt%5D%20-%20%5Chat%7B%5Cmu%7D%5Bt-1%5D%20%5C%5C%0A%20%20%20%20g%5E%2B%5Bt%5D%20%3D%20max%5Cleft(g%5E%2B%5Bt-1%5D%20%2B%20s%5Bt%5D-drift%2C%5C%3B%200%5Cright)%20%5C%5C%0A%20%20%20%20g%5E-%5Bt%5D%20%3D%20max%5Cleft(g%5E-%5Bt-1%5D%20-%20s%5Bt%5D-drift%2C%5C%3B%200%5Cright)%0A%20%20%20%20%5Cend%7Barray%7D%20%5Cright.%20%5C%5C%0A%20%20%20%20%5C%5C%0A%20%20%20%20%5C%3B%20if%20%5C%3B%5C%3B%5C%3B%20g%5E%2B%5Bt%5D%20%3E%20threshold%20%5C%3B%5C%3B%5C%3B%20or%20%5C%3B%5C%3B%5C%3B%20%20g%5E-%5Bt%5D%20%3E%20threshold%3A%20%5C%5C%0A%20%20%20%20%5C%5C%0A%20%20%20%20%5Cleft%5C%7B%20%5Cbegin%7Barray%7D%7Bl%20l%7D%0A%20%20%20%20t_%7Btalarm%7D%3Dt%20%5C%5C%0A%20%20%20%20g%5E%2B%5Bt%5D%20%3D%200%20%5C%5C%0A%20%20%20%20g%5E-%5Bt%5D%20%3D%200%0A%20%20%20%20%5Cend%7Barray%7D%20%5Cright.%0A%20%20%20%20%5Cend%7Barray%7D%20%24%24%0A%0A%20%20%20%20where%20%24%5Chat%7B%5Cmu%7D%5Bt-1%5D%24%20is%20a%20reference%20level%20for%20the%20data%2C%20an%20estimate%20of%20the%20data%20mean%20before%20the%20change.%20Implementations%20of%20the%20CUSUM%20algorithm%20differ%20in%20this%20reference%20level%2C%20and%20%60detect_cusum%60%20offers%20the%20following%20ones%20(parameter%20%60reference%60)%3A%0A%0A%20%20%20%20%7C%20%60reference%60%20%7C%20%24%5Chat%7B%5Cmu%7D%5Bt-1%5D%24%20%7C%20Known%20as%20%7C%0A%20%20%20%20%7C---%7C---%7C---%7C%0A%20%20%20%20%7C%20%60'previous'%60%20(default)%20%7C%20the%20previous%20sample%2C%20%24x%5Bt-1%5D%24%20%7C%20detecta%200.0.5%20%7C%0A%20%20%20%20%7C%20%60'residual'%60%20%7C%20exponentially%20weighted%20mean%20of%20the%20data%20(smoothing%20factor%20%60alpha%60)%20%7C%20Gustafsson%20(2000)%20%7C%0A%20%20%20%20%7C%20%60'run_mean'%60%20%7C%20mean%20of%20all%20the%20data%20so%20far%20%7C%20Page-Hinkley%20test%20(Hinkley%201971)%20%7C%0A%20%20%20%20%7C%20%60'mean'%60%20%7C%20mean%20of%20the%20first%20%60n_baseline%60%20samples%20%7C%20classical%20CUSUM%20(Page%201954)%20%7C%0A%20%20%20%20%7C%20a%20number%20%7C%20a%20known%20reference%20level%2C%20%24%5Cmu_0%24%20%7C%20classical%20CUSUM%20(Page%201954)%20%7C%0A%0A%20%20%20%20With%20the%20previous%20sample%20as%20reference%2C%20%24s%5Bt%5D%24%20is%20the%20difference%20between%20consecutive%20samples%20and%20the%20cumulative%20sum%20is%20simply%20the%20difference%20between%20the%20current%20sample%20and%20the%20sample%20where%20the%20sum%20restarted.%20This%20form%20detects%20abrupt%20jumps%20in%20the%20data%2C%20but%20the%20evidence%20for%20a%20change%20does%20not%20accumulate%20over%20time.%20With%20the%20other%20references%2C%20the%20deviations%20from%20the%20level%20before%20the%20change%20accumulate%2C%20and%20a%20small%20but%20sustained%20change%20can%20be%20detected.%20After%20a%20change%20is%20detected%2C%20the%20estimated%20references%20(%60'residual'%60%2C%20%60'run_mean'%60%2C%20and%20%60'mean'%60)%20restart%20from%20the%20data%20after%20the%20alarm.%0A%0A%20%20%20%20There%20are%20other%20implementations%20of%20the%20CUSUM%20algorithm%3B%20for%20example%2C%20the%20sum%20term%20(%24s%5Bt%5D%24%20above)%20can%20be%20normalized%20by%20the%20data%20variance%2C%20or%20it%20can%20be%20squared%20for%20detecting%20both%20variance%20and%20parameter%20changes%2C%20etc.%0A%0A%20%20%20%20For%20the%20CUSUM%20algorithm%20to%20work%20properly%2C%20it%20depends%20on%20tuning%20the%20parameters%20%24threshold%24%20and%20%24drift%24%20to%20what%20is%20meant%20by%20a%20change%20in%20the%20data.%20According%20to%20Gustafsson%20(2000)%2C%20this%20tuning%20can%20be%20performed%20following%20these%20steps%3A%0A%0A%20%20%20%20-%20Start%20with%20a%20very%20large%20%24threshold%24.%0A%20%20%20%20-%20Choose%20%24drift%24%20to%20one%20half%20of%20the%20expected%20change%2C%20or%20adjust%20%24drift%24%20such%20that%20%24g%24%20%3D%200%20more%20than%2050%25%20of%20the%20time.%0A%20%20%20%20-%20Then%20set%20the%20%24threshold%24%20so%20the%20required%20number%20of%20false%20alarms%20(this%20can%20be%20done%20automatically)%20or%20delay%20for%20detection%20is%20obtained.%0A%20%20%20%20-%20If%20faster%20detection%20is%20sought%2C%20try%20to%20decrease%20%24drift%24.%0A%20%20%20%20-%20If%20fewer%20false%20alarms%20are%20wanted%2C%20try%20to%20increase%20%24drift%24.%0A%20%20%20%20-%20If%20there%20is%20a%20subset%20of%20the%20change%20times%20that%20does%20not%20make%20sense%2C%20try%20to%20increase%20%24drift%24.%0A%0A%20%20%20%20The%20function%20%60detect_cusum.py%60%20(%5Bsource%20code%5D(https%3A%2F%2Fgithub.com%2Fdemotu%2Fdetecta%2Fblob%2Fmaster%2Fdetecta%2Fdetect_cusum.py))%20implements%20the%20CUSUM%20algorithm%20and%20a%20procedure%20to%20calculate%20the%20ending%20of%20the%20detected%20change.%20The%20function%20signature%20is%3A%0A%20%20%20%20%60%60%60python%0A%20%20%20%20ta%2C%20tai%2C%20taf%2C%20amp%20%3D%20detect_cusum(x%2C%20threshold%3D1%2C%20drift%3D0%2C%20ending%3DFalse%2C%20show%3DTrue%2C%20ax%3DNone%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%20reference%3D'previous'%2C%20alpha%3D0.05%2C%20n_baseline%3DNone)%0A%20%20%20%20%60%60%60%0A%20%20%20%20The%20ending%20of%20each%20change%20(%60taf%60%2C%20when%20%60ending%3DTrue%60)%20is%20estimated%20by%20running%20the%20CUSUM%20algorithm%20backwards%20in%20time%2C%20from%20the%20beginning%20of%20the%20next%20change%20to%20the%20ending%20of%20the%20previous%20one%2C%20and%20the%20amplitude%20of%20the%20change%20(%60amp%60)%20is%20the%20difference%20between%20the%20mean%20of%20the%20data%20after%20and%20before%20the%20change.%0A%20%20%20%20Let's%20see%20how%20to%20use%20%60detect_cusum.py%60%3B%20first%20let's%20import%20the%20necessary%20Python%20libraries%20and%20configure%20the%20environment.%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%20Installation%0A%0A%20%20%20%20%60%60%60bash%0A%20%20%20%20pip%20install%20%22detecta%5Bplot%5D%22%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20Or%0A%0A%20%20%20%20%60%60%60bash%0A%20%20%20%20conda%20install%20-c%20duartexyz%20detecta%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20To%20run%20this%20%5Bmarimo%5D(https%3A%2F%2Fmarimo.io)%20notebook%20in%20an%20isolated%20environment%20with%20all%20its%20dependencies%3A%0A%0A%20%20%20%20%60%60%60bash%0A%20%20%20%20uvx%20marimo%20edit%20--sandbox%20detect_cusum.py%0A%20%20%20%20%60%60%60%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%20timeit%0A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20pyversions%0A%0A%20%20%20%20from%20detecta%20import%20detect_cusum%0A%0A%20%20%20%20return%20detect_cusum%2C%20mo%2C%20np%2C%20pyversions%2C%20timeit%0A%0A%0A%40app.cell%0Adef%20_(pyversions)%3A%0A%20%20%20%20_info%20%3D%20pyversions.versions()%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%20Examples%0A%0A%20%20%20%20A%20ramp%20change%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_cusum%2C%20np)%3A%0A%20%20%20%20_rng%20%3D%20np.random.default_rng(42)%0A%20%20%20%20_x%20%3D%20_rng.standard_normal(300)%2F5%0A%20%20%20%20_x%5B100%3A200%5D%20%2B%3D%20np.arange(0%2C%204%2C%204%2F100)%0A%20%20%20%20_ta%2C%20_tai%2C%20_taf%2C%20_amp%20%3D%20detect_cusum(_x%2C%202%2C%20.02%2C%20True%2C%20True)%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%20A%20step%20change%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_cusum%2C%20np)%3A%0A%20%20%20%20_rng%20%3D%20np.random.default_rng(42)%0A%20%20%20%20_x%20%3D%20_rng.standard_normal(300)%0A%20%20%20%20_x%5B100%3A200%5D%20%2B%3D%206%0A%20%20%20%20detect_cusum(_x%2C%204%2C%201.5%2C%20True%2C%20True)%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%20A%20sinusoid%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_cusum%2C%20np)%3A%0A%20%20%20%20_x%20%3D%202*np.sin(2*np.pi*np.arange(0%2C%203%2C%20.01))%0A%20%20%20%20_ta%2C%20_tai%2C%20_taf%2C%20_amp%20%3D%20detect_cusum(_x%2C%201%2C%20.05%2C%20True%2C%20True)%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%20Reference%20level%0A%0A%20%20%20%20Let's%20compare%20the%20references%20on%20data%20with%20a%20small%20but%20sustained%20change%3A%20noise%20with%20standard%20deviation%20of%201%20and%20a%20change%20of%201.5%20in%20the%20mean%20between%20samples%20200%20and%20400.%20Following%20Gustafsson's%20tuning%20steps%2C%20%60drift%60%20is%20one%20half%20of%20the%20expected%20change%20(0.75)%2C%20and%20%60threshold%60%20is%20large%20enough%20to%20avoid%20false%20alarms%20(8)%3A%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_rng%20%3D%20np.random.default_rng(42)%0A%20%20%20%20x_shift%20%3D%20_rng.normal(0%2C%201%2C%20600)%0A%20%20%20%20x_shift%5B200%3A400%5D%20%2B%3D%201.5%0A%20%20%20%20return%20(x_shift%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%60reference%3D'previous'%60%20(the%20default)%3A%20the%20cumulative%20sum%20of%20the%20differences%20between%20consecutive%20samples%20is%20just%20the%20difference%20between%20the%20current%20sample%20and%20the%20sample%20where%20the%20sum%20restarted%2C%20which%20never%20exceeds%20the%20threshold%20here%3B%20the%20change%20is%20not%20detected%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_cusum%2C%20x_shift)%3A%0A%20%20%20%20detect_cusum(x_shift%2C%208%2C%20.75%2C%20True%2C%20True%2C%20reference%3D'previous')%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%60reference%3D'mean'%60%20(classical%20CUSUM)%3A%20the%20reference%20is%20the%20mean%20of%20the%20first%20%60n_baseline%60%20samples%20(by%20default%2C%2010%25%20of%20the%20data)%2C%20and%20it%20is%20estimated%20again%20after%20each%20alarm.%20Both%20changes%20are%20detected%2C%20with%20their%20beginning%2C%20ending%2C%20and%20amplitude%20(the%20reference%20level%20is%20shown%20in%20orange)%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_cusum%2C%20x_shift)%3A%0A%20%20%20%20detect_cusum(x_shift%2C%208%2C%20.75%2C%20True%2C%20True%2C%20reference%3D'mean')%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%60reference%3D'run_mean'%60%20(as%20in%20the%20Page-Hinkley%20test)%3A%20the%20reference%20is%20the%20mean%20of%20all%20the%20data%20since%20the%20last%20alarm%2C%20which%20does%20not%20require%20a%20baseline%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_cusum%2C%20x_shift)%3A%0A%20%20%20%20detect_cusum(x_shift%2C%208%2C%20.75%2C%20True%2C%20True%2C%20reference%3D'run_mean')%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%60reference%3D'residual'%60%20(Gustafsson%2C%202000)%3A%20the%20reference%20is%20an%20exponentially%20weighted%20mean%20of%20the%20data%2C%20which%20follows%20slow%20variations%20in%20the%20data%20level.%20The%20smoothing%20factor%20%60alpha%60%20sets%20how%20fast%20the%20reference%20follows%20the%20data%20(it%20averages%20about%20the%20last%201%2F%60alpha%60%20samples)%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_cusum%2C%20x_shift)%3A%0A%20%20%20%20detect_cusum(x_shift%2C%208%2C%20.75%2C%20True%2C%20True%2C%20reference%3D'residual'%2C%20alpha%3D.01)%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%20If%20the%20reference%20follows%20the%20data%20too%20fast%20(larger%20%60alpha%60)%2C%20the%20deviation%20from%20the%20reference%20vanishes%20before%20the%20evidence%20for%20the%20change%20accumulates%2C%20and%20the%20first%20change%20is%20not%20detected%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_cusum%2C%20x_shift)%3A%0A%20%20%20%20detect_cusum(x_shift%2C%208%2C%20.75%2C%20True%2C%20True%2C%20reference%3D'residual'%2C%20alpha%3D.05)%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%20A%20number%20as%20%60reference%60%20is%20a%20known%20level%20(%24%5Cmu_0%24)%20that%20is%20kept%20fixed%2C%20as%20in%20quality%20control%2C%20where%20the%20process%20is%20corrected%20after%20each%20alarm.%20Here%2C%20the%20data%20are%20not%20corrected%20after%20the%20change%2C%20and%20the%20alarms%20repeat%20while%20the%20data%20stay%20away%20from%20the%20reference%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_cusum%2C%20x_shift)%3A%0A%20%20%20%20detect_cusum(x_shift%2C%208%2C%20.75%2C%20False%2C%20True%2C%20reference%3D0)%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%20Ending%20of%20the%20change%0A%0A%20%20%20%20Data%20with%20steps%20and%20a%20ramp%20(between%20samples%20300%20and%20320)%20of%204%20in%20noise%20with%20standard%20deviation%20of%201.%20The%20beginning%20and%20ending%20of%20a%20step%20are%20found%20within%20one%20sample%3B%20the%20beginning%20and%20ending%20of%20the%20ramp%20are%20found%20where%20its%20deviation%20exceeds%20the%20%60drift%60%2C%20a%20few%20samples%20inside%20the%20ramp%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_cusum%2C%20np)%3A%0A%20%20%20%20_rng%20%3D%20np.random.default_rng(3)%0A%20%20%20%20_x%20%3D%20_rng.normal(0%2C%201%2C%20600)%0A%20%20%20%20_x%5B150%3A%5D%20%2B%3D%204%0A%20%20%20%20_x%5B300%3A320%5D%20-%3D%20np.linspace(4%2F20%2C%204%2C%2020)%0A%20%20%20%20_x%5B320%3A%5D%20-%3D%204%0A%20%20%20%20_x%5B450%3A%5D%20%2B%3D%204%0A%20%20%20%20_ta%2C%20_tai%2C%20_taf%2C%20_amp%20%3D%20detect_cusum(_x%2C%206%2C%202%2C%20True%2C%20True%2C%20reference%3D'mean')%0A%20%20%20%20print('Beginning%3A'%2C%20_tai%2C%20'%5CnEnding%3A%20%20%20'%2C%20_taf%2C%20'%5CnAmplitude%3A'%2C%20_amp.round(2))%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%20Interactive%20example%0A%0A%20%20%20%20Choose%20the%20data%20and%20the%20reference%2C%20tune%20%60threshold%60%20and%20%60drift%60%20following%20the%20steps%20above%2C%20and%20see%20the%20detected%20changes%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20signal%20%3D%20mo.ui.dropdown(%5B'large%20step'%2C%20'small%20shift'%2C%20'steps%20and%20ramp'%5D%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%20value%3D'large%20step'%2C%20label%3D'data')%0A%20%20%20%20reference%20%3D%20mo.ui.dropdown(%5B'previous'%2C%20'mean'%2C%20'run_mean'%2C%20'residual'%5D%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%20value%3D'previous'%2C%20label%3D'reference')%0A%20%20%20%20threshold%20%3D%20mo.ui.slider(0.5%2C%2015%2C%20step%3D0.5%2C%20value%3D3%2C%20label%3D'threshold'%2C%20show_value%3DTrue)%0A%20%20%20%20drift%20%3D%20mo.ui.slider(0%2C%203%2C%20step%3D0.05%2C%20value%3D1.5%2C%20label%3D'drift'%2C%20show_value%3DTrue)%0A%20%20%20%20alpha%20%3D%20mo.ui.slider(0.005%2C%201%2C%20step%3D0.005%2C%20value%3D0.05%2C%20label%3D'alpha'%2C%20show_value%3DTrue)%0A%20%20%20%20n_baseline%20%3D%20mo.ui.slider(5%2C%20200%2C%20value%3D30%2C%20label%3D'n_baseline'%2C%20show_value%3DTrue)%0A%20%20%20%20ending%20%3D%20mo.ui.checkbox(value%3DTrue%2C%20label%3D'ending')%0A%20%20%20%20mo.hstack(%5Bmo.vstack(%5Bsignal%2C%20reference%2C%20ending%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.vstack(%5Bthreshold%2C%20drift%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.vstack(%5Balpha%2C%20n_baseline%5D)%5D%2C%20justify%3D'start'%2C%20gap%3D4)%0A%20%20%20%20return%20alpha%2C%20drift%2C%20ending%2C%20n_baseline%2C%20reference%2C%20signal%2C%20threshold%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20alpha%2C%0A%20%20%20%20detect_cusum%2C%0A%20%20%20%20drift%2C%0A%20%20%20%20ending%2C%0A%20%20%20%20n_baseline%2C%0A%20%20%20%20np%2C%0A%20%20%20%20reference%2C%0A%20%20%20%20signal%2C%0A%20%20%20%20threshold%2C%0A)%3A%0A%20%20%20%20_rng%20%3D%20np.random.default_rng(42)%0A%20%20%20%20if%20signal.value%20%3D%3D%20'large%20step'%3A%0A%20%20%20%20%20%20%20%20_x%20%3D%20_rng.normal(0%2C%201%2C%20300)%0A%20%20%20%20%20%20%20%20_x%5B100%3A200%5D%20%2B%3D%206%0A%20%20%20%20elif%20signal.value%20%3D%3D%20'small%20shift'%3A%0A%20%20%20%20%20%20%20%20_x%20%3D%20_rng.normal(0%2C%201%2C%20600)%0A%20%20%20%20%20%20%20%20_x%5B200%3A400%5D%20%2B%3D%201.5%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20_x%20%3D%20_rng.normal(0%2C%201%2C%20600)%0A%20%20%20%20%20%20%20%20_x%5B150%3A%5D%20%2B%3D%204%0A%20%20%20%20%20%20%20%20_x%5B300%3A320%5D%20-%3D%20np.linspace(4%2F20%2C%204%2C%2020)%0A%20%20%20%20%20%20%20%20_x%5B320%3A%5D%20-%3D%204%0A%20%20%20%20%20%20%20%20_x%5B450%3A%5D%20%2B%3D%204%0A%20%20%20%20detect_cusum(_x%2C%20threshold.value%2C%20drift.value%2C%20ending.value%2C%20True%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20reference%3Dreference.value%2C%20alpha%3Dalpha.value%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20n_baseline%3Dn_baseline.value)%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%20performance%0A%0A%20%20%20%20Here%20is%20a%20poor%20test%20of%20the%20%60detect_cusum.py%60%20performance%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(detect_cusum%2C%20np%2C%20timeit)%3A%0A%20%20%20%20_rng%20%3D%20np.random.default_rng(42)%0A%20%20%20%20_x%20%3D%20_rng.standard_normal(10000)%0A%20%20%20%20_x%5B400%3A600%5D%20%2B%3D%206%0A%20%20%20%20print('Detection%20of%20onset%20(data%20size%20%3D%20%25d)%3A'%20%25%20_x.size)%0A%20%20%20%20_number%20%3D%2010%0A%20%20%20%20_t%20%3D%20min(timeit.repeat(lambda%3A%20detect_cusum(_x%2C%204%2C%201.5%2C%20True%2C%20False)%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%20number%3D_number%2C%20repeat%3D5))%20%2F%20_number%0A%20%20%20%20print('%25.3f%20ms%20per%20loop'%20%25%20(1e3*_t))%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%20References%0A%0A%20%20%20%20-%20Mich%C3%A8le%20Basseville%20and%20Igor%20V.%20Nikiforov%20(1993).%20%5BDetection%20of%20Abrupt%20Changes%3A%20Theory%20and%20Application%5D(http%3A%2F%2Fbooks.google.com.br%2Fbooks%2Fabout%2FDetection_of_abrupt_changes.html%3Fid%3DVu5SAAAAMAAJ).%20Prentice-Hall.%0A%20%20%20%20-%20Fredrik%20Gustafsson%20(2000)%20%5BAdaptive%20Filtering%20and%20Change%20Detection%5D(http%3A%2F%2Fbooks.google.com.br%2Fbooks%3Fid%3DcyNTAAAAMAAJ).%20Wiley.%0A%20%20%20%20-%20David%20V.%20Hinkley%20(1971)%20%5BInference%20about%20the%20change-point%20from%20cumulative%20sum%20tests%5D(https%3A%2F%2Fdoi.org%2F10.1093%2Fbiomet%2F58.3.509).%20Biometrika%2C%2058%2C%20509-523.%0A%20%20%20%20-%20E.%20S.%20Page%20(1954)%20%5BContinuous%20inspection%20schemes%5D(https%3A%2F%2Fdoi.org%2F10.1093%2Fbiomet%2F41.1-2.100).%20Biometrika%2C%2041%2C%20100-115.%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
873a345036a5eecfa269acd8538cbe76