test_distributions.py 409 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483
  1. """
  2. Test functions for stats module
  3. """
  4. import warnings
  5. import re
  6. import sys
  7. import pickle
  8. import threading
  9. from pathlib import Path
  10. import os
  11. import json
  12. import platform
  13. from numpy.testing import (assert_equal, assert_array_equal,
  14. assert_almost_equal, assert_array_almost_equal,
  15. assert_allclose, assert_,
  16. assert_array_less, assert_array_max_ulp)
  17. import pytest
  18. from pytest import raises as assert_raises
  19. import numpy as np
  20. from numpy import typecodes, array
  21. from numpy.lib.recfunctions import rec_append_fields
  22. from scipy import special
  23. from scipy._lib._util import check_random_state
  24. from scipy.integrate import (IntegrationWarning, quad, trapezoid,
  25. cumulative_trapezoid)
  26. import scipy.stats as stats
  27. from scipy.stats._distn_infrastructure import argsreduce
  28. from scipy.stats._constants import _XMAX
  29. import scipy.stats.distributions
  30. from scipy.special import xlogy, polygamma, entr
  31. from scipy.stats._distr_params import distcont, invdistcont
  32. from .test_discrete_basic import distdiscrete, invdistdiscrete
  33. from scipy.stats._continuous_distns import FitDataError, _argus_phi
  34. from scipy.optimize import root, fmin, differential_evolution
  35. from itertools import product
  36. # python -OO strips docstrings
  37. DOCSTRINGS_STRIPPED = sys.flags.optimize > 1
  38. # Failing on macOS 11, Intel CPUs. See gh-14901
  39. MACOS_INTEL = (sys.platform == 'darwin') and (platform.machine() == 'x86_64')
  40. # distributions to skip while testing the fix for the support method
  41. # introduced in gh-13294. These distributions are skipped as they
  42. # always return a non-nan support for every parametrization.
  43. skip_test_support_gh13294_regression = ['tukeylambda', 'pearson3']
  44. def _assert_hasattr(a, b, msg=None):
  45. if msg is None:
  46. msg = f'{a} does not have attribute {b}'
  47. assert_(hasattr(a, b), msg=msg)
  48. def test_api_regression():
  49. # https://github.com/scipy/scipy/issues/3802
  50. _assert_hasattr(scipy.stats.distributions, 'f_gen')
  51. def test_distributions_submodule():
  52. actual = set(scipy.stats.distributions.__all__)
  53. continuous = [dist[0] for dist in distcont] # continuous dist names
  54. discrete = [dist[0] for dist in distdiscrete] # discrete dist names
  55. other = ['rv_discrete', 'rv_continuous', 'rv_histogram',
  56. 'entropy']
  57. expected = continuous + discrete + other
  58. # need to remove, e.g.,
  59. # <scipy.stats._continuous_distns.trapezoid_gen at 0x1df83bbc688>
  60. expected = set(filter(lambda s: not str(s).startswith('<'), expected))
  61. assert actual == expected
  62. class TestVonMises:
  63. def setup_method(self):
  64. self.rng = np.random.default_rng(6320571663)
  65. @pytest.mark.parametrize('k', [0.1, 1, 101])
  66. @pytest.mark.parametrize('x', [0, 1, np.pi, 10, 100])
  67. def test_vonmises_periodic(self, k, x):
  68. def check_vonmises_pdf_periodic(k, L, s, x):
  69. vm = stats.vonmises(k, loc=L, scale=s)
  70. assert_almost_equal(vm.pdf(x), vm.pdf(x % (2 * np.pi * s)))
  71. def check_vonmises_cdf_periodic(k, L, s, x):
  72. vm = stats.vonmises(k, loc=L, scale=s)
  73. assert_almost_equal(vm.cdf(x) % 1,
  74. vm.cdf(x % (2 * np.pi * s)) % 1)
  75. check_vonmises_pdf_periodic(k, 0, 1, x)
  76. check_vonmises_pdf_periodic(k, 1, 1, x)
  77. check_vonmises_pdf_periodic(k, 0, 10, x)
  78. check_vonmises_cdf_periodic(k, 0, 1, x)
  79. check_vonmises_cdf_periodic(k, 1, 1, x)
  80. check_vonmises_cdf_periodic(k, 0, 10, x)
  81. def test_vonmises_line_support(self):
  82. assert_equal(stats.vonmises_line.a, -np.pi)
  83. assert_equal(stats.vonmises_line.b, np.pi)
  84. def test_vonmises_numerical(self):
  85. vm = stats.vonmises(800)
  86. assert_almost_equal(vm.cdf(0), 0.5)
  87. # Expected values of the vonmises PDF were computed using
  88. # mpmath with 50 digits of precision:
  89. #
  90. # def vmpdf_mp(x, kappa):
  91. # x = mpmath.mpf(x)
  92. # kappa = mpmath.mpf(kappa)
  93. # num = mpmath.exp(kappa*mpmath.cos(x))
  94. # den = 2 * mpmath.pi * mpmath.besseli(0, kappa)
  95. # return num/den
  96. @pytest.mark.parametrize('x, kappa, expected_pdf',
  97. [(0.1, 0.01, 0.16074242744907072),
  98. (0.1, 25.0, 1.7515464099118245),
  99. (0.1, 800, 0.2073272544458798),
  100. (2.0, 0.01, 0.15849003875385817),
  101. (2.0, 25.0, 8.356882934278192e-16),
  102. (2.0, 800, 0.0)])
  103. def test_vonmises_pdf(self, x, kappa, expected_pdf):
  104. pdf = stats.vonmises.pdf(x, kappa)
  105. assert_allclose(pdf, expected_pdf, rtol=1e-15)
  106. # Expected values of the vonmises entropy were computed using
  107. # mpmath with 50 digits of precision:
  108. #
  109. # def vonmises_entropy(kappa):
  110. # kappa = mpmath.mpf(kappa)
  111. # return (-kappa * mpmath.besseli(1, kappa) /
  112. # mpmath.besseli(0, kappa) + mpmath.log(2 * mpmath.pi *
  113. # mpmath.besseli(0, kappa)))
  114. # >>> float(vonmises_entropy(kappa))
  115. @pytest.mark.parametrize('kappa, expected_entropy',
  116. [(1, 1.6274014590199897),
  117. (5, 0.6756431570114528),
  118. (100, -0.8811275441649473),
  119. (1000, -2.03468891852547),
  120. (2000, -2.3813876496587847)])
  121. def test_vonmises_entropy(self, kappa, expected_entropy):
  122. entropy = stats.vonmises.entropy(kappa)
  123. assert_allclose(entropy, expected_entropy, rtol=1e-13)
  124. def test_vonmises_rvs_gh4598(self):
  125. # check that random variates wrap around as discussed in gh-4598
  126. seed = 30899520
  127. rng1 = np.random.default_rng(seed)
  128. rng2 = np.random.default_rng(seed)
  129. rng3 = np.random.default_rng(seed)
  130. rvs1 = stats.vonmises(1, loc=0, scale=1).rvs(random_state=rng1)
  131. rvs2 = stats.vonmises(1, loc=2*np.pi, scale=1).rvs(random_state=rng2)
  132. rvs3 = stats.vonmises(1, loc=0,
  133. scale=(2*np.pi/abs(rvs1)+1)).rvs(random_state=rng3)
  134. assert_allclose(rvs1, rvs2, atol=1e-15)
  135. assert_allclose(rvs1, rvs3, atol=1e-15)
  136. # Expected values of the vonmises LOGPDF were computed
  137. # using wolfram alpha:
  138. # kappa * cos(x) - log(2*pi*I0(kappa))
  139. @pytest.mark.parametrize('x, kappa, expected_logpdf',
  140. [(0.1, 0.01, -1.8279520246003170),
  141. (0.1, 25.0, 0.5604990605420549),
  142. (0.1, 800, -1.5734567947337514),
  143. (2.0, 0.01, -1.8420635346185686),
  144. (2.0, 25.0, -34.7182759850871489),
  145. (2.0, 800, -1130.4942582548682739)])
  146. def test_vonmises_logpdf(self, x, kappa, expected_logpdf):
  147. logpdf = stats.vonmises.logpdf(x, kappa)
  148. assert_allclose(logpdf, expected_logpdf, rtol=1e-15)
  149. def test_vonmises_expect(self):
  150. """
  151. Test that the vonmises expectation values are
  152. computed correctly. This test checks that the
  153. numeric integration estimates the correct normalization
  154. (1) and mean angle (loc). These expectations are
  155. independent of the chosen 2pi interval.
  156. """
  157. rng = np.random.default_rng(6762668991392531563)
  158. loc, kappa, lb = rng.random(3) * 10
  159. res = stats.vonmises(loc=loc, kappa=kappa).expect(lambda x: 1)
  160. assert_allclose(res, 1)
  161. assert np.issubdtype(res.dtype, np.floating)
  162. bounds = lb, lb + 2 * np.pi
  163. res = stats.vonmises(loc=loc, kappa=kappa).expect(lambda x: 1, *bounds)
  164. assert_allclose(res, 1)
  165. assert np.issubdtype(res.dtype, np.floating)
  166. bounds = lb, lb + 2 * np.pi
  167. res = stats.vonmises(loc=loc, kappa=kappa).expect(lambda x: np.exp(1j*x),
  168. *bounds, complex_func=1)
  169. assert_allclose(np.angle(res), loc % (2*np.pi))
  170. assert np.issubdtype(res.dtype, np.complexfloating)
  171. @pytest.mark.xslow
  172. @pytest.mark.parametrize("rvs_loc", [0, 2])
  173. @pytest.mark.parametrize("rvs_shape", [1, 100, 1e8])
  174. @pytest.mark.parametrize('fix_loc', [True, False])
  175. @pytest.mark.parametrize('fix_shape', [True, False])
  176. def test_fit_MLE_comp_optimizer(self, rvs_loc, rvs_shape,
  177. fix_loc, fix_shape):
  178. if fix_shape and fix_loc:
  179. pytest.skip("Nothing to fit.")
  180. rng = np.random.default_rng(6762668991392531563)
  181. data = stats.vonmises.rvs(rvs_shape, size=1000, loc=rvs_loc,
  182. random_state=rng)
  183. kwds = {'fscale': 1}
  184. if fix_loc:
  185. kwds['floc'] = rvs_loc
  186. if fix_shape:
  187. kwds['f0'] = rvs_shape
  188. _assert_less_or_close_loglike(stats.vonmises, data,
  189. stats.vonmises.nnlf, **kwds)
  190. @pytest.mark.slow
  191. def test_vonmises_fit_bad_floc(self):
  192. data = [-0.92923506, -0.32498224, 0.13054989, -0.97252014, 2.79658071,
  193. -0.89110948, 1.22520295, 1.44398065, 2.49163859, 1.50315096,
  194. 3.05437696, -2.73126329, -3.06272048, 1.64647173, 1.94509247,
  195. -1.14328023, 0.8499056, 2.36714682, -1.6823179, -0.88359996]
  196. data = np.asarray(data)
  197. loc = -0.5 * np.pi
  198. kappa_fit, loc_fit, scale_fit = stats.vonmises.fit(data, floc=loc)
  199. assert kappa_fit == np.finfo(float).tiny
  200. _assert_less_or_close_loglike(stats.vonmises, data,
  201. stats.vonmises.nnlf, fscale=1, floc=loc)
  202. @pytest.mark.parametrize('sign', [-1, 1])
  203. def test_vonmises_fit_unwrapped_data(self, sign):
  204. rng = np.random.default_rng(6762668991392531563)
  205. data = stats.vonmises(loc=sign*0.5*np.pi, kappa=10).rvs(100000,
  206. random_state=rng)
  207. shifted_data = data + 4*np.pi
  208. kappa_fit, loc_fit, scale_fit = stats.vonmises.fit(data)
  209. kappa_fit_shifted, loc_fit_shifted, _ = stats.vonmises.fit(shifted_data)
  210. assert_allclose(loc_fit, loc_fit_shifted)
  211. assert_allclose(kappa_fit, kappa_fit_shifted)
  212. assert scale_fit == 1
  213. assert -np.pi < loc_fit < np.pi
  214. def test_vonmises_kappa_0_gh18166(self):
  215. # Check that kappa = 0 is supported.
  216. dist = stats.vonmises(0)
  217. assert_allclose(dist.pdf(0), 1 / (2 * np.pi), rtol=1e-15)
  218. assert_allclose(dist.cdf(np.pi/2), 0.75, rtol=1e-15)
  219. assert_allclose(dist.sf(-np.pi/2), 0.75, rtol=1e-15)
  220. assert_allclose(dist.ppf(0.9), np.pi*0.8, rtol=1e-15)
  221. assert_allclose(dist.mean(), 0, atol=1e-15)
  222. assert_allclose(dist.expect(), 0, atol=1e-15)
  223. assert np.all(np.abs(dist.rvs(size=10, random_state=self.rng)) <= np.pi)
  224. def test_vonmises_fit_equal_data(self):
  225. # When all data are equal, expect kappa = 1e16.
  226. kappa, loc, scale = stats.vonmises.fit([0])
  227. assert kappa == 1e16 and loc == 0 and scale == 1
  228. def test_vonmises_fit_bounds(self):
  229. # For certain input data, the root bracket is violated numerically.
  230. # Test that this situation is handled. The input data below are
  231. # crafted to trigger the bound violation for the current choice of
  232. # bounds and the specific way the bounds and the objective function
  233. # are computed.
  234. # Test that no exception is raised when the lower bound is violated.
  235. scipy.stats.vonmises.fit([0, 3.7e-08], floc=0)
  236. # Test that no exception is raised when the upper bound is violated.
  237. scipy.stats.vonmises.fit([np.pi/2*(1-4.86e-9)], floc=0)
  238. def _assert_less_or_close_loglike(dist, data, func=None, maybe_identical=False,
  239. **kwds):
  240. """
  241. This utility function checks that the negative log-likelihood function
  242. (or `func`) of the result computed using dist.fit() is less than or equal
  243. to the result computed using the generic fit method. Because of
  244. normal numerical imprecision, the "equality" check is made using
  245. `np.allclose` with a relative tolerance of 1e-15.
  246. """
  247. if func is None:
  248. func = dist.nnlf
  249. mle_analytical = dist.fit(data, **kwds)
  250. numerical_opt = super(type(dist), dist).fit(data, **kwds)
  251. # Sanity check that the analytical MLE is actually executed.
  252. # Due to floating point arithmetic, the generic MLE is unlikely
  253. # to produce the exact same result as the analytical MLE.
  254. if not maybe_identical:
  255. assert np.any(mle_analytical != numerical_opt)
  256. ll_mle_analytical = func(mle_analytical, data)
  257. ll_numerical_opt = func(numerical_opt, data)
  258. assert (ll_mle_analytical <= ll_numerical_opt or
  259. np.allclose(ll_mle_analytical, ll_numerical_opt, rtol=1e-15))
  260. # Ideally we'd check that shapes are correctly fixed, too, but that is
  261. # complicated by the many ways of fixing them (e.g. f0, fix_a, fa).
  262. if 'floc' in kwds:
  263. assert mle_analytical[-2] == kwds['floc']
  264. if 'fscale' in kwds:
  265. assert mle_analytical[-1] == kwds['fscale']
  266. def assert_fit_warnings(dist):
  267. param = ['floc', 'fscale']
  268. if dist.shapes:
  269. nshapes = len(dist.shapes.split(","))
  270. param += ['f0', 'f1', 'f2'][:nshapes]
  271. all_fixed = dict(zip(param, np.arange(len(param))))
  272. data = [1, 2, 3]
  273. with pytest.raises(RuntimeError,
  274. match="All parameters fixed. There is nothing "
  275. "to optimize."):
  276. dist.fit(data, **all_fixed)
  277. with pytest.raises(ValueError,
  278. match="The data contains non-finite values"):
  279. dist.fit([np.nan])
  280. with pytest.raises(ValueError,
  281. match="The data contains non-finite values"):
  282. dist.fit([np.inf])
  283. with pytest.raises(TypeError, match="Unknown keyword arguments:"):
  284. dist.fit(data, extra_keyword=2)
  285. with pytest.raises(TypeError, match="Too many positional arguments."):
  286. dist.fit(data, *[1]*(len(param) - 1))
  287. @pytest.mark.parametrize('dist',
  288. ['alpha', 'betaprime',
  289. 'fatiguelife', 'invgamma', 'invgauss', 'invweibull',
  290. 'johnsonsb', 'levy', 'levy_l', 'lognorm', 'gibrat',
  291. 'powerlognorm', 'rayleigh', 'wald'])
  292. def test_support(dist):
  293. """gh-6235"""
  294. dct = dict(distcont)
  295. args = dct[dist]
  296. dist = getattr(stats, dist)
  297. assert_almost_equal(dist.pdf(dist.a, *args), 0)
  298. assert_equal(dist.logpdf(dist.a, *args), -np.inf)
  299. assert_almost_equal(dist.pdf(dist.b, *args), 0)
  300. assert_equal(dist.logpdf(dist.b, *args), -np.inf)
  301. class TestRandInt:
  302. def setup_method(self):
  303. self.rng = np.random.default_rng(8826485737)
  304. def test_rvs(self):
  305. vals = stats.randint.rvs(5, 30, size=100, random_state=self.rng)
  306. assert_(np.all(vals < 30) & np.all(vals >= 5))
  307. assert_(len(vals) == 100)
  308. vals = stats.randint.rvs(5, 30, size=(2, 50), random_state=self.rng)
  309. assert_(np.shape(vals) == (2, 50))
  310. assert_(vals.dtype.char in typecodes['AllInteger'])
  311. val = stats.randint.rvs(15, 46, random_state=self.rng)
  312. assert_((val >= 15) & (val < 46))
  313. assert_(isinstance(val, np.ScalarType), msg=repr(type(val)))
  314. val = stats.randint(15, 46).rvs(3, random_state=self.rng)
  315. assert_(val.dtype.char in typecodes['AllInteger'])
  316. def test_pdf(self):
  317. k = np.r_[0:36]
  318. out = np.where((k >= 5) & (k < 30), 1.0/(30-5), 0)
  319. vals = stats.randint.pmf(k, 5, 30)
  320. assert_array_almost_equal(vals, out)
  321. def test_cdf(self):
  322. x = np.linspace(0, 36, 100)
  323. k = np.floor(x)
  324. out = np.select([k >= 30, k >= 5], [1.0, (k-5.0+1)/(30-5.0)], 0)
  325. vals = stats.randint.cdf(x, 5, 30)
  326. assert_array_almost_equal(vals, out, decimal=12)
  327. class TestBinom:
  328. def setup_method(self):
  329. self.rng = np.random.default_rng(1778595878)
  330. def test_rvs(self):
  331. vals = stats.binom.rvs(10, 0.75, size=(2, 50), random_state=self.rng)
  332. assert_(np.all(vals >= 0) & np.all(vals <= 10))
  333. assert_(np.shape(vals) == (2, 50))
  334. assert_(vals.dtype.char in typecodes['AllInteger'])
  335. val = stats.binom.rvs(10, 0.75, random_state=self.rng)
  336. assert_(isinstance(val, int))
  337. val = stats.binom(10, 0.75).rvs(3, random_state=self.rng)
  338. assert_(isinstance(val, np.ndarray))
  339. assert_(val.dtype.char in typecodes['AllInteger'])
  340. def test_pmf(self):
  341. # regression test for Ticket #1842
  342. vals1 = stats.binom.pmf(100, 100, 1)
  343. vals2 = stats.binom.pmf(0, 100, 0)
  344. assert_allclose(vals1, 1.0, rtol=1e-15, atol=0)
  345. assert_allclose(vals2, 1.0, rtol=1e-15, atol=0)
  346. def test_entropy(self):
  347. # Basic entropy tests.
  348. b = stats.binom(2, 0.5)
  349. expected_p = np.array([0.25, 0.5, 0.25])
  350. expected_h = -sum(xlogy(expected_p, expected_p))
  351. h = b.entropy()
  352. assert_allclose(h, expected_h)
  353. b = stats.binom(2, 0.0)
  354. h = b.entropy()
  355. assert_equal(h, 0.0)
  356. b = stats.binom(2, 1.0)
  357. h = b.entropy()
  358. assert_equal(h, 0.0)
  359. def test_warns_p0(self):
  360. # no spurious warnings are generated for p=0; gh-3817
  361. with warnings.catch_warnings():
  362. warnings.simplefilter("error", RuntimeWarning)
  363. assert_equal(stats.binom(n=2, p=0).mean(), 0)
  364. assert_equal(stats.binom(n=2, p=0).std(), 0)
  365. def test_ppf_p1(self):
  366. # Check that gh-17388 is resolved: PPF == n when p = 1
  367. n = 4
  368. assert stats.binom.ppf(q=0.3, n=n, p=1.0) == n
  369. def test_pmf_poisson(self):
  370. # Check that gh-17146 is resolved: binom -> poisson
  371. n = 1541096362225563.0
  372. p = 1.0477878413173978e-18
  373. x = np.arange(3)
  374. res = stats.binom.pmf(x, n=n, p=p)
  375. ref = stats.poisson.pmf(x, n * p)
  376. assert_allclose(res, ref, atol=1e-16)
  377. def test_pmf_cdf(self):
  378. # Check that gh-17809 is resolved: binom.pmf(0) ~ binom.cdf(0)
  379. n = 25.0 * 10 ** 21
  380. p = 1.0 * 10 ** -21
  381. r = 0
  382. res = stats.binom.pmf(r, n, p)
  383. ref = stats.binom.cdf(r, n, p)
  384. assert_allclose(res, ref, atol=1e-16)
  385. def test_pmf_gh15101(self):
  386. # Check that gh-15101 is resolved (no divide warnings when p~1, n~oo)
  387. res = stats.binom.pmf(3, 2000, 0.999)
  388. assert_allclose(res, 0, atol=1e-16)
  389. class TestArcsine:
  390. def test_endpoints(self):
  391. # Regression test for gh-13697. The following calculation
  392. # should not generate a warning.
  393. p = stats.arcsine.pdf([0, 1])
  394. assert_equal(p, [np.inf, np.inf])
  395. class TestBernoulli:
  396. def setup_method(self):
  397. self.rng = np.random.default_rng(7836792223)
  398. def test_rvs(self):
  399. vals = stats.bernoulli.rvs(0.75, size=(2, 50), random_state=self.rng)
  400. assert_(np.all(vals >= 0) & np.all(vals <= 1))
  401. assert_(np.shape(vals) == (2, 50))
  402. assert_(vals.dtype.char in typecodes['AllInteger'])
  403. val = stats.bernoulli.rvs(0.75, random_state=self.rng)
  404. assert_(isinstance(val, int))
  405. val = stats.bernoulli(0.75).rvs(3, random_state=self.rng)
  406. assert_(isinstance(val, np.ndarray))
  407. assert_(val.dtype.char in typecodes['AllInteger'])
  408. def test_entropy(self):
  409. # Simple tests of entropy.
  410. b = stats.bernoulli(0.25)
  411. expected_h = -0.25*np.log(0.25) - 0.75*np.log(0.75)
  412. h = b.entropy()
  413. assert_allclose(h, expected_h)
  414. b = stats.bernoulli(0.0)
  415. h = b.entropy()
  416. assert_equal(h, 0.0)
  417. b = stats.bernoulli(1.0)
  418. h = b.entropy()
  419. assert_equal(h, 0.0)
  420. class TestBradford:
  421. # gh-6216
  422. def test_cdf_ppf(self):
  423. c = 0.1
  424. x = np.logspace(-20, -4)
  425. q = stats.bradford.cdf(x, c)
  426. xx = stats.bradford.ppf(q, c)
  427. assert_allclose(x, xx)
  428. class TestCauchy:
  429. def test_pdf_no_overflow_warning(self):
  430. # The argument is large enough that x**2 will overflow to
  431. # infinity and 1/(1 + x**2) will be 0. This should not
  432. # trigger a warning.
  433. p = stats.cauchy.pdf(1e200)
  434. assert p == 0.0
  435. # Reference values were computed with mpmath.
  436. @pytest.mark.parametrize(
  437. 'x, ref',
  438. [(0.0, -1.1447298858494002),
  439. (5e-324, -1.1447298858494002),
  440. (1e-34, -1.1447298858494002),
  441. (2.2e-16, -1.1447298858494002),
  442. (2e-8, -1.1447298858494006),
  443. (5e-4, -1.144730135849369),
  444. (0.1, -1.1546802167025683),
  445. (1.5, -2.3233848821910463),
  446. (2e18, -85.42408759475494),
  447. (1e200, -922.1787670834676),
  448. (_XMAX, -1420.7101556726175)])
  449. def test_logpdf(self, x, ref):
  450. logp = stats.cauchy.logpdf([x, -x])
  451. assert_allclose(logp, [ref, ref], rtol=1e-15)
  452. # Reference values were computed with mpmath.
  453. @pytest.mark.parametrize(
  454. 'x, ref',
  455. [(-5e15, 6.366197723675814e-17),
  456. (-5, 0.06283295818900118),
  457. (-1, 0.25),
  458. (0, 0.5),
  459. (1, 0.75),
  460. (5, 0.9371670418109989),
  461. (5e15, 0.9999999999999999)]
  462. )
  463. @pytest.mark.parametrize(
  464. 'method, sgn',
  465. [(stats.cauchy.cdf, 1),
  466. (stats.cauchy.sf, -1)]
  467. )
  468. def test_cdf_sf(self, x, ref, method, sgn):
  469. p = method(sgn*x)
  470. assert_allclose(p, ref, rtol=1e-15)
  471. # Reference values were computed with mpmath.
  472. @pytest.mark.parametrize('x, ref',
  473. [(4e250, -7.957747154594767e-252),
  474. (1e25, -3.1830988618379063e-26),
  475. (10.0, -0.03223967552667532),
  476. (0.0, -0.6931471805599453),
  477. (-10.0, -3.4506339556469654),
  478. (-7e45, -106.70696921963678),
  479. (-3e225, -520.3249880981778)])
  480. def test_logcdf_logsf(self, x, ref):
  481. logcdf = stats.cauchy.logcdf(x)
  482. assert_allclose(logcdf, ref, rtol=5e-15)
  483. logsf = stats.cauchy.logsf(-x)
  484. assert_allclose(logsf, ref, rtol=5e-15)
  485. # Reference values were computed with mpmath.
  486. @pytest.mark.parametrize(
  487. 'p, ref',
  488. [(1e-20, -3.1830988618379067e+19),
  489. (1e-9, -318309886.1837906),
  490. (0.25, -1.0),
  491. (0.50, 0.0),
  492. (0.75, 1.0),
  493. (0.999999, 318309.88617359026),
  494. (0.999999999999, 318316927901.77966)]
  495. )
  496. @pytest.mark.parametrize(
  497. 'method, sgn',
  498. [(stats.cauchy.ppf, 1),
  499. (stats.cauchy.isf, -1)])
  500. def test_ppf_isf(self, p, ref, method, sgn):
  501. x = sgn*method(p)
  502. assert_allclose(x, ref, rtol=1e-15)
  503. class TestChi:
  504. # "Exact" value of chi.sf(10, 4), as computed by Wolfram Alpha with
  505. # 1 - CDF[ChiDistribution[4], 10]
  506. CHI_SF_10_4 = 9.83662422461598e-21
  507. # "Exact" value of chi.mean(df=1000) as computed by Wolfram Alpha with
  508. # Mean[ChiDistribution[1000]]
  509. CHI_MEAN_1000 = 31.614871896980
  510. def test_sf(self):
  511. s = stats.chi.sf(10, 4)
  512. assert_allclose(s, self.CHI_SF_10_4, rtol=1e-15)
  513. def test_isf(self):
  514. x = stats.chi.isf(self.CHI_SF_10_4, 4)
  515. assert_allclose(x, 10, rtol=1e-15)
  516. def test_logcdf(self):
  517. x = 10.0
  518. df = 15
  519. logcdf = stats.chi.logcdf(x, df)
  520. # Reference value computed with mpath.
  521. assert_allclose(logcdf, -1.304704343625153e-14, rtol=5e-15)
  522. def test_logsf(self):
  523. x = 0.01
  524. df = 15
  525. logsf = stats.chi.logsf(x, df)
  526. # Reference value computed with mpath.
  527. assert_allclose(logsf, -3.936060782678026e-37, rtol=5e-15)
  528. # reference value for 1e14 was computed via mpmath
  529. # from mpmath import mp
  530. # mp.dps = 500
  531. # df = mp.mpf(1e14)
  532. # float(mp.rf(mp.mpf(0.5) * df, mp.mpf(0.5)) * mp.sqrt(2.))
  533. @pytest.mark.parametrize('df, ref',
  534. [(1e3, CHI_MEAN_1000),
  535. (1e14, 9999999.999999976)])
  536. def test_mean(self, df, ref):
  537. assert_allclose(stats.chi.mean(df), ref, rtol=1e-12)
  538. # Entropy references values were computed with the following mpmath code
  539. # from mpmath import mp
  540. # mp.dps = 50
  541. # def chi_entropy_mpmath(df):
  542. # df = mp.mpf(df)
  543. # half_df = 0.5 * df
  544. # entropy = mp.log(mp.gamma(half_df)) + 0.5 * \
  545. # (df - mp.log(2) - (df - mp.one) * mp.digamma(half_df))
  546. # return float(entropy)
  547. @pytest.mark.parametrize('df, ref',
  548. [(1e-4, -9989.7316027504),
  549. (1, 0.7257913526447274),
  550. (1e3, 1.0721981095025448),
  551. (1e10, 1.0723649429080335),
  552. (1e100, 1.0723649429247002)])
  553. def test_entropy(self, df, ref):
  554. assert_allclose(stats.chi(df).entropy(), ref, rtol=1e-15)
  555. class TestCrystalBall:
  556. def test_pdf(self):
  557. """
  558. All values are calculated using the independent implementation of the
  559. ROOT framework (see https://root.cern.ch/).
  560. Corresponding ROOT code is given in the comments.
  561. """
  562. X = np.linspace(-5.0, 5.0, 21)[:-1]
  563. # for (double x = -5.0; x < 5.0; x += 0.5) {
  564. # cout << setprecision(16)
  565. # << ROOT::Math::crystalball_pdf(x, 1.0, 2.0, 1.0)
  566. # << ", ";
  567. # }
  568. calculated = stats.crystalball.pdf(X, beta=1.0, m=2.0)
  569. expected = np.array([0.02028666423671257, 0.02414280702550917,
  570. 0.02921279650086611, 0.03606518086526679,
  571. 0.04564499453260328, 0.05961795204258388,
  572. 0.08114665694685029, 0.1168511860034644,
  573. 0.1825799781304131, 0.2656523006609301,
  574. 0.3010234935475763, 0.2656523006609301,
  575. 0.1825799781304131, 0.09772801991305094,
  576. 0.0407390997601359, 0.01322604925508607,
  577. 0.003344068947749631, 0.0006584862184997063,
  578. 0.0001009821322058648, 1.206059579124873e-05])
  579. assert_allclose(expected, calculated, rtol=1e-14)
  580. # for (double x = -5.0; x < 5.0; x += 0.5) {
  581. # cout << setprecision(16)
  582. # << ROOT::Math::crystalball_pdf(x, 2.0, 3.0, 1.0)
  583. # << ", ";
  584. # }
  585. calculated = stats.crystalball.pdf(X, beta=2.0, m=3.0)
  586. expected = np.array([0.00196480373120913, 0.0027975428126005,
  587. 0.004175923965164595, 0.006631212592830816,
  588. 0.01145873536041165, 0.022380342500804,
  589. 0.05304970074264653, 0.1272596164638828,
  590. 0.237752264003024, 0.3459275029304401,
  591. 0.3919872148188981, 0.3459275029304401,
  592. 0.237752264003024, 0.1272596164638828,
  593. 0.05304970074264653, 0.01722271623872227,
  594. 0.004354584612458383, 0.0008574685508575863,
  595. 0.000131497061187334, 1.570508433595375e-05])
  596. assert_allclose(expected, calculated, rtol=1e-14)
  597. # for (double x = -5.0; x < 5.0; x += 0.5) {
  598. # cout << setprecision(16)
  599. # << ROOT::Math::crystalball_pdf(x, 2.0, 3.0, 2.0, 0.5)
  600. # << ", ";
  601. # }
  602. calculated = stats.crystalball.pdf(X, beta=2.0, m=3.0, loc=0.5, scale=2.0)
  603. expected = np.array([0.007859214924836521, 0.011190171250402,
  604. 0.01670369586065838, 0.02652485037132326,
  605. 0.04238659020399594, 0.06362980823194138,
  606. 0.08973241216601403, 0.118876132001512,
  607. 0.1479437366093383, 0.17296375146522,
  608. 0.1899635180461471, 0.1959936074094491,
  609. 0.1899635180461471, 0.17296375146522,
  610. 0.1479437366093383, 0.118876132001512,
  611. 0.08973241216601403, 0.06362980823194138,
  612. 0.04238659020399594, 0.02652485037132326])
  613. assert_allclose(expected, calculated, rtol=1e-14)
  614. def test_cdf(self):
  615. """
  616. All values are calculated using the independent implementation of the
  617. ROOT framework (see https://root.cern.ch/).
  618. Corresponding ROOT code is given in the comments.
  619. """
  620. X = np.linspace(-5.0, 5.0, 21)[:-1]
  621. # for (double x = -5.0; x < 5.0; x += 0.5) {
  622. # cout << setprecision(16)
  623. # << ROOT::Math::crystalball_cdf(x, 1.0, 2.0, 1.0)
  624. # << ", ";
  625. # }
  626. calculated = stats.crystalball.cdf(X, beta=1.0, m=2.0)
  627. expected = np.array([0.1217199854202754, 0.1327854386403005,
  628. 0.1460639825043305, 0.1622933138937006,
  629. 0.1825799781304132, 0.2086628321490436,
  630. 0.2434399708405509, 0.292127965008661,
  631. 0.3651599562608263, 0.4782542338198316,
  632. 0.6227229998727213, 0.7671917659256111,
  633. 0.8802860434846165, 0.9495903590367718,
  634. 0.9828337969321823, 0.9953144721881936,
  635. 0.9989814290402977, 0.9998244687978383,
  636. 0.9999761023377818, 0.9999974362721522])
  637. assert_allclose(expected, calculated, rtol=1e-13)
  638. # for (double x = -5.0; x < 5.0; x += 0.5) {
  639. # cout << setprecision(16)
  640. # << ROOT::Math::crystalball_cdf(x, 2.0, 3.0, 1.0)
  641. # << ", ";
  642. # }
  643. calculated = stats.crystalball.cdf(X, beta=2.0, m=3.0)
  644. expected = np.array([0.004420808395220632, 0.005595085625200946,
  645. 0.007307866939038177, 0.009946818889246312,
  646. 0.01432341920051472, 0.02238034250080412,
  647. 0.03978727555698502, 0.08307626432678494,
  648. 0.1733230597116304, 0.3205923321191123,
  649. 0.508716882020547, 0.6968414319219818,
  650. 0.8441107043294638, 0.934357499714309,
  651. 0.9776464884841091, 0.9938985925142876,
  652. 0.9986736357721329, 0.9997714265214375,
  653. 0.9999688809071239, 0.9999966615611068])
  654. assert_allclose(expected, calculated, rtol=1e-13)
  655. # for (double x = -5.0; x < 5.0; x += 0.5) {
  656. # cout << setprecision(16)
  657. # << ROOT::Math::crystalball_cdf(x, 2.0, 3.0, 2.0, 0.5);
  658. # << ", ";
  659. # }
  660. calculated = stats.crystalball.cdf(X, beta=2.0, m=3.0, loc=0.5, scale=2.0)
  661. expected = np.array([0.0176832335808822, 0.02238034250080412,
  662. 0.02923146775615237, 0.03978727555698502,
  663. 0.05679453901646225, 0.08307626432678494,
  664. 0.1212416644828466, 0.1733230597116304,
  665. 0.2401101486313661, 0.3205923321191123,
  666. 0.4117313791289429, 0.508716882020547,
  667. 0.6057023849121512, 0.6968414319219818,
  668. 0.7773236154097279, 0.8441107043294638,
  669. 0.8961920995582476, 0.934357499714309,
  670. 0.9606392250246318, 0.9776464884841091])
  671. assert_allclose(expected, calculated, rtol=1e-13)
  672. # Reference value computed with ROOT, e.g.
  673. # cout << setprecision(16)
  674. # << ROOT::Math::crystalball_cdf_c(12.0, 1.0, 2.0, 1.0)
  675. # << endl;
  676. @pytest.mark.parametrize(
  677. 'x, beta, m, rootref',
  678. [(12.0, 1.0, 2.0, 1.340451684048897e-33),
  679. (9.0, 4.0, 1.25, 1.12843537145273e-19),
  680. (20, 0.1, 1.001, 6.929038716892384e-93),
  681. (-4.5, 2.0, 3.0, 0.9944049143747991),
  682. (-30.0, 0.5, 5.0, 0.9976994814571858),
  683. (-1e50, 1.5, 1.1, 0.9999951099570382)]
  684. )
  685. def test_sf(self, x, beta, m, rootref):
  686. sf = stats.crystalball.sf(x, beta=beta, m=m)
  687. assert_allclose(sf, rootref, rtol=1e-13)
  688. def test_moments(self):
  689. """
  690. All values are calculated using the pdf formula and the integrate function
  691. of Mathematica
  692. """
  693. # The Last two (alpha, n) pairs test the special case n == alpha**2
  694. beta = np.array([2.0, 1.0, 3.0, 2.0, 3.0])
  695. m = np.array([3.0, 3.0, 2.0, 4.0, 9.0])
  696. # The distribution should be correctly normalised
  697. expected_0th_moment = np.array([1.0, 1.0, 1.0, 1.0, 1.0])
  698. calculated_0th_moment = stats.crystalball._munp(0, beta, m)
  699. assert_allclose(expected_0th_moment, calculated_0th_moment, rtol=0.001)
  700. # calculated using wolframalpha.com
  701. # e.g. for beta = 2 and m = 3 we calculate the norm like this:
  702. # integrate exp(-x^2/2) from -2 to infinity +
  703. # integrate (3/2)^3*exp(-2^2/2)*(3/2-2-x)^(-3) from -infinity to -2
  704. norm = np.array([2.5511, 3.01873, 2.51065, 2.53983, 2.507410455])
  705. a = np.array([-0.21992, -3.03265, np.inf, -0.135335, -0.003174])
  706. expected_1th_moment = a / norm
  707. calculated_1th_moment = stats.crystalball._munp(1, beta, m)
  708. assert_allclose(expected_1th_moment, calculated_1th_moment, rtol=0.001)
  709. a = np.array([np.inf, np.inf, np.inf, 3.2616, 2.519908])
  710. expected_2th_moment = a / norm
  711. calculated_2th_moment = stats.crystalball._munp(2, beta, m)
  712. assert_allclose(expected_2th_moment, calculated_2th_moment, rtol=0.001)
  713. a = np.array([np.inf, np.inf, np.inf, np.inf, -0.0577668])
  714. expected_3th_moment = a / norm
  715. calculated_3th_moment = stats.crystalball._munp(3, beta, m)
  716. assert_allclose(expected_3th_moment, calculated_3th_moment, rtol=0.001)
  717. a = np.array([np.inf, np.inf, np.inf, np.inf, 7.78468])
  718. expected_4th_moment = a / norm
  719. calculated_4th_moment = stats.crystalball._munp(4, beta, m)
  720. assert_allclose(expected_4th_moment, calculated_4th_moment, rtol=0.001)
  721. a = np.array([np.inf, np.inf, np.inf, np.inf, -1.31086])
  722. expected_5th_moment = a / norm
  723. calculated_5th_moment = stats.crystalball._munp(5, beta, m)
  724. assert_allclose(expected_5th_moment, calculated_5th_moment, rtol=0.001)
  725. def test_entropy(self):
  726. # regression test for gh-13602
  727. cb = stats.crystalball(2, 3)
  728. res1 = cb.entropy()
  729. # -20000 and 30 are negative and positive infinity, respectively
  730. lo, hi, N = -20000, 30, 200000
  731. x = np.linspace(lo, hi, N)
  732. res2 = trapezoid(entr(cb.pdf(x)), x)
  733. assert_allclose(res1, res2, rtol=1e-7)
  734. class TestNBinom:
  735. def setup_method(self):
  736. self.rng = np.random.default_rng(5861367021)
  737. def test_rvs(self):
  738. vals = stats.nbinom.rvs(10, 0.75, size=(2, 50), random_state=self.rng)
  739. assert_(np.all(vals >= 0))
  740. assert_(np.shape(vals) == (2, 50))
  741. assert_(vals.dtype.char in typecodes['AllInteger'])
  742. val = stats.nbinom.rvs(10, 0.75, random_state=self.rng)
  743. assert_(isinstance(val, int))
  744. val = stats.nbinom(10, 0.75).rvs(3, random_state=self.rng)
  745. assert_(isinstance(val, np.ndarray))
  746. assert_(val.dtype.char in typecodes['AllInteger'])
  747. def test_pmf(self):
  748. # regression test for ticket 1779
  749. assert_allclose(np.exp(stats.nbinom.logpmf(700, 721, 0.52)),
  750. stats.nbinom.pmf(700, 721, 0.52))
  751. # logpmf(0,1,1) shouldn't return nan (regression test for gh-4029)
  752. val = scipy.stats.nbinom.logpmf(0, 1, 1)
  753. assert_equal(val, 0)
  754. def test_logcdf_gh16159(self):
  755. # check that gh16159 is resolved.
  756. vals = stats.nbinom.logcdf([0, 5, 0, 5], n=4.8, p=0.45)
  757. ref = np.log(stats.nbinom.cdf([0, 5, 0, 5], n=4.8, p=0.45))
  758. assert_allclose(vals, ref)
  759. class TestGenInvGauss:
  760. def setup_method(self):
  761. self.rng = np.random.default_rng(6473281180)
  762. @pytest.mark.slow
  763. def test_rvs_with_mode_shift(self):
  764. # ratio_unif w/ mode shift
  765. gig = stats.geninvgauss(2.3, 1.5)
  766. _, p = stats.kstest(gig.rvs(size=1500, random_state=self.rng), gig.cdf)
  767. assert_equal(p > 0.05, True)
  768. @pytest.mark.slow
  769. def test_rvs_without_mode_shift(self):
  770. # ratio_unif w/o mode shift
  771. gig = stats.geninvgauss(0.9, 0.75)
  772. _, p = stats.kstest(gig.rvs(size=1500, random_state=self.rng), gig.cdf)
  773. assert_equal(p > 0.05, True)
  774. @pytest.mark.slow
  775. def test_rvs_new_method(self):
  776. # new algorithm of Hoermann / Leydold
  777. gig = stats.geninvgauss(0.1, 0.2)
  778. _, p = stats.kstest(gig.rvs(size=1500, random_state=self.rng), gig.cdf)
  779. assert_equal(p > 0.05, True)
  780. @pytest.mark.slow
  781. def test_rvs_p_zero(self):
  782. def my_ks_check(p, b):
  783. gig = stats.geninvgauss(p, b)
  784. rvs = gig.rvs(size=1500, random_state=self.rng)
  785. return stats.kstest(rvs, gig.cdf)[1] > 0.05
  786. # boundary cases when p = 0
  787. assert_equal(my_ks_check(0, 0.2), True) # new algo
  788. assert_equal(my_ks_check(0, 0.9), True) # ratio_unif w/o shift
  789. assert_equal(my_ks_check(0, 1.5), True) # ratio_unif with shift
  790. def test_rvs_negative_p(self):
  791. # if p negative, return inverse
  792. assert_equal(
  793. stats.geninvgauss(-1.5, 2).rvs(size=10, random_state=1234),
  794. 1 / stats.geninvgauss(1.5, 2).rvs(size=10, random_state=1234))
  795. def test_invgauss(self):
  796. # test that invgauss is special case
  797. ig = stats.geninvgauss.rvs(size=1500, p=-0.5, b=1, random_state=1464878613)
  798. assert_equal(stats.kstest(ig, 'invgauss', args=[1])[1] > 0.15, True)
  799. # test pdf and cdf
  800. mu, x = 100, np.linspace(0.01, 1, 10)
  801. pdf_ig = stats.geninvgauss.pdf(x, p=-0.5, b=1 / mu, scale=mu)
  802. assert_allclose(pdf_ig, stats.invgauss(mu).pdf(x))
  803. cdf_ig = stats.geninvgauss.cdf(x, p=-0.5, b=1 / mu, scale=mu)
  804. assert_allclose(cdf_ig, stats.invgauss(mu).cdf(x))
  805. def test_pdf_R(self):
  806. # test against R package GIGrvg
  807. # x <- seq(0.01, 5, length.out = 10)
  808. # GIGrvg::dgig(x, 0.5, 1, 1)
  809. vals_R = np.array([2.081176820e-21, 4.488660034e-01, 3.747774338e-01,
  810. 2.693297528e-01, 1.905637275e-01, 1.351476913e-01,
  811. 9.636538981e-02, 6.909040154e-02, 4.978006801e-02,
  812. 3.602084467e-02])
  813. x = np.linspace(0.01, 5, 10)
  814. assert_allclose(vals_R, stats.geninvgauss.pdf(x, 0.5, 1))
  815. def test_pdf_zero(self):
  816. # pdf at 0 is 0, needs special treatment to avoid 1/x in pdf
  817. assert_equal(stats.geninvgauss.pdf(0, 0.5, 0.5), 0)
  818. # if x is large and p is moderate, make sure that pdf does not
  819. # overflow because of x**(p-1); exp(-b*x) forces pdf to zero
  820. assert_equal(stats.geninvgauss.pdf(2e6, 50, 2), 0)
  821. class TestGenHyperbolic:
  822. def test_pdf_r(self):
  823. # test against R package GeneralizedHyperbolic
  824. # x <- seq(-10, 10, length.out = 10)
  825. # GeneralizedHyperbolic::dghyp(
  826. # x = x, lambda = 2, alpha = 2, beta = 1, delta = 1.5, mu = 0.5
  827. # )
  828. vals_R = np.array([
  829. 2.94895678275316e-13, 1.75746848647696e-10, 9.48149804073045e-08,
  830. 4.17862521692026e-05, 0.0103947630463822, 0.240864958986839,
  831. 0.162833527161649, 0.0374609592899472, 0.00634894847327781,
  832. 0.000941920705790324
  833. ])
  834. lmbda, alpha, beta = 2, 2, 1
  835. mu, delta = 0.5, 1.5
  836. args = (lmbda, alpha*delta, beta*delta)
  837. gh = stats.genhyperbolic(*args, loc=mu, scale=delta)
  838. x = np.linspace(-10, 10, 10)
  839. assert_allclose(gh.pdf(x), vals_R, atol=0, rtol=1e-13)
  840. def test_cdf_r(self):
  841. # test against R package GeneralizedHyperbolic
  842. # q <- seq(-10, 10, length.out = 10)
  843. # GeneralizedHyperbolic::pghyp(
  844. # q = q, lambda = 2, alpha = 2, beta = 1, delta = 1.5, mu = 0.5
  845. # )
  846. vals_R = np.array([
  847. 1.01881590921421e-13, 6.13697274983578e-11, 3.37504977637992e-08,
  848. 1.55258698166181e-05, 0.00447005453832497, 0.228935323956347,
  849. 0.755759458895243, 0.953061062884484, 0.992598013917513,
  850. 0.998942646586662
  851. ])
  852. lmbda, alpha, beta = 2, 2, 1
  853. mu, delta = 0.5, 1.5
  854. args = (lmbda, alpha*delta, beta*delta)
  855. gh = stats.genhyperbolic(*args, loc=mu, scale=delta)
  856. x = np.linspace(-10, 10, 10)
  857. assert_allclose(gh.cdf(x), vals_R, atol=0, rtol=1e-6)
  858. # The reference values were computed by implementing the PDF with mpmath
  859. # and integrating it with mp.quad. The values were computed with
  860. # mp.dps=250, and then again with mp.dps=400 to ensure the full 64 bit
  861. # precision was computed.
  862. @pytest.mark.parametrize(
  863. 'x, p, a, b, loc, scale, ref',
  864. [(-15, 2, 3, 1.5, 0.5, 1.5, 4.770036428808252e-20),
  865. (-15, 10, 1.5, 0.25, 1, 5, 0.03282964575089294),
  866. (-15, 10, 1.5, 1.375, 0, 1, 3.3711159600215594e-23),
  867. (-15, 0.125, 1.5, 1.49995, 0, 1, 4.729401428898605e-23),
  868. (-1, 0.125, 1.5, 1.49995, 0, 1, 0.0003565725914786859),
  869. (5, -0.125, 1.5, 1.49995, 0, 1, 0.2600651974023352),
  870. (5, -0.125, 1000, 999, 0, 1, 5.923270556517253e-28),
  871. (20, -0.125, 1000, 999, 0, 1, 0.23452293711665634),
  872. (40, -0.125, 1000, 999, 0, 1, 0.9999648749561968),
  873. (60, -0.125, 1000, 999, 0, 1, 0.9999999999975475)]
  874. )
  875. def test_cdf_mpmath(self, x, p, a, b, loc, scale, ref):
  876. cdf = stats.genhyperbolic.cdf(x, p, a, b, loc=loc, scale=scale)
  877. assert_allclose(cdf, ref, rtol=5e-12)
  878. # The reference values were computed by implementing the PDF with mpmath
  879. # and integrating it with mp.quad. The values were computed with
  880. # mp.dps=250, and then again with mp.dps=400 to ensure the full 64 bit
  881. # precision was computed.
  882. @pytest.mark.parametrize(
  883. 'x, p, a, b, loc, scale, ref',
  884. [(0, 1e-6, 12, -1, 0, 1, 0.38520358671350524),
  885. (-1, 3, 2.5, 2.375, 1, 3, 0.9999901774267577),
  886. (-20, 3, 2.5, 2.375, 1, 3, 1.0),
  887. (25, 2, 3, 1.5, 0.5, 1.5, 8.593419916523976e-10),
  888. (300, 10, 1.5, 0.25, 1, 5, 6.137415609872158e-24),
  889. (60, -0.125, 1000, 999, 0, 1, 2.4524915075944173e-12),
  890. (75, -0.125, 1000, 999, 0, 1, 2.9435194886214633e-18)]
  891. )
  892. def test_sf_mpmath(self, x, p, a, b, loc, scale, ref):
  893. sf = stats.genhyperbolic.sf(x, p, a, b, loc=loc, scale=scale)
  894. assert_allclose(sf, ref, rtol=5e-12)
  895. def test_moments_r(self):
  896. # test against R package GeneralizedHyperbolic
  897. # sapply(1:4,
  898. # function(x) GeneralizedHyperbolic::ghypMom(
  899. # order = x, lambda = 2, alpha = 2,
  900. # beta = 1, delta = 1.5, mu = 0.5,
  901. # momType = 'raw')
  902. # )
  903. vals_R = [2.36848366948115, 8.4739346779246,
  904. 37.8870502710066, 205.76608511485]
  905. lmbda, alpha, beta = 2, 2, 1
  906. mu, delta = 0.5, 1.5
  907. args = (lmbda, alpha*delta, beta*delta)
  908. vals_us = [
  909. stats.genhyperbolic(*args, loc=mu, scale=delta).moment(i)
  910. for i in range(1, 5)
  911. ]
  912. assert_allclose(vals_us, vals_R, atol=0, rtol=1e-13)
  913. def test_rvs(self):
  914. # Kolmogorov-Smirnov test to ensure alignment
  915. # of analytical and empirical cdfs
  916. lmbda, alpha, beta = 2, 2, 1
  917. mu, delta = 0.5, 1.5
  918. args = (lmbda, alpha*delta, beta*delta)
  919. gh = stats.genhyperbolic(*args, loc=mu, scale=delta)
  920. _, p = stats.kstest(gh.rvs(size=1500, random_state=1234), gh.cdf)
  921. assert_equal(p > 0.05, True)
  922. def test_pdf_t(self):
  923. # Test Against T-Student with 1 - 30 df
  924. df = np.linspace(1, 30, 10)
  925. # in principle alpha should be zero in practice for big lmbdas
  926. # alpha cannot be too small else pdf does not integrate
  927. alpha, beta = np.float_power(df, 2)*np.finfo(np.float32).eps, 0
  928. mu, delta = 0, np.sqrt(df)
  929. args = (-df/2, alpha, beta)
  930. gh = stats.genhyperbolic(*args, loc=mu, scale=delta)
  931. x = np.linspace(gh.ppf(0.01), gh.ppf(0.99), 50)[:, np.newaxis]
  932. assert_allclose(
  933. gh.pdf(x), stats.t.pdf(x, df),
  934. atol=0, rtol=1e-6
  935. )
  936. def test_pdf_cauchy(self):
  937. # Test Against Cauchy distribution
  938. # in principle alpha should be zero in practice for big lmbdas
  939. # alpha cannot be too small else pdf does not integrate
  940. lmbda, alpha, beta = -0.5, np.finfo(np.float32).eps, 0
  941. mu, delta = 0, 1
  942. args = (lmbda, alpha, beta)
  943. gh = stats.genhyperbolic(*args, loc=mu, scale=delta)
  944. x = np.linspace(gh.ppf(0.01), gh.ppf(0.99), 50)[:, np.newaxis]
  945. assert_allclose(
  946. gh.pdf(x), stats.cauchy.pdf(x),
  947. atol=0, rtol=1e-6
  948. )
  949. def test_pdf_laplace(self):
  950. # Test Against Laplace with location param [-10, 10]
  951. loc = np.linspace(-10, 10, 10)
  952. # in principle delta should be zero in practice for big loc delta
  953. # cannot be too small else pdf does not integrate
  954. delta = np.finfo(np.float32).eps
  955. lmbda, alpha, beta = 1, 1, 0
  956. args = (lmbda, alpha*delta, beta*delta)
  957. # ppf does not integrate for scale < 5e-4
  958. # therefore using simple linspace to define the support
  959. gh = stats.genhyperbolic(*args, loc=loc, scale=delta)
  960. x = np.linspace(-20, 20, 50)[:, np.newaxis]
  961. assert_allclose(
  962. gh.pdf(x), stats.laplace.pdf(x, loc=loc, scale=1),
  963. atol=0, rtol=1e-11
  964. )
  965. def test_pdf_norminvgauss(self):
  966. # Test Against NIG with varying alpha/beta/delta/mu
  967. alpha, beta, delta, mu = (
  968. np.linspace(1, 20, 10),
  969. np.linspace(0, 19, 10)*np.float_power(-1, range(10)),
  970. np.linspace(1, 1, 10),
  971. np.linspace(-100, 100, 10)
  972. )
  973. lmbda = - 0.5
  974. args = (lmbda, alpha * delta, beta * delta)
  975. gh = stats.genhyperbolic(*args, loc=mu, scale=delta)
  976. x = np.linspace(gh.ppf(0.01), gh.ppf(0.99), 50)[:, np.newaxis]
  977. assert_allclose(
  978. gh.pdf(x), stats.norminvgauss.pdf(
  979. x, a=alpha, b=beta, loc=mu, scale=delta),
  980. atol=0, rtol=1e-13
  981. )
  982. class TestHypSecant:
  983. # Reference values were computed with the mpmath expression
  984. # float((2/mp.pi)*mp.atan(mp.exp(-x)))
  985. # and mp.dps = 50.
  986. @pytest.mark.parametrize('x, reference',
  987. [(30, 5.957247804324683e-14),
  988. (50, 1.2278802891647964e-22)])
  989. def test_sf(self, x, reference):
  990. sf = stats.hypsecant.sf(x)
  991. assert_allclose(sf, reference, rtol=5e-15)
  992. # Reference values were computed with the mpmath expression
  993. # float(-mp.log(mp.tan((mp.pi/2)*p)))
  994. # and mp.dps = 50.
  995. @pytest.mark.parametrize('p, reference',
  996. [(1e-6, 13.363927852673998),
  997. (1e-12, 27.179438410639094)])
  998. def test_isf(self, p, reference):
  999. x = stats.hypsecant.isf(p)
  1000. assert_allclose(x, reference, rtol=5e-15)
  1001. def test_logcdf_logsf(self):
  1002. x = 50.0
  1003. # Reference value was computed with mpmath.
  1004. ref = -1.2278802891647964e-22
  1005. logcdf = stats.hypsecant.logcdf(x)
  1006. assert_allclose(logcdf, ref, rtol=5e-15)
  1007. logsf = stats.hypsecant.logsf(-x)
  1008. assert_allclose(logsf, ref, rtol=5e-15)
  1009. class TestNormInvGauss:
  1010. def test_cdf_R(self):
  1011. # test pdf and cdf vals against R
  1012. # require("GeneralizedHyperbolic")
  1013. # x_test <- c(-7, -5, 0, 8, 15)
  1014. # r_cdf <- GeneralizedHyperbolic::pnig(x_test, mu = 0, a = 1, b = 0.5)
  1015. # r_pdf <- GeneralizedHyperbolic::dnig(x_test, mu = 0, a = 1, b = 0.5)
  1016. r_cdf = np.array([8.034920282e-07, 2.512671945e-05, 3.186661051e-01,
  1017. 9.988650664e-01, 9.999848769e-01])
  1018. x_test = np.array([-7, -5, 0, 8, 15])
  1019. vals_cdf = stats.norminvgauss.cdf(x_test, a=1, b=0.5)
  1020. assert_allclose(vals_cdf, r_cdf, atol=1e-9)
  1021. def test_pdf_R(self):
  1022. # values from R as defined in test_cdf_R
  1023. r_pdf = np.array([1.359600783e-06, 4.413878805e-05, 4.555014266e-01,
  1024. 7.450485342e-04, 8.917889931e-06])
  1025. x_test = np.array([-7, -5, 0, 8, 15])
  1026. vals_pdf = stats.norminvgauss.pdf(x_test, a=1, b=0.5)
  1027. assert_allclose(vals_pdf, r_pdf, atol=1e-9)
  1028. @pytest.mark.parametrize('x, a, b, sf, rtol',
  1029. [(-1, 1, 0, 0.8759652211005315, 1e-13),
  1030. (25, 1, 0, 1.1318690184042579e-13, 1e-4),
  1031. (1, 5, -1.5, 0.002066711134653577, 1e-12),
  1032. (10, 5, -1.5, 2.308435233930669e-29, 1e-9)])
  1033. def test_sf_isf_mpmath(self, x, a, b, sf, rtol):
  1034. # Reference data generated with `reference_distributions.NormInvGauss`,
  1035. # e.g. `NormInvGauss(alpha=1, beta=0).sf(-1)` with mp.dps = 50
  1036. s = stats.norminvgauss.sf(x, a, b)
  1037. assert_allclose(s, sf, rtol=rtol)
  1038. i = stats.norminvgauss.isf(sf, a, b)
  1039. assert_allclose(i, x, rtol=rtol)
  1040. def test_sf_isf_mpmath_vectorized(self):
  1041. x = [-1, 25]
  1042. a = [1, 1]
  1043. b = 0
  1044. sf = [0.8759652211005315, 1.1318690184042579e-13] # see previous test
  1045. s = stats.norminvgauss.sf(x, a, b)
  1046. assert_allclose(s, sf, rtol=1e-13, atol=1e-16)
  1047. i = stats.norminvgauss.isf(sf, a, b)
  1048. # Not perfect, but better than it was. See gh-13338.
  1049. assert_allclose(i, x, rtol=1e-6)
  1050. def test_gh8718(self):
  1051. # Add test that gh-13338 resolved gh-8718
  1052. dst = stats.norminvgauss(1, 0)
  1053. x = np.arange(0, 20, 2)
  1054. sf = dst.sf(x)
  1055. isf = dst.isf(sf)
  1056. assert_allclose(isf, x)
  1057. def test_stats(self):
  1058. a, b = 1, 0.5
  1059. gamma = np.sqrt(a**2 - b**2)
  1060. v_stats = (b / gamma, a**2 / gamma**3, 3.0 * b / (a * np.sqrt(gamma)),
  1061. 3.0 * (1 + 4 * b**2 / a**2) / gamma)
  1062. assert_equal(v_stats, stats.norminvgauss.stats(a, b, moments='mvsk'))
  1063. def test_ppf(self):
  1064. a, b = 1, 0.5
  1065. x_test = np.array([0.001, 0.5, 0.999])
  1066. vals = stats.norminvgauss.ppf(x_test, a, b)
  1067. assert_allclose(x_test, stats.norminvgauss.cdf(vals, a, b))
  1068. class TestGeom:
  1069. def setup_method(self):
  1070. self.rng = np.random.default_rng(7672986002)
  1071. def test_rvs(self):
  1072. vals = stats.geom.rvs(0.75, size=(2, 50), random_state=self.rng)
  1073. assert_(np.all(vals >= 0))
  1074. assert_(np.shape(vals) == (2, 50))
  1075. assert_(vals.dtype.char in typecodes['AllInteger'])
  1076. val = stats.geom.rvs(0.75, random_state=self.rng)
  1077. assert_(isinstance(val, int))
  1078. val = stats.geom(0.75).rvs(3, random_state=self.rng)
  1079. assert_(isinstance(val, np.ndarray))
  1080. assert_(val.dtype.char in typecodes['AllInteger'])
  1081. def test_rvs_9313(self):
  1082. # previously, RVS were converted to `np.int32` on some platforms,
  1083. # causing overflow for moderately large integer output (gh-9313).
  1084. # Check that this is resolved to the extent possible w/ `np.int64`.
  1085. rvs = stats.geom.rvs(np.exp(-35), size=5, random_state=self.rng)
  1086. assert rvs.dtype == np.int64
  1087. assert np.all(rvs > np.iinfo(np.int32).max)
  1088. def test_pmf(self):
  1089. vals = stats.geom.pmf([1, 2, 3], 0.5)
  1090. assert_array_almost_equal(vals, [0.5, 0.25, 0.125])
  1091. def test_logpmf(self):
  1092. # regression test for ticket 1793
  1093. vals1 = np.log(stats.geom.pmf([1, 2, 3], 0.5))
  1094. vals2 = stats.geom.logpmf([1, 2, 3], 0.5)
  1095. assert_allclose(vals1, vals2, rtol=1e-15, atol=0)
  1096. # regression test for gh-4028
  1097. val = stats.geom.logpmf(1, 1)
  1098. assert_equal(val, 0.0)
  1099. def test_cdf_sf(self):
  1100. vals = stats.geom.cdf([1, 2, 3], 0.5)
  1101. vals_sf = stats.geom.sf([1, 2, 3], 0.5)
  1102. expected = array([0.5, 0.75, 0.875])
  1103. assert_array_almost_equal(vals, expected)
  1104. assert_array_almost_equal(vals_sf, 1-expected)
  1105. def test_logcdf_logsf(self):
  1106. vals = stats.geom.logcdf([1, 2, 3], 0.5)
  1107. vals_sf = stats.geom.logsf([1, 2, 3], 0.5)
  1108. expected = array([0.5, 0.75, 0.875])
  1109. assert_array_almost_equal(vals, np.log(expected))
  1110. assert_array_almost_equal(vals_sf, np.log1p(-expected))
  1111. def test_ppf(self):
  1112. vals = stats.geom.ppf([0.5, 0.75, 0.875], 0.5)
  1113. expected = array([1.0, 2.0, 3.0])
  1114. assert_array_almost_equal(vals, expected)
  1115. def test_ppf_underflow(self):
  1116. # this should not underflow
  1117. assert_allclose(stats.geom.ppf(1e-20, 1e-20), 1.0, atol=1e-14)
  1118. def test_entropy_gh18226(self):
  1119. # gh-18226 reported that `geom.entropy` produced a warning and
  1120. # inaccurate output for small p. Check that this is resolved.
  1121. h = stats.geom(0.0146).entropy()
  1122. assert_allclose(h, 5.219397961962308, rtol=1e-15)
  1123. def test_rvs_gh18372(self):
  1124. # gh-18372 reported that `geom.rvs` could produce negative numbers,
  1125. # with `RandomState` PRNG, but the support is positive integers.
  1126. # Check that this is resolved.
  1127. random_state = np.random.RandomState(294582935)
  1128. assert (stats.geom.rvs(1e-30, size=10, random_state=random_state) > 0).all()
  1129. class TestPlanck:
  1130. def test_sf(self):
  1131. vals = stats.planck.sf([1, 2, 3], 5.)
  1132. expected = array([4.5399929762484854e-05,
  1133. 3.0590232050182579e-07,
  1134. 2.0611536224385579e-09])
  1135. assert_array_almost_equal(vals, expected)
  1136. def test_logsf(self):
  1137. vals = stats.planck.logsf([1000., 2000., 3000.], 1000.)
  1138. expected = array([-1001000., -2001000., -3001000.])
  1139. assert_array_almost_equal(vals, expected)
  1140. class TestGennorm:
  1141. def test_laplace(self):
  1142. # test against Laplace (special case for beta=1)
  1143. points = [1, 2, 3]
  1144. pdf1 = stats.gennorm.pdf(points, 1)
  1145. pdf2 = stats.laplace.pdf(points)
  1146. assert_almost_equal(pdf1, pdf2)
  1147. def test_norm(self):
  1148. # test against normal (special case for beta=2)
  1149. points = [1, 2, 3]
  1150. pdf1 = stats.gennorm.pdf(points, 2)
  1151. pdf2 = stats.norm.pdf(points, scale=2**-.5)
  1152. assert_almost_equal(pdf1, pdf2)
  1153. def test_rvs(self):
  1154. # 0 < beta < 1
  1155. dist = stats.gennorm(0.5)
  1156. rng = np.random.default_rng(2204049394)
  1157. rvs = dist.rvs(size=1000, random_state=rng)
  1158. assert stats.kstest(rvs, dist.cdf).pvalue > 0.1
  1159. # beta = 1
  1160. dist = stats.gennorm(1)
  1161. rvs = dist.rvs(size=1000, random_state=rng)
  1162. rvs_laplace = stats.laplace.rvs(size=1000, random_state=rng)
  1163. assert stats.ks_2samp(rvs, rvs_laplace).pvalue > 0.1
  1164. # beta = 2
  1165. dist = stats.gennorm(2)
  1166. dist.random_state = rng
  1167. rvs = dist.rvs(size=1000, random_state=rng)
  1168. rvs_norm = stats.norm.rvs(scale=1/2**0.5, size=1000, random_state=rng)
  1169. assert stats.ks_2samp(rvs, rvs_norm).pvalue > 0.1
  1170. def test_rvs_broadcasting(self):
  1171. dist = stats.gennorm([[0.5, 1.], [2., 5.]])
  1172. rng = np.random.default_rng(2204049394)
  1173. rvs = dist.rvs(size=[1000, 2, 2], random_state=rng)
  1174. assert stats.kstest(rvs[:, 0, 0], stats.gennorm(0.5).cdf)[1] > 0.1
  1175. assert stats.kstest(rvs[:, 0, 1], stats.gennorm(1.0).cdf)[1] > 0.1
  1176. assert stats.kstest(rvs[:, 1, 0], stats.gennorm(2.0).cdf)[1] > 0.1
  1177. assert stats.kstest(rvs[:, 1, 1], stats.gennorm(5.0).cdf)[1] > 0.1
  1178. class TestGibrat:
  1179. # sfx is sf(x). The values were computed with mpmath:
  1180. #
  1181. # from mpmath import mp
  1182. # mp.dps = 100
  1183. # def gibrat_sf(x):
  1184. # return 1 - mp.ncdf(mp.log(x))
  1185. #
  1186. # E.g.
  1187. #
  1188. # >>> float(gibrat_sf(1.5))
  1189. # 0.3425678305148459
  1190. #
  1191. @pytest.mark.parametrize('x, sfx', [(1.5, 0.3425678305148459),
  1192. (5000, 8.173334352522493e-18)])
  1193. def test_sf_isf(self, x, sfx):
  1194. assert_allclose(stats.gibrat.sf(x), sfx, rtol=2e-14)
  1195. assert_allclose(stats.gibrat.isf(sfx), x, rtol=2e-14)
  1196. class TestGompertz:
  1197. def test_gompertz_accuracy(self):
  1198. # Regression test for gh-4031
  1199. p = stats.gompertz.ppf(stats.gompertz.cdf(1e-100, 1), 1)
  1200. assert_allclose(p, 1e-100)
  1201. # sfx is sf(x). The values were computed with mpmath:
  1202. #
  1203. # from mpmath import mp
  1204. # mp.dps = 100
  1205. # def gompertz_sf(x, c):
  1206. # return mp.exp(-c*mp.expm1(x))
  1207. #
  1208. # E.g.
  1209. #
  1210. # >>> float(gompertz_sf(1, 2.5))
  1211. # 0.013626967146253437
  1212. #
  1213. @pytest.mark.parametrize('x, c, sfx', [(1, 2.5, 0.013626967146253437),
  1214. (3, 2.5, 1.8973243273704087e-21),
  1215. (0.05, 5, 0.7738668242570479),
  1216. (2.25, 5, 3.707795833465481e-19)])
  1217. def test_sf_isf(self, x, c, sfx):
  1218. assert_allclose(stats.gompertz.sf(x, c), sfx, rtol=1e-14)
  1219. assert_allclose(stats.gompertz.isf(sfx, c), x, rtol=1e-14)
  1220. def test_logcdf(self):
  1221. x = 8.0
  1222. c = 0.1
  1223. # Reference value computed with mpmath.
  1224. ref = -3.820049516821143e-130
  1225. logcdf = stats.gompertz.logcdf(x, c)
  1226. assert_allclose(logcdf, ref, rtol=5e-15)
  1227. def test_logsf(self):
  1228. x = 3e-80
  1229. c = 12
  1230. # Reference value computed with mpmath.
  1231. ref = -3.6e-79
  1232. logsf = stats.gompertz.logsf(x, c)
  1233. assert_allclose(logsf, ref, rtol=5e-15)
  1234. # reference values were computed with mpmath
  1235. # from mpmath import mp
  1236. # mp.dps = 100
  1237. # def gompertz_entropy(c):
  1238. # c = mp.mpf(c)
  1239. # return float(mp.one - mp.log(c) - mp.exp(c)*mp.e1(c))
  1240. @pytest.mark.parametrize('c, ref', [(1e-4, 1.5762523017634573),
  1241. (1, 0.4036526376768059),
  1242. (1000, -5.908754280976161),
  1243. (1e10, -22.025850930040455)])
  1244. def test_entropy(self, c, ref):
  1245. assert_allclose(stats.gompertz.entropy(c), ref, rtol=1e-14)
  1246. class TestFoldNorm:
  1247. # reference values were computed with mpmath with 50 digits of precision
  1248. # from mpmath import mp
  1249. # mp.dps = 50
  1250. # mp.mpf(0.5) * (mp.erf((x - c)/mp.sqrt(2)) + mp.erf((x + c)/mp.sqrt(2)))
  1251. @pytest.mark.parametrize('x, c, ref', [(1e-4, 1e-8, 7.978845594730578e-05),
  1252. (1e-4, 1e-4, 7.97884555483635e-05)])
  1253. def test_cdf(self, x, c, ref):
  1254. assert_allclose(stats.foldnorm.cdf(x, c), ref, rtol=1e-15)
  1255. class TestHalfNorm:
  1256. # sfx is sf(x). The values were computed with mpmath:
  1257. #
  1258. # from mpmath import mp
  1259. # mp.dps = 100
  1260. # def halfnorm_sf(x):
  1261. # return 2*(1 - mp.ncdf(x))
  1262. #
  1263. # E.g.
  1264. #
  1265. # >>> float(halfnorm_sf(1))
  1266. # 0.3173105078629141
  1267. #
  1268. @pytest.mark.parametrize('x, sfx', [(1, 0.3173105078629141),
  1269. (10, 1.523970604832105e-23)])
  1270. def test_sf_isf(self, x, sfx):
  1271. assert_allclose(stats.halfnorm.sf(x), sfx, rtol=1e-14)
  1272. assert_allclose(stats.halfnorm.isf(sfx), x, rtol=1e-14)
  1273. # reference values were computed via mpmath
  1274. # from mpmath import mp
  1275. # mp.dps = 100
  1276. # def halfnorm_cdf_mpmath(x):
  1277. # x = mp.mpf(x)
  1278. # return float(mp.erf(x/mp.sqrt(2.)))
  1279. @pytest.mark.parametrize('x, ref', [(1e-40, 7.978845608028653e-41),
  1280. (1e-18, 7.978845608028654e-19),
  1281. (8, 0.9999999999999988)])
  1282. def test_cdf(self, x, ref):
  1283. assert_allclose(stats.halfnorm.cdf(x), ref, rtol=1e-15)
  1284. @pytest.mark.parametrize("rvs_loc", [1e-5, 1e10])
  1285. @pytest.mark.parametrize("rvs_scale", [1e-2, 100, 1e8])
  1286. @pytest.mark.parametrize('fix_loc', [True, False])
  1287. @pytest.mark.parametrize('fix_scale', [True, False])
  1288. def test_fit_MLE_comp_optimizer(self, rvs_loc, rvs_scale,
  1289. fix_loc, fix_scale):
  1290. rng = np.random.default_rng(6762668991392531563)
  1291. data = stats.halfnorm.rvs(loc=rvs_loc, scale=rvs_scale, size=1000,
  1292. random_state=rng)
  1293. if fix_loc and fix_scale:
  1294. error_msg = ("All parameters fixed. There is nothing to "
  1295. "optimize.")
  1296. with pytest.raises(RuntimeError, match=error_msg):
  1297. stats.halflogistic.fit(data, floc=rvs_loc, fscale=rvs_scale)
  1298. return
  1299. kwds = {}
  1300. if fix_loc:
  1301. kwds['floc'] = rvs_loc
  1302. if fix_scale:
  1303. kwds['fscale'] = rvs_scale
  1304. # Numerical result may equal analytical result if the initial guess
  1305. # computed from moment condition is already optimal.
  1306. _assert_less_or_close_loglike(stats.halfnorm, data, **kwds,
  1307. maybe_identical=True)
  1308. def test_fit_error(self):
  1309. # `floc` bigger than the minimal data point
  1310. with pytest.raises(FitDataError):
  1311. stats.halfnorm.fit([1, 2, 3], floc=2)
  1312. class TestHalfCauchy:
  1313. @pytest.mark.parametrize("rvs_loc", [1e-5, 1e10])
  1314. @pytest.mark.parametrize("rvs_scale", [1e-2, 1e8])
  1315. @pytest.mark.parametrize('fix_loc', [True, False])
  1316. @pytest.mark.parametrize('fix_scale', [True, False])
  1317. def test_fit_MLE_comp_optimizer(self, rvs_loc, rvs_scale,
  1318. fix_loc, fix_scale):
  1319. rng = np.random.default_rng(6762668991392531563)
  1320. data = stats.halfnorm.rvs(loc=rvs_loc, scale=rvs_scale, size=1000,
  1321. random_state=rng)
  1322. if fix_loc and fix_scale:
  1323. error_msg = ("All parameters fixed. There is nothing to "
  1324. "optimize.")
  1325. with pytest.raises(RuntimeError, match=error_msg):
  1326. stats.halfcauchy.fit(data, floc=rvs_loc, fscale=rvs_scale)
  1327. return
  1328. kwds = {}
  1329. if fix_loc:
  1330. kwds['floc'] = rvs_loc
  1331. if fix_scale:
  1332. kwds['fscale'] = rvs_scale
  1333. _assert_less_or_close_loglike(stats.halfcauchy, data, **kwds)
  1334. def test_fit_error(self):
  1335. # `floc` bigger than the minimal data point
  1336. with pytest.raises(FitDataError):
  1337. stats.halfcauchy.fit([1, 2, 3], floc=2)
  1338. class TestHalfLogistic:
  1339. # survival function reference values were computed with mpmath
  1340. # from mpmath import mp
  1341. # mp.dps = 50
  1342. # def sf_mpmath(x):
  1343. # x = mp.mpf(x)
  1344. # return float(mp.mpf(2.)/(mp.exp(x) + mp.one))
  1345. @pytest.mark.parametrize('x, ref', [(100, 7.440151952041672e-44),
  1346. (200, 2.767793053473475e-87)])
  1347. def test_sf(self, x, ref):
  1348. assert_allclose(stats.halflogistic.sf(x), ref, rtol=1e-15)
  1349. # inverse survival function reference values were computed with mpmath
  1350. # from mpmath import mp
  1351. # mp.dps = 200
  1352. # def isf_mpmath(x):
  1353. # halfx = mp.mpf(x)/2
  1354. # return float(-mp.log(halfx/(mp.one - halfx)))
  1355. @pytest.mark.parametrize('q, ref', [(7.440151952041672e-44, 100),
  1356. (2.767793053473475e-87, 200),
  1357. (1-1e-9, 1.999999943436137e-09),
  1358. (1-1e-15, 1.9984014443252818e-15)])
  1359. def test_isf(self, q, ref):
  1360. assert_allclose(stats.halflogistic.isf(q), ref, rtol=1e-15)
  1361. def test_logcdf(self):
  1362. x = 30.0
  1363. # Reference value computed with mpmath.
  1364. ref = -1.871524593768035e-13
  1365. logcdf = stats.halflogistic.logcdf(x)
  1366. assert_allclose(logcdf, ref, rtol=5e-15)
  1367. def test_logsf(self):
  1368. x = 2e-14
  1369. # Reference value computed with mpmath.
  1370. ref = -1.000000000000005e-14
  1371. logsf = stats.halflogistic.logsf(x)
  1372. assert_allclose(logsf, ref, rtol=5e-15)
  1373. @pytest.mark.parametrize("rvs_loc", [1e-5, 1e10])
  1374. @pytest.mark.parametrize("rvs_scale", [1e-2, 100, 1e8])
  1375. @pytest.mark.parametrize('fix_loc', [True, False])
  1376. @pytest.mark.parametrize('fix_scale', [True, False])
  1377. def test_fit_MLE_comp_optimizer(self, rvs_loc, rvs_scale,
  1378. fix_loc, fix_scale):
  1379. rng = np.random.default_rng(6762668991392531563)
  1380. data = stats.halflogistic.rvs(loc=rvs_loc, scale=rvs_scale, size=1000,
  1381. random_state=rng)
  1382. kwds = {}
  1383. if fix_loc and fix_scale:
  1384. error_msg = ("All parameters fixed. There is nothing to "
  1385. "optimize.")
  1386. with pytest.raises(RuntimeError, match=error_msg):
  1387. stats.halflogistic.fit(data, floc=rvs_loc, fscale=rvs_scale)
  1388. return
  1389. if fix_loc:
  1390. kwds['floc'] = rvs_loc
  1391. if fix_scale:
  1392. kwds['fscale'] = rvs_scale
  1393. # Numerical result may equal analytical result if the initial guess
  1394. # computed from moment condition is already optimal.
  1395. _assert_less_or_close_loglike(stats.halflogistic, data, **kwds,
  1396. maybe_identical=True)
  1397. def test_fit_bad_floc(self):
  1398. msg = r" Maximum likelihood estimation with 'halflogistic' requires"
  1399. with assert_raises(FitDataError, match=msg):
  1400. stats.halflogistic.fit([0, 2, 4], floc=1)
  1401. class TestHalfgennorm:
  1402. def test_expon(self):
  1403. # test against exponential (special case for beta=1)
  1404. points = [1, 2, 3]
  1405. pdf1 = stats.halfgennorm.pdf(points, 1)
  1406. pdf2 = stats.expon.pdf(points)
  1407. assert_almost_equal(pdf1, pdf2)
  1408. def test_halfnorm(self):
  1409. # test against half normal (special case for beta=2)
  1410. points = [1, 2, 3]
  1411. pdf1 = stats.halfgennorm.pdf(points, 2)
  1412. pdf2 = stats.halfnorm.pdf(points, scale=2**-.5)
  1413. assert_almost_equal(pdf1, pdf2)
  1414. def test_gennorm(self):
  1415. # test against generalized normal
  1416. points = [1, 2, 3]
  1417. pdf1 = stats.halfgennorm.pdf(points, .497324)
  1418. pdf2 = stats.gennorm.pdf(points, .497324)
  1419. assert_almost_equal(pdf1, 2*pdf2)
  1420. class TestLaplaceasymmetric:
  1421. def test_laplace(self):
  1422. # test against Laplace (special case for kappa=1)
  1423. points = np.array([1, 2, 3])
  1424. pdf1 = stats.laplace_asymmetric.pdf(points, 1)
  1425. pdf2 = stats.laplace.pdf(points)
  1426. assert_allclose(pdf1, pdf2)
  1427. def test_asymmetric_laplace_pdf(self):
  1428. # test asymmetric Laplace
  1429. points = np.array([1, 2, 3])
  1430. kappa = 2
  1431. kapinv = 1/kappa
  1432. pdf1 = stats.laplace_asymmetric.pdf(points, kappa)
  1433. pdf2 = stats.laplace_asymmetric.pdf(points*(kappa**2), kapinv)
  1434. assert_allclose(pdf1, pdf2)
  1435. def test_asymmetric_laplace_log_10_16(self):
  1436. # test asymmetric Laplace
  1437. points = np.array([-np.log(16), np.log(10)])
  1438. kappa = 2
  1439. pdf1 = stats.laplace_asymmetric.pdf(points, kappa)
  1440. cdf1 = stats.laplace_asymmetric.cdf(points, kappa)
  1441. sf1 = stats.laplace_asymmetric.sf(points, kappa)
  1442. pdf2 = np.array([1/10, 1/250])
  1443. cdf2 = np.array([1/5, 1 - 1/500])
  1444. sf2 = np.array([4/5, 1/500])
  1445. ppf1 = stats.laplace_asymmetric.ppf(cdf2, kappa)
  1446. ppf2 = points
  1447. isf1 = stats.laplace_asymmetric.isf(sf2, kappa)
  1448. isf2 = points
  1449. assert_allclose(np.concatenate((pdf1, cdf1, sf1, ppf1, isf1)),
  1450. np.concatenate((pdf2, cdf2, sf2, ppf2, isf2)))
  1451. class TestTruncnorm:
  1452. def setup_method(self):
  1453. self.rng = np.random.default_rng(3255963201)
  1454. @pytest.mark.parametrize("a, b, ref",
  1455. [(0, 100, 0.7257913526447274),
  1456. (0.6, 0.7, -2.3027610681852573),
  1457. (1e-06, 2e-06, -13.815510557964274)])
  1458. def test_entropy(self, a, b, ref):
  1459. # All reference values were calculated with mpmath:
  1460. # import numpy as np
  1461. # from mpmath import mp
  1462. # mp.dps = 50
  1463. # def entropy_trun(a, b):
  1464. # a, b = mp.mpf(a), mp.mpf(b)
  1465. # Z = mp.ncdf(b) - mp.ncdf(a)
  1466. #
  1467. # def pdf(x):
  1468. # return mp.npdf(x) / Z
  1469. #
  1470. # res = -mp.quad(lambda t: pdf(t) * mp.log(pdf(t)), [a, b])
  1471. # return np.float64(res)
  1472. assert_allclose(stats.truncnorm.entropy(a, b), ref, rtol=1e-10)
  1473. @pytest.mark.parametrize("a, b, ref",
  1474. [(1e-11, 10000000000.0, 0.725791352640738),
  1475. (1e-100, 1e+100, 0.7257913526447274),
  1476. (-1e-100, 1e+100, 0.7257913526447274),
  1477. (-1e+100, 1e+100, 1.4189385332046727)])
  1478. def test_extreme_entropy(self, a, b, ref):
  1479. # The reference values were calculated with mpmath
  1480. # import numpy as np
  1481. # from mpmath import mp
  1482. # mp.dps = 50
  1483. # def trunc_norm_entropy(a, b):
  1484. # a, b = mp.mpf(a), mp.mpf(b)
  1485. # Z = mp.ncdf(b) - mp.ncdf(a)
  1486. # A = mp.log(mp.sqrt(2 * mp.pi * mp.e) * Z)
  1487. # B = (a * mp.npdf(a) - b * mp.npdf(b)) / (2 * Z)
  1488. # return np.float64(A + B)
  1489. assert_allclose(stats.truncnorm.entropy(a, b), ref, rtol=1e-14)
  1490. def test_ppf_ticket1131(self):
  1491. vals = stats.truncnorm.ppf([-0.5, 0, 1e-4, 0.5, 1-1e-4, 1, 2], -1., 1.,
  1492. loc=[3]*7, scale=2)
  1493. expected = np.array([np.nan, 1, 1.00056419, 3, 4.99943581, 5, np.nan])
  1494. assert_array_almost_equal(vals, expected)
  1495. def test_isf_ticket1131(self):
  1496. vals = stats.truncnorm.isf([-0.5, 0, 1e-4, 0.5, 1-1e-4, 1, 2], -1., 1.,
  1497. loc=[3]*7, scale=2)
  1498. expected = np.array([np.nan, 5, 4.99943581, 3, 1.00056419, 1, np.nan])
  1499. assert_array_almost_equal(vals, expected)
  1500. def test_gh_2477_small_values(self):
  1501. # Check a case that worked in the original issue.
  1502. low, high = -11, -10
  1503. x = stats.truncnorm.rvs(low, high, 0, 1, size=10, random_state=self.rng)
  1504. assert_(low < x.min() < x.max() < high)
  1505. # Check a case that failed in the original issue.
  1506. low, high = 10, 11
  1507. x = stats.truncnorm.rvs(low, high, 0, 1, size=10, random_state=self.rng)
  1508. assert_(low < x.min() < x.max() < high)
  1509. def test_gh_2477_large_values(self):
  1510. # Check a case that used to fail because of extreme tailness.
  1511. low, high = 100, 101
  1512. x = stats.truncnorm.rvs(low, high, 0, 1, size=10, random_state=self.rng)
  1513. assert_(low <= x.min() <= x.max() <= high), str([low, high, x])
  1514. # Check some additional extreme tails
  1515. low, high = 1000, 1001
  1516. x = stats.truncnorm.rvs(low, high, 0, 1, size=10, random_state=self.rng)
  1517. assert_(low < x.min() < x.max() < high)
  1518. low, high = 10000, 10001
  1519. x = stats.truncnorm.rvs(low, high, 0, 1, size=10, random_state=self.rng)
  1520. assert_(low < x.min() < x.max() < high)
  1521. low, high = -10001, -10000
  1522. x = stats.truncnorm.rvs(low, high, 0, 1, size=10, random_state=self.rng)
  1523. assert_(low < x.min() < x.max() < high)
  1524. def test_gh_9403_nontail_values(self):
  1525. for low, high in [[3, 4], [-4, -3]]:
  1526. xvals = np.array([-np.inf, low, high, np.inf])
  1527. xmid = (high+low)/2.0
  1528. cdfs = stats.truncnorm.cdf(xvals, low, high)
  1529. sfs = stats.truncnorm.sf(xvals, low, high)
  1530. pdfs = stats.truncnorm.pdf(xvals, low, high)
  1531. expected_cdfs = np.array([0, 0, 1, 1])
  1532. expected_sfs = np.array([1.0, 1.0, 0.0, 0.0])
  1533. expected_pdfs = np.array([0, 3.3619772, 0.1015229, 0])
  1534. if low < 0:
  1535. expected_pdfs = np.array([0, 0.1015229, 3.3619772, 0])
  1536. assert_almost_equal(cdfs, expected_cdfs)
  1537. assert_almost_equal(sfs, expected_sfs)
  1538. assert_almost_equal(pdfs, expected_pdfs)
  1539. assert_almost_equal(np.log(expected_pdfs[1]/expected_pdfs[2]),
  1540. low + 0.5)
  1541. pvals = np.array([0, 0.5, 1.0])
  1542. ppfs = stats.truncnorm.ppf(pvals, low, high)
  1543. expected_ppfs = np.array([low, np.sign(low)*3.1984741, high])
  1544. assert_almost_equal(ppfs, expected_ppfs)
  1545. if low < 0:
  1546. assert_almost_equal(stats.truncnorm.sf(xmid, low, high),
  1547. 0.8475544278436675)
  1548. assert_almost_equal(stats.truncnorm.cdf(xmid, low, high),
  1549. 0.1524455721563326)
  1550. else:
  1551. assert_almost_equal(stats.truncnorm.cdf(xmid, low, high),
  1552. 0.8475544278436675)
  1553. assert_almost_equal(stats.truncnorm.sf(xmid, low, high),
  1554. 0.1524455721563326)
  1555. pdf = stats.truncnorm.pdf(xmid, low, high)
  1556. assert_almost_equal(np.log(pdf/expected_pdfs[2]), (xmid+0.25)/2)
  1557. def test_gh_9403_medium_tail_values(self):
  1558. for low, high in [[39, 40], [-40, -39]]:
  1559. xvals = np.array([-np.inf, low, high, np.inf])
  1560. xmid = (high+low)/2.0
  1561. cdfs = stats.truncnorm.cdf(xvals, low, high)
  1562. sfs = stats.truncnorm.sf(xvals, low, high)
  1563. pdfs = stats.truncnorm.pdf(xvals, low, high)
  1564. expected_cdfs = np.array([0, 0, 1, 1])
  1565. expected_sfs = np.array([1.0, 1.0, 0.0, 0.0])
  1566. expected_pdfs = np.array([0, 3.90256074e+01, 2.73349092e-16, 0])
  1567. if low < 0:
  1568. expected_pdfs = np.array([0, 2.73349092e-16,
  1569. 3.90256074e+01, 0])
  1570. assert_almost_equal(cdfs, expected_cdfs)
  1571. assert_almost_equal(sfs, expected_sfs)
  1572. assert_almost_equal(pdfs, expected_pdfs)
  1573. assert_almost_equal(np.log(expected_pdfs[1]/expected_pdfs[2]),
  1574. low + 0.5)
  1575. pvals = np.array([0, 0.5, 1.0])
  1576. ppfs = stats.truncnorm.ppf(pvals, low, high)
  1577. expected_ppfs = np.array([low, np.sign(low)*39.01775731, high])
  1578. assert_almost_equal(ppfs, expected_ppfs)
  1579. cdfs = stats.truncnorm.cdf(ppfs, low, high)
  1580. assert_almost_equal(cdfs, pvals)
  1581. if low < 0:
  1582. assert_almost_equal(stats.truncnorm.sf(xmid, low, high),
  1583. 0.9999999970389126)
  1584. assert_almost_equal(stats.truncnorm.cdf(xmid, low, high),
  1585. 2.961048103554866e-09)
  1586. else:
  1587. assert_almost_equal(stats.truncnorm.cdf(xmid, low, high),
  1588. 0.9999999970389126)
  1589. assert_almost_equal(stats.truncnorm.sf(xmid, low, high),
  1590. 2.961048103554866e-09)
  1591. pdf = stats.truncnorm.pdf(xmid, low, high)
  1592. assert_almost_equal(np.log(pdf/expected_pdfs[2]), (xmid+0.25)/2)
  1593. xvals = np.linspace(low, high, 11)
  1594. xvals2 = -xvals[::-1]
  1595. assert_almost_equal(stats.truncnorm.cdf(xvals, low, high),
  1596. stats.truncnorm.sf(xvals2, -high, -low)[::-1])
  1597. assert_almost_equal(stats.truncnorm.sf(xvals, low, high),
  1598. stats.truncnorm.cdf(xvals2, -high, -low)[::-1])
  1599. assert_almost_equal(stats.truncnorm.pdf(xvals, low, high),
  1600. stats.truncnorm.pdf(xvals2, -high, -low)[::-1])
  1601. def test_cdf_tail_15110_14753(self):
  1602. # Check accuracy issues reported in gh-14753 and gh-155110
  1603. # Ground truth values calculated using Wolfram Alpha, e.g.
  1604. # (CDF[NormalDistribution[0,1],83/10]-CDF[NormalDistribution[0,1],8])/
  1605. # (1 - CDF[NormalDistribution[0,1],8])
  1606. assert_allclose(stats.truncnorm(13., 15.).cdf(14.),
  1607. 0.9999987259565643)
  1608. assert_allclose(stats.truncnorm(8, np.inf).cdf(8.3),
  1609. 0.9163220907327540)
  1610. # Test data for the truncnorm stats() method.
  1611. # The data in each row is:
  1612. # a, b, mean, variance, skewness, excess kurtosis. Generated using
  1613. # https://gist.github.com/WarrenWeckesser/636b537ee889679227d53543d333a720
  1614. _truncnorm_stats_data = [
  1615. [-30, 30,
  1616. 0.0, 1.0, 0.0, 0.0],
  1617. [-10, 10,
  1618. 0.0, 1.0, 0.0, -1.4927521335810455e-19],
  1619. [-3, 3,
  1620. 0.0, 0.9733369246625415, 0.0, -0.17111443639774404],
  1621. [-2, 2,
  1622. 0.0, 0.7737413035499232, 0.0, -0.6344632828703505],
  1623. [0, np.inf,
  1624. 0.7978845608028654,
  1625. 0.3633802276324187,
  1626. 0.995271746431156,
  1627. 0.8691773036059741],
  1628. [-np.inf, 0,
  1629. -0.7978845608028654,
  1630. 0.3633802276324187,
  1631. -0.995271746431156,
  1632. 0.8691773036059741],
  1633. [-1, 3,
  1634. 0.282786110727154,
  1635. 0.6161417353578293,
  1636. 0.5393018494027877,
  1637. -0.20582065135274694],
  1638. [-3, 1,
  1639. -0.282786110727154,
  1640. 0.6161417353578293,
  1641. -0.5393018494027877,
  1642. -0.20582065135274694],
  1643. [-10, -9,
  1644. -9.108456288012409,
  1645. 0.011448805821636248,
  1646. -1.8985607290949496,
  1647. 5.0733461105025075],
  1648. ]
  1649. _truncnorm_stats_data = np.array(_truncnorm_stats_data)
  1650. @pytest.mark.parametrize("case", _truncnorm_stats_data)
  1651. def test_moments(self, case):
  1652. a, b, m0, v0, s0, k0 = case
  1653. m, v, s, k = stats.truncnorm.stats(a, b, moments='mvsk')
  1654. assert_allclose([m, v, s, k], [m0, v0, s0, k0], atol=1e-17)
  1655. def test_9902_moments(self):
  1656. m, v = stats.truncnorm.stats(0, np.inf, moments='mv')
  1657. assert_almost_equal(m, 0.79788456)
  1658. assert_almost_equal(v, 0.36338023)
  1659. def test_gh_1489_trac_962_rvs(self):
  1660. # Check the original example.
  1661. low, high = 10, 15
  1662. x = stats.truncnorm.rvs(low, high, 0, 1, size=10, random_state=self.rng)
  1663. assert_(low < x.min() < x.max() < high)
  1664. def test_gh_11299_rvs(self):
  1665. # Arose from investigating gh-11299
  1666. # Test multiple shape parameters simultaneously.
  1667. low = [-10, 10, -np.inf, -5, -np.inf, -np.inf, -45, -45, 40, -10, 40]
  1668. high = [-5, 11, 5, np.inf, 40, -40, 40, -40, 45, np.inf, np.inf]
  1669. x = stats.truncnorm.rvs(low, high, size=(5, len(low)), random_state=self.rng)
  1670. assert np.shape(x) == (5, len(low))
  1671. assert_(np.all(low <= x.min(axis=0)))
  1672. assert_(np.all(x.max(axis=0) <= high))
  1673. def test_rvs_Generator(self):
  1674. # check that rvs can use a Generator
  1675. if hasattr(np.random, "default_rng"):
  1676. stats.truncnorm.rvs(-10, -5, size=5, random_state=self.rng)
  1677. def test_logcdf_gh17064(self):
  1678. # regression test for gh-17064 - avoid roundoff error for logcdfs ~0
  1679. a = np.array([-np.inf, -np.inf, -8, -np.inf, 10])
  1680. b = np.array([np.inf, np.inf, 8, 10, np.inf])
  1681. x = np.array([10, 7.5, 7.5, 9, 20])
  1682. expected = [-7.619853024160525e-24, -3.190891672910947e-14,
  1683. -3.128682067168231e-14, -1.1285122074235991e-19,
  1684. -3.61374964828753e-66]
  1685. assert_allclose(stats.truncnorm(a, b).logcdf(x), expected)
  1686. assert_allclose(stats.truncnorm(-b, -a).logsf(-x), expected)
  1687. def test_moments_gh18634(self):
  1688. # gh-18634 reported that moments 5 and higher didn't work; check that
  1689. # this is resolved
  1690. res = stats.truncnorm(-2, 3).moment(5)
  1691. # From Mathematica:
  1692. # Moment[TruncatedDistribution[{-2, 3}, NormalDistribution[]], 5]
  1693. ref = 1.645309620208361
  1694. assert_allclose(res, ref)
  1695. class TestGenLogistic:
  1696. # Expected values computed with mpmath with 50 digits of precision.
  1697. @pytest.mark.parametrize('x, expected', [(-1000, -1499.5945348918917),
  1698. (-125, -187.09453489189184),
  1699. (0, -1.3274028432916989),
  1700. (100, -99.59453489189184),
  1701. (1000, -999.5945348918918)])
  1702. def test_logpdf(self, x, expected):
  1703. c = 1.5
  1704. logp = stats.genlogistic.logpdf(x, c)
  1705. assert_allclose(logp, expected, rtol=1e-13)
  1706. # Expected values computed with mpmath with 50 digits of precision
  1707. # from mpmath import mp
  1708. # mp.dps = 50
  1709. # def entropy_mp(c):
  1710. # c = mp.mpf(c)
  1711. # return float(-mp.log(c)+mp.one+mp.digamma(c + mp.one) + mp.euler)
  1712. @pytest.mark.parametrize('c, ref', [(1e-100, 231.25850929940458),
  1713. (1e-4, 10.21050485336338),
  1714. (1e8, 1.577215669901533),
  1715. (1e100, 1.5772156649015328)])
  1716. def test_entropy(self, c, ref):
  1717. assert_allclose(stats.genlogistic.entropy(c), ref, rtol=5e-15)
  1718. # Expected values computed with mpmath with 50 digits of precision
  1719. # from mpmath import mp
  1720. # mp.dps = 1000
  1721. #
  1722. # def genlogistic_cdf_mp(x, c):
  1723. # x = mp.mpf(x)
  1724. # c = mp.mpf(c)
  1725. # return (mp.one + mp.exp(-x)) ** (-c)
  1726. #
  1727. # def genlogistic_sf_mp(x, c):
  1728. # return mp.one - genlogistic_cdf_mp(x, c)
  1729. #
  1730. # x, c, ref = 100, 0.02, -7.440151952041672e-466
  1731. # print(float(mp.log(genlogistic_cdf_mp(x, c))))
  1732. # ppf/isf reference values generated by passing in `ref` (`q` is produced)
  1733. @pytest.mark.parametrize('x, c, ref', [(200, 10, 1.3838965267367375e-86),
  1734. (500, 20, 1.424915281348257e-216)])
  1735. def test_sf(self, x, c, ref):
  1736. assert_allclose(stats.genlogistic.sf(x, c), ref, rtol=1e-14)
  1737. @pytest.mark.parametrize('q, c, ref', [(0.01, 200, 9.898441467379765),
  1738. (0.001, 2, 7.600152115573173)])
  1739. def test_isf(self, q, c, ref):
  1740. assert_allclose(stats.genlogistic.isf(q, c), ref, rtol=5e-16)
  1741. @pytest.mark.parametrize('q, c, ref', [(0.5, 200, 5.6630969187064615),
  1742. (0.99, 20, 7.595630231412436)])
  1743. def test_ppf(self, q, c, ref):
  1744. assert_allclose(stats.genlogistic.ppf(q, c), ref, rtol=5e-16)
  1745. @pytest.mark.parametrize('x, c, ref', [(100, 0.02, -7.440151952041672e-46),
  1746. (50, 20, -3.857499695927835e-21)])
  1747. def test_logcdf(self, x, c, ref):
  1748. assert_allclose(stats.genlogistic.logcdf(x, c), ref, rtol=1e-15)
  1749. class TestHypergeom:
  1750. def setup_method(self):
  1751. self.rng = np.random.default_rng(1765545342)
  1752. def test_rvs(self):
  1753. vals = stats.hypergeom.rvs(20, 10, 3, size=(2, 50), random_state=self.rng)
  1754. assert np.all(vals >= 0) & np.all(vals <= 3)
  1755. assert np.shape(vals) == (2, 50)
  1756. assert vals.dtype.char in typecodes['AllInteger']
  1757. val = stats.hypergeom.rvs(20, 3, 10, random_state=self.rng)
  1758. assert isinstance(val, int)
  1759. val = stats.hypergeom(20, 3, 10).rvs(3, random_state=self.rng)
  1760. assert isinstance(val, np.ndarray)
  1761. assert val.dtype.char in typecodes['AllInteger']
  1762. def test_precision(self):
  1763. # comparison number from mpmath
  1764. M = 2500
  1765. n = 50
  1766. N = 500
  1767. tot = M
  1768. good = n
  1769. hgpmf = stats.hypergeom.pmf(2, tot, good, N)
  1770. assert_almost_equal(hgpmf, 0.0010114963068932233, 11)
  1771. def test_args(self):
  1772. # test correct output for corner cases of arguments
  1773. # see gh-2325
  1774. assert_almost_equal(stats.hypergeom.pmf(0, 2, 1, 0), 1.0, 11)
  1775. assert_almost_equal(stats.hypergeom.pmf(1, 2, 1, 0), 0.0, 11)
  1776. assert_almost_equal(stats.hypergeom.pmf(0, 2, 0, 2), 1.0, 11)
  1777. assert_almost_equal(stats.hypergeom.pmf(1, 2, 1, 0), 0.0, 11)
  1778. def test_cdf_above_one(self):
  1779. # for some values of parameters, hypergeom cdf was >1, see gh-2238
  1780. assert_(0 <= stats.hypergeom.cdf(30, 13397950, 4363, 12390) <= 1.0)
  1781. def test_precision2(self):
  1782. # Test hypergeom precision for large numbers. See #1218.
  1783. # Results compared with those from R.
  1784. oranges = 9.9e4
  1785. pears = 1.1e5
  1786. fruits_eaten = np.array([3, 3.8, 3.9, 4, 4.1, 4.2, 5]) * 1e4
  1787. quantile = 2e4
  1788. res = [stats.hypergeom.sf(quantile, oranges + pears, oranges, eaten)
  1789. for eaten in fruits_eaten]
  1790. expected = np.array([0, 1.904153e-114, 2.752693e-66, 4.931217e-32,
  1791. 8.265601e-11, 0.1237904, 1])
  1792. assert_allclose(res, expected, atol=0, rtol=5e-7)
  1793. # Test with array_like first argument
  1794. quantiles = [1.9e4, 2e4, 2.1e4, 2.15e4]
  1795. res2 = stats.hypergeom.sf(quantiles, oranges + pears, oranges, 4.2e4)
  1796. expected2 = [1, 0.1237904, 6.511452e-34, 3.277667e-69]
  1797. assert_allclose(res2, expected2, atol=0, rtol=5e-7)
  1798. def test_entropy(self):
  1799. # Simple tests of entropy.
  1800. hg = stats.hypergeom(4, 1, 1)
  1801. h = hg.entropy()
  1802. expected_p = np.array([0.75, 0.25])
  1803. expected_h = -np.sum(xlogy(expected_p, expected_p))
  1804. assert_allclose(h, expected_h)
  1805. hg = stats.hypergeom(1, 1, 1)
  1806. h = hg.entropy()
  1807. assert_equal(h, 0.0)
  1808. def test_logsf(self):
  1809. # Test logsf for very large numbers. See issue #4982
  1810. # Results compare with those from R (v3.2.0):
  1811. # phyper(k, n, M-n, N, lower.tail=FALSE, log.p=TRUE)
  1812. # -2239.771
  1813. k = 1e4
  1814. M = 1e7
  1815. n = 1e6
  1816. N = 5e4
  1817. result = stats.hypergeom.logsf(k, M, n, N)
  1818. expected = -2239.771 # From R
  1819. assert_almost_equal(result, expected, decimal=3)
  1820. k = 1
  1821. M = 1600
  1822. n = 600
  1823. N = 300
  1824. result = stats.hypergeom.logsf(k, M, n, N)
  1825. expected = -2.566567e-68 # From R
  1826. assert_almost_equal(result, expected, decimal=15)
  1827. def test_logcdf(self):
  1828. # Test logcdf for very large numbers. See issue #8692
  1829. # Results compare with those from R (v3.3.2):
  1830. # phyper(k, n, M-n, N, lower.tail=TRUE, log.p=TRUE)
  1831. # -5273.335
  1832. k = 1
  1833. M = 1e7
  1834. n = 1e6
  1835. N = 5e4
  1836. result = stats.hypergeom.logcdf(k, M, n, N)
  1837. expected = -5273.335 # From R
  1838. assert_almost_equal(result, expected, decimal=3)
  1839. # Same example as in issue #8692
  1840. k = 40
  1841. M = 1600
  1842. n = 50
  1843. N = 300
  1844. result = stats.hypergeom.logcdf(k, M, n, N)
  1845. expected = -7.565148879229e-23 # From R
  1846. assert_almost_equal(result, expected, decimal=15)
  1847. k = 125
  1848. M = 1600
  1849. n = 250
  1850. N = 500
  1851. result = stats.hypergeom.logcdf(k, M, n, N)
  1852. expected = -4.242688e-12 # From R
  1853. assert_almost_equal(result, expected, decimal=15)
  1854. # test broadcasting robustness based on reviewer
  1855. # concerns in PR 9603; using an array version of
  1856. # the example from issue #8692
  1857. k = np.array([40, 40, 40])
  1858. M = 1600
  1859. n = 50
  1860. N = 300
  1861. result = stats.hypergeom.logcdf(k, M, n, N)
  1862. expected = np.full(3, -7.565148879229e-23) # filled from R result
  1863. assert_almost_equal(result, expected, decimal=15)
  1864. def test_mean_gh18511(self):
  1865. # gh-18511 reported that the `mean` was incorrect for large arguments;
  1866. # check that this is resolved
  1867. M = 390_000
  1868. n = 370_000
  1869. N = 12_000
  1870. hm = stats.hypergeom.mean(M, n, N)
  1871. rm = n / M * N
  1872. assert_allclose(hm, rm)
  1873. @pytest.mark.xslow
  1874. def test_sf_gh18506(self):
  1875. # gh-18506 reported that `sf` was incorrect for large population;
  1876. # check that this is resolved
  1877. n = 10
  1878. N = 10**5
  1879. i = np.arange(5, 15)
  1880. population_size = 10.**i
  1881. p = stats.hypergeom.sf(n - 1, population_size, N, n)
  1882. assert np.all(p > 0)
  1883. assert np.all(np.diff(p) < 0)
  1884. class TestLoggamma:
  1885. def setup_method(self):
  1886. self.rng = np.random.default_rng(8638464332)
  1887. # Expected cdf values were computed with mpmath. For given x and c,
  1888. # x = mpmath.mpf(x)
  1889. # c = mpmath.mpf(c)
  1890. # cdf = mpmath.gammainc(c, 0, mpmath.exp(x),
  1891. # regularized=True)
  1892. @pytest.mark.parametrize('x, c, cdf',
  1893. [(1, 2, 0.7546378854206702),
  1894. (-1, 14, 6.768116452566383e-18),
  1895. (-745.1, 0.001, 0.4749605142005238),
  1896. (-800, 0.001, 0.44958802911019136),
  1897. (-725, 0.1, 3.4301205868273265e-32),
  1898. (-740, 0.75, 1.0074360436599631e-241)])
  1899. def test_cdf_ppf(self, x, c, cdf):
  1900. p = stats.loggamma.cdf(x, c)
  1901. assert_allclose(p, cdf, rtol=1e-13)
  1902. y = stats.loggamma.ppf(cdf, c)
  1903. assert_allclose(y, x, rtol=1e-13)
  1904. # Expected sf values were computed with mpmath. For given x and c,
  1905. # x = mpmath.mpf(x)
  1906. # c = mpmath.mpf(c)
  1907. # sf = mpmath.gammainc(c, mpmath.exp(x), mpmath.inf,
  1908. # regularized=True)
  1909. @pytest.mark.parametrize('x, c, sf',
  1910. [(4, 1.5, 1.6341528919488565e-23),
  1911. (6, 100, 8.23836829202024e-74),
  1912. (-800, 0.001, 0.5504119708898086),
  1913. (-743, 0.0025, 0.8437131370024089)])
  1914. def test_sf_isf(self, x, c, sf):
  1915. s = stats.loggamma.sf(x, c)
  1916. assert_allclose(s, sf, rtol=1e-13)
  1917. y = stats.loggamma.isf(sf, c)
  1918. assert_allclose(y, x, rtol=1e-13)
  1919. def test_logpdf(self):
  1920. # Test logpdf with x=-500, c=2. ln(gamma(2)) = 0, and
  1921. # exp(-500) ~= 7e-218, which is far smaller than the ULP
  1922. # of c*x=-1000, so logpdf(-500, 2) = c*x - exp(x) - ln(gamma(2))
  1923. # should give -1000.0.
  1924. lp = stats.loggamma.logpdf(-500, 2)
  1925. assert_allclose(lp, -1000.0, rtol=1e-14)
  1926. def test_logcdf(self):
  1927. x = 4.0
  1928. c = 4.5
  1929. logcdf = stats.loggamma.logcdf(x, c)
  1930. # Reference value computed with mpmath.
  1931. ref = -2.1429747073164531e-19
  1932. assert_allclose(logcdf, ref, rtol=5e-15)
  1933. def test_logsf(self):
  1934. x = -25.0
  1935. c = 3.5
  1936. logsf = stats.loggamma.logsf(x, c)
  1937. # Reference value computed with mpmath.
  1938. ref = -8.58200139319556e-40
  1939. assert_allclose(logsf, ref, rtol=5e-15)
  1940. def test_stats(self):
  1941. # The following precomputed values are from the table in section 2.2
  1942. # of "A Statistical Study of Log-Gamma Distribution", by Ping Shing
  1943. # Chan (thesis, McMaster University, 1993).
  1944. table = np.array([
  1945. # c, mean, var, skew, exc. kurt.
  1946. 0.5, -1.9635, 4.9348, -1.5351, 4.0000,
  1947. 1.0, -0.5772, 1.6449, -1.1395, 2.4000,
  1948. 12.0, 2.4427, 0.0869, -0.2946, 0.1735,
  1949. ]).reshape(-1, 5)
  1950. for c, mean, var, skew, kurt in table:
  1951. computed = stats.loggamma.stats(c, moments='msvk')
  1952. assert_array_almost_equal(computed, [mean, var, skew, kurt],
  1953. decimal=4)
  1954. @pytest.mark.parametrize('c', [0.1, 0.001])
  1955. def test_rvs(self, c):
  1956. # Regression test for gh-11094.
  1957. x = stats.loggamma.rvs(c, size=100000, random_state=self.rng)
  1958. # Before gh-11094 was fixed, the case with c=0.001 would
  1959. # generate many -inf values.
  1960. assert np.isfinite(x).all()
  1961. # Crude statistical test. About half the values should be
  1962. # less than the median and half greater than the median.
  1963. med = stats.loggamma.median(c)
  1964. btest = stats.binomtest(np.count_nonzero(x < med), len(x))
  1965. ci = btest.proportion_ci(confidence_level=0.999)
  1966. assert ci.low < 0.5 < ci.high
  1967. @pytest.mark.parametrize("c, ref",
  1968. [(1e-8, 19.420680753952364),
  1969. (1, 1.5772156649015328),
  1970. (1e4, -3.186214986116763),
  1971. (1e10, -10.093986931748889),
  1972. (1e100, -113.71031611649761)])
  1973. def test_entropy(self, c, ref):
  1974. # Reference values were calculated with mpmath
  1975. # from mpmath import mp
  1976. # mp.dps = 500
  1977. # def loggamma_entropy_mpmath(c):
  1978. # c = mp.mpf(c)
  1979. # return float(mp.log(mp.gamma(c)) + c * (mp.one - mp.digamma(c)))
  1980. assert_allclose(stats.loggamma.entropy(c), ref, rtol=1e-14)
  1981. class TestJohnsonsu:
  1982. # reference values were computed via mpmath
  1983. # from mpmath import mp
  1984. # mp.dps = 50
  1985. # def johnsonsu_sf(x, a, b):
  1986. # x = mp.mpf(x)
  1987. # a = mp.mpf(a)
  1988. # b = mp.mpf(b)
  1989. # return float(mp.ncdf(-(a + b * mp.log(x + mp.sqrt(x*x + 1)))))
  1990. # Order is x, a, b, sf, isf tol
  1991. # (Can't expect full precision when the ISF input is very nearly 1)
  1992. cases = [(-500, 1, 1, 0.9999999982660072, 1e-8),
  1993. (2000, 1, 1, 7.426351000595343e-21, 5e-14),
  1994. (100000, 1, 1, 4.046923979269977e-40, 5e-14)]
  1995. @pytest.mark.parametrize("case", cases)
  1996. def test_sf_isf(self, case):
  1997. x, a, b, sf, tol = case
  1998. assert_allclose(stats.johnsonsu.sf(x, a, b), sf, rtol=5e-14)
  1999. assert_allclose(stats.johnsonsu.isf(sf, a, b), x, rtol=tol)
  2000. class TestJohnsonb:
  2001. # reference values were computed via mpmath
  2002. # from mpmath import mp
  2003. # mp.dps = 50
  2004. # def johnsonb_sf(x, a, b):
  2005. # x = mp.mpf(x)
  2006. # a = mp.mpf(a)
  2007. # b = mp.mpf(b)
  2008. # return float(mp.ncdf(-(a + b * mp.log(x/(mp.one - x)))))
  2009. # Order is x, a, b, sf, isf atol
  2010. # (Can't expect full precision when the ISF input is very nearly 1)
  2011. cases = [(1e-4, 1, 1, 0.9999999999999999, 1e-7),
  2012. (0.9999, 1, 1, 8.921114313932308e-25, 5e-14),
  2013. (0.999999, 1, 1, 5.815197487181902e-50, 5e-14)]
  2014. @pytest.mark.parametrize("case", cases)
  2015. def test_sf_isf(self, case):
  2016. x, a, b, sf, tol = case
  2017. assert_allclose(stats.johnsonsb.sf(x, a, b), sf, rtol=5e-14)
  2018. assert_allclose(stats.johnsonsb.isf(sf, a, b), x, atol=tol)
  2019. class TestLogistic:
  2020. def setup_method(self):
  2021. self.rng = np.random.default_rng(2807014525)
  2022. # gh-6226
  2023. def test_cdf_ppf(self):
  2024. x = np.linspace(-20, 20)
  2025. y = stats.logistic.cdf(x)
  2026. xx = stats.logistic.ppf(y)
  2027. assert_allclose(x, xx)
  2028. def test_sf_isf(self):
  2029. x = np.linspace(-20, 20)
  2030. y = stats.logistic.sf(x)
  2031. xx = stats.logistic.isf(y)
  2032. assert_allclose(x, xx)
  2033. def test_extreme_values(self):
  2034. # p is chosen so that 1 - (1 - p) == p in double precision
  2035. p = 9.992007221626409e-16
  2036. desired = 34.53957599234088
  2037. assert_allclose(stats.logistic.ppf(1 - p), desired)
  2038. assert_allclose(stats.logistic.isf(p), desired)
  2039. def test_logpdf_basic(self):
  2040. logp = stats.logistic.logpdf([-15, 0, 10])
  2041. # Expected values computed with mpmath with 50 digits of precision.
  2042. expected = [-15.000000611804547,
  2043. -1.3862943611198906,
  2044. -10.000090797798434]
  2045. assert_allclose(logp, expected, rtol=1e-13)
  2046. def test_logpdf_extreme_values(self):
  2047. logp = stats.logistic.logpdf([800, -800])
  2048. # For such large arguments, logpdf(x) = -abs(x) when computed
  2049. # with 64 bit floating point.
  2050. assert_equal(logp, [-800, -800])
  2051. @pytest.mark.parametrize("loc_rvs,scale_rvs", [(0.4484955, 0.10216821),
  2052. (0.62918191, 0.74367064)])
  2053. def test_fit(self, loc_rvs, scale_rvs):
  2054. data = stats.logistic.rvs(size=100, loc=loc_rvs, scale=scale_rvs,
  2055. random_state=self.rng)
  2056. # test that result of fit method is the same as optimization
  2057. def func(input, data):
  2058. a, b = input
  2059. n = len(data)
  2060. x1 = np.sum(np.exp((data - a) / b) /
  2061. (1 + np.exp((data - a) / b))) - n / 2
  2062. x2 = np.sum(((data - a) / b) *
  2063. ((np.exp((data - a) / b) - 1) /
  2064. (np.exp((data - a) / b) + 1))) - n
  2065. return x1, x2
  2066. expected_solution = root(func, stats.logistic._fitstart(data), args=(
  2067. data,)).x
  2068. fit_method = stats.logistic.fit(data)
  2069. # other than computational variances, the fit method and the solution
  2070. # to this system of equations are equal
  2071. assert_allclose(fit_method, expected_solution, atol=1e-30)
  2072. def test_fit_comp_optimizer(self):
  2073. data = stats.logistic.rvs(size=100, loc=0.5, scale=2, random_state=self.rng)
  2074. _assert_less_or_close_loglike(stats.logistic, data)
  2075. _assert_less_or_close_loglike(stats.logistic, data, floc=1)
  2076. _assert_less_or_close_loglike(stats.logistic, data, fscale=1)
  2077. @pytest.mark.parametrize('testlogcdf', [True, False])
  2078. def test_logcdfsf_tails(self, testlogcdf):
  2079. # Test either logcdf or logsf. By symmetry, we can use the same
  2080. # expected values for both by switching the sign of x for logsf.
  2081. x = np.array([-10000, -800, 17, 50, 500])
  2082. if testlogcdf:
  2083. y = stats.logistic.logcdf(x)
  2084. else:
  2085. y = stats.logistic.logsf(-x)
  2086. # The expected values were computed with mpmath.
  2087. expected = [-10000.0, -800.0, -4.139937633089748e-08,
  2088. -1.9287498479639178e-22, -7.124576406741286e-218]
  2089. assert_allclose(y, expected, rtol=2e-15)
  2090. def test_fit_gh_18176(self):
  2091. # logistic.fit returned `scale < 0` for this data. Check that this has
  2092. # been fixed.
  2093. data = np.array([-459, 37, 43, 45, 45, 48, 54, 55, 58]
  2094. + [59] * 3 + [61] * 9)
  2095. # If scale were negative, NLLF would be infinite, so this would fail
  2096. _assert_less_or_close_loglike(stats.logistic, data)
  2097. class TestLogser:
  2098. def setup_method(self):
  2099. self.rng = np.random.default_rng(187505461)
  2100. def test_rvs(self):
  2101. vals = stats.logser.rvs(0.75, size=(2, 50), random_state=self.rng)
  2102. assert np.all(vals >= 1)
  2103. assert np.shape(vals) == (2, 50)
  2104. assert vals.dtype.char in typecodes['AllInteger']
  2105. val = stats.logser.rvs(0.75, random_state=self.rng)
  2106. assert isinstance(val, int)
  2107. val = stats.logser(0.75).rvs(3, random_state=self.rng)
  2108. assert isinstance(val, np.ndarray)
  2109. assert val.dtype.char in typecodes['AllInteger']
  2110. def test_pmf_small_p(self):
  2111. m = stats.logser.pmf(4, 1e-20)
  2112. # The expected value was computed using mpmath:
  2113. # >>> import mpmath
  2114. # >>> mpmath.mp.dps = 64
  2115. # >>> k = 4
  2116. # >>> p = mpmath.mpf('1e-20')
  2117. # >>> float(-(p**k)/k/mpmath.log(1-p))
  2118. # 2.5e-61
  2119. # It is also clear from noticing that for very small p,
  2120. # log(1-p) is approximately -p, and the formula becomes
  2121. # p**(k-1) / k
  2122. assert_allclose(m, 2.5e-61)
  2123. def test_mean_small_p(self):
  2124. m = stats.logser.mean(1e-8)
  2125. # The expected mean was computed using mpmath:
  2126. # >>> import mpmath
  2127. # >>> mpmath.dps = 60
  2128. # >>> p = mpmath.mpf('1e-8')
  2129. # >>> float(-p / ((1 - p)*mpmath.log(1 - p)))
  2130. # 1.000000005
  2131. assert_allclose(m, 1.000000005)
  2132. def test_sf(self):
  2133. p = [[0.5], [1e-5], [1 - 1e-5]]
  2134. k = [1, 10, 100, 1000]
  2135. # Reference values from Wolfram Alpha, e.g.
  2136. # SurvivalFunction[LogSeriesDistribution[99999/100000], 1000]
  2137. # 0.35068668662799737584735036958139157462633608106500173019897861351038286634
  2138. ref = [[0.2786524795555183, 0.00011876901682721189,
  2139. 1.1159788564768581e-32, 1.3437300083506688e-304],
  2140. [5.000008333375e-06, 9.090946969973778e-52, 0, 0],
  2141. [0.9131419722083134, 0.745601735620566,
  2142. 0.5495169511115096, 0.3506866866279974]]
  2143. res = stats.logser.sf(k, p)
  2144. np.testing.assert_allclose(res, ref, atol=1e-300)
  2145. class TestGumbel_r_l:
  2146. @pytest.fixture(scope='function')
  2147. def rng(self):
  2148. return np.random.default_rng(1234)
  2149. @pytest.mark.parametrize("dist", [stats.gumbel_r, stats.gumbel_l])
  2150. @pytest.mark.parametrize("loc_rvs", [-1, 0, 1])
  2151. @pytest.mark.parametrize("scale_rvs", [.1, 1, 5])
  2152. @pytest.mark.parametrize('fix_loc, fix_scale',
  2153. ([True, False], [False, True]))
  2154. def test_fit_comp_optimizer(self, dist, loc_rvs, scale_rvs,
  2155. fix_loc, fix_scale, rng):
  2156. data = dist.rvs(size=100, loc=loc_rvs, scale=scale_rvs,
  2157. random_state=rng)
  2158. kwds = dict()
  2159. # the fixed location and scales are arbitrarily modified to not be
  2160. # close to the true value.
  2161. if fix_loc:
  2162. kwds['floc'] = loc_rvs * 2
  2163. if fix_scale:
  2164. kwds['fscale'] = scale_rvs * 2
  2165. # test that the gumbel_* fit method is better than super method
  2166. _assert_less_or_close_loglike(dist, data, **kwds)
  2167. @pytest.mark.parametrize("dist, sgn", [(stats.gumbel_r, 1),
  2168. (stats.gumbel_l, -1)])
  2169. def test_fit(self, dist, sgn):
  2170. z = sgn*np.array([3, 3, 3, 3, 3, 3, 3, 3.00000001])
  2171. loc, scale = dist.fit(z)
  2172. # The expected values were computed with mpmath with 60 digits
  2173. # of precision.
  2174. assert_allclose(loc, sgn*3.0000000001667906)
  2175. assert_allclose(scale, 1.2495222465145514e-09, rtol=1e-6)
  2176. class TestPareto:
  2177. def test_stats(self):
  2178. # Check the stats() method with some simple values. Also check
  2179. # that the calculations do not trigger RuntimeWarnings.
  2180. with warnings.catch_warnings():
  2181. warnings.simplefilter("error", RuntimeWarning)
  2182. m, v, s, k = stats.pareto.stats(0.5, moments='mvsk')
  2183. assert_equal(m, np.inf)
  2184. assert_equal(v, np.inf)
  2185. assert_equal(s, np.nan)
  2186. assert_equal(k, np.nan)
  2187. m, v, s, k = stats.pareto.stats(1.0, moments='mvsk')
  2188. assert_equal(m, np.inf)
  2189. assert_equal(v, np.inf)
  2190. assert_equal(s, np.nan)
  2191. assert_equal(k, np.nan)
  2192. m, v, s, k = stats.pareto.stats(1.5, moments='mvsk')
  2193. assert_equal(m, 3.0)
  2194. assert_equal(v, np.inf)
  2195. assert_equal(s, np.nan)
  2196. assert_equal(k, np.nan)
  2197. m, v, s, k = stats.pareto.stats(2.0, moments='mvsk')
  2198. assert_equal(m, 2.0)
  2199. assert_equal(v, np.inf)
  2200. assert_equal(s, np.nan)
  2201. assert_equal(k, np.nan)
  2202. m, v, s, k = stats.pareto.stats(2.5, moments='mvsk')
  2203. assert_allclose(m, 2.5 / 1.5)
  2204. assert_allclose(v, 2.5 / (1.5*1.5*0.5))
  2205. assert_equal(s, np.nan)
  2206. assert_equal(k, np.nan)
  2207. m, v, s, k = stats.pareto.stats(3.0, moments='mvsk')
  2208. assert_allclose(m, 1.5)
  2209. assert_allclose(v, 0.75)
  2210. assert_equal(s, np.nan)
  2211. assert_equal(k, np.nan)
  2212. m, v, s, k = stats.pareto.stats(3.5, moments='mvsk')
  2213. assert_allclose(m, 3.5 / 2.5)
  2214. assert_allclose(v, 3.5 / (2.5*2.5*1.5))
  2215. assert_allclose(s, (2*4.5/0.5)*np.sqrt(1.5/3.5))
  2216. assert_equal(k, np.nan)
  2217. m, v, s, k = stats.pareto.stats(4.0, moments='mvsk')
  2218. assert_allclose(m, 4.0 / 3.0)
  2219. assert_allclose(v, 4.0 / 18.0)
  2220. assert_allclose(s, 2*(1+4.0)/(4.0-3) * np.sqrt((4.0-2)/4.0))
  2221. assert_equal(k, np.nan)
  2222. m, v, s, k = stats.pareto.stats(4.5, moments='mvsk')
  2223. assert_allclose(m, 4.5 / 3.5)
  2224. assert_allclose(v, 4.5 / (3.5*3.5*2.5))
  2225. assert_allclose(s, (2*5.5/1.5) * np.sqrt(2.5/4.5))
  2226. assert_allclose(k, 6*(4.5**3 + 4.5**2 - 6*4.5 - 2)/(4.5*1.5*0.5))
  2227. def test_sf(self):
  2228. x = 1e9
  2229. b = 2
  2230. scale = 1.5
  2231. p = stats.pareto.sf(x, b, loc=0, scale=scale)
  2232. expected = (scale/x)**b # 2.25e-18
  2233. assert_allclose(p, expected)
  2234. @pytest.mark.filterwarnings("ignore:invalid value encountered in "
  2235. "double_scalars")
  2236. @pytest.mark.parametrize("rvs_shape", [1, 2])
  2237. @pytest.mark.parametrize("rvs_loc", [0, 2])
  2238. @pytest.mark.parametrize("rvs_scale", [1, 5])
  2239. def test_fit(self, rvs_shape, rvs_loc, rvs_scale):
  2240. rng = np.random.default_rng(1234)
  2241. data = stats.pareto.rvs(size=100, b=rvs_shape, scale=rvs_scale,
  2242. loc=rvs_loc, random_state=rng)
  2243. # shape can still be fixed with multiple names
  2244. shape_mle_analytical1 = stats.pareto.fit(data, floc=0, f0=1.04)[0]
  2245. shape_mle_analytical2 = stats.pareto.fit(data, floc=0, fix_b=1.04)[0]
  2246. shape_mle_analytical3 = stats.pareto.fit(data, floc=0, fb=1.04)[0]
  2247. assert (shape_mle_analytical1 == shape_mle_analytical2 ==
  2248. shape_mle_analytical3 == 1.04)
  2249. # data can be shifted with changes to `loc`
  2250. data = stats.pareto.rvs(size=100, b=rvs_shape, scale=rvs_scale,
  2251. loc=(rvs_loc + 2), random_state=rng)
  2252. shape_mle_a, loc_mle_a, scale_mle_a = stats.pareto.fit(data, floc=2)
  2253. assert_equal(scale_mle_a + 2, data.min())
  2254. data_shift = data - 2
  2255. ndata = data_shift.shape[0]
  2256. assert_equal(shape_mle_a,
  2257. ndata / np.sum(np.log(data_shift/data_shift.min())))
  2258. assert_equal(loc_mle_a, 2)
  2259. @pytest.mark.parametrize("rvs_shape", [.1, 2])
  2260. @pytest.mark.parametrize("rvs_loc", [0, 2])
  2261. @pytest.mark.parametrize("rvs_scale", [1, 5])
  2262. @pytest.mark.parametrize('fix_shape, fix_loc, fix_scale',
  2263. [p for p in product([True, False], repeat=3)
  2264. if False in p])
  2265. @np.errstate(invalid="ignore")
  2266. def test_fit_MLE_comp_optimizer(self, rvs_shape, rvs_loc, rvs_scale,
  2267. fix_shape, fix_loc, fix_scale):
  2268. rng = np.random.default_rng(1234)
  2269. data = stats.pareto.rvs(size=100, b=rvs_shape, scale=rvs_scale,
  2270. loc=rvs_loc, random_state=rng)
  2271. kwds = {}
  2272. if fix_shape:
  2273. kwds['f0'] = rvs_shape
  2274. if fix_loc:
  2275. kwds['floc'] = rvs_loc
  2276. if fix_scale:
  2277. kwds['fscale'] = rvs_scale
  2278. _assert_less_or_close_loglike(stats.pareto, data, **kwds)
  2279. @np.errstate(invalid="ignore")
  2280. def test_fit_known_bad_seed(self):
  2281. # Tests a known seed and set of parameters that would produce a result
  2282. # would violate the support of Pareto if the fit method did not check
  2283. # the constraint `fscale + floc < min(data)`.
  2284. shape, location, scale = 1, 0, 1
  2285. data = stats.pareto.rvs(shape, location, scale, size=100,
  2286. random_state=np.random.default_rng(2535619))
  2287. _assert_less_or_close_loglike(stats.pareto, data)
  2288. def test_fit_warnings(self):
  2289. assert_fit_warnings(stats.pareto)
  2290. # `floc` that causes invalid negative data
  2291. assert_raises(FitDataError, stats.pareto.fit, [1, 2, 3], floc=2)
  2292. # `floc` and `fscale` combination causes invalid data
  2293. assert_raises(FitDataError, stats.pareto.fit, [5, 2, 3], floc=1,
  2294. fscale=3)
  2295. def test_negative_data(self):
  2296. rng = np.random.default_rng(1234)
  2297. data = stats.pareto.rvs(loc=-130, b=1, size=100, random_state=rng)
  2298. assert_array_less(data, 0)
  2299. # The purpose of this test is to make sure that no runtime warnings are
  2300. # raised for all negative data, not the output of the fit method. Other
  2301. # methods test the output but have to silence warnings from the super
  2302. # method.
  2303. _ = stats.pareto.fit(data)
  2304. class TestGenpareto:
  2305. def test_ab(self):
  2306. # c >= 0: a, b = [0, inf]
  2307. for c in [1., 0.]:
  2308. c = np.asarray(c)
  2309. a, b = stats.genpareto._get_support(c)
  2310. assert_equal(a, 0.)
  2311. assert_(np.isposinf(b))
  2312. # c < 0: a=0, b=1/|c|
  2313. c = np.asarray(-2.)
  2314. a, b = stats.genpareto._get_support(c)
  2315. assert_allclose([a, b], [0., 0.5])
  2316. def test_c0(self):
  2317. # with c=0, genpareto reduces to the exponential distribution
  2318. # rv = stats.genpareto(c=0.)
  2319. rv = stats.genpareto(c=0.)
  2320. x = np.linspace(0, 10., 30)
  2321. assert_allclose(rv.pdf(x), stats.expon.pdf(x))
  2322. assert_allclose(rv.cdf(x), stats.expon.cdf(x))
  2323. assert_allclose(rv.sf(x), stats.expon.sf(x))
  2324. q = np.linspace(0., 1., 10)
  2325. assert_allclose(rv.ppf(q), stats.expon.ppf(q))
  2326. def test_cm1(self):
  2327. # with c=-1, genpareto reduces to the uniform distr on [0, 1]
  2328. rv = stats.genpareto(c=-1.)
  2329. x = np.linspace(0, 10., 30)
  2330. assert_allclose(rv.pdf(x), stats.uniform.pdf(x))
  2331. assert_allclose(rv.cdf(x), stats.uniform.cdf(x))
  2332. assert_allclose(rv.sf(x), stats.uniform.sf(x))
  2333. q = np.linspace(0., 1., 10)
  2334. assert_allclose(rv.ppf(q), stats.uniform.ppf(q))
  2335. # logpdf(1., c=-1) should be zero
  2336. assert_allclose(rv.logpdf(1), 0)
  2337. def test_x_inf(self):
  2338. # make sure x=inf is handled gracefully
  2339. rv = stats.genpareto(c=0.1)
  2340. assert_allclose([rv.pdf(np.inf), rv.cdf(np.inf)], [0., 1.])
  2341. assert_(np.isneginf(rv.logpdf(np.inf)))
  2342. rv = stats.genpareto(c=0.)
  2343. assert_allclose([rv.pdf(np.inf), rv.cdf(np.inf)], [0., 1.])
  2344. assert_(np.isneginf(rv.logpdf(np.inf)))
  2345. rv = stats.genpareto(c=-1.)
  2346. assert_allclose([rv.pdf(np.inf), rv.cdf(np.inf)], [0., 1.])
  2347. assert_(np.isneginf(rv.logpdf(np.inf)))
  2348. def test_c_continuity(self):
  2349. # pdf is continuous at c=0, -1
  2350. x = np.linspace(0, 10, 30)
  2351. for c in [0, -1]:
  2352. pdf0 = stats.genpareto.pdf(x, c)
  2353. for dc in [1e-14, -1e-14]:
  2354. pdfc = stats.genpareto.pdf(x, c + dc)
  2355. assert_allclose(pdf0, pdfc, atol=1e-12)
  2356. cdf0 = stats.genpareto.cdf(x, c)
  2357. for dc in [1e-14, 1e-14]:
  2358. cdfc = stats.genpareto.cdf(x, c + dc)
  2359. assert_allclose(cdf0, cdfc, atol=1e-12)
  2360. def test_c_continuity_ppf(self):
  2361. q = np.r_[np.logspace(1e-12, 0.01, base=0.1),
  2362. np.linspace(0.01, 1, 30, endpoint=False),
  2363. 1. - np.logspace(1e-12, 0.01, base=0.1)]
  2364. for c in [0., -1.]:
  2365. ppf0 = stats.genpareto.ppf(q, c)
  2366. for dc in [1e-14, -1e-14]:
  2367. ppfc = stats.genpareto.ppf(q, c + dc)
  2368. assert_allclose(ppf0, ppfc, atol=1e-12)
  2369. def test_c_continuity_isf(self):
  2370. q = np.r_[np.logspace(1e-12, 0.01, base=0.1),
  2371. np.linspace(0.01, 1, 30, endpoint=False),
  2372. 1. - np.logspace(1e-12, 0.01, base=0.1)]
  2373. for c in [0., -1.]:
  2374. isf0 = stats.genpareto.isf(q, c)
  2375. for dc in [1e-14, -1e-14]:
  2376. isfc = stats.genpareto.isf(q, c + dc)
  2377. assert_allclose(isf0, isfc, atol=1e-12)
  2378. def test_cdf_ppf_roundtrip(self):
  2379. # this should pass with machine precision. hat tip @pbrod
  2380. q = np.r_[np.logspace(1e-12, 0.01, base=0.1),
  2381. np.linspace(0.01, 1, 30, endpoint=False),
  2382. 1. - np.logspace(1e-12, 0.01, base=0.1)]
  2383. for c in [1e-8, -1e-18, 1e-15, -1e-15]:
  2384. assert_allclose(stats.genpareto.cdf(stats.genpareto.ppf(q, c), c),
  2385. q, atol=1e-15)
  2386. def test_logsf(self):
  2387. logp = stats.genpareto.logsf(1e10, .01, 0, 1)
  2388. assert_allclose(logp, -1842.0680753952365)
  2389. # Values in 'expected_stats' are
  2390. # [mean, variance, skewness, excess kurtosis].
  2391. @pytest.mark.parametrize(
  2392. 'c, expected_stats',
  2393. [(0, [1, 1, 2, 6]),
  2394. (1/4, [4/3, 32/9, 10/np.sqrt(2), np.nan]),
  2395. (1/9, [9/8, (81/64)*(9/7), (10/9)*np.sqrt(7), 754/45]),
  2396. (-1, [1/2, 1/12, 0, -6/5])])
  2397. def test_stats(self, c, expected_stats):
  2398. result = stats.genpareto.stats(c, moments='mvsk')
  2399. assert_allclose(result, expected_stats, rtol=1e-13, atol=1e-15)
  2400. def test_var(self):
  2401. # Regression test for gh-11168.
  2402. v = stats.genpareto.var(1e-8)
  2403. assert_allclose(v, 1.000000040000001, rtol=1e-13)
  2404. class TestPearson3:
  2405. def setup_method(self):
  2406. self.rng = np.random.default_rng(2775995570)
  2407. def test_rvs(self):
  2408. vals = stats.pearson3.rvs(0.1, size=(2, 50), random_state=self.rng)
  2409. assert np.shape(vals) == (2, 50)
  2410. assert vals.dtype.char in typecodes['AllFloat']
  2411. val = stats.pearson3.rvs(0.5, random_state=self.rng)
  2412. assert isinstance(val, float)
  2413. val = stats.pearson3(0.5).rvs(3, random_state=self.rng)
  2414. assert isinstance(val, np.ndarray)
  2415. assert val.dtype.char in typecodes['AllFloat']
  2416. assert len(val) == 3
  2417. def test_pdf(self):
  2418. vals = stats.pearson3.pdf(2, [0.0, 0.1, 0.2])
  2419. assert_allclose(vals, np.array([0.05399097, 0.05555481, 0.05670246]),
  2420. atol=1e-6)
  2421. vals = stats.pearson3.pdf(-3, 0.1)
  2422. assert_allclose(vals, np.array([0.00313791]), atol=1e-6)
  2423. vals = stats.pearson3.pdf([-3, -2, -1, 0, 1], 0.1)
  2424. assert_allclose(vals, np.array([0.00313791, 0.05192304, 0.25028092,
  2425. 0.39885918, 0.23413173]), atol=1e-6)
  2426. def test_cdf(self):
  2427. vals = stats.pearson3.cdf(2, [0.0, 0.1, 0.2])
  2428. assert_allclose(vals, np.array([0.97724987, 0.97462004, 0.97213626]),
  2429. atol=1e-6)
  2430. vals = stats.pearson3.cdf(-3, 0.1)
  2431. assert_allclose(vals, [0.00082256], atol=1e-6)
  2432. vals = stats.pearson3.cdf([-3, -2, -1, 0, 1], 0.1)
  2433. assert_allclose(vals, [8.22563821e-04, 1.99860448e-02, 1.58550710e-01,
  2434. 5.06649130e-01, 8.41442111e-01], atol=1e-6)
  2435. def test_negative_cdf_bug_11186(self):
  2436. # incorrect CDFs for negative skews in gh-11186; fixed in gh-12640
  2437. # Also check vectorization w/ negative, zero, and positive skews
  2438. skews = [-3, -1, 0, 0.5]
  2439. x_eval = 0.5
  2440. neg_inf = -30 # avoid RuntimeWarning caused by np.log(0)
  2441. cdfs = stats.pearson3.cdf(x_eval, skews)
  2442. int_pdfs = [quad(stats.pearson3(skew).pdf, neg_inf, x_eval)[0]
  2443. for skew in skews]
  2444. assert_allclose(cdfs, int_pdfs)
  2445. def test_return_array_bug_11746(self):
  2446. # pearson3.moment was returning size 0 or 1 array instead of float
  2447. # The first moment is equal to the loc, which defaults to zero
  2448. moment = stats.pearson3.moment(1, 2)
  2449. assert_equal(moment, 0)
  2450. assert isinstance(moment, np.number)
  2451. moment = stats.pearson3.moment(1, 0.000001)
  2452. assert_equal(moment, 0)
  2453. assert isinstance(moment, np.number)
  2454. def test_ppf_bug_17050(self):
  2455. # incorrect PPF for negative skews were reported in gh-17050
  2456. # Check that this is fixed (even in the array case)
  2457. skews = [-3, -1, 0, 0.5]
  2458. x_eval = 0.5
  2459. res = stats.pearson3.ppf(stats.pearson3.cdf(x_eval, skews), skews)
  2460. assert_allclose(res, x_eval)
  2461. # Negation of the skew flips the distribution about the origin, so
  2462. # the following should hold
  2463. skew = np.array([[-0.5], [1.5]])
  2464. x = np.linspace(-2, 2)
  2465. assert_allclose(stats.pearson3.pdf(x, skew),
  2466. stats.pearson3.pdf(-x, -skew))
  2467. assert_allclose(stats.pearson3.cdf(x, skew),
  2468. stats.pearson3.sf(-x, -skew))
  2469. assert_allclose(stats.pearson3.ppf(x, skew),
  2470. -stats.pearson3.isf(x, -skew))
  2471. def test_sf(self):
  2472. # reference values were computed via the reference distribution, e.g.
  2473. # mp.dps = 50; Pearson3(skew=skew).sf(x). Check positive, negative,
  2474. # and zero skew due to branching.
  2475. skew = [0.1, 0.5, 1.0, -0.1]
  2476. x = [5.0, 10.0, 50.0, 8.0]
  2477. ref = [1.64721926440872e-06, 8.271911573556123e-11,
  2478. 1.3149506021756343e-40, 2.763057937820296e-21]
  2479. assert_allclose(stats.pearson3.sf(x, skew), ref, rtol=2e-14)
  2480. assert_allclose(stats.pearson3.sf(x, 0), stats.norm.sf(x), rtol=2e-14)
  2481. class TestKappa4:
  2482. def test_cdf_genpareto(self):
  2483. # h = 1 and k != 0 is generalized Pareto
  2484. x = [0.0, 0.1, 0.2, 0.5]
  2485. h = 1.0
  2486. for k in [-1.9, -1.0, -0.5, -0.2, -0.1, 0.1, 0.2, 0.5, 1.0,
  2487. 1.9]:
  2488. vals = stats.kappa4.cdf(x, h, k)
  2489. # shape parameter is opposite what is expected
  2490. vals_comp = stats.genpareto.cdf(x, -k)
  2491. assert_allclose(vals, vals_comp)
  2492. def test_cdf_genextreme(self):
  2493. # h = 0 and k != 0 is generalized extreme value
  2494. x = np.linspace(-5, 5, 10)
  2495. h = 0.0
  2496. k = np.linspace(-3, 3, 10)
  2497. vals = stats.kappa4.cdf(x, h, k)
  2498. vals_comp = stats.genextreme.cdf(x, k)
  2499. assert_allclose(vals, vals_comp)
  2500. def test_cdf_expon(self):
  2501. # h = 1 and k = 0 is exponential
  2502. x = np.linspace(0, 10, 10)
  2503. h = 1.0
  2504. k = 0.0
  2505. vals = stats.kappa4.cdf(x, h, k)
  2506. vals_comp = stats.expon.cdf(x)
  2507. assert_allclose(vals, vals_comp)
  2508. def test_cdf_gumbel_r(self):
  2509. # h = 0 and k = 0 is gumbel_r
  2510. x = np.linspace(-5, 5, 10)
  2511. h = 0.0
  2512. k = 0.0
  2513. vals = stats.kappa4.cdf(x, h, k)
  2514. vals_comp = stats.gumbel_r.cdf(x)
  2515. assert_allclose(vals, vals_comp)
  2516. def test_cdf_logistic(self):
  2517. # h = -1 and k = 0 is logistic
  2518. x = np.linspace(-5, 5, 10)
  2519. h = -1.0
  2520. k = 0.0
  2521. vals = stats.kappa4.cdf(x, h, k)
  2522. vals_comp = stats.logistic.cdf(x)
  2523. assert_allclose(vals, vals_comp)
  2524. def test_cdf_uniform(self):
  2525. # h = 1 and k = 1 is uniform
  2526. x = np.linspace(-5, 5, 10)
  2527. h = 1.0
  2528. k = 1.0
  2529. vals = stats.kappa4.cdf(x, h, k)
  2530. vals_comp = stats.uniform.cdf(x)
  2531. assert_allclose(vals, vals_comp)
  2532. def test_integers_ctor(self):
  2533. # regression test for gh-7416: _argcheck fails for integer h and k
  2534. # in numpy 1.12
  2535. stats.kappa4(1, 2)
  2536. class TestPoisson:
  2537. def setup_method(self):
  2538. self.rng = np.random.default_rng(9799340796)
  2539. def test_pmf_basic(self):
  2540. # Basic case
  2541. ln2 = np.log(2)
  2542. vals = stats.poisson.pmf([0, 1, 2], ln2)
  2543. expected = [0.5, ln2/2, ln2**2/4]
  2544. assert_allclose(vals, expected)
  2545. def test_mu0(self):
  2546. # Edge case: mu=0
  2547. vals = stats.poisson.pmf([0, 1, 2], 0)
  2548. expected = [1, 0, 0]
  2549. assert_array_equal(vals, expected)
  2550. interval = stats.poisson.interval(0.95, 0)
  2551. assert_equal(interval, (0, 0))
  2552. def test_rvs(self):
  2553. vals = stats.poisson.rvs(0.5, size=(2, 50), random_state=self.rng)
  2554. assert np.all(vals >= 0)
  2555. assert np.shape(vals) == (2, 50)
  2556. assert vals.dtype.char in typecodes['AllInteger']
  2557. val = stats.poisson.rvs(0.5, random_state=self.rng)
  2558. assert isinstance(val, int)
  2559. val = stats.poisson(0.5).rvs(3, random_state=self.rng)
  2560. assert isinstance(val, np.ndarray)
  2561. assert val.dtype.char in typecodes['AllInteger']
  2562. def test_stats(self):
  2563. mu = 16.0
  2564. result = stats.poisson.stats(mu, moments='mvsk')
  2565. assert_allclose(result, [mu, mu, np.sqrt(1.0/mu), 1.0/mu])
  2566. mu = np.array([0.0, 1.0, 2.0])
  2567. result = stats.poisson.stats(mu, moments='mvsk')
  2568. expected = (mu, mu, [np.inf, 1, 1/np.sqrt(2)], [np.inf, 1, 0.5])
  2569. assert_allclose(result, expected)
  2570. class TestKSTwo:
  2571. def test_cdf(self):
  2572. for n in [1, 2, 3, 10, 100, 1000]:
  2573. # Test x-values:
  2574. # 0, 1/2n, where the cdf should be 0
  2575. # 1/n, where the cdf should be n!/n^n
  2576. # 0.5, where the cdf should match ksone.cdf
  2577. # 1-1/n, where cdf = 1-2/n^n
  2578. # 1, where cdf == 1
  2579. # (E.g. Exact values given by Eqn 1 in Simard / L'Ecuyer)
  2580. x = np.array([0, 0.5/n, 1/n, 0.5, 1-1.0/n, 1])
  2581. v1 = (1.0/n)**n
  2582. lg = scipy.special.gammaln(n+1)
  2583. elg = (np.exp(lg) if v1 != 0 else 0)
  2584. expected = np.array([0, 0, v1 * elg,
  2585. 1 - 2*stats.ksone.sf(0.5, n),
  2586. max(1 - 2*v1, 0.0),
  2587. 1.0])
  2588. vals_cdf = stats.kstwo.cdf(x, n)
  2589. assert_allclose(vals_cdf, expected)
  2590. def test_sf(self):
  2591. x = np.linspace(0, 1, 11)
  2592. for n in [1, 2, 3, 10, 100, 1000]:
  2593. # Same x values as in test_cdf, and use sf = 1 - cdf
  2594. x = np.array([0, 0.5/n, 1/n, 0.5, 1-1.0/n, 1])
  2595. v1 = (1.0/n)**n
  2596. lg = scipy.special.gammaln(n+1)
  2597. elg = (np.exp(lg) if v1 != 0 else 0)
  2598. expected = np.array([1.0, 1.0,
  2599. 1 - v1 * elg,
  2600. 2*stats.ksone.sf(0.5, n),
  2601. min(2*v1, 1.0), 0])
  2602. vals_sf = stats.kstwo.sf(x, n)
  2603. assert_allclose(vals_sf, expected)
  2604. def test_cdf_sqrtn(self):
  2605. # For fixed a, cdf(a/sqrt(n), n) -> kstwobign(a) as n->infinity
  2606. # cdf(a/sqrt(n), n) is an increasing function of n (and a)
  2607. # Check that the function is indeed increasing (allowing for some
  2608. # small floating point and algorithm differences.)
  2609. x = np.linspace(0, 2, 11)[1:]
  2610. ns = [50, 100, 200, 400, 1000, 2000]
  2611. for _x in x:
  2612. xn = _x / np.sqrt(ns)
  2613. probs = stats.kstwo.cdf(xn, ns)
  2614. diffs = np.diff(probs)
  2615. assert_array_less(diffs, 1e-8)
  2616. def test_cdf_sf(self):
  2617. x = np.linspace(0, 1, 11)
  2618. for n in [1, 2, 3, 10, 100, 1000]:
  2619. vals_cdf = stats.kstwo.cdf(x, n)
  2620. vals_sf = stats.kstwo.sf(x, n)
  2621. assert_array_almost_equal(vals_cdf, 1 - vals_sf)
  2622. def test_cdf_sf_sqrtn(self):
  2623. x = np.linspace(0, 1, 11)
  2624. for n in [1, 2, 3, 10, 100, 1000]:
  2625. xn = x / np.sqrt(n)
  2626. vals_cdf = stats.kstwo.cdf(xn, n)
  2627. vals_sf = stats.kstwo.sf(xn, n)
  2628. assert_array_almost_equal(vals_cdf, 1 - vals_sf)
  2629. def test_ppf_of_cdf(self):
  2630. x = np.linspace(0, 1, 11)
  2631. for n in [1, 2, 3, 10, 100, 1000]:
  2632. xn = x[x > 0.5/n]
  2633. vals_cdf = stats.kstwo.cdf(xn, n)
  2634. # CDFs close to 1 are better dealt with using the SF
  2635. cond = (0 < vals_cdf) & (vals_cdf < 0.99)
  2636. vals = stats.kstwo.ppf(vals_cdf, n)
  2637. assert_allclose(vals[cond], xn[cond], rtol=1e-4)
  2638. def test_isf_of_sf(self):
  2639. x = np.linspace(0, 1, 11)
  2640. for n in [1, 2, 3, 10, 100, 1000]:
  2641. xn = x[x > 0.5/n]
  2642. vals_isf = stats.kstwo.isf(xn, n)
  2643. cond = (0 < vals_isf) & (vals_isf < 1.0)
  2644. vals = stats.kstwo.sf(vals_isf, n)
  2645. assert_allclose(vals[cond], xn[cond], rtol=1e-4)
  2646. def test_ppf_of_cdf_sqrtn(self):
  2647. x = np.linspace(0, 1, 11)
  2648. for n in [1, 2, 3, 10, 100, 1000]:
  2649. xn = (x / np.sqrt(n))[x > 0.5/n]
  2650. vals_cdf = stats.kstwo.cdf(xn, n)
  2651. cond = (0 < vals_cdf) & (vals_cdf < 1.0)
  2652. vals = stats.kstwo.ppf(vals_cdf, n)
  2653. assert_allclose(vals[cond], xn[cond])
  2654. def test_isf_of_sf_sqrtn(self):
  2655. x = np.linspace(0, 1, 11)
  2656. for n in [1, 2, 3, 10, 100, 1000]:
  2657. xn = (x / np.sqrt(n))[x > 0.5/n]
  2658. vals_sf = stats.kstwo.sf(xn, n)
  2659. # SFs close to 1 are better dealt with using the CDF
  2660. cond = (0 < vals_sf) & (vals_sf < 0.95)
  2661. vals = stats.kstwo.isf(vals_sf, n)
  2662. assert_allclose(vals[cond], xn[cond])
  2663. def test_ppf(self):
  2664. probs = np.linspace(0, 1, 11)[1:]
  2665. for n in [1, 2, 3, 10, 100, 1000]:
  2666. xn = stats.kstwo.ppf(probs, n)
  2667. vals_cdf = stats.kstwo.cdf(xn, n)
  2668. assert_allclose(vals_cdf, probs)
  2669. def test_simard_lecuyer_table1(self):
  2670. # Compute the cdf for values near the mean of the distribution.
  2671. # The mean u ~ log(2)*sqrt(pi/(2n))
  2672. # Compute for x in [u/4, u/3, u/2, u, 2u, 3u]
  2673. # This is the computation of Table 1 of Simard, R., L'Ecuyer, P. (2011)
  2674. # "Computing the Two-Sided Kolmogorov-Smirnov Distribution".
  2675. # Except that the values below are not from the published table, but
  2676. # were generated using an independent SageMath implementation of
  2677. # Durbin's algorithm (with the exponentiation and scaling of
  2678. # Marsaglia/Tsang/Wang's version) using 500 bit arithmetic.
  2679. # Some of the values in the published table have relative
  2680. # errors greater than 1e-4.
  2681. ns = [10, 50, 100, 200, 500, 1000]
  2682. ratios = np.array([1.0/4, 1.0/3, 1.0/2, 1, 2, 3])
  2683. expected = np.array([
  2684. [1.92155292e-08, 5.72933228e-05, 2.15233226e-02, 6.31566589e-01,
  2685. 9.97685592e-01, 9.99999942e-01],
  2686. [2.28096224e-09, 1.99142563e-05, 1.42617934e-02, 5.95345542e-01,
  2687. 9.96177701e-01, 9.99998662e-01],
  2688. [1.00201886e-09, 1.32673079e-05, 1.24608594e-02, 5.86163220e-01,
  2689. 9.95866877e-01, 9.99998240e-01],
  2690. [4.93313022e-10, 9.52658029e-06, 1.12123138e-02, 5.79486872e-01,
  2691. 9.95661824e-01, 9.99997964e-01],
  2692. [2.37049293e-10, 6.85002458e-06, 1.01309221e-02, 5.73427224e-01,
  2693. 9.95491207e-01, 9.99997750e-01],
  2694. [1.56990874e-10, 5.71738276e-06, 9.59725430e-03, 5.70322692e-01,
  2695. 9.95409545e-01, 9.99997657e-01]
  2696. ])
  2697. for idx, n in enumerate(ns):
  2698. x = ratios * np.log(2) * np.sqrt(np.pi/2/n)
  2699. vals_cdf = stats.kstwo.cdf(x, n)
  2700. assert_allclose(vals_cdf, expected[idx], rtol=1e-5)
  2701. class TestZipf:
  2702. def setup_method(self):
  2703. self.rng = np.random.default_rng(2444103536)
  2704. def test_rvs(self):
  2705. vals = stats.zipf.rvs(1.5, size=(2, 50), random_state=self.rng)
  2706. assert np.all(vals >= 1)
  2707. assert np.shape(vals) == (2, 50)
  2708. assert vals.dtype.char in typecodes['AllInteger']
  2709. val = stats.zipf.rvs(1.5, random_state=self.rng)
  2710. assert isinstance(val, int)
  2711. val = stats.zipf(1.5).rvs(3, random_state=self.rng)
  2712. assert isinstance(val, np.ndarray)
  2713. assert val.dtype.char in typecodes['AllInteger']
  2714. def test_moments(self):
  2715. # n-th moment is finite iff a > n + 1
  2716. m, v = stats.zipf.stats(a=2.8)
  2717. assert_(np.isfinite(m))
  2718. assert_equal(v, np.inf)
  2719. s, k = stats.zipf.stats(a=4.8, moments='sk')
  2720. assert_(not np.isfinite([s, k]).all())
  2721. class TestDLaplace:
  2722. def setup_method(self):
  2723. self.rng = np.random.default_rng(460403075)
  2724. def test_rvs(self):
  2725. vals = stats.dlaplace.rvs(1.5, size=(2, 50), random_state=self.rng)
  2726. assert np.shape(vals) == (2, 50)
  2727. assert vals.dtype.char in typecodes['AllInteger']
  2728. val = stats.dlaplace.rvs(1.5, random_state=self.rng)
  2729. assert isinstance(val, int)
  2730. val = stats.dlaplace(1.5).rvs(3, random_state=self.rng)
  2731. assert isinstance(val, np.ndarray)
  2732. assert val.dtype.char in typecodes['AllInteger']
  2733. assert stats.dlaplace.rvs(0.8, random_state=self.rng) is not None
  2734. def test_stats(self):
  2735. # compare the explicit formulas w/ direct summation using pmf
  2736. a = 1.
  2737. dl = stats.dlaplace(a)
  2738. m, v, s, k = dl.stats('mvsk')
  2739. N = 37
  2740. xx = np.arange(-N, N+1)
  2741. pp = dl.pmf(xx)
  2742. m2, m4 = np.sum(pp*xx**2), np.sum(pp*xx**4)
  2743. assert_equal((m, s), (0, 0))
  2744. assert_allclose((v, k), (m2, m4/m2**2 - 3.), atol=1e-14, rtol=1e-8)
  2745. def test_stats2(self):
  2746. a = np.log(2.)
  2747. dl = stats.dlaplace(a)
  2748. m, v, s, k = dl.stats('mvsk')
  2749. assert_equal((m, s), (0., 0.))
  2750. assert_allclose((v, k), (4., 3.25))
  2751. class TestInvgauss:
  2752. def setup_method(self):
  2753. self.rng = np.random.default_rng(5422839947)
  2754. @pytest.mark.parametrize("rvs_mu,rvs_loc,rvs_scale",
  2755. [(2, 0, 1), (4.635, 4.362, 6.303)])
  2756. def test_fit(self, rvs_mu, rvs_loc, rvs_scale):
  2757. data = stats.invgauss.rvs(size=100, mu=rvs_mu,
  2758. loc=rvs_loc, scale=rvs_scale, random_state=self.rng)
  2759. # Analytical MLEs are calculated with formula when `floc` is fixed
  2760. mu, loc, scale = stats.invgauss.fit(data, floc=rvs_loc)
  2761. data = data - rvs_loc
  2762. mu_temp = np.mean(data)
  2763. scale_mle = len(data) / (np.sum(data**(-1) - mu_temp**(-1)))
  2764. mu_mle = mu_temp/scale_mle
  2765. # `mu` and `scale` match analytical formula
  2766. assert_allclose(mu_mle, mu, atol=1e-15, rtol=1e-15)
  2767. assert_allclose(scale_mle, scale, atol=1e-15, rtol=1e-15)
  2768. assert_equal(loc, rvs_loc)
  2769. data = stats.invgauss.rvs(size=100, mu=rvs_mu,
  2770. loc=rvs_loc, scale=rvs_scale, random_state=self.rng)
  2771. # fixed parameters are returned
  2772. mu, loc, scale = stats.invgauss.fit(data, floc=rvs_loc - 1,
  2773. fscale=rvs_scale + 1)
  2774. assert_equal(rvs_scale + 1, scale)
  2775. assert_equal(rvs_loc - 1, loc)
  2776. # shape can still be fixed with multiple names
  2777. shape_mle1 = stats.invgauss.fit(data, fmu=1.04)[0]
  2778. shape_mle2 = stats.invgauss.fit(data, fix_mu=1.04)[0]
  2779. shape_mle3 = stats.invgauss.fit(data, f0=1.04)[0]
  2780. assert shape_mle1 == shape_mle2 == shape_mle3 == 1.04
  2781. @pytest.mark.parametrize("rvs_mu,rvs_loc,rvs_scale",
  2782. [(2, 0, 1), (6.311, 3.225, 4.520)])
  2783. def test_fit_MLE_comp_optimizer(self, rvs_mu, rvs_loc, rvs_scale):
  2784. rng = np.random.RandomState(1234)
  2785. data = stats.invgauss.rvs(size=100, mu=rvs_mu,
  2786. loc=rvs_loc, scale=rvs_scale, random_state=rng)
  2787. super_fit = super(type(stats.invgauss), stats.invgauss).fit
  2788. # fitting without `floc` uses superclass fit method
  2789. super_fitted = super_fit(data)
  2790. invgauss_fit = stats.invgauss.fit(data)
  2791. assert_equal(super_fitted, invgauss_fit)
  2792. # fitting with `fmu` is uses superclass fit method
  2793. super_fitted = super_fit(data, floc=0, fmu=2)
  2794. invgauss_fit = stats.invgauss.fit(data, floc=0, fmu=2)
  2795. assert_equal(super_fitted, invgauss_fit)
  2796. # fixed `floc` uses analytical formula and provides better fit than
  2797. # super method
  2798. _assert_less_or_close_loglike(stats.invgauss, data, floc=rvs_loc)
  2799. # fixed `floc` not resulting in invalid data < 0 uses analytical
  2800. # formulas and provides a better fit than the super method
  2801. assert np.all((data - (rvs_loc - 1)) > 0)
  2802. _assert_less_or_close_loglike(stats.invgauss, data, floc=rvs_loc - 1)
  2803. # fixed `floc` to an arbitrary number, 0, still provides a better fit
  2804. # than the super method
  2805. _assert_less_or_close_loglike(stats.invgauss, data, floc=0)
  2806. # fixed `fscale` to an arbitrary number still provides a better fit
  2807. # than the super method
  2808. _assert_less_or_close_loglike(stats.invgauss, data, floc=rvs_loc,
  2809. fscale=self.rng.random(1)[0])
  2810. def test_fit_raise_errors(self):
  2811. assert_fit_warnings(stats.invgauss)
  2812. # FitDataError is raised when negative invalid data
  2813. with pytest.raises(FitDataError):
  2814. stats.invgauss.fit([1, 2, 3], floc=2)
  2815. def test_cdf_sf(self):
  2816. # Regression tests for gh-13614.
  2817. # Ground truth from R's statmod library (pinvgauss), e.g.
  2818. # library(statmod)
  2819. # options(digits=15)
  2820. # mu = c(4.17022005e-04, 7.20324493e-03, 1.14374817e-06,
  2821. # 3.02332573e-03, 1.46755891e-03)
  2822. # print(pinvgauss(5, mu, 1))
  2823. # make sure a finite value is returned when mu is very small. see
  2824. # GH-13614
  2825. mu = [4.17022005e-04, 7.20324493e-03, 1.14374817e-06,
  2826. 3.02332573e-03, 1.46755891e-03]
  2827. expected = [1, 1, 1, 1, 1]
  2828. actual = stats.invgauss.cdf(0.4, mu=mu)
  2829. assert_equal(expected, actual)
  2830. # test if the function can distinguish small left/right tail
  2831. # probabilities from zero.
  2832. cdf_actual = stats.invgauss.cdf(0.001, mu=1.05)
  2833. assert_allclose(cdf_actual, 4.65246506892667e-219)
  2834. sf_actual = stats.invgauss.sf(110, mu=1.05)
  2835. assert_allclose(sf_actual, 4.12851625944048e-25)
  2836. # test if x does not cause numerical issues when mu is very small
  2837. # and x is close to mu in value.
  2838. # slightly smaller than mu
  2839. actual = stats.invgauss.cdf(0.00009, 0.0001)
  2840. assert_allclose(actual, 2.9458022894924e-26)
  2841. # slightly bigger than mu
  2842. actual = stats.invgauss.cdf(0.000102, 0.0001)
  2843. assert_allclose(actual, 0.976445540507925)
  2844. def test_logcdf_logsf(self):
  2845. # Regression tests for improvements made in gh-13616.
  2846. # Ground truth from R's statmod library (pinvgauss), e.g.
  2847. # library(statmod)
  2848. # options(digits=15)
  2849. # print(pinvgauss(0.001, 1.05, 1, log.p=TRUE, lower.tail=FALSE))
  2850. # test if logcdf and logsf can compute values too small to
  2851. # be represented on the unlogged scale. See: gh-13616
  2852. logcdf = stats.invgauss.logcdf(0.0001, mu=1.05)
  2853. assert_allclose(logcdf, -5003.87872590367)
  2854. logcdf = stats.invgauss.logcdf(110, 1.05)
  2855. assert_allclose(logcdf, -4.12851625944087e-25)
  2856. logsf = stats.invgauss.logsf(0.001, mu=1.05)
  2857. assert_allclose(logsf, -4.65246506892676e-219)
  2858. logsf = stats.invgauss.logsf(110, 1.05)
  2859. assert_allclose(logsf, -56.1467092416426)
  2860. # from mpmath import mp
  2861. # mp.dps = 100
  2862. # mu = mp.mpf(1e-2)
  2863. # ref = (1/2 * mp.log(2 * mp.pi * mp.e * mu**3)
  2864. # - 3/2* mp.exp(2/mu) * mp.e1(2/mu))
  2865. @pytest.mark.parametrize("mu, ref", [(2e-8, -25.172361826883957),
  2866. (1e-3, -8.943444010642972),
  2867. (1e-2, -5.4962796152622335),
  2868. (1e8, 3.3244822568873476),
  2869. (1e100, 3.32448280139689)])
  2870. def test_entropy(self, mu, ref):
  2871. assert_allclose(stats.invgauss.entropy(mu), ref, rtol=5e-14)
  2872. def test_mu_inf_gh13666(self):
  2873. # invgauss methods should return correct result when mu=inf
  2874. # invgauss as mu -> oo is invgamma with shape and scale 0.5;
  2875. # see gh-13666 and gh-22496
  2876. dist = stats.invgauss(mu=np.inf)
  2877. dist0 = stats.invgamma(0.5, scale=0.5)
  2878. x, p = 1., 0.5
  2879. assert_allclose(dist.logpdf(x), dist0.logpdf(x))
  2880. assert_allclose(dist.pdf(x), dist0.pdf(x))
  2881. assert_allclose(dist.logcdf(x), dist0.logcdf(x))
  2882. assert_allclose(dist.cdf(x), dist0.cdf(x))
  2883. assert_allclose(dist.logsf(x), dist0.logsf(x))
  2884. assert_allclose(dist.sf(x), dist0.sf(x))
  2885. assert_allclose(dist.ppf(p), dist0.ppf(p))
  2886. assert_allclose(dist.isf(p), dist0.isf(p))
  2887. class TestLandau:
  2888. @pytest.mark.parametrize('name', ['pdf', 'cdf', 'sf', 'ppf', 'isf'])
  2889. def test_landau_levy_agreement(self, name):
  2890. # Test PDF to confirm that this is the Landau distribution
  2891. # Test other methods with tighter tolerance than generic tests
  2892. # Levy entropy is slow and inaccurate, and RVS is tested generically
  2893. if name in {'ppf', 'isf'}:
  2894. x = np.linspace(0.1, 0.9, 5),
  2895. else:
  2896. x = np.linspace(-2, 5, 10),
  2897. landau_method = getattr(stats.landau, name)
  2898. levy_method = getattr(stats.levy_stable, name)
  2899. res = landau_method(*x)
  2900. ref = levy_method(*x, 1, 1)
  2901. assert_allclose(res, ref, rtol=1e-14)
  2902. def test_moments(self):
  2903. # I would test these against Levy above, but Levy says variance is infinite.
  2904. assert_equal(stats.landau.stats(moments='mvsk'), (np.nan,)*4)
  2905. assert_equal(stats.landau.moment(5), np.nan)
  2906. class TestLaplace:
  2907. @pytest.mark.parametrize("rvs_loc", [-5, 0, 1, 2])
  2908. @pytest.mark.parametrize("rvs_scale", [1, 2, 3, 10])
  2909. def test_fit(self, rvs_loc, rvs_scale):
  2910. # tests that various inputs follow expected behavior
  2911. # for a variety of `loc` and `scale`.
  2912. rng = np.random.RandomState(1234)
  2913. data = stats.laplace.rvs(size=100, loc=rvs_loc, scale=rvs_scale,
  2914. random_state=rng)
  2915. # MLE estimates are given by
  2916. loc_mle = np.median(data)
  2917. scale_mle = np.sum(np.abs(data - loc_mle)) / len(data)
  2918. # standard outputs should match analytical MLE formulas
  2919. loc, scale = stats.laplace.fit(data)
  2920. assert_allclose(loc, loc_mle, atol=1e-15, rtol=1e-15)
  2921. assert_allclose(scale, scale_mle, atol=1e-15, rtol=1e-15)
  2922. # fixed parameter should use analytical formula for other
  2923. loc, scale = stats.laplace.fit(data, floc=loc_mle)
  2924. assert_allclose(scale, scale_mle, atol=1e-15, rtol=1e-15)
  2925. loc, scale = stats.laplace.fit(data, fscale=scale_mle)
  2926. assert_allclose(loc, loc_mle)
  2927. # test with non-mle fixed parameter
  2928. # create scale with non-median loc
  2929. loc = rvs_loc * 2
  2930. scale_mle = np.sum(np.abs(data - loc)) / len(data)
  2931. # fixed loc to non median, scale should match
  2932. # scale calculation with modified loc
  2933. loc, scale = stats.laplace.fit(data, floc=loc)
  2934. assert_equal(scale_mle, scale)
  2935. # fixed scale created with non median loc,
  2936. # loc output should still be the data median.
  2937. loc, scale = stats.laplace.fit(data, fscale=scale_mle)
  2938. assert_equal(loc_mle, loc)
  2939. # error raised when both `floc` and `fscale` are fixed
  2940. assert_raises(RuntimeError, stats.laplace.fit, data, floc=loc_mle,
  2941. fscale=scale_mle)
  2942. # error is raised with non-finite values
  2943. assert_raises(ValueError, stats.laplace.fit, [np.nan])
  2944. assert_raises(ValueError, stats.laplace.fit, [np.inf])
  2945. @pytest.mark.parametrize("rvs_loc,rvs_scale", [(-5, 10),
  2946. (10, 5),
  2947. (0.5, 0.2)])
  2948. def test_fit_MLE_comp_optimizer(self, rvs_loc, rvs_scale):
  2949. rng = np.random.RandomState(1234)
  2950. data = stats.laplace.rvs(size=1000, loc=rvs_loc, scale=rvs_scale,
  2951. random_state=rng)
  2952. # the log-likelihood function for laplace is given by
  2953. def ll(loc, scale, data):
  2954. return -1 * (- (len(data)) * np.log(2*scale) -
  2955. (1/scale)*np.sum(np.abs(data - loc)))
  2956. # test that the objective function result of the analytical MLEs is
  2957. # less than or equal to that of the numerically optimized estimate
  2958. loc, scale = stats.laplace.fit(data)
  2959. loc_opt, scale_opt = super(type(stats.laplace),
  2960. stats.laplace).fit(data)
  2961. ll_mle = ll(loc, scale, data)
  2962. ll_opt = ll(loc_opt, scale_opt, data)
  2963. assert ll_mle < ll_opt or np.allclose(ll_mle, ll_opt,
  2964. atol=1e-15, rtol=1e-15)
  2965. def test_fit_simple_non_random_data(self):
  2966. data = np.array([1.0, 1.0, 3.0, 5.0, 8.0, 14.0])
  2967. # with `floc` fixed to 6, scale should be 4.
  2968. loc, scale = stats.laplace.fit(data, floc=6)
  2969. assert_allclose(scale, 4, atol=1e-15, rtol=1e-15)
  2970. # with `fscale` fixed to 6, loc should be 4.
  2971. loc, scale = stats.laplace.fit(data, fscale=6)
  2972. assert_allclose(loc, 4, atol=1e-15, rtol=1e-15)
  2973. def test_sf_cdf_extremes(self):
  2974. # These calculations should not generate warnings.
  2975. x = 1000
  2976. p0 = stats.laplace.cdf(-x)
  2977. # The exact value is smaller than can be represented with
  2978. # 64 bit floating point, so the expected result is 0.
  2979. assert p0 == 0.0
  2980. # The closest 64 bit floating point representation of the
  2981. # exact value is 1.0.
  2982. p1 = stats.laplace.cdf(x)
  2983. assert p1 == 1.0
  2984. p0 = stats.laplace.sf(x)
  2985. # The exact value is smaller than can be represented with
  2986. # 64 bit floating point, so the expected result is 0.
  2987. assert p0 == 0.0
  2988. # The closest 64 bit floating point representation of the
  2989. # exact value is 1.0.
  2990. p1 = stats.laplace.sf(-x)
  2991. assert p1 == 1.0
  2992. def test_sf(self):
  2993. x = 200
  2994. p = stats.laplace.sf(x)
  2995. assert_allclose(p, np.exp(-x)/2, rtol=1e-13)
  2996. def test_isf(self):
  2997. p = 1e-25
  2998. x = stats.laplace.isf(p)
  2999. assert_allclose(x, -np.log(2*p), rtol=1e-13)
  3000. def test_logcdf_logsf(self):
  3001. x = 40
  3002. # Reference value computed with mpmath.
  3003. ref = -2.1241771276457944e-18
  3004. logcdf = stats.laplace.logcdf(x)
  3005. assert_allclose(logcdf, ref)
  3006. logsf = stats.laplace.logsf(-x)
  3007. assert_allclose(logsf, ref, rtol=5e-15)
  3008. class TestLogLaplace:
  3009. def test_sf(self):
  3010. # reference values were computed via the reference distribution, e.g.
  3011. # mp.dps = 100; LogLaplace(c=c).sf(x).
  3012. c = np.array([2.0, 3.0, 5.0])
  3013. x = np.array([1e-5, 1e10, 1e15])
  3014. ref = [0.99999999995, 5e-31, 5e-76]
  3015. assert_allclose(stats.loglaplace.sf(x, c), ref, rtol=1e-15)
  3016. def test_isf(self):
  3017. # reference values were computed via the reference distribution, e.g.
  3018. # mp.dps = 100; LogLaplace(c=c).isf(q).
  3019. c = 3.25
  3020. q = [0.8, 0.1, 1e-10, 1e-20, 1e-40]
  3021. ref = [0.7543222539245642, 1.6408455124660906, 964.4916294395846,
  3022. 1151387.578354072, 1640845512466.0906]
  3023. assert_allclose(stats.loglaplace.isf(q, c), ref, rtol=1e-14)
  3024. @pytest.mark.parametrize('r', [1, 2, 3, 4])
  3025. def test_moments_stats(self, r):
  3026. mom = 'mvsk'[r - 1]
  3027. c = np.arange(0.5, r + 0.5, 0.5)
  3028. # r-th non-central moment is infinite if |r| >= c.
  3029. assert_allclose(stats.loglaplace.moment(r, c), np.inf)
  3030. # r-th non-central moment is non-finite (inf or nan) if r >= c.
  3031. assert not np.any(np.isfinite(stats.loglaplace.stats(c, moments=mom)))
  3032. @pytest.mark.parametrize("c", [0.5, 1.0, 2.0])
  3033. @pytest.mark.parametrize("loc, scale", [(-1.2, 3.45)])
  3034. @pytest.mark.parametrize("fix_c", [True, False])
  3035. @pytest.mark.parametrize("fix_scale", [True, False])
  3036. def test_fit_analytic_mle(self, c, loc, scale, fix_c, fix_scale):
  3037. # Test that the analytical MLE produces no worse result than the
  3038. # generic (numerical) MLE.
  3039. rng = np.random.default_rng(6762668991392531563)
  3040. data = stats.loglaplace.rvs(c, loc=loc, scale=scale, size=100,
  3041. random_state=rng)
  3042. kwds = {'floc': loc}
  3043. if fix_c:
  3044. kwds['fc'] = c
  3045. if fix_scale:
  3046. kwds['fscale'] = scale
  3047. nfree = 3 - len(kwds)
  3048. if nfree == 0:
  3049. error_msg = "All parameters fixed. There is nothing to optimize."
  3050. with pytest.raises((RuntimeError, ValueError), match=error_msg):
  3051. stats.loglaplace.fit(data, **kwds)
  3052. return
  3053. _assert_less_or_close_loglike(stats.loglaplace, data, **kwds)
  3054. class TestPowerlaw:
  3055. # In the following data, `sf` was computed with mpmath.
  3056. @pytest.mark.parametrize('x, a, sf',
  3057. [(0.25, 2.0, 0.9375),
  3058. (0.99609375, 1/256, 1.528855235208108e-05)])
  3059. def test_sf(self, x, a, sf):
  3060. assert_allclose(stats.powerlaw.sf(x, a), sf, rtol=1e-15)
  3061. @pytest.fixture(scope='function')
  3062. def rng(self):
  3063. return np.random.default_rng(1234)
  3064. @pytest.mark.parametrize("rvs_shape", [.1, .5, .75, 1, 2])
  3065. @pytest.mark.parametrize("rvs_loc", [-1, 0, 1])
  3066. @pytest.mark.parametrize("rvs_scale", [.1, 1, 5])
  3067. @pytest.mark.parametrize('fix_shape, fix_loc, fix_scale',
  3068. [p for p in product([True, False], repeat=3)
  3069. if False in p])
  3070. def test_fit_MLE_comp_optimizer(self, rvs_shape, rvs_loc, rvs_scale,
  3071. fix_shape, fix_loc, fix_scale, rng):
  3072. data = stats.powerlaw.rvs(size=250, a=rvs_shape, loc=rvs_loc,
  3073. scale=rvs_scale, random_state=rng)
  3074. kwds = dict()
  3075. if fix_shape:
  3076. kwds['f0'] = rvs_shape
  3077. if fix_loc:
  3078. kwds['floc'] = np.nextafter(data.min(), -np.inf)
  3079. if fix_scale:
  3080. kwds['fscale'] = rvs_scale
  3081. # Numerical result may equal analytical result if some code path
  3082. # of the analytical routine makes use of numerical optimization.
  3083. _assert_less_or_close_loglike(stats.powerlaw, data, **kwds,
  3084. maybe_identical=True)
  3085. def test_problem_case(self):
  3086. # An observed problem with the test method indicated that some fixed
  3087. # scale values could cause bad results, this is now corrected.
  3088. a = 2.50002862645130604506
  3089. location = 0.0
  3090. scale = 35.249023299873095
  3091. data = stats.powerlaw.rvs(a=a, loc=location, scale=scale, size=100,
  3092. random_state=np.random.default_rng(5))
  3093. kwds = {'fscale': np.ptp(data) * 2}
  3094. _assert_less_or_close_loglike(stats.powerlaw, data, **kwds)
  3095. def test_fit_warnings(self):
  3096. assert_fit_warnings(stats.powerlaw)
  3097. # test for error when `fscale + floc <= np.max(data)` is not satisfied
  3098. msg = r" Maximum likelihood estimation with 'powerlaw' requires"
  3099. with assert_raises(FitDataError, match=msg):
  3100. stats.powerlaw.fit([1, 2, 4], floc=0, fscale=3)
  3101. # test for error when `data - floc >= 0` is not satisfied
  3102. msg = r" Maximum likelihood estimation with 'powerlaw' requires"
  3103. with assert_raises(FitDataError, match=msg):
  3104. stats.powerlaw.fit([1, 2, 4], floc=2)
  3105. # test for fixed location not less than `min(data)`.
  3106. msg = r" Maximum likelihood estimation with 'powerlaw' requires"
  3107. with assert_raises(FitDataError, match=msg):
  3108. stats.powerlaw.fit([1, 2, 4], floc=1)
  3109. # test for when fixed scale is less than or equal to range of data
  3110. msg = r"Negative or zero `fscale` is outside"
  3111. with assert_raises(ValueError, match=msg):
  3112. stats.powerlaw.fit([1, 2, 4], fscale=-3)
  3113. # test for when fixed scale is less than or equal to range of data
  3114. msg = r"`fscale` must be greater than the range of data."
  3115. with assert_raises(ValueError, match=msg):
  3116. stats.powerlaw.fit([1, 2, 4], fscale=3)
  3117. def test_minimum_data_zero_gh17801(self):
  3118. # gh-17801 reported an overflow error when the minimum value of the
  3119. # data is zero. Check that this problem is resolved.
  3120. data = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6]
  3121. dist = stats.powerlaw
  3122. with np.errstate(over='ignore'):
  3123. _assert_less_or_close_loglike(dist, data)
  3124. class TestPowerLogNorm:
  3125. # reference values were computed via mpmath
  3126. # from mpmath import mp
  3127. # mp.dps = 80
  3128. # def powerlognorm_sf_mp(x, c, s):
  3129. # x = mp.mpf(x)
  3130. # c = mp.mpf(c)
  3131. # s = mp.mpf(s)
  3132. # return mp.ncdf(-mp.log(x) / s)**c
  3133. #
  3134. # def powerlognormal_cdf_mp(x, c, s):
  3135. # return mp.one - powerlognorm_sf_mp(x, c, s)
  3136. #
  3137. # x, c, s = 100, 20, 1
  3138. # print(float(powerlognorm_sf_mp(x, c, s)))
  3139. @pytest.mark.parametrize("x, c, s, ref",
  3140. [(100, 20, 1, 1.9057100820561928e-114),
  3141. (1e-3, 20, 1, 0.9999999999507617),
  3142. (1e-3, 0.02, 1, 0.9999999999999508),
  3143. (1e22, 0.02, 1, 6.50744044621611e-12)])
  3144. def test_sf(self, x, c, s, ref):
  3145. assert_allclose(stats.powerlognorm.sf(x, c, s), ref, rtol=1e-13)
  3146. # reference values were computed via mpmath using the survival
  3147. # function above (passing in `ref` and getting `q`).
  3148. @pytest.mark.parametrize("q, c, s, ref",
  3149. [(0.9999999587870905, 0.02, 1, 0.01),
  3150. (6.690376686108851e-233, 20, 1, 1000)])
  3151. def test_isf(self, q, c, s, ref):
  3152. assert_allclose(stats.powerlognorm.isf(q, c, s), ref, rtol=5e-11)
  3153. @pytest.mark.parametrize("x, c, s, ref",
  3154. [(1e25, 0.02, 1, 0.9999999999999963),
  3155. (1e-6, 0.02, 1, 2.054921078040843e-45),
  3156. (1e-6, 200, 1, 2.0549210780408428e-41),
  3157. (0.3, 200, 1, 0.9999999999713368)])
  3158. def test_cdf(self, x, c, s, ref):
  3159. assert_allclose(stats.powerlognorm.cdf(x, c, s), ref, rtol=3e-14)
  3160. # reference values were computed via mpmath
  3161. # from mpmath import mp
  3162. # mp.dps = 50
  3163. # def powerlognorm_pdf_mpmath(x, c, s):
  3164. # x = mp.mpf(x)
  3165. # c = mp.mpf(c)
  3166. # s = mp.mpf(s)
  3167. # res = (c/(x * s) * mp.npdf(mp.log(x)/s) *
  3168. # mp.ncdf(-mp.log(x)/s)**(c - mp.one))
  3169. # return float(res)
  3170. @pytest.mark.parametrize("x, c, s, ref",
  3171. [(1e22, 0.02, 1, 6.5954987852335016e-34),
  3172. (1e20, 1e-3, 1, 1.588073750563988e-22),
  3173. (1e40, 1e-3, 1, 1.3179391812506349e-43)])
  3174. def test_pdf(self, x, c, s, ref):
  3175. assert_allclose(stats.powerlognorm.pdf(x, c, s), ref, rtol=3e-12)
  3176. class TestPowerNorm:
  3177. # survival function references were computed with mpmath via
  3178. # from mpmath import mp
  3179. # x = mp.mpf(x)
  3180. # c = mp.mpf(x)
  3181. # float(mp.ncdf(-x)**c)
  3182. @pytest.mark.parametrize("x, c, ref",
  3183. [(9, 1, 1.1285884059538405e-19),
  3184. (20, 2, 7.582445786569958e-178),
  3185. (100, 0.02, 3.330957891903866e-44),
  3186. (200, 0.01, 1.3004759092324774e-87)])
  3187. def test_sf(self, x, c, ref):
  3188. assert_allclose(stats.powernorm.sf(x, c), ref, rtol=1e-13)
  3189. # inverse survival function references were computed with mpmath via
  3190. # from mpmath import mp
  3191. # def isf_mp(q, c):
  3192. # q = mp.mpf(q)
  3193. # c = mp.mpf(c)
  3194. # arg = q**(mp.one / c)
  3195. # return float(-mp.sqrt(2) * mp.erfinv(mp.mpf(2.) * arg - mp.one))
  3196. @pytest.mark.parametrize("q, c, ref",
  3197. [(1e-5, 20, -0.15690800666514138),
  3198. (0.99999, 100, -5.19933666203545),
  3199. (0.9999, 0.02, -2.576676052143387),
  3200. (5e-2, 0.02, 17.089518110222244),
  3201. (1e-18, 2, 5.9978070150076865),
  3202. (1e-50, 5, 6.361340902404057)])
  3203. def test_isf(self, q, c, ref):
  3204. assert_allclose(stats.powernorm.isf(q, c), ref, rtol=5e-12)
  3205. # CDF reference values were computed with mpmath via
  3206. # from mpmath import mp
  3207. # def cdf_mp(x, c):
  3208. # x = mp.mpf(x)
  3209. # c = mp.mpf(c)
  3210. # return float(mp.one - mp.ncdf(-x)**c)
  3211. @pytest.mark.parametrize("x, c, ref",
  3212. [(-12, 9, 1.598833900869911e-32),
  3213. (2, 9, 0.9999999999999983),
  3214. (-20, 9, 2.4782617067456103e-88),
  3215. (-5, 0.02, 5.733032242841443e-09),
  3216. (-20, 0.02, 5.507248237212467e-91)])
  3217. def test_cdf(self, x, c, ref):
  3218. assert_allclose(stats.powernorm.cdf(x, c), ref, rtol=5e-14)
  3219. class TestInvGamma:
  3220. def test_invgamma_inf_gh_1866(self):
  3221. # invgamma's moments are only finite for a>n
  3222. # specific numbers checked w/ boost 1.54
  3223. with warnings.catch_warnings():
  3224. warnings.simplefilter('error', RuntimeWarning)
  3225. mvsk = stats.invgamma.stats(a=19.31, moments='mvsk')
  3226. expected = [0.05461496450, 0.0001723162534, 1.020362676,
  3227. 2.055616582]
  3228. assert_allclose(mvsk, expected)
  3229. a = [1.1, 3.1, 5.6]
  3230. mvsk = stats.invgamma.stats(a=a, moments='mvsk')
  3231. expected = ([10., 0.476190476, 0.2173913043], # mmm
  3232. [np.inf, 0.2061430632, 0.01312749422], # vvv
  3233. [np.nan, 41.95235392, 2.919025532], # sss
  3234. [np.nan, np.nan, 24.51923076]) # kkk
  3235. for x, y in zip(mvsk, expected):
  3236. assert_almost_equal(x, y)
  3237. def test_cdf_ppf(self):
  3238. # gh-6245
  3239. x = np.logspace(-2.6, 0)
  3240. y = stats.invgamma.cdf(x, 1)
  3241. xx = stats.invgamma.ppf(y, 1)
  3242. assert_allclose(x, xx)
  3243. def test_sf_isf(self):
  3244. # gh-6245
  3245. if sys.maxsize > 2**32:
  3246. x = np.logspace(2, 100)
  3247. else:
  3248. # Invgamme roundtrip on 32-bit systems has relative accuracy
  3249. # ~1e-15 until x=1e+15, and becomes inf above x=1e+18
  3250. x = np.logspace(2, 18)
  3251. y = stats.invgamma.sf(x, 1)
  3252. xx = stats.invgamma.isf(y, 1)
  3253. assert_allclose(x, xx, rtol=1.0)
  3254. def test_logcdf(self):
  3255. x = 1e7
  3256. a = 2.25
  3257. # Reference value computed with mpmath.
  3258. ref = -6.97567687425534e-17
  3259. logcdf = stats.invgamma.logcdf(x, a)
  3260. assert_allclose(logcdf, ref, rtol=5e-15)
  3261. def test_logsf(self):
  3262. x = 0.01
  3263. a = 3.5
  3264. # Reference value computed with mpmath.
  3265. ref = -1.147781224014262e-39
  3266. logsf = stats.invgamma.logsf(x, a)
  3267. assert_allclose(logsf, ref, rtol=5e-15)
  3268. @pytest.mark.parametrize("a, ref",
  3269. [(100000000.0, -26.21208257605721),
  3270. (1e+100, -343.9688254159022)])
  3271. def test_large_entropy(self, a, ref):
  3272. # The reference values were calculated with mpmath:
  3273. # from mpmath import mp
  3274. # mp.dps = 500
  3275. # def invgamma_entropy(a):
  3276. # a = mp.mpf(a)
  3277. # h = a + mp.loggamma(a) - (mp.one + a) * mp.digamma(a)
  3278. # return float(h)
  3279. assert_allclose(stats.invgamma.entropy(a), ref, rtol=1e-15)
  3280. class TestF:
  3281. def test_endpoints(self):
  3282. # Compute the pdf at the left endpoint dst.a.
  3283. data = [[stats.f, (2, 1), 1.0]]
  3284. for _f, _args, _correct in data:
  3285. ans = _f.pdf(_f.a, *_args)
  3286. ans = [_f.pdf(_f.a, *_args) for _f, _args, _ in data]
  3287. correct = [_correct_ for _f, _args, _correct_ in data]
  3288. assert_array_almost_equal(ans, correct)
  3289. def test_f_moments(self):
  3290. # n-th moment of F distributions is only finite for n < dfd / 2
  3291. m, v, s, k = stats.f.stats(11, 6.5, moments='mvsk')
  3292. assert_(np.isfinite(m))
  3293. assert_(np.isfinite(v))
  3294. assert_(np.isfinite(s))
  3295. assert_(not np.isfinite(k))
  3296. def test_moments_warnings(self):
  3297. # no warnings should be generated for dfd = 2, 4, 6, 8 (div by zero)
  3298. with warnings.catch_warnings():
  3299. warnings.simplefilter('error', RuntimeWarning)
  3300. stats.f.stats(dfn=[11]*4, dfd=[2, 4, 6, 8], moments='mvsk')
  3301. def test_stats_broadcast(self):
  3302. dfn = np.array([[3], [11]])
  3303. dfd = np.array([11, 12])
  3304. m, v, s, k = stats.f.stats(dfn=dfn, dfd=dfd, moments='mvsk')
  3305. m2 = [dfd / (dfd - 2)]*2
  3306. assert_allclose(m, m2)
  3307. v2 = 2 * dfd**2 * (dfn + dfd - 2) / dfn / (dfd - 2)**2 / (dfd - 4)
  3308. assert_allclose(v, v2)
  3309. s2 = ((2*dfn + dfd - 2) * np.sqrt(8*(dfd - 4)) /
  3310. ((dfd - 6) * np.sqrt(dfn*(dfn + dfd - 2))))
  3311. assert_allclose(s, s2)
  3312. k2num = 12 * (dfn * (5*dfd - 22) * (dfn + dfd - 2) +
  3313. (dfd - 4) * (dfd - 2)**2)
  3314. k2den = dfn * (dfd - 6) * (dfd - 8) * (dfn + dfd - 2)
  3315. k2 = k2num / k2den
  3316. assert_allclose(k, k2)
  3317. class TestStudentT:
  3318. def test_rvgeneric_std(self):
  3319. # Regression test for #1191
  3320. assert_array_almost_equal(stats.t.std([5, 6]), [1.29099445, 1.22474487])
  3321. def test_moments_t(self):
  3322. # regression test for #8786
  3323. assert_equal(stats.t.stats(df=1, moments='mvsk'),
  3324. (np.inf, np.nan, np.nan, np.nan))
  3325. assert_equal(stats.t.stats(df=1.01, moments='mvsk'),
  3326. (0.0, np.inf, np.nan, np.nan))
  3327. assert_equal(stats.t.stats(df=2, moments='mvsk'),
  3328. (0.0, np.inf, np.nan, np.nan))
  3329. assert_equal(stats.t.stats(df=2.01, moments='mvsk'),
  3330. (0.0, 2.01/(2.01-2.0), np.nan, np.inf))
  3331. assert_equal(stats.t.stats(df=3, moments='sk'), (np.nan, np.inf))
  3332. assert_equal(stats.t.stats(df=3.01, moments='sk'), (0.0, np.inf))
  3333. assert_equal(stats.t.stats(df=4, moments='sk'), (0.0, np.inf))
  3334. assert_allclose(stats.t.stats(df=4.01, moments='sk'), (0.0, 6.0/(4.01 - 4.0)),
  3335. rtol=1e-14)
  3336. def test_t_entropy(self):
  3337. df = [1, 2, 25, 100]
  3338. # Expected values were computed with mpmath.
  3339. expected = [2.5310242469692907, 1.9602792291600821,
  3340. 1.459327578078393, 1.4289633653182439]
  3341. assert_allclose(stats.t.entropy(df), expected, rtol=1e-13)
  3342. @pytest.mark.parametrize("v, ref",
  3343. [(100, 1.4289633653182439),
  3344. (1e+100, 1.4189385332046727)])
  3345. def test_t_extreme_entropy(self, v, ref):
  3346. # Reference values were calculated with mpmath:
  3347. # from mpmath import mp
  3348. # mp.dps = 500
  3349. #
  3350. # def t_entropy(v):
  3351. # v = mp.mpf(v)
  3352. # C = (v + mp.one) / 2
  3353. # A = C * (mp.digamma(C) - mp.digamma(v / 2))
  3354. # B = 0.5 * mp.log(v) + mp.log(mp.beta(v / 2, mp.one / 2))
  3355. # h = A + B
  3356. # return float(h)
  3357. assert_allclose(stats.t.entropy(v), ref, rtol=1e-14)
  3358. @pytest.mark.parametrize("methname", ["pdf", "logpdf", "cdf",
  3359. "ppf", "sf", "isf"])
  3360. @pytest.mark.parametrize("df_infmask", [[0, 0], [1, 1], [0, 1],
  3361. [[0, 1, 0], [1, 1, 1]],
  3362. [[1, 0], [0, 1]],
  3363. [[0], [1]]])
  3364. def test_t_inf_df(self, methname, df_infmask):
  3365. df_infmask = np.asarray(df_infmask, dtype=bool)
  3366. rng = np.random.default_rng(5442451539)
  3367. df = rng.uniform(0, 10, size=df_infmask.shape)
  3368. x = rng.standard_normal(df_infmask.shape)
  3369. df[df_infmask] = np.inf
  3370. t_dist = stats.t(df=df, loc=3, scale=1)
  3371. t_dist_ref = stats.t(df=df[~df_infmask], loc=3, scale=1)
  3372. norm_dist = stats.norm(loc=3, scale=1)
  3373. t_meth = getattr(t_dist, methname)
  3374. t_meth_ref = getattr(t_dist_ref, methname)
  3375. norm_meth = getattr(norm_dist, methname)
  3376. res = t_meth(x)
  3377. assert_allclose(res[df_infmask], norm_meth(x[df_infmask]), rtol=5e-15)
  3378. assert_equal(res[~df_infmask], t_meth_ref(x[~df_infmask]))
  3379. @pytest.mark.parametrize("df_infmask", [[0, 0], [1, 1], [0, 1],
  3380. [[0, 1, 0], [1, 1, 1]],
  3381. [[1, 0], [0, 1]],
  3382. [[0], [1]]])
  3383. def test_t_inf_df_stats_entropy(self, df_infmask):
  3384. df_infmask = np.asarray(df_infmask, dtype=bool)
  3385. rng = np.random.default_rng(5442451539)
  3386. df = rng.uniform(0, 10, size=df_infmask.shape)
  3387. df[df_infmask] = np.inf
  3388. res = stats.t.stats(df=df, loc=3, scale=1, moments='mvsk')
  3389. res_ex_inf = stats.norm.stats(loc=3, scale=1, moments='mvsk')
  3390. res_ex_noinf = stats.t.stats(df=df[~df_infmask], loc=3, scale=1,
  3391. moments='mvsk')
  3392. for i in range(4):
  3393. assert_equal(res[i][df_infmask], res_ex_inf[i])
  3394. assert_equal(res[i][~df_infmask], res_ex_noinf[i])
  3395. res = stats.t.entropy(df=df, loc=3, scale=1)
  3396. res_ex_inf = stats.norm.entropy(loc=3, scale=1)
  3397. res_ex_noinf = stats.t.entropy(df=df[~df_infmask], loc=3, scale=1)
  3398. assert_equal(res[df_infmask], res_ex_inf)
  3399. assert_equal(res[~df_infmask], res_ex_noinf)
  3400. def test_logpdf_pdf(self):
  3401. # reference values were computed via the reference distribution, e.g.
  3402. # mp.dps = 500; StudentT(df=df).logpdf(x), StudentT(df=df).pdf(x)
  3403. x = [1, 1e3, 10, 1]
  3404. df = [1e100, 1e50, 1e20, 1]
  3405. logpdf_ref = [-1.4189385332046727, -500000.9189385332,
  3406. -50.918938533204674, -1.8378770664093456]
  3407. pdf_ref = [0.24197072451914334, 0,
  3408. 7.69459862670642e-23, 0.15915494309189535]
  3409. assert_allclose(stats.t.logpdf(x, df), logpdf_ref, rtol=1e-14)
  3410. assert_allclose(stats.t.pdf(x, df), pdf_ref, rtol=1e-14)
  3411. # Reference values were computed with mpmath, and double-checked with
  3412. # Wolfram Alpha.
  3413. @pytest.mark.parametrize('x, df, ref',
  3414. [(-75.0, 15, -46.76036184546812),
  3415. (0, 15, -0.6931471805599453),
  3416. (75.0, 15, -4.9230344937641665e-21)])
  3417. def test_logcdf_logsf(self, x, df, ref):
  3418. logcdf = stats.t.logcdf(x, df)
  3419. assert_allclose(logcdf, ref, rtol=5e-15)
  3420. # The reference value is logcdf(x, df) == logsf(-x, df).
  3421. logsf = stats.t.logsf(-x, df)
  3422. assert_allclose(logsf, ref, rtol=5e-15)
  3423. class TestRvDiscrete:
  3424. def setup_method(self):
  3425. self.rng = np.random.default_rng(333348228)
  3426. def test_rvs(self):
  3427. states = [-1, 0, 1, 2, 3, 4]
  3428. probability = [0.0, 0.3, 0.4, 0.0, 0.3, 0.0]
  3429. samples = 1000
  3430. r = stats.rv_discrete(name='sample', values=(states, probability))
  3431. x = r.rvs(size=samples, random_state=self.rng)
  3432. assert isinstance(x, np.ndarray)
  3433. for s, p in zip(states, probability):
  3434. assert abs(sum(x == s)/float(samples) - p) < 0.05
  3435. x = r.rvs(random_state=self.rng)
  3436. assert np.issubdtype(type(x), np.integer)
  3437. def test_entropy(self):
  3438. # Basic tests of entropy.
  3439. pvals = np.array([0.25, 0.45, 0.3])
  3440. p = stats.rv_discrete(values=([0, 1, 2], pvals))
  3441. expected_h = -sum(xlogy(pvals, pvals))
  3442. h = p.entropy()
  3443. assert_allclose(h, expected_h)
  3444. p = stats.rv_discrete(values=([0, 1, 2], [1.0, 0, 0]))
  3445. h = p.entropy()
  3446. assert_equal(h, 0.0)
  3447. def test_pmf(self):
  3448. xk = [1, 2, 4]
  3449. pk = [0.5, 0.3, 0.2]
  3450. rv = stats.rv_discrete(values=(xk, pk))
  3451. x = [[1., 4.],
  3452. [3., 2]]
  3453. assert_allclose(rv.pmf(x),
  3454. [[0.5, 0.2],
  3455. [0., 0.3]], atol=1e-14)
  3456. def test_cdf(self):
  3457. xk = [1, 2, 4]
  3458. pk = [0.5, 0.3, 0.2]
  3459. rv = stats.rv_discrete(values=(xk, pk))
  3460. x_values = [-2, 1., 1.1, 1.5, 2.0, 3.0, 4, 5]
  3461. expected = [0, 0.5, 0.5, 0.5, 0.8, 0.8, 1, 1]
  3462. assert_allclose(rv.cdf(x_values), expected, atol=1e-14)
  3463. # also check scalar arguments
  3464. assert_allclose([rv.cdf(xx) for xx in x_values],
  3465. expected, atol=1e-14)
  3466. def test_ppf(self):
  3467. xk = [1, 2, 4]
  3468. pk = [0.5, 0.3, 0.2]
  3469. rv = stats.rv_discrete(values=(xk, pk))
  3470. q_values = [0.1, 0.5, 0.6, 0.8, 0.9, 1.]
  3471. expected = [1, 1, 2, 2, 4, 4]
  3472. assert_allclose(rv.ppf(q_values), expected, atol=1e-14)
  3473. # also check scalar arguments
  3474. assert_allclose([rv.ppf(q) for q in q_values],
  3475. expected, atol=1e-14)
  3476. def test_cdf_ppf_next(self):
  3477. # copied and special cased from test_discrete_basic
  3478. vals = ([1, 2, 4, 7, 8], [0.1, 0.2, 0.3, 0.3, 0.1])
  3479. rv = stats.rv_discrete(values=vals)
  3480. assert_array_equal(rv.ppf(rv.cdf(rv.xk[:-1]) + 1e-8),
  3481. rv.xk[1:])
  3482. def test_multidimension(self):
  3483. xk = np.arange(12).reshape((3, 4))
  3484. pk = np.array([[0.1, 0.1, 0.15, 0.05],
  3485. [0.1, 0.1, 0.05, 0.05],
  3486. [0.1, 0.1, 0.05, 0.05]])
  3487. rv = stats.rv_discrete(values=(xk, pk))
  3488. assert_allclose(rv.expect(), np.sum(rv.xk * rv.pk), atol=1e-14)
  3489. def test_bad_input(self):
  3490. xk = [1, 2, 3]
  3491. pk = [0.5, 0.5]
  3492. assert_raises(ValueError, stats.rv_discrete, **dict(values=(xk, pk)))
  3493. pk = [1, 2, 3]
  3494. assert_raises(ValueError, stats.rv_discrete, **dict(values=(xk, pk)))
  3495. xk = [1, 2, 3]
  3496. pk = [0.5, 1.2, -0.7]
  3497. assert_raises(ValueError, stats.rv_discrete, **dict(values=(xk, pk)))
  3498. xk = [1, 2, 3, 4, 5]
  3499. pk = [0.3, 0.3, 0.3, 0.3, -0.2]
  3500. assert_raises(ValueError, stats.rv_discrete, **dict(values=(xk, pk)))
  3501. xk = [1, 1]
  3502. pk = [0.5, 0.5]
  3503. assert_raises(ValueError, stats.rv_discrete, **dict(values=(xk, pk)))
  3504. def test_shape_rv_sample(self):
  3505. # tests added for gh-9565
  3506. # mismatch of 2d inputs
  3507. xk, pk = np.arange(4).reshape((2, 2)), np.full((2, 3), 1/6)
  3508. assert_raises(ValueError, stats.rv_discrete, **dict(values=(xk, pk)))
  3509. # same number of elements, but shapes not compatible
  3510. xk, pk = np.arange(6).reshape((3, 2)), np.full((2, 3), 1/6)
  3511. assert_raises(ValueError, stats.rv_discrete, **dict(values=(xk, pk)))
  3512. # same shapes => no error
  3513. xk, pk = np.arange(6).reshape((3, 2)), np.full((3, 2), 1/6)
  3514. assert_equal(stats.rv_discrete(values=(xk, pk)).pmf(0), 1/6)
  3515. def test_expect1(self):
  3516. xk = [1, 2, 4, 6, 7, 11]
  3517. pk = [0.1, 0.2, 0.2, 0.2, 0.2, 0.1]
  3518. rv = stats.rv_discrete(values=(xk, pk))
  3519. assert_allclose(rv.expect(), np.sum(rv.xk * rv.pk), atol=1e-14)
  3520. def test_expect2(self):
  3521. # rv_sample should override _expect. Bug report from
  3522. # https://stackoverflow.com/questions/63199792
  3523. y = [200.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0,
  3524. 1100.0, 1200.0, 1300.0, 1400.0, 1500.0, 1600.0, 1700.0, 1800.0,
  3525. 1900.0, 2000.0, 2100.0, 2200.0, 2300.0, 2400.0, 2500.0, 2600.0,
  3526. 2700.0, 2800.0, 2900.0, 3000.0, 3100.0, 3200.0, 3300.0, 3400.0,
  3527. 3500.0, 3600.0, 3700.0, 3800.0, 3900.0, 4000.0, 4100.0, 4200.0,
  3528. 4300.0, 4400.0, 4500.0, 4600.0, 4700.0, 4800.0]
  3529. py = [0.0004, 0.0, 0.0033, 0.006500000000000001, 0.0, 0.0,
  3530. 0.004399999999999999, 0.6862, 0.0, 0.0, 0.0,
  3531. 0.00019999999999997797, 0.0006000000000000449,
  3532. 0.024499999999999966, 0.006400000000000072,
  3533. 0.0043999999999999595, 0.019499999999999962,
  3534. 0.03770000000000007, 0.01759999999999995, 0.015199999999999991,
  3535. 0.018100000000000005, 0.04500000000000004, 0.0025999999999999357,
  3536. 0.0, 0.0041000000000001036, 0.005999999999999894,
  3537. 0.0042000000000000925, 0.0050000000000000044,
  3538. 0.0041999999999999815, 0.0004999999999999449,
  3539. 0.009199999999999986, 0.008200000000000096,
  3540. 0.0, 0.0, 0.0046999999999999265, 0.0019000000000000128,
  3541. 0.0006000000000000449, 0.02510000000000001, 0.0,
  3542. 0.007199999999999984, 0.0, 0.012699999999999934, 0.0, 0.0,
  3543. 0.008199999999999985, 0.005600000000000049, 0.0]
  3544. rv = stats.rv_discrete(values=(y, py))
  3545. # check the mean
  3546. assert_allclose(rv.expect(), rv.mean(), atol=1e-14)
  3547. assert_allclose(rv.expect(),
  3548. sum(v * w for v, w in zip(y, py)), atol=1e-14)
  3549. # also check the second moment
  3550. assert_allclose(rv.expect(lambda x: x**2),
  3551. sum(v**2 * w for v, w in zip(y, py)), atol=1e-14)
  3552. class TestSkewCauchy:
  3553. def test_cauchy(self):
  3554. x = np.linspace(-5, 5, 100)
  3555. assert_array_almost_equal(stats.skewcauchy.pdf(x, a=0),
  3556. stats.cauchy.pdf(x))
  3557. assert_array_almost_equal(stats.skewcauchy.cdf(x, a=0),
  3558. stats.cauchy.cdf(x))
  3559. assert_array_almost_equal(stats.skewcauchy.ppf(x, a=0),
  3560. stats.cauchy.ppf(x))
  3561. def test_skewcauchy_R(self):
  3562. # options(digits=16)
  3563. # library(sgt)
  3564. # # lmbda, x contain the values generated for a, x below
  3565. # lmbda <- c(0.0976270078546495, 0.430378732744839, 0.2055267521432877,
  3566. # 0.0897663659937937, -0.15269040132219, 0.2917882261333122,
  3567. # -0.12482557747462, 0.7835460015641595, 0.9273255210020589,
  3568. # -0.2331169623484446)
  3569. # x <- c(2.917250380826646, 0.2889491975290444, 0.6804456109393229,
  3570. # 4.25596638292661, -4.289639418021131, -4.1287070029845925,
  3571. # -4.797816025596743, 3.32619845547938, 2.7815675094985046,
  3572. # 3.700121482468191)
  3573. # pdf = dsgt(x, mu=0, lambda=lambda, sigma=1, q=1/2, mean.cent=FALSE,
  3574. # var.adj = sqrt(2))
  3575. # cdf = psgt(x, mu=0, lambda=lambda, sigma=1, q=1/2, mean.cent=FALSE,
  3576. # var.adj = sqrt(2))
  3577. # qsgt(cdf, mu=0, lambda=lambda, sigma=1, q=1/2, mean.cent=FALSE,
  3578. # var.adj = sqrt(2))
  3579. rng = np.random.RandomState(0)
  3580. a = rng.rand(10) * 2 - 1
  3581. x = rng.rand(10) * 10 - 5
  3582. pdf = [0.039473975217333909, 0.305829714049903223, 0.24140158118994162,
  3583. 0.019585772402693054, 0.021436553695989482, 0.00909817103867518,
  3584. 0.01658423410016873, 0.071083288030394126, 0.103250045941454524,
  3585. 0.013110230778426242]
  3586. cdf = [0.87426677718213752, 0.37556468910780882, 0.59442096496538066,
  3587. 0.91304659850890202, 0.09631964100300605, 0.03829624330921733,
  3588. 0.08245240578402535, 0.72057062945510386, 0.62826415852515449,
  3589. 0.95011308463898292]
  3590. assert_allclose(stats.skewcauchy.pdf(x, a), pdf)
  3591. assert_allclose(stats.skewcauchy.cdf(x, a), cdf)
  3592. assert_allclose(stats.skewcauchy.ppf(cdf, a), x)
  3593. class TestJFSkewT:
  3594. def test_compare_t(self):
  3595. # Verify that jf_skew_t with a=b recovers the t distribution with 2a
  3596. # degrees of freedom
  3597. a = b = 5
  3598. df = a * 2
  3599. x = [-1.0, 0.0, 1.0, 2.0]
  3600. q = [0.0, 0.1, 0.25, 0.75, 0.90, 1.0]
  3601. jf = stats.jf_skew_t(a, b)
  3602. t = stats.t(df)
  3603. assert_allclose(jf.pdf(x), t.pdf(x))
  3604. assert_allclose(jf.cdf(x), t.cdf(x))
  3605. assert_allclose(jf.ppf(q), t.ppf(q))
  3606. assert_allclose(jf.stats('mvsk'), t.stats('mvsk'))
  3607. @pytest.fixture
  3608. def gamlss_pdf_data(self):
  3609. """Sample data points computed using the `ST5` distribution from the
  3610. GAMLSS package in R. The pdf has been calculated for (a,b)=(2,3),
  3611. (a,b)=(8,4), and (a,b)=(12,13) for x in `np.linspace(-10, 10, 41)`.
  3612. N.B. the `ST5` distribution in R uses an alternative parameterization
  3613. in terms of nu and tau, where:
  3614. - nu = (a - b) / (a * b * (a + b)) ** 0.5
  3615. - tau = 2 / (a + b)
  3616. """
  3617. data = np.load(
  3618. Path(__file__).parent / "data/jf_skew_t_gamlss_pdf_data.npy"
  3619. )
  3620. return np.rec.fromarrays(data, names="x,pdf,a,b")
  3621. @pytest.mark.parametrize("a,b", [(2, 3), (8, 4), (12, 13)])
  3622. def test_compare_with_gamlss_r(self, gamlss_pdf_data, a, b):
  3623. """Compare the pdf with a table of reference values. The table of
  3624. reference values was produced using R, where the Jones and Faddy skew
  3625. t distribution is available in the GAMLSS package as `ST5`.
  3626. """
  3627. data = gamlss_pdf_data[
  3628. (gamlss_pdf_data["a"] == a) & (gamlss_pdf_data["b"] == b)
  3629. ]
  3630. x, pdf = data["x"], data["pdf"]
  3631. assert_allclose(pdf, stats.jf_skew_t(a, b).pdf(x), rtol=1e-12)
  3632. # Test data for TestSkewNorm.test_noncentral_moments()
  3633. # The expected noncentral moments were computed by Wolfram Alpha.
  3634. # In Wolfram Alpha, enter
  3635. # SkewNormalDistribution[0, 1, a] moment
  3636. # with `a` replaced by the desired shape parameter. In the results, there
  3637. # should be a table of the first four moments. Click on "More" to get more
  3638. # moments. The expected moments start with the first moment (order = 1).
  3639. _skewnorm_noncentral_moments = [
  3640. (2, [2*np.sqrt(2/(5*np.pi)),
  3641. 1,
  3642. 22/5*np.sqrt(2/(5*np.pi)),
  3643. 3,
  3644. 446/25*np.sqrt(2/(5*np.pi)),
  3645. 15,
  3646. 2682/25*np.sqrt(2/(5*np.pi)),
  3647. 105,
  3648. 107322/125*np.sqrt(2/(5*np.pi))]),
  3649. (0.1, [np.sqrt(2/(101*np.pi)),
  3650. 1,
  3651. 302/101*np.sqrt(2/(101*np.pi)),
  3652. 3,
  3653. (152008*np.sqrt(2/(101*np.pi)))/10201,
  3654. 15,
  3655. (107116848*np.sqrt(2/(101*np.pi)))/1030301,
  3656. 105,
  3657. (97050413184*np.sqrt(2/(101*np.pi)))/104060401]),
  3658. (-3, [-3/np.sqrt(5*np.pi),
  3659. 1,
  3660. -63/(10*np.sqrt(5*np.pi)),
  3661. 3,
  3662. -2529/(100*np.sqrt(5*np.pi)),
  3663. 15,
  3664. -30357/(200*np.sqrt(5*np.pi)),
  3665. 105,
  3666. -2428623/(2000*np.sqrt(5*np.pi)),
  3667. 945,
  3668. -242862867/(20000*np.sqrt(5*np.pi)),
  3669. 10395,
  3670. -29143550277/(200000*np.sqrt(5*np.pi)),
  3671. 135135]),
  3672. ]
  3673. class TestSkewNorm:
  3674. def setup_method(self):
  3675. self.rng = check_random_state(1234)
  3676. def test_normal(self):
  3677. # When the skewness is 0 the distribution is normal
  3678. x = np.linspace(-5, 5, 100)
  3679. assert_array_almost_equal(stats.skewnorm.pdf(x, a=0),
  3680. stats.norm.pdf(x))
  3681. def test_rvs(self):
  3682. rng = check_random_state(1234)
  3683. shape = (3, 4, 5)
  3684. x = stats.skewnorm.rvs(a=0.75, size=shape, random_state=rng)
  3685. assert_equal(shape, x.shape)
  3686. x = stats.skewnorm.rvs(a=-3, size=shape, random_state=rng)
  3687. assert_equal(shape, x.shape)
  3688. def test_moments(self):
  3689. rng = check_random_state(1234)
  3690. X = stats.skewnorm.rvs(a=4, size=int(1e6), loc=5, scale=2,
  3691. random_state=rng)
  3692. expected = [np.mean(X), np.var(X), stats.skew(X), stats.kurtosis(X)]
  3693. computed = stats.skewnorm.stats(a=4, loc=5, scale=2, moments='mvsk')
  3694. assert_array_almost_equal(computed, expected, decimal=2)
  3695. X = stats.skewnorm.rvs(a=-4, size=int(1e6), loc=5, scale=2,
  3696. random_state=rng)
  3697. expected = [np.mean(X), np.var(X), stats.skew(X), stats.kurtosis(X)]
  3698. computed = stats.skewnorm.stats(a=-4, loc=5, scale=2, moments='mvsk')
  3699. assert_array_almost_equal(computed, expected, decimal=2)
  3700. def test_pdf_large_x(self):
  3701. # Triples are [x, a, logpdf(x, a)]. These values were computed
  3702. # using Log[PDF[SkewNormalDistribution[0, 1, a], x]] in Wolfram Alpha.
  3703. logpdfvals = [
  3704. [40, -1, -1604.834233366398515598970],
  3705. [40, -1/2, -1004.142946723741991369168],
  3706. [40, 0, -800.9189385332046727417803],
  3707. [40, 1/2, -800.2257913526447274323631],
  3708. [-40, -1/2, -800.2257913526447274323631],
  3709. [-2, 1e7, -2.000000000000199559727173e14],
  3710. [2, -1e7, -2.000000000000199559727173e14],
  3711. ]
  3712. for x, a, logpdfval in logpdfvals:
  3713. logp = stats.skewnorm.logpdf(x, a)
  3714. assert_allclose(logp, logpdfval, rtol=1e-8)
  3715. def test_cdf_large_x(self):
  3716. # Regression test for gh-7746.
  3717. # The x values are large enough that the closest 64 bit floating
  3718. # point representation of the exact CDF is 1.0.
  3719. p = stats.skewnorm.cdf([10, 20, 30], -1)
  3720. assert_allclose(p, np.ones(3), rtol=1e-14)
  3721. p = stats.skewnorm.cdf(25, 2.5)
  3722. assert_allclose(p, 1.0, rtol=1e-14)
  3723. def test_cdf_sf_small_values(self):
  3724. # Triples are [x, a, cdf(x, a)]. These values were computed
  3725. # using CDF[SkewNormalDistribution[0, 1, a], x] in Wolfram Alpha.
  3726. cdfvals = [
  3727. [-8, 1, 3.870035046664392611e-31],
  3728. [-4, 2, 8.1298399188811398e-21],
  3729. [-2, 5, 1.55326826787106273e-26],
  3730. [-9, -1, 2.257176811907681295e-19],
  3731. [-10, -4, 1.523970604832105213e-23],
  3732. ]
  3733. for x, a, cdfval in cdfvals:
  3734. p = stats.skewnorm.cdf(x, a)
  3735. assert_allclose(p, cdfval, rtol=1e-8)
  3736. # For the skew normal distribution, sf(-x, -a) = cdf(x, a).
  3737. p = stats.skewnorm.sf(-x, -a)
  3738. assert_allclose(p, cdfval, rtol=1e-8)
  3739. @pytest.mark.parametrize('a, moments', _skewnorm_noncentral_moments)
  3740. def test_noncentral_moments(self, a, moments):
  3741. for order, expected in enumerate(moments, start=1):
  3742. mom = stats.skewnorm.moment(order, a)
  3743. assert_allclose(mom, expected, rtol=1e-14)
  3744. def test_fit(self):
  3745. rng = np.random.default_rng(4609813989115202851)
  3746. a, loc, scale = -2, 3.5, 0.5 # arbitrary, valid parameters
  3747. dist = stats.skewnorm(a, loc, scale)
  3748. rvs = dist.rvs(size=100, random_state=rng)
  3749. # test that MLE still honors guesses and fixed parameters
  3750. a2, loc2, scale2 = stats.skewnorm.fit(rvs, -1.5, floc=3)
  3751. a3, loc3, scale3 = stats.skewnorm.fit(rvs, -1.6, floc=3)
  3752. assert loc2 == loc3 == 3 # fixed parameter is respected
  3753. assert a2 != a3 # different guess -> (slightly) different outcome
  3754. # quality of fit is tested elsewhere
  3755. # test that MoM honors fixed parameters, accepts (but ignores) guesses
  3756. a4, loc4, scale4 = stats.skewnorm.fit(rvs, 3, fscale=3, method='mm')
  3757. assert scale4 == 3
  3758. # because scale was fixed, only the mean and skewness will be matched
  3759. dist4 = stats.skewnorm(a4, loc4, scale4)
  3760. res = dist4.stats(moments='ms')
  3761. ref = np.mean(rvs), stats.skew(rvs)
  3762. assert_allclose(res, ref)
  3763. # Test behavior when skew of data is beyond maximum of skewnorm
  3764. rvs2 = stats.pareto.rvs(1, size=100, random_state=rng)
  3765. # MLE still works
  3766. res = stats.skewnorm.fit(rvs2)
  3767. assert np.all(np.isfinite(res))
  3768. # MoM fits variance and skewness
  3769. a5, loc5, scale5 = stats.skewnorm.fit(rvs2, method='mm')
  3770. assert np.isinf(a5)
  3771. # distribution infrastructure doesn't allow infinite shape parameters
  3772. # into _stats; it just bypasses it and produces NaNs. Calculate
  3773. # moments manually.
  3774. m, v = np.mean(rvs2), np.var(rvs2)
  3775. assert_allclose(m, loc5 + scale5 * np.sqrt(2/np.pi))
  3776. assert_allclose(v, scale5**2 * (1 - 2 / np.pi))
  3777. # test that MLE and MoM behave as expected under sign changes
  3778. a6p, loc6p, scale6p = stats.skewnorm.fit(rvs, method='mle')
  3779. a6m, loc6m, scale6m = stats.skewnorm.fit(-rvs, method='mle')
  3780. assert_allclose([a6m, loc6m, scale6m], [-a6p, -loc6p, scale6p])
  3781. a7p, loc7p, scale7p = stats.skewnorm.fit(rvs, method='mm')
  3782. a7m, loc7m, scale7m = stats.skewnorm.fit(-rvs, method='mm')
  3783. assert_allclose([a7m, loc7m, scale7m], [-a7p, -loc7p, scale7p])
  3784. def test_fit_gh19332(self):
  3785. # When the skewness of the data was high, `skewnorm.fit` fell back on
  3786. # generic `fit` behavior with a bad guess of the skewness parameter.
  3787. # Test that this is improved; `skewnorm.fit` is now better at finding
  3788. # the global optimum when the sample is highly skewed. See gh-19332.
  3789. x = np.array([-5, -1, 1 / 100_000] + 12 * [1] + [5])
  3790. params = stats.skewnorm.fit(x)
  3791. res = stats.skewnorm.nnlf(params, x)
  3792. # Compare overridden fit against generic fit.
  3793. # res should be about 32.01, and generic fit is worse at 32.64.
  3794. # In case the generic fit improves, remove this assertion (see gh-19333).
  3795. params_super = stats.skewnorm.fit(x, superfit=True)
  3796. ref = stats.skewnorm.nnlf(params_super, x)
  3797. assert res < ref - 0.5
  3798. # Compare overridden fit against stats.fit
  3799. rng = np.random.default_rng(9842356982345693637)
  3800. bounds = {'a': (-5, 5), 'loc': (-10, 10), 'scale': (1e-16, 10)}
  3801. def optimizer(fun, bounds):
  3802. return differential_evolution(fun, bounds, rng=rng)
  3803. fit_result = stats.fit(stats.skewnorm, x, bounds, optimizer=optimizer)
  3804. np.testing.assert_allclose(params, fit_result.params, rtol=1e-4)
  3805. def test_ppf(self):
  3806. # gh-20124 reported that Boost's ppf was wrong for high skewness
  3807. # Reference value was calculated using
  3808. # N[InverseCDF[SkewNormalDistribution[0, 1, 500], 1/100], 14] in Wolfram Alpha.
  3809. assert_allclose(stats.skewnorm.ppf(0.01, 500), 0.012533469508013, rtol=1e-13)
  3810. class TestExpon:
  3811. def test_zero(self):
  3812. assert_equal(stats.expon.pdf(0), 1)
  3813. def test_tail(self): # Regression test for ticket 807
  3814. assert_equal(stats.expon.cdf(1e-18), 1e-18)
  3815. assert_equal(stats.expon.isf(stats.expon.sf(40)), 40)
  3816. def test_nan_raises_error(self):
  3817. # see gh-issue 10300
  3818. x = np.array([1.6483, 2.7169, 2.4667, 1.1791, 3.5433, np.nan])
  3819. assert_raises(ValueError, stats.expon.fit, x)
  3820. def test_inf_raises_error(self):
  3821. # see gh-issue 10300
  3822. x = np.array([1.6483, 2.7169, 2.4667, 1.1791, 3.5433, np.inf])
  3823. assert_raises(ValueError, stats.expon.fit, x)
  3824. class TestNorm:
  3825. def test_nan_raises_error(self):
  3826. # see gh-issue 10300
  3827. x = np.array([1.6483, 2.7169, 2.4667, 1.1791, 3.5433, np.nan])
  3828. assert_raises(ValueError, stats.norm.fit, x)
  3829. def test_inf_raises_error(self):
  3830. # see gh-issue 10300
  3831. x = np.array([1.6483, 2.7169, 2.4667, 1.1791, 3.5433, np.inf])
  3832. assert_raises(ValueError, stats.norm.fit, x)
  3833. def test_bad_keyword_arg(self):
  3834. x = [1, 2, 3]
  3835. assert_raises(TypeError, stats.norm.fit, x, plate="shrimp")
  3836. @pytest.mark.parametrize('loc', [0, 1])
  3837. def test_delta_cdf(self, loc):
  3838. # The expected value is computed with mpmath:
  3839. # >>> import mpmath
  3840. # >>> mpmath.mp.dps = 60
  3841. # >>> float(mpmath.ncdf(12) - mpmath.ncdf(11))
  3842. # 1.910641809677555e-28
  3843. expected = 1.910641809677555e-28
  3844. delta = stats.norm._delta_cdf(11+loc, 12+loc, loc=loc)
  3845. assert_allclose(delta, expected, rtol=1e-13)
  3846. delta = stats.norm._delta_cdf(-(12+loc), -(11+loc), loc=-loc)
  3847. assert_allclose(delta, expected, rtol=1e-13)
  3848. class TestUniform:
  3849. """gh-10300"""
  3850. def test_nan_raises_error(self):
  3851. # see gh-issue 10300
  3852. x = np.array([1.6483, 2.7169, 2.4667, 1.1791, 3.5433, np.nan])
  3853. assert_raises(ValueError, stats.uniform.fit, x)
  3854. def test_inf_raises_error(self):
  3855. # see gh-issue 10300
  3856. x = np.array([1.6483, 2.7169, 2.4667, 1.1791, 3.5433, np.inf])
  3857. assert_raises(ValueError, stats.uniform.fit, x)
  3858. class TestExponNorm:
  3859. def test_moments(self):
  3860. # Some moment test cases based on non-loc/scaled formula
  3861. def get_moms(lam, sig, mu):
  3862. # See wikipedia for these formulae
  3863. # where it is listed as an exponentially modified gaussian
  3864. opK2 = 1.0 + 1 / (lam*sig)**2
  3865. exp_skew = 2 / (lam * sig)**3 * opK2**(-1.5)
  3866. exp_kurt = 6.0 * (1 + (lam * sig)**2)**(-2)
  3867. return [mu + 1/lam, sig*sig + 1.0/(lam*lam), exp_skew, exp_kurt]
  3868. mu, sig, lam = 0, 1, 1
  3869. K = 1.0 / (lam * sig)
  3870. sts = stats.exponnorm.stats(K, loc=mu, scale=sig, moments='mvsk')
  3871. assert_almost_equal(sts, get_moms(lam, sig, mu))
  3872. mu, sig, lam = -3, 2, 0.1
  3873. K = 1.0 / (lam * sig)
  3874. sts = stats.exponnorm.stats(K, loc=mu, scale=sig, moments='mvsk')
  3875. assert_almost_equal(sts, get_moms(lam, sig, mu))
  3876. mu, sig, lam = 0, 3, 1
  3877. K = 1.0 / (lam * sig)
  3878. sts = stats.exponnorm.stats(K, loc=mu, scale=sig, moments='mvsk')
  3879. assert_almost_equal(sts, get_moms(lam, sig, mu))
  3880. mu, sig, lam = -5, 11, 3.5
  3881. K = 1.0 / (lam * sig)
  3882. sts = stats.exponnorm.stats(K, loc=mu, scale=sig, moments='mvsk')
  3883. assert_almost_equal(sts, get_moms(lam, sig, mu))
  3884. def test_nan_raises_error(self):
  3885. # see gh-issue 10300
  3886. x = np.array([1.6483, 2.7169, 2.4667, 1.1791, 3.5433, np.nan])
  3887. assert_raises(ValueError, stats.exponnorm.fit, x, floc=0, fscale=1)
  3888. def test_inf_raises_error(self):
  3889. # see gh-issue 10300
  3890. x = np.array([1.6483, 2.7169, 2.4667, 1.1791, 3.5433, np.inf])
  3891. assert_raises(ValueError, stats.exponnorm.fit, x, floc=0, fscale=1)
  3892. def test_extremes_x(self):
  3893. # Test for extreme values against overflows
  3894. assert_almost_equal(stats.exponnorm.pdf(-900, 1), 0.0)
  3895. assert_almost_equal(stats.exponnorm.pdf(+900, 1), 0.0)
  3896. assert_almost_equal(stats.exponnorm.pdf(-900, 0.01), 0.0)
  3897. assert_almost_equal(stats.exponnorm.pdf(+900, 0.01), 0.0)
  3898. # Expected values for the PDF were computed with mpmath, with
  3899. # the following function, and with mpmath.mp.dps = 50.
  3900. #
  3901. # def exponnorm_stdpdf(x, K):
  3902. # x = mpmath.mpf(x)
  3903. # K = mpmath.mpf(K)
  3904. # t1 = mpmath.exp(1/(2*K**2) - x/K)
  3905. # erfcarg = -(x - 1/K)/mpmath.sqrt(2)
  3906. # t2 = mpmath.erfc(erfcarg)
  3907. # return t1 * t2 / (2*K)
  3908. #
  3909. @pytest.mark.parametrize('x, K, expected',
  3910. [(20, 0.01, 6.90010764753618e-88),
  3911. (1, 0.01, 0.24438994313247364),
  3912. (-1, 0.01, 0.23955149623472075),
  3913. (-20, 0.01, 4.6004708690125477e-88),
  3914. (10, 1, 7.48518298877006e-05),
  3915. (10, 10000, 9.990005048283775e-05)])
  3916. def test_std_pdf(self, x, K, expected):
  3917. assert_allclose(stats.exponnorm.pdf(x, K), expected, rtol=5e-12)
  3918. # Expected values for the CDF were computed with mpmath using
  3919. # the following function and with mpmath.mp.dps = 60:
  3920. #
  3921. # def mp_exponnorm_cdf(x, K, loc=0, scale=1):
  3922. # x = mpmath.mpf(x)
  3923. # K = mpmath.mpf(K)
  3924. # loc = mpmath.mpf(loc)
  3925. # scale = mpmath.mpf(scale)
  3926. # z = (x - loc)/scale
  3927. # return (mpmath.ncdf(z)
  3928. # - mpmath.exp((1/(2*K) - z)/K)*mpmath.ncdf(z - 1/K))
  3929. #
  3930. @pytest.mark.parametrize('x, K, scale, expected',
  3931. [[0, 0.01, 1, 0.4960109760186432],
  3932. [-5, 0.005, 1, 2.7939945412195734e-07],
  3933. [-1e4, 0.01, 100, 0.0],
  3934. [-1e4, 0.01, 1000, 6.920401854427357e-24],
  3935. [5, 0.001, 1, 0.9999997118542392]])
  3936. def test_cdf_small_K(self, x, K, scale, expected):
  3937. p = stats.exponnorm.cdf(x, K, scale=scale)
  3938. if expected == 0.0:
  3939. assert p == 0.0
  3940. else:
  3941. assert_allclose(p, expected, rtol=1e-13)
  3942. # Expected values for the SF were computed with mpmath using
  3943. # the following function and with mpmath.mp.dps = 60:
  3944. #
  3945. # def mp_exponnorm_sf(x, K, loc=0, scale=1):
  3946. # x = mpmath.mpf(x)
  3947. # K = mpmath.mpf(K)
  3948. # loc = mpmath.mpf(loc)
  3949. # scale = mpmath.mpf(scale)
  3950. # z = (x - loc)/scale
  3951. # return (mpmath.ncdf(-z)
  3952. # + mpmath.exp((1/(2*K) - z)/K)*mpmath.ncdf(z - 1/K))
  3953. #
  3954. @pytest.mark.parametrize('x, K, scale, expected',
  3955. [[10, 0.01, 1, 8.474702916146657e-24],
  3956. [2, 0.005, 1, 0.02302280664231312],
  3957. [5, 0.005, 0.5, 8.024820681931086e-24],
  3958. [10, 0.005, 0.5, 3.0603340062892486e-89],
  3959. [20, 0.005, 0.5, 0.0],
  3960. [-3, 0.001, 1, 0.9986545205566117]])
  3961. def test_sf_small_K(self, x, K, scale, expected):
  3962. p = stats.exponnorm.sf(x, K, scale=scale)
  3963. if expected == 0.0:
  3964. assert p == 0.0
  3965. else:
  3966. assert_allclose(p, expected, rtol=5e-13)
  3967. class TestGenExpon:
  3968. def test_pdf_unity_area(self):
  3969. from scipy.integrate import simpson
  3970. # PDF should integrate to one
  3971. p = stats.genexpon.pdf(np.arange(0, 10, 0.01), 0.5, 0.5, 2.0)
  3972. assert_almost_equal(simpson(p, dx=0.01), 1, 1)
  3973. def test_cdf_bounds(self):
  3974. # CDF should always be positive
  3975. cdf = stats.genexpon.cdf(np.arange(0, 10, 0.01), 0.5, 0.5, 2.0)
  3976. assert np.all((0 <= cdf) & (cdf <= 1))
  3977. # The values of p in the following data were computed with mpmath.
  3978. # E.g. the script
  3979. # from mpmath import mp
  3980. # mp.dps = 80
  3981. # x = mp.mpf('15.0')
  3982. # a = mp.mpf('1.0')
  3983. # b = mp.mpf('2.0')
  3984. # c = mp.mpf('1.5')
  3985. # print(float(mp.exp((-a-b)*x + (b/c)*-mp.expm1(-c*x))))
  3986. # prints
  3987. # 1.0859444834514553e-19
  3988. @pytest.mark.parametrize('x, p, a, b, c',
  3989. [(15, 1.0859444834514553e-19, 1, 2, 1.5),
  3990. (0.25, 0.7609068232534623, 0.5, 2, 3),
  3991. (0.25, 0.09026661397565876, 9.5, 2, 0.5),
  3992. (0.01, 0.9753038265071597, 2.5, 0.25, 0.5),
  3993. (3.25, 0.0001962824553094492, 2.5, 0.25, 0.5),
  3994. (0.125, 0.9508674287164001, 0.25, 5, 0.5)])
  3995. def test_sf_isf(self, x, p, a, b, c):
  3996. sf = stats.genexpon.sf(x, a, b, c)
  3997. assert_allclose(sf, p, rtol=2e-14)
  3998. isf = stats.genexpon.isf(p, a, b, c)
  3999. assert_allclose(isf, x, rtol=2e-14)
  4000. # The values of p in the following data were computed with mpmath.
  4001. @pytest.mark.parametrize('x, p, a, b, c',
  4002. [(0.25, 0.2390931767465377, 0.5, 2, 3),
  4003. (0.25, 0.9097333860243412, 9.5, 2, 0.5),
  4004. (0.01, 0.0246961734928403, 2.5, 0.25, 0.5),
  4005. (3.25, 0.9998037175446906, 2.5, 0.25, 0.5),
  4006. (0.125, 0.04913257128359998, 0.25, 5, 0.5)])
  4007. def test_cdf_ppf(self, x, p, a, b, c):
  4008. cdf = stats.genexpon.cdf(x, a, b, c)
  4009. assert_allclose(cdf, p, rtol=2e-14)
  4010. ppf = stats.genexpon.ppf(p, a, b, c)
  4011. assert_allclose(ppf, x, rtol=2e-14)
  4012. class TestTruncexpon:
  4013. def test_sf_isf(self):
  4014. # reference values were computed via the reference distribution, e.g.
  4015. # mp.dps = 50; TruncExpon(b=b).sf(x)
  4016. b = [20, 100]
  4017. x = [19.999999, 99.999999]
  4018. ref = [2.0611546593828472e-15, 3.7200778266671455e-50]
  4019. assert_allclose(stats.truncexpon.sf(x, b), ref, rtol=1.5e-10)
  4020. assert_allclose(stats.truncexpon.isf(ref, b), x, rtol=1e-12)
  4021. class TestExponpow:
  4022. def test_tail(self):
  4023. assert_almost_equal(stats.exponpow.cdf(1e-10, 2.), 1e-20)
  4024. assert_almost_equal(stats.exponpow.isf(stats.exponpow.sf(5, .8), .8),
  4025. 5)
  4026. class TestSkellam:
  4027. def test_pmf(self):
  4028. # comparison to R
  4029. k = np.arange(-10, 15)
  4030. mu1, mu2 = 10, 5
  4031. skpmfR = np.array(
  4032. [4.2254582961926893e-005, 1.1404838449648488e-004,
  4033. 2.8979625801752660e-004, 6.9177078182101231e-004,
  4034. 1.5480716105844708e-003, 3.2412274963433889e-003,
  4035. 6.3373707175123292e-003, 1.1552351566696643e-002,
  4036. 1.9606152375042644e-002, 3.0947164083410337e-002,
  4037. 4.5401737566767360e-002, 6.1894328166820688e-002,
  4038. 7.8424609500170578e-002, 9.2418812533573133e-002,
  4039. 1.0139793148019728e-001, 1.0371927988298846e-001,
  4040. 9.9076583077406091e-002, 8.8546660073089561e-002,
  4041. 7.4187842052486810e-002, 5.8392772862200251e-002,
  4042. 4.3268692953013159e-002, 3.0248159818374226e-002,
  4043. 1.9991434305603021e-002, 1.2516877303301180e-002,
  4044. 7.4389876226229707e-003])
  4045. assert_almost_equal(stats.skellam.pmf(k, mu1, mu2), skpmfR, decimal=15)
  4046. def test_cdf(self):
  4047. # comparison to R, only 5 decimals
  4048. k = np.arange(-10, 15)
  4049. mu1, mu2 = 10, 5
  4050. skcdfR = np.array(
  4051. [6.4061475386192104e-005, 1.7810985988267694e-004,
  4052. 4.6790611790020336e-004, 1.1596768997212152e-003,
  4053. 2.7077485103056847e-003, 5.9489760066490718e-003,
  4054. 1.2286346724161398e-002, 2.3838698290858034e-002,
  4055. 4.3444850665900668e-002, 7.4392014749310995e-002,
  4056. 1.1979375231607835e-001, 1.8168808048289900e-001,
  4057. 2.6011268998306952e-001, 3.5253150251664261e-001,
  4058. 4.5392943399683988e-001, 5.5764871387982828e-001,
  4059. 6.5672529695723436e-001, 7.4527195703032389e-001,
  4060. 8.1945979908281064e-001, 8.7785257194501087e-001,
  4061. 9.2112126489802404e-001, 9.5136942471639818e-001,
  4062. 9.7136085902200120e-001, 9.8387773632530240e-001,
  4063. 9.9131672394792536e-001])
  4064. assert_almost_equal(stats.skellam.cdf(k, mu1, mu2), skcdfR, decimal=5)
  4065. def test_extreme_mu2(self):
  4066. # check that crash reported by gh-17916 large mu2 is resolved
  4067. x, mu1, mu2 = 0, 1, 4820232647677555.0
  4068. assert_allclose(stats.skellam.pmf(x, mu1, mu2), 0, atol=1e-16)
  4069. assert_allclose(stats.skellam.cdf(x, mu1, mu2), 1, atol=1e-16)
  4070. class TestLognorm:
  4071. def test_pdf(self):
  4072. # Regression test for Ticket #1471: avoid nan with 0/0 situation
  4073. # Also make sure there are no warnings at x=0, cf gh-5202
  4074. with warnings.catch_warnings():
  4075. warnings.simplefilter('error', RuntimeWarning)
  4076. pdf = stats.lognorm.pdf([0, 0.5, 1], 1)
  4077. assert_array_almost_equal(pdf, [0.0, 0.62749608, 0.39894228])
  4078. def test_logcdf(self):
  4079. # Regression test for gh-5940: sf et al would underflow too early
  4080. x2, mu, sigma = 201.68, 195, 0.149
  4081. assert_allclose(stats.lognorm.sf(x2-mu, s=sigma),
  4082. stats.norm.sf(np.log(x2-mu)/sigma))
  4083. assert_allclose(stats.lognorm.logsf(x2-mu, s=sigma),
  4084. stats.norm.logsf(np.log(x2-mu)/sigma))
  4085. @pytest.fixture(scope='function')
  4086. def rng(self):
  4087. return np.random.default_rng(1234)
  4088. @pytest.mark.parametrize("rvs_shape", [.1, 2])
  4089. @pytest.mark.parametrize("rvs_loc", [-2, 0, 2])
  4090. @pytest.mark.parametrize("rvs_scale", [.2, 1, 5])
  4091. @pytest.mark.parametrize('fix_shape, fix_loc, fix_scale',
  4092. [e for e in product((False, True), repeat=3)
  4093. if False in e])
  4094. @np.errstate(invalid="ignore")
  4095. def test_fit_MLE_comp_optimizer(self, rvs_shape, rvs_loc, rvs_scale,
  4096. fix_shape, fix_loc, fix_scale, rng):
  4097. data = stats.lognorm.rvs(size=100, s=rvs_shape, scale=rvs_scale,
  4098. loc=rvs_loc, random_state=rng)
  4099. kwds = {}
  4100. if fix_shape:
  4101. kwds['f0'] = rvs_shape
  4102. if fix_loc:
  4103. kwds['floc'] = rvs_loc
  4104. if fix_scale:
  4105. kwds['fscale'] = rvs_scale
  4106. # Numerical result may equal analytical result if some code path
  4107. # of the analytical routine makes use of numerical optimization.
  4108. _assert_less_or_close_loglike(stats.lognorm, data, **kwds,
  4109. maybe_identical=True)
  4110. def test_isf(self):
  4111. # reference values were computed via the reference distribution, e.g.
  4112. # mp.dps = 100;
  4113. # LogNormal(s=s).isf(q=0.1, guess=0)
  4114. # LogNormal(s=s).isf(q=2e-10, guess=100)
  4115. s = 0.954
  4116. q = [0.1, 2e-10, 5e-20, 6e-40]
  4117. ref = [3.3960065375794937, 390.07632793595974, 5830.5020828128445,
  4118. 287872.84087457904]
  4119. assert_allclose(stats.lognorm.isf(q, s), ref, rtol=1e-14)
  4120. class TestBeta:
  4121. def test_logpdf(self):
  4122. # Regression test for Ticket #1326: avoid nan with 0*log(0) situation
  4123. logpdf = stats.beta.logpdf(0, 1, 0.5)
  4124. assert_almost_equal(logpdf, -0.69314718056)
  4125. logpdf = stats.beta.logpdf(0, 0.5, 1)
  4126. assert_almost_equal(logpdf, np.inf)
  4127. def test_logpdf_ticket_1866(self):
  4128. alpha, beta = 267, 1472
  4129. x = np.array([0.2, 0.5, 0.6])
  4130. b = stats.beta(alpha, beta)
  4131. assert_allclose(b.logpdf(x).sum(), -1201.699061824062)
  4132. assert_allclose(b.pdf(x), np.exp(b.logpdf(x)))
  4133. def test_fit_bad_keyword_args(self):
  4134. x = [0.1, 0.5, 0.6]
  4135. assert_raises(TypeError, stats.beta.fit, x, floc=0, fscale=1,
  4136. plate="shrimp")
  4137. def test_fit_duplicated_fixed_parameter(self):
  4138. # At most one of 'f0', 'fa' or 'fix_a' can be given to the fit method.
  4139. # More than one raises a ValueError.
  4140. x = [0.1, 0.5, 0.6]
  4141. assert_raises(ValueError, stats.beta.fit, x, fa=0.5, fix_a=0.5)
  4142. @pytest.mark.skipif(MACOS_INTEL, reason="Overflow, see gh-14901")
  4143. def test_issue_12635(self):
  4144. # Confirm that Boost's beta distribution resolves gh-12635.
  4145. # Check against R:
  4146. # options(digits=16)
  4147. # p = 0.9999999999997369
  4148. # a = 75.0
  4149. # b = 66334470.0
  4150. # print(qbeta(p, a, b))
  4151. p, a, b = 0.9999999999997369, 75.0, 66334470.0
  4152. assert_allclose(stats.beta.ppf(p, a, b), 2.343620802982393e-06)
  4153. @pytest.mark.skipif(MACOS_INTEL, reason="Overflow, see gh-14901")
  4154. def test_issue_12794(self):
  4155. # Confirm that Boost's beta distribution resolves gh-12794.
  4156. # Check against R.
  4157. # options(digits=16)
  4158. # p = 1e-11
  4159. # count_list = c(10,100,1000)
  4160. # print(qbeta(1-p, count_list + 1, 100000 - count_list))
  4161. inv_R = np.array([0.0004944464889611935,
  4162. 0.0018360586912635726,
  4163. 0.0122663919942518351])
  4164. count_list = np.array([10, 100, 1000])
  4165. p = 1e-11
  4166. inv = stats.beta.isf(p, count_list + 1, 100000 - count_list)
  4167. assert_allclose(inv, inv_R)
  4168. res = stats.beta.sf(inv, count_list + 1, 100000 - count_list)
  4169. assert_allclose(res, p)
  4170. @pytest.mark.skipif(MACOS_INTEL, reason="Overflow, see gh-14901")
  4171. def test_issue_12796(self):
  4172. # Confirm that Boost's beta distribution succeeds in the case
  4173. # of gh-12796
  4174. alpha_2 = 5e-6
  4175. count_ = np.arange(1, 20)
  4176. nobs = 100000
  4177. q, a, b = 1 - alpha_2, count_ + 1, nobs - count_
  4178. inv = stats.beta.ppf(q, a, b)
  4179. res = stats.beta.cdf(inv, a, b)
  4180. assert_allclose(res, 1 - alpha_2)
  4181. def test_endpoints(self):
  4182. # Confirm that boost's beta distribution returns inf at x=1
  4183. # when b<1
  4184. a, b = 1, 0.5
  4185. assert_equal(stats.beta.pdf(1, a, b), np.inf)
  4186. # Confirm that boost's beta distribution returns inf at x=0
  4187. # when a<1
  4188. a, b = 0.2, 3
  4189. assert_equal(stats.beta.pdf(0, a, b), np.inf)
  4190. # Confirm that boost's beta distribution returns 5 at x=0
  4191. # when a=1, b=5
  4192. a, b = 1, 5
  4193. assert_equal(stats.beta.pdf(0, a, b), 5)
  4194. assert_equal(stats.beta.pdf(1e-310, a, b), 5)
  4195. # Confirm that boost's beta distribution returns 5 at x=1
  4196. # when a=5, b=1
  4197. a, b = 5, 1
  4198. assert_equal(stats.beta.pdf(1, a, b), 5)
  4199. assert_equal(stats.beta.pdf(1-1e-310, a, b), 5)
  4200. def test_boost_eval_issue_14606(self):
  4201. q, a, b = 0.995, 1.0e11, 1.0e13
  4202. stats.beta.ppf(q, a, b)
  4203. @pytest.mark.parametrize('method', [stats.beta.ppf, stats.beta.isf])
  4204. @pytest.mark.parametrize('a, b', [(1e-310, 12.5), (12.5, 1e-310)])
  4205. def test_beta_ppf_with_subnormal_a_b(self, method, a, b):
  4206. # Regression test for gh-17444: beta.ppf(p, a, b) and beta.isf(p, a, b)
  4207. # would result in a segmentation fault if either a or b was subnormal.
  4208. p = 0.9
  4209. # Depending on the version of Boost that we have vendored and
  4210. # our setting of the Boost double promotion policy, the call
  4211. # `stats.beta.ppf(p, a, b)` might raise an OverflowError or
  4212. # return a value. We'll accept either behavior (and not care about
  4213. # the value), because our goal here is to verify that the call does
  4214. # not trigger a segmentation fault.
  4215. try:
  4216. method(p, a, b)
  4217. except OverflowError:
  4218. # The OverflowError exception occurs with Boost 1.80 or earlier
  4219. # when Boost's double promotion policy is false; see
  4220. # https://github.com/boostorg/math/issues/882
  4221. # and
  4222. # https://github.com/boostorg/math/pull/883
  4223. # Once we have vendored the fixed version of Boost, we can drop
  4224. # this try-except wrapper and just call the function.
  4225. pass
  4226. # Reference values computed with mpmath.
  4227. @pytest.mark.parametrize('x, a, b, ref',
  4228. [(0.999, 1.5, 2.5, -6.439838145196121e-08),
  4229. (2e-9, 3.25, 2.5, -63.13030939685114)])
  4230. def test_logcdf(self, x, a, b, ref):
  4231. logcdf = stats.beta.logcdf(x, a, b)
  4232. assert_allclose(logcdf, ref, rtol=5e-15)
  4233. # Reference values computed with mpmath.
  4234. @pytest.mark.parametrize('x, a, b, ref',
  4235. [(2e-9, 1.5, 2.5, -3.0368535131140806e-13),
  4236. (0.998, 3.25, 2.5, -13.309796070871489)])
  4237. def test_logsf(self, x, a, b, ref):
  4238. logsf = stats.beta.logsf(x, a, b)
  4239. assert_allclose(logsf, ref, 5e-15)
  4240. # entropy accuracy was confirmed using the following mpmath function
  4241. # from mpmath import mp
  4242. # mp.dps = 50
  4243. # def beta_entropy_mpmath(a, b):
  4244. # a = mp.mpf(a)
  4245. # b = mp.mpf(b)
  4246. # entropy = mp.log(mp.beta(a, b)) - (a - 1) * mp.digamma(a) -\
  4247. # (b - 1) * mp.digamma(b) + (a + b -2) * mp.digamma(a + b)
  4248. # return float(entropy)
  4249. @pytest.mark.parametrize('a, b, ref',
  4250. [(0.5, 0.5, -0.24156447527049044),
  4251. (0.001, 1, -992.0922447210179),
  4252. (1, 10000, -8.210440371976183),
  4253. (100000, 100000, -5.377247470132859)])
  4254. def test_entropy(self, a, b, ref):
  4255. assert_allclose(stats.beta(a, b).entropy(), ref)
  4256. @pytest.mark.parametrize(
  4257. "a, b, ref, tol",
  4258. [
  4259. (1, 10, -1.4025850929940458, 1e-14),
  4260. (10, 20, -1.0567887388936708, 1e-13),
  4261. (4e6, 4e6+20, -7.221686009678741, 1e-9),
  4262. (5e6, 5e6+10, -7.333257022834638, 1e-8),
  4263. (1e10, 1e10+20, -11.133707703130474, 1e-11),
  4264. (1e50, 1e50+20, -57.185409562486385, 1e-15),
  4265. (2, 1e10, -21.448635265288925, 1e-11),
  4266. (2, 1e20, -44.47448619497938, 1e-14),
  4267. (2, 1e50, -113.55203898480075, 1e-14),
  4268. (5, 1e10, -20.87226777401971, 1e-10),
  4269. (5, 1e20, -43.89811870326017, 1e-14),
  4270. (5, 1e50, -112.97567149308153, 1e-14),
  4271. (10, 1e10, -20.489796752909477, 1e-9),
  4272. (10, 1e20, -43.51564768139993, 1e-14),
  4273. (10, 1e50, -112.59320047122131, 1e-14),
  4274. (1e20, 2, -44.47448619497938, 1e-14),
  4275. (1e20, 5, -43.89811870326017, 1e-14),
  4276. (1e50, 10, -112.59320047122131, 1e-14),
  4277. ]
  4278. )
  4279. def test_extreme_entropy(self, a, b, ref, tol):
  4280. # Reference values were calculated with mpmath:
  4281. # from mpmath import mp
  4282. # mp.dps = 500
  4283. #
  4284. # def beta_entropy_mpmath(a, b):
  4285. # a = mp.mpf(a)
  4286. # b = mp.mpf(b)
  4287. # entropy = (
  4288. # mp.log(mp.beta(a, b)) - (a - 1) * mp.digamma(a)
  4289. # - (b - 1) * mp.digamma(b) + (a + b - 2) * mp.digamma(a + b)
  4290. # )
  4291. # return float(entropy)
  4292. assert_allclose(stats.beta(a, b).entropy(), ref, rtol=tol)
  4293. def test_entropy_broadcasting(self):
  4294. # gh-23127 reported that the entropy method of the beta
  4295. # distribution did not broadcast correctly.
  4296. Beta = stats.make_distribution(stats.beta)
  4297. a = np.asarray([5e6, 100, 1e9, 10])
  4298. b = np.asarray([5e6, 1e9, 100, 20])
  4299. res = Beta(a=a, b=b).entropy()
  4300. ref = np.asarray([Beta(a=a[0], b=b[0]).entropy(),
  4301. Beta(a=a[1], b=b[1]).entropy(),
  4302. Beta(a=a[2], b=b[2]).entropy(),
  4303. Beta(a=a[3], b=b[3]).entropy()])
  4304. assert_allclose(res, ref)
  4305. class TestBetaPrime:
  4306. # the test values are used in test_cdf_gh_17631 / test_ppf_gh_17631
  4307. # They are computed with mpmath. Example:
  4308. # from mpmath import mp
  4309. # mp.dps = 50
  4310. # a, b = mp.mpf(0.05), mp.mpf(0.1)
  4311. # x = mp.mpf(1e22)
  4312. # float(mp.betainc(a, b, 0.0, x/(1+x), regularized=True))
  4313. # note: we use the values computed by the cdf to test whether
  4314. # ppf(cdf(x)) == x (up to a small tolerance)
  4315. # since the ppf can be very sensitive to small variations of the input,
  4316. # it can be required to generate the test case for the ppf separately,
  4317. # see self.test_ppf
  4318. cdf_vals = [
  4319. (1e22, 100.0, 0.05, 0.8973027435427167),
  4320. (1e10, 100.0, 0.05, 0.5911548582766262),
  4321. (1e8, 0.05, 0.1, 0.9467768090820048),
  4322. (1e8, 100.0, 0.05, 0.4852944858726726),
  4323. (1e-10, 0.05, 0.1, 0.21238845427095),
  4324. (1e-10, 1.5, 1.5, 1.697652726007973e-15),
  4325. (1e-10, 0.05, 100.0, 0.40884514172337383),
  4326. (1e-22, 0.05, 0.1, 0.053349567649287326),
  4327. (1e-22, 1.5, 1.5, 1.6976527263135503e-33),
  4328. (1e-22, 0.05, 100.0, 0.10269725645728331),
  4329. (1e-100, 0.05, 0.1, 6.7163126421919795e-06),
  4330. (1e-100, 1.5, 1.5, 1.6976527263135503e-150),
  4331. (1e-100, 0.05, 100.0, 1.2928818587561651e-05),
  4332. ]
  4333. def test_logpdf(self):
  4334. alpha, beta = 267, 1472
  4335. x = np.array([0.2, 0.5, 0.6])
  4336. b = stats.betaprime(alpha, beta)
  4337. assert_(np.isfinite(b.logpdf(x)).all())
  4338. assert_allclose(b.pdf(x), np.exp(b.logpdf(x)))
  4339. def test_cdf(self):
  4340. # regression test for gh-4030: Implementation of
  4341. # scipy.stats.betaprime.cdf()
  4342. x = stats.betaprime.cdf(0, 0.2, 0.3)
  4343. assert_equal(x, 0.0)
  4344. alpha, beta = 267, 1472
  4345. x = np.array([0.2, 0.5, 0.6])
  4346. cdfs = stats.betaprime.cdf(x, alpha, beta)
  4347. assert_(np.isfinite(cdfs).all())
  4348. # check the new cdf implementation vs generic one:
  4349. gen_cdf = stats.rv_continuous._cdf_single
  4350. cdfs_g = [gen_cdf(stats.betaprime, val, alpha, beta) for val in x]
  4351. assert_allclose(cdfs, cdfs_g, atol=0, rtol=2e-12)
  4352. # The expected values for test_ppf() were computed with mpmath, e.g.
  4353. #
  4354. # from mpmath import mp
  4355. # mp.dps = 125
  4356. # p = 0.01
  4357. # a, b = 1.25, 2.5
  4358. # x = mp.findroot(lambda t: mp.betainc(a, b, x1=0, x2=t/(1+t),
  4359. # regularized=True) - p,
  4360. # x0=(0.01, 0.011), method='secant')
  4361. # print(float(x))
  4362. #
  4363. # prints
  4364. #
  4365. # 0.01080162700956614
  4366. #
  4367. @pytest.mark.parametrize(
  4368. 'p, a, b, expected',
  4369. [(0.010, 1.25, 2.5, 0.01080162700956614),
  4370. (1e-12, 1.25, 2.5, 1.0610141996279122e-10),
  4371. (1e-18, 1.25, 2.5, 1.6815941817974941e-15),
  4372. (1e-17, 0.25, 7.0, 1.0179194531881782e-69),
  4373. (0.375, 0.25, 7.0, 0.002036820346115211),
  4374. (0.9978811466052919, 0.05, 0.1, 1.0000000000001218e22),]
  4375. )
  4376. def test_ppf(self, p, a, b, expected):
  4377. x = stats.betaprime.ppf(p, a, b)
  4378. assert_allclose(x, expected, rtol=1e-14)
  4379. @pytest.mark.parametrize('x, a, b, p', cdf_vals)
  4380. def test_ppf_gh_17631(self, x, a, b, p):
  4381. assert_allclose(stats.betaprime.ppf(p, a, b), x, rtol=2e-14)
  4382. def test__ppf(self):
  4383. # Verify that _ppf supports scalar arrays.
  4384. a = np.array(1.0)
  4385. b = np.array(1.0)
  4386. p = np.array(0.5)
  4387. assert_allclose(stats.betaprime._ppf(p, a, b), 1.0, rtol=5e-16)
  4388. @pytest.mark.parametrize(
  4389. 'x, a, b, expected',
  4390. cdf_vals + [
  4391. (1e10, 1.5, 1.5, 0.9999999999999983),
  4392. (1e10, 0.05, 0.1, 0.9664184367890859),
  4393. (1e22, 0.05, 0.1, 0.9978811466052919),
  4394. ])
  4395. def test_cdf_gh_17631(self, x, a, b, expected):
  4396. assert_allclose(stats.betaprime.cdf(x, a, b), expected, rtol=1e-14)
  4397. @pytest.mark.parametrize(
  4398. 'x, a, b, expected',
  4399. [(1e50, 0.05, 0.1, 0.9999966641709545),
  4400. (1e50, 100.0, 0.05, 0.995925162631006)])
  4401. def test_cdf_extreme_tails(self, x, a, b, expected):
  4402. # for even more extreme values, we only get a few correct digits
  4403. # results are still < 1
  4404. y = stats.betaprime.cdf(x, a, b)
  4405. assert y < 1.0
  4406. assert_allclose(y, expected, rtol=2e-5)
  4407. def test_sf(self):
  4408. # reference values were computed via the reference distribution,
  4409. # e.g.
  4410. # mp.dps = 50
  4411. # a, b = 5, 3
  4412. # x = 1e10
  4413. # BetaPrime(a=a, b=b).sf(x); returns 3.4999999979e-29
  4414. a = [5, 4, 2, 0.05, 0.05, 0.05, 0.05, 100.0, 100.0, 0.05, 0.05,
  4415. 0.05, 1.5, 1.5]
  4416. b = [3, 2, 1, 0.1, 0.1, 0.1, 0.1, 0.05, 0.05, 100.0, 100.0,
  4417. 100.0, 1.5, 1.5]
  4418. x = [1e10, 1e20, 1e30, 1e22, 1e-10, 1e-22, 1e-100, 1e22, 1e10,
  4419. 1e-10, 1e-22, 1e-100, 1e10, 1e-10]
  4420. ref = [3.4999999979e-29, 9.999999999994357e-40, 1.9999999999999998e-30,
  4421. 0.0021188533947081017, 0.78761154572905, 0.9466504323507127,
  4422. 0.9999932836873578, 0.10269725645728331, 0.40884514172337383,
  4423. 0.5911548582766262, 0.8973027435427167, 0.9999870711814124,
  4424. 1.6976527260079727e-15, 0.9999999999999983]
  4425. sf_values = stats.betaprime.sf(x, a, b)
  4426. assert_allclose(sf_values, ref, rtol=1e-12)
  4427. def test_logcdf(self):
  4428. x = 800
  4429. a = 0.5
  4430. b = 5.0
  4431. ref = -7.467307556554531e-16
  4432. logcdf = stats.betaprime.logcdf(x, a, b)
  4433. assert_allclose(logcdf, ref, rtol=5e-15)
  4434. def test_logsf(self):
  4435. x = 1e-8
  4436. a = 4.5
  4437. b = 0.5
  4438. ref = -2.5868992866500915e-37
  4439. logsf = stats.betaprime.logsf(x, a, b)
  4440. assert_allclose(logsf, ref, rtol=5e-15)
  4441. def test_fit_stats_gh18274(self):
  4442. # gh-18274 reported spurious warning emitted when fitting `betaprime`
  4443. # to data. Some of these were emitted by stats, too. Check that the
  4444. # warnings are no longer emitted.
  4445. stats.betaprime.fit([0.1, 0.25, 0.3, 1.2, 1.6], floc=0, fscale=1)
  4446. stats.betaprime(a=1, b=1).stats('mvsk')
  4447. def test_moment_gh18634(self):
  4448. # Testing for gh-18634 revealed that `betaprime` raised a
  4449. # NotImplementedError for higher moments. Check that this is
  4450. # resolved. Parameters are arbitrary but lie on either side of the
  4451. # moment order (5) to test both branches of `xpx.apply_where`.
  4452. # Reference values produced with Mathematica, e.g.
  4453. # `Moment[BetaPrimeDistribution[2,7],5]`
  4454. ref = [np.inf, 0.867096912929055]
  4455. res = stats.betaprime(2, [4.2, 7.1]).moment(5)
  4456. assert_allclose(res, ref)
  4457. class TestGamma:
  4458. def test_pdf(self):
  4459. # a few test cases to compare with R
  4460. pdf = stats.gamma.pdf(90, 394, scale=1./5)
  4461. assert_almost_equal(pdf, 0.002312341)
  4462. pdf = stats.gamma.pdf(3, 10, scale=1./5)
  4463. assert_almost_equal(pdf, 0.1620358)
  4464. def test_logpdf(self):
  4465. # Regression test for Ticket #1326: cornercase avoid nan with 0*log(0)
  4466. # situation
  4467. logpdf = stats.gamma.logpdf(0, 1)
  4468. assert_almost_equal(logpdf, 0)
  4469. def test_fit_bad_keyword_args(self):
  4470. x = [0.1, 0.5, 0.6]
  4471. assert_raises(TypeError, stats.gamma.fit, x, floc=0, plate="shrimp")
  4472. def test_isf(self):
  4473. # Test cases for when the probability is very small. See gh-13664.
  4474. # The expected values can be checked with mpmath. With mpmath,
  4475. # the survival function sf(x, k) can be computed as
  4476. #
  4477. # mpmath.gammainc(k, x, mpmath.inf, regularized=True)
  4478. #
  4479. # Here we have:
  4480. #
  4481. # >>> mpmath.mp.dps = 60
  4482. # >>> float(mpmath.gammainc(1, 39.14394658089878, mpmath.inf,
  4483. # ... regularized=True))
  4484. # 9.99999999999999e-18
  4485. # >>> float(mpmath.gammainc(100, 330.6557590436547, mpmath.inf,
  4486. # regularized=True))
  4487. # 1.000000000000028e-50
  4488. #
  4489. assert np.isclose(stats.gamma.isf(1e-17, 1),
  4490. 39.14394658089878, atol=1e-14)
  4491. assert np.isclose(stats.gamma.isf(1e-50, 100),
  4492. 330.6557590436547, atol=1e-13)
  4493. def test_logcdf(self):
  4494. x = 80
  4495. a = 7
  4496. ref = -7.096510270453943e-27
  4497. logcdf = stats.gamma.logcdf(x, a)
  4498. assert_allclose(logcdf, ref, rtol=5e-15)
  4499. def test_logsf(self):
  4500. x = 0.001
  4501. a = 3.0
  4502. ref = -1.6654171666664883e-10
  4503. logsf = stats.gamma.logsf(x, a)
  4504. assert_allclose(logsf, ref, rtol=5e-15)
  4505. @pytest.mark.parametrize('scale', [1.0, 5.0])
  4506. def test_delta_cdf(self, scale):
  4507. # Expected value computed with mpmath:
  4508. #
  4509. # >>> import mpmath
  4510. # >>> mpmath.mp.dps = 150
  4511. # >>> cdf1 = mpmath.gammainc(3, 0, 245, regularized=True)
  4512. # >>> cdf2 = mpmath.gammainc(3, 0, 250, regularized=True)
  4513. # >>> float(cdf2 - cdf1)
  4514. # 1.1902609356171962e-102
  4515. #
  4516. delta = stats.gamma._delta_cdf(scale*245, scale*250, 3, scale=scale)
  4517. assert_allclose(delta, 1.1902609356171962e-102, rtol=1e-13)
  4518. @pytest.mark.parametrize('a, ref, rtol',
  4519. [(1e-4, -9990.366610819761, 1e-15),
  4520. (2, 1.5772156649015328, 1e-15),
  4521. (100, 3.7181819485047463, 1e-13),
  4522. (1e4, 6.024075385026086, 1e-15),
  4523. (1e18, 22.142204370151084, 1e-15),
  4524. (1e100, 116.54819318290696, 1e-15)])
  4525. def test_entropy(self, a, ref, rtol):
  4526. # expected value computed with mpmath:
  4527. # from mpmath import mp
  4528. # mp.dps = 500
  4529. # def gamma_entropy_reference(x):
  4530. # x = mp.mpf(x)
  4531. # return float(mp.digamma(x) * (mp.one - x) + x + mp.loggamma(x))
  4532. assert_allclose(stats.gamma.entropy(a), ref, rtol=rtol)
  4533. @pytest.mark.parametrize("a", [1e-2, 1, 1e2])
  4534. @pytest.mark.parametrize("loc", [1e-2, 0, 1e2])
  4535. @pytest.mark.parametrize('scale', [1e-2, 1, 1e2])
  4536. @pytest.mark.parametrize('fix_a', [True, False])
  4537. @pytest.mark.parametrize('fix_loc', [True, False])
  4538. @pytest.mark.parametrize('fix_scale', [True, False])
  4539. def test_fit_mm(self, a, loc, scale, fix_a, fix_loc, fix_scale):
  4540. rng = np.random.default_rng(6762668991392531563)
  4541. data = stats.gamma.rvs(a, loc=loc, scale=scale, size=100,
  4542. random_state=rng)
  4543. kwds = {}
  4544. if fix_a:
  4545. kwds['fa'] = a
  4546. if fix_loc:
  4547. kwds['floc'] = loc
  4548. if fix_scale:
  4549. kwds['fscale'] = scale
  4550. nfree = 3 - len(kwds)
  4551. if nfree == 0:
  4552. error_msg = "All parameters fixed. There is nothing to optimize."
  4553. with pytest.raises(ValueError, match=error_msg):
  4554. stats.gamma.fit(data, method='mm', **kwds)
  4555. return
  4556. theta = stats.gamma.fit(data, method='mm', **kwds)
  4557. dist = stats.gamma(*theta)
  4558. if nfree >= 1:
  4559. assert_allclose(dist.mean(), np.mean(data))
  4560. if nfree >= 2:
  4561. assert_allclose(dist.moment(2), np.mean(data**2))
  4562. if nfree >= 3:
  4563. assert_allclose(dist.moment(3), np.mean(data**3))
  4564. def test_pdf_overflow_gh19616():
  4565. # Confirm that gh19616 (intermediate over/underflows in PDF) is resolved
  4566. # Reference value from R GeneralizedHyperbolic library
  4567. # library(GeneralizedHyperbolic)
  4568. # options(digits=16)
  4569. # jitter = 1e-3
  4570. # dnig(1, a=2**0.5 / jitter**2, b=1 / jitter**2)
  4571. jitter = 1e-3
  4572. Z = stats.norminvgauss(2**0.5 / jitter**2, 1 / jitter**2, loc=0, scale=1)
  4573. assert_allclose(Z.pdf(1.0), 282.0948446666433)
  4574. class TestDgamma:
  4575. def test_pdf(self):
  4576. rng = np.random.default_rng(3791303244302340058)
  4577. size = 10 # number of points to check
  4578. x = rng.normal(scale=10, size=size)
  4579. a = rng.uniform(high=10, size=size)
  4580. res = stats.dgamma.pdf(x, a)
  4581. ref = stats.gamma.pdf(np.abs(x), a) / 2
  4582. assert_allclose(res, ref)
  4583. dist = stats.dgamma(a)
  4584. # There was an intermittent failure with assert_equal on Linux - 32 bit
  4585. assert_allclose(dist.pdf(x), res, rtol=5e-16)
  4586. # mpmath was used to compute the expected values.
  4587. # For x < 0, cdf(x, a) is mp.gammainc(a, -x, mp.inf, regularized=True)/2
  4588. # For x > 0, cdf(x, a) is (1 + mp.gammainc(a, 0, x, regularized=True))/2
  4589. # E.g.
  4590. # from mpmath import mp
  4591. # mp.dps = 50
  4592. # print(float(mp.gammainc(1, 20, mp.inf, regularized=True)/2))
  4593. # prints
  4594. # 1.030576811219279e-09
  4595. @pytest.mark.parametrize('x, a, expected',
  4596. [(-20, 1, 1.030576811219279e-09),
  4597. (-40, 1, 2.1241771276457944e-18),
  4598. (-50, 5, 2.7248509914602648e-17),
  4599. (-25, 0.125, 5.333071920958156e-14),
  4600. (5, 1, 0.9966310265004573)])
  4601. def test_cdf_ppf_sf_isf_tail(self, x, a, expected):
  4602. cdf = stats.dgamma.cdf(x, a)
  4603. assert_allclose(cdf, expected, rtol=5e-15)
  4604. ppf = stats.dgamma.ppf(expected, a)
  4605. assert_allclose(ppf, x, rtol=5e-15)
  4606. sf = stats.dgamma.sf(-x, a)
  4607. assert_allclose(sf, expected, rtol=5e-15)
  4608. isf = stats.dgamma.isf(expected, a)
  4609. assert_allclose(isf, -x, rtol=5e-15)
  4610. @pytest.mark.parametrize("a, ref",
  4611. [(1.5, 2.0541199559354117),
  4612. (1.3, 1.9357296377121247),
  4613. (1.1, 1.7856502333412134)])
  4614. def test_entropy(self, a, ref):
  4615. # The reference values were calculated with mpmath:
  4616. # def entropy_dgamma(a):
  4617. # def pdf(x):
  4618. # A = mp.one / (mp.mpf(2.) * mp.gamma(a))
  4619. # B = mp.fabs(x) ** (a - mp.one)
  4620. # C = mp.exp(-mp.fabs(x))
  4621. # h = A * B * C
  4622. # return h
  4623. #
  4624. # return -mp.quad(lambda t: pdf(t) * mp.log(pdf(t)),
  4625. # [-mp.inf, mp.inf])
  4626. assert_allclose(stats.dgamma.entropy(a), ref, rtol=1e-14)
  4627. @pytest.mark.parametrize("a, ref",
  4628. [(1e-100, -1e+100),
  4629. (1e-10, -9999999975.858217),
  4630. (1e-5, -99987.37111657023),
  4631. (1e4, 6.717222565586032),
  4632. (1000000000000000.0, 19.38147391121996),
  4633. (1e+100, 117.2413403634669)])
  4634. def test_entropy_entreme_values(self, a, ref):
  4635. # The reference values were calculated with mpmath:
  4636. # from mpmath import mp
  4637. # mp.dps = 500
  4638. # def second_dgamma(a):
  4639. # a = mp.mpf(a)
  4640. # x_1 = a + mp.log(2) + mp.loggamma(a)
  4641. # x_2 = (mp.one - a) * mp.digamma(a)
  4642. # h = x_1 + x_2
  4643. # return h
  4644. assert_allclose(stats.dgamma.entropy(a), ref, rtol=1e-10)
  4645. def test_entropy_array_input(self):
  4646. x = np.array([1, 5, 1e20, 1e-5])
  4647. y = stats.dgamma.entropy(x)
  4648. for i in range(len(y)):
  4649. assert y[i] == stats.dgamma.entropy(x[i])
  4650. class TestChi2:
  4651. # regression tests after precision improvements, ticket:1041, not verified
  4652. def test_precision(self):
  4653. assert_almost_equal(stats.chi2.pdf(1000, 1000), 8.919133934753128e-003,
  4654. decimal=14)
  4655. assert_almost_equal(stats.chi2.pdf(100, 100), 0.028162503162596778,
  4656. decimal=14)
  4657. # Reference values computed with mpmath.
  4658. @pytest.mark.parametrize(
  4659. 'x, df, ref',
  4660. [(750.0, 3, -3.0172957781136564e-162),
  4661. (120.0, 15, -1.8924849646375648e-18),
  4662. (15.0, 13, -0.36723446372517876)]
  4663. )
  4664. def test_logcdf(self, x, df, ref):
  4665. logcdf = stats.chi2.logcdf(x, df)
  4666. assert_allclose(logcdf, ref, rtol=5e-15)
  4667. # Reference values computed with mpmath.
  4668. @pytest.mark.parametrize(
  4669. 'x, df, ref',
  4670. [(1e-4, 15, -3.936060782678026e-37),
  4671. (1.5, 40, -6.384797888313517e-22),
  4672. (3.0, 10, -0.018750635779926784)]
  4673. )
  4674. def test_logsf(self, x, df, ref):
  4675. logsf = stats.chi2.logsf(x, df)
  4676. assert_allclose(logsf, ref, rtol=5e-15)
  4677. def test_ppf(self):
  4678. # Expected values computed with mpmath.
  4679. df = 4.8
  4680. x = stats.chi2.ppf(2e-47, df)
  4681. assert_allclose(x, 1.098472479575179840604902808e-19, rtol=1e-10)
  4682. x = stats.chi2.ppf(0.5, df)
  4683. assert_allclose(x, 4.15231407598589358660093156, rtol=1e-10)
  4684. df = 13
  4685. x = stats.chi2.ppf(2e-77, df)
  4686. assert_allclose(x, 1.0106330688195199050507943e-11, rtol=1e-10)
  4687. x = stats.chi2.ppf(0.1, df)
  4688. assert_allclose(x, 7.041504580095461859307179763, rtol=1e-10)
  4689. # Entropy references values were computed with the following mpmath code
  4690. # from mpmath import mp
  4691. # mp.dps = 50
  4692. # def chisq_entropy_mpmath(df):
  4693. # df = mp.mpf(df)
  4694. # half_df = 0.5 * df
  4695. # entropy = (half_df + mp.log(2) + mp.log(mp.gamma(half_df)) +
  4696. # (mp.one - half_df) * mp.digamma(half_df))
  4697. # return float(entropy)
  4698. @pytest.mark.parametrize('df, ref',
  4699. [(1e-4, -19988.980448690163),
  4700. (1, 0.7837571104739337),
  4701. (100, 4.061397128938114),
  4702. (251, 4.525577254045129),
  4703. (1e15, 19.034900320939986)])
  4704. def test_entropy(self, df, ref):
  4705. assert_allclose(stats.chi2(df).entropy(), ref, rtol=1e-13)
  4706. def test_regression_ticket_1326(self):
  4707. # adjust to avoid nan with 0*log(0)
  4708. assert_almost_equal(stats.chi2.pdf(0.0, 2), 0.5, 14)
  4709. class TestGumbelL:
  4710. def setup_method(self):
  4711. self.rng = np.random.default_rng(3922444007)
  4712. # gh-6228
  4713. def test_cdf_ppf(self):
  4714. x = np.linspace(-100, -4)
  4715. y = stats.gumbel_l.cdf(x)
  4716. xx = stats.gumbel_l.ppf(y)
  4717. assert_allclose(x, xx)
  4718. def test_logcdf_logsf(self):
  4719. x = np.linspace(-100, -4)
  4720. y = stats.gumbel_l.logcdf(x)
  4721. z = stats.gumbel_l.logsf(x)
  4722. u = np.exp(y)
  4723. v = -special.expm1(z)
  4724. assert_allclose(u, v)
  4725. def test_sf_isf(self):
  4726. x = np.linspace(-20, 5)
  4727. y = stats.gumbel_l.sf(x)
  4728. xx = stats.gumbel_l.isf(y)
  4729. assert_allclose(x, xx)
  4730. @pytest.mark.parametrize('loc', [-1, 1])
  4731. def test_fit_fixed_param(self, loc):
  4732. # ensure fixed location is correctly reflected from `gumbel_r.fit`
  4733. # See comments at end of gh-12737.
  4734. data = stats.gumbel_l.rvs(size=100, loc=loc, random_state=self.rng)
  4735. fitted_loc, _ = stats.gumbel_l.fit(data, floc=loc)
  4736. assert_equal(fitted_loc, loc)
  4737. class TestGumbelR:
  4738. def test_sf(self):
  4739. # Expected value computed with mpmath:
  4740. # >>> import mpmath
  4741. # >>> mpmath.mp.dps = 40
  4742. # >>> float(mpmath.mp.one - mpmath.exp(-mpmath.exp(-50)))
  4743. # 1.9287498479639178e-22
  4744. assert_allclose(stats.gumbel_r.sf(50), 1.9287498479639178e-22,
  4745. rtol=1e-14)
  4746. def test_isf(self):
  4747. # Expected value computed with mpmath:
  4748. # >>> import mpmath
  4749. # >>> mpmath.mp.dps = 40
  4750. # >>> float(-mpmath.log(-mpmath.log(mpmath.mp.one - 1e-17)))
  4751. # 39.14394658089878
  4752. assert_allclose(stats.gumbel_r.isf(1e-17), 39.14394658089878,
  4753. rtol=1e-14)
  4754. class TestLevyStable:
  4755. def setup_method(self):
  4756. self.rng = np.random.default_rng(7195199371)
  4757. @pytest.fixture(autouse=True)
  4758. def reset_levy_stable_params(self):
  4759. """Setup default parameters for levy_stable generator"""
  4760. stats.levy_stable.parameterization = "S1"
  4761. stats.levy_stable.cdf_default_method = "piecewise"
  4762. stats.levy_stable.pdf_default_method = "piecewise"
  4763. stats.levy_stable.quad_eps = stats._levy_stable._QUAD_EPS
  4764. @pytest.fixture
  4765. def nolan_pdf_sample_data(self):
  4766. """Sample data points for pdf computed with Nolan's stablec
  4767. See - http://fs2.american.edu/jpnolan/www/stable/stable.html
  4768. There's a known limitation of Nolan's executable for alpha < 0.2.
  4769. The data table loaded below is generated from Nolan's stablec
  4770. with the following parameter space:
  4771. alpha = 0.1, 0.2, ..., 2.0
  4772. beta = -1.0, -0.9, ..., 1.0
  4773. p = 0.01, 0.05, 0.1, 0.25, 0.35, 0.5,
  4774. and the equivalent for the right tail
  4775. Typically inputs for stablec:
  4776. stablec.exe <<
  4777. 1 # pdf
  4778. 1 # Nolan S equivalent to S0 in scipy
  4779. .25,2,.25 # alpha
  4780. -1,-1,0 # beta
  4781. -10,10,1 # x
  4782. 1,0 # gamma, delta
  4783. 2 # output file
  4784. """
  4785. data = np.load(
  4786. Path(__file__).parent /
  4787. 'data/levy_stable/stable-Z1-pdf-sample-data.npy'
  4788. )
  4789. data = np.rec.fromarrays(data.T, names='x,p,alpha,beta,pct')
  4790. return data
  4791. @pytest.fixture
  4792. def nolan_cdf_sample_data(self):
  4793. """Sample data points for cdf computed with Nolan's stablec
  4794. See - http://fs2.american.edu/jpnolan/www/stable/stable.html
  4795. There's a known limitation of Nolan's executable for alpha < 0.2.
  4796. The data table loaded below is generated from Nolan's stablec
  4797. with the following parameter space:
  4798. alpha = 0.1, 0.2, ..., 2.0
  4799. beta = -1.0, -0.9, ..., 1.0
  4800. p = 0.01, 0.05, 0.1, 0.25, 0.35, 0.5,
  4801. and the equivalent for the right tail
  4802. Ideally, Nolan's output for CDF values should match the percentile
  4803. from where they have been sampled from. Even more so as we extract
  4804. percentile x positions from stablec too. However, we note at places
  4805. Nolan's stablec will produce absolute errors in order of 1e-5. We
  4806. compare against his calculations here. In future, once we less
  4807. reliant on Nolan's paper we might switch to comparing directly at
  4808. percentiles (those x values being produced from some alternative
  4809. means).
  4810. Typically inputs for stablec:
  4811. stablec.exe <<
  4812. 2 # cdf
  4813. 1 # Nolan S equivalent to S0 in scipy
  4814. .25,2,.25 # alpha
  4815. -1,-1,0 # beta
  4816. -10,10,1 # x
  4817. 1,0 # gamma, delta
  4818. 2 # output file
  4819. """
  4820. data = np.load(
  4821. Path(__file__).parent /
  4822. 'data/levy_stable/stable-Z1-cdf-sample-data.npy'
  4823. )
  4824. data = np.rec.fromarrays(data.T, names='x,p,alpha,beta,pct')
  4825. return data
  4826. @pytest.fixture
  4827. def nolan_loc_scale_sample_data(self):
  4828. """Sample data where loc, scale are different from 0, 1
  4829. Data extracted in similar way to pdf/cdf above using
  4830. Nolan's stablec but set to an arbitrary location scale of
  4831. (2, 3) for various important parameters alpha, beta and for
  4832. parameterisations S0 and S1.
  4833. """
  4834. data = np.load(
  4835. Path(__file__).parent /
  4836. 'data/levy_stable/stable-loc-scale-sample-data.npy'
  4837. )
  4838. return data
  4839. @pytest.mark.slow
  4840. @pytest.mark.parametrize(
  4841. "sample_size", [
  4842. pytest.param(50), pytest.param(1500, marks=pytest.mark.slow)
  4843. ]
  4844. )
  4845. @pytest.mark.parametrize("parameterization", ["S0", "S1"])
  4846. @pytest.mark.parametrize(
  4847. "alpha,beta", [(1.0, 0), (1.0, -0.5), (1.5, 0), (1.9, 0.5)]
  4848. )
  4849. @pytest.mark.parametrize("gamma,delta", [(1, 0), (3, 2)])
  4850. def test_rvs(
  4851. self,
  4852. parameterization,
  4853. alpha,
  4854. beta,
  4855. gamma,
  4856. delta,
  4857. sample_size,
  4858. ):
  4859. stats.levy_stable.parameterization = parameterization
  4860. ls = stats.levy_stable(
  4861. alpha=alpha, beta=beta, scale=gamma, loc=delta
  4862. )
  4863. _, p = stats.kstest(
  4864. ls.rvs(size=sample_size, random_state=self.rng), ls.cdf
  4865. )
  4866. assert p > 0.05
  4867. @pytest.mark.xslow
  4868. @pytest.mark.parametrize('beta', [0.5, 1])
  4869. def test_rvs_alpha1(self, beta):
  4870. """Additional test cases for rvs for alpha equal to 1."""
  4871. alpha = 1.0
  4872. loc = 0.5
  4873. scale = 1.5
  4874. x = stats.levy_stable.rvs(alpha, beta, loc=loc, scale=scale,
  4875. size=5000, random_state=self.rng)
  4876. stat, p = stats.kstest(x, 'levy_stable',
  4877. args=(alpha, beta, loc, scale))
  4878. assert p > 0.01
  4879. def test_fit(self):
  4880. # construct data to have percentiles that match
  4881. # example in McCulloch 1986.
  4882. x = [
  4883. -.05413, -.05413, 0., 0., 0., 0., .00533, .00533, .00533, .00533,
  4884. .00533, .03354, .03354, .03354, .03354, .03354, .05309, .05309,
  4885. .05309, .05309, .05309
  4886. ]
  4887. alpha1, beta1, loc1, scale1 = stats.levy_stable._fitstart(x)
  4888. assert_allclose(alpha1, 1.48, rtol=0, atol=0.01)
  4889. assert_almost_equal(beta1, -.22, 2)
  4890. assert_almost_equal(scale1, 0.01717, 4)
  4891. assert_almost_equal(
  4892. loc1, 0.00233, 2
  4893. ) # to 2 dps due to rounding error in McCulloch86
  4894. # cover alpha=2 scenario
  4895. x2 = x + [.05309, .05309, .05309, .05309, .05309]
  4896. alpha2, beta2, loc2, scale2 = stats.levy_stable._fitstart(x2)
  4897. assert_equal(alpha2, 2)
  4898. assert_equal(beta2, -1)
  4899. assert_almost_equal(scale2, .02503, 4)
  4900. assert_almost_equal(loc2, .03354, 4)
  4901. @pytest.mark.xfail(reason="Unknown problem with fitstart.")
  4902. @pytest.mark.parametrize(
  4903. "alpha,beta,delta,gamma",
  4904. [
  4905. (1.5, 0.4, 2, 3),
  4906. (1.0, 0.4, 2, 3),
  4907. ]
  4908. )
  4909. @pytest.mark.parametrize(
  4910. "parametrization", ["S0", "S1"]
  4911. )
  4912. def test_fit_rvs(self, alpha, beta, delta, gamma, parametrization):
  4913. """Test that fit agrees with rvs for each parametrization."""
  4914. stats.levy_stable.parametrization = parametrization
  4915. data = stats.levy_stable.rvs(
  4916. alpha, beta, loc=delta, scale=gamma, size=10000, random_state=self.rng
  4917. )
  4918. fit = stats.levy_stable._fitstart(data)
  4919. alpha_obs, beta_obs, delta_obs, gamma_obs = fit
  4920. assert_allclose(
  4921. [alpha, beta, delta, gamma],
  4922. [alpha_obs, beta_obs, delta_obs, gamma_obs],
  4923. rtol=0.01,
  4924. )
  4925. def test_fit_beta_flip(self):
  4926. # Confirm that sign of beta affects loc, not alpha or scale.
  4927. x = np.array([1, 1, 3, 3, 10, 10, 10, 30, 30, 100, 100])
  4928. alpha1, beta1, loc1, scale1 = stats.levy_stable._fitstart(x)
  4929. alpha2, beta2, loc2, scale2 = stats.levy_stable._fitstart(-x)
  4930. assert_equal(beta1, 1)
  4931. assert loc1 != 0
  4932. assert_almost_equal(alpha2, alpha1)
  4933. assert_almost_equal(beta2, -beta1)
  4934. assert_almost_equal(loc2, -loc1)
  4935. assert_almost_equal(scale2, scale1)
  4936. def test_fit_delta_shift(self):
  4937. # Confirm that loc slides up and down if data shifts.
  4938. SHIFT = 1
  4939. x = np.array([1, 1, 3, 3, 10, 10, 10, 30, 30, 100, 100])
  4940. alpha1, beta1, loc1, scale1 = stats.levy_stable._fitstart(-x)
  4941. alpha2, beta2, loc2, scale2 = stats.levy_stable._fitstart(-x + SHIFT)
  4942. assert_almost_equal(alpha2, alpha1)
  4943. assert_almost_equal(beta2, beta1)
  4944. assert_almost_equal(loc2, loc1 + SHIFT)
  4945. assert_almost_equal(scale2, scale1)
  4946. def test_fit_loc_extrap(self):
  4947. # Confirm that loc goes out of sample for alpha close to 1.
  4948. x = [1, 1, 3, 3, 10, 10, 10, 30, 30, 140, 140]
  4949. alpha1, beta1, loc1, scale1 = stats.levy_stable._fitstart(x)
  4950. assert alpha1 < 1, f"Expected alpha < 1, got {alpha1}"
  4951. assert loc1 < min(x), f"Expected loc < {min(x)}, got {loc1}"
  4952. x2 = [1, 1, 3, 3, 10, 10, 10, 30, 30, 130, 130]
  4953. alpha2, beta2, loc2, scale2 = stats.levy_stable._fitstart(x2)
  4954. assert alpha2 > 1, f"Expected alpha > 1, got {alpha2}"
  4955. assert loc2 > max(x2), f"Expected loc > {max(x2)}, got {loc2}"
  4956. @pytest.mark.slow
  4957. @pytest.mark.parametrize(
  4958. "pct_range,alpha_range,beta_range", [
  4959. pytest.param(
  4960. [.01, .5, .99],
  4961. [.1, 1, 2],
  4962. [-1, 0, .8],
  4963. ),
  4964. pytest.param(
  4965. [.01, .05, .5, .95, .99],
  4966. [.1, .5, 1, 1.5, 2],
  4967. [-.9, -.5, 0, .3, .6, 1],
  4968. marks=pytest.mark.slow
  4969. ),
  4970. pytest.param(
  4971. [.01, .05, .1, .25, .35, .5, .65, .75, .9, .95, .99],
  4972. np.linspace(0.1, 2, 20),
  4973. np.linspace(-1, 1, 21),
  4974. marks=pytest.mark.xslow,
  4975. ),
  4976. ]
  4977. )
  4978. def test_pdf_nolan_samples(
  4979. self, nolan_pdf_sample_data, pct_range, alpha_range, beta_range
  4980. ):
  4981. """Test pdf values against Nolan's stablec.exe output"""
  4982. data = nolan_pdf_sample_data
  4983. # some tests break on linux 32 bit
  4984. uname = platform.uname()
  4985. is_linux_32 = uname.system == 'Linux' and uname.machine == 'i686'
  4986. platform_desc = "/".join(
  4987. [uname.system, uname.machine, uname.processor])
  4988. # fmt: off
  4989. # There are a number of cases which fail on some but not all platforms.
  4990. # These are excluded by the filters below. TODO: Rewrite tests so that
  4991. # the now filtered out test cases are still run but marked in pytest as
  4992. # expected to fail.
  4993. tests = [
  4994. [
  4995. 'dni', 1e-7, lambda r: (
  4996. np.isin(r['pct'], pct_range) &
  4997. np.isin(r['alpha'], alpha_range) &
  4998. np.isin(r['beta'], beta_range) &
  4999. ~(
  5000. (
  5001. (r['beta'] == 0) &
  5002. (r['pct'] == 0.5)
  5003. ) |
  5004. (
  5005. (r['beta'] >= 0.9) &
  5006. (r['alpha'] >= 1.6) &
  5007. (r['pct'] == 0.5)
  5008. ) |
  5009. (
  5010. (r['alpha'] <= 0.4) &
  5011. np.isin(r['pct'], [.01, .99])
  5012. ) |
  5013. (
  5014. (r['alpha'] <= 0.3) &
  5015. np.isin(r['pct'], [.05, .95])
  5016. ) |
  5017. (
  5018. (r['alpha'] <= 0.2) &
  5019. np.isin(r['pct'], [.1, .9])
  5020. ) |
  5021. (
  5022. (r['alpha'] == 0.1) &
  5023. np.isin(r['pct'], [.25, .75]) &
  5024. np.isin(np.abs(r['beta']), [.5, .6, .7])
  5025. ) |
  5026. (
  5027. (r['alpha'] == 0.1) &
  5028. np.isin(r['pct'], [.5]) &
  5029. np.isin(np.abs(r['beta']), [.1])
  5030. ) |
  5031. (
  5032. (r['alpha'] == 0.1) &
  5033. np.isin(r['pct'], [.35, .65]) &
  5034. np.isin(np.abs(r['beta']), [-.4, -.3, .3, .4, .5])
  5035. ) |
  5036. (
  5037. (r['alpha'] == 0.2) &
  5038. (r['beta'] == 0.5) &
  5039. (r['pct'] == 0.25)
  5040. ) |
  5041. (
  5042. (r['alpha'] == 0.2) &
  5043. (r['beta'] == -0.3) &
  5044. (r['pct'] == 0.65)
  5045. ) |
  5046. (
  5047. (r['alpha'] == 0.2) &
  5048. (r['beta'] == 0.3) &
  5049. (r['pct'] == 0.35)
  5050. ) |
  5051. (
  5052. (r['alpha'] == 1.) &
  5053. np.isin(r['pct'], [.5]) &
  5054. np.isin(np.abs(r['beta']), [.1, .2, .3, .4])
  5055. ) |
  5056. (
  5057. (r['alpha'] == 1.) &
  5058. np.isin(r['pct'], [.35, .65]) &
  5059. np.isin(np.abs(r['beta']), [.8, .9, 1.])
  5060. ) |
  5061. (
  5062. (r['alpha'] == 1.) &
  5063. np.isin(r['pct'], [.01, .99]) &
  5064. np.isin(np.abs(r['beta']), [-.1, .1])
  5065. ) |
  5066. # various points ok but too sparse to list
  5067. (r['alpha'] >= 1.1)
  5068. )
  5069. )
  5070. ],
  5071. # piecewise generally good accuracy
  5072. [
  5073. 'piecewise', 1e-11, lambda r: (
  5074. np.isin(r['pct'], pct_range) &
  5075. np.isin(r['alpha'], alpha_range) &
  5076. np.isin(r['beta'], beta_range) &
  5077. (r['alpha'] > 0.2) &
  5078. (r['alpha'] != 1.)
  5079. )
  5080. ],
  5081. # for alpha = 1. for linux 32 bit optimize.bisect
  5082. # has some issues for .01 and .99 percentile
  5083. [
  5084. 'piecewise', 1e-11, lambda r: (
  5085. (r['alpha'] == 1.) &
  5086. (not is_linux_32) &
  5087. np.isin(r['pct'], pct_range) &
  5088. (1. in alpha_range) &
  5089. np.isin(r['beta'], beta_range)
  5090. )
  5091. ],
  5092. # for small alpha very slightly reduced accuracy
  5093. [
  5094. 'piecewise', 2.5e-10, lambda r: (
  5095. np.isin(r['pct'], pct_range) &
  5096. np.isin(r['alpha'], alpha_range) &
  5097. np.isin(r['beta'], beta_range) &
  5098. (r['alpha'] <= 0.2)
  5099. )
  5100. ],
  5101. # fft accuracy reduces as alpha decreases
  5102. [
  5103. 'fft-simpson', 1e-5, lambda r: (
  5104. (r['alpha'] >= 1.9) &
  5105. np.isin(r['pct'], pct_range) &
  5106. np.isin(r['alpha'], alpha_range) &
  5107. np.isin(r['beta'], beta_range)
  5108. ),
  5109. ],
  5110. [
  5111. 'fft-simpson', 1e-6, lambda r: (
  5112. np.isin(r['pct'], pct_range) &
  5113. np.isin(r['alpha'], alpha_range) &
  5114. np.isin(r['beta'], beta_range) &
  5115. (r['alpha'] > 1) &
  5116. (r['alpha'] < 1.9)
  5117. )
  5118. ],
  5119. # fft relative errors for alpha < 1, will raise if enabled
  5120. # ['fft-simpson', 1e-4, lambda r: r['alpha'] == 0.9],
  5121. # ['fft-simpson', 1e-3, lambda r: r['alpha'] == 0.8],
  5122. # ['fft-simpson', 1e-2, lambda r: r['alpha'] == 0.7],
  5123. # ['fft-simpson', 1e-1, lambda r: r['alpha'] == 0.6],
  5124. ]
  5125. # fmt: on
  5126. for ix, (default_method, rtol,
  5127. filter_func) in enumerate(tests):
  5128. stats.levy_stable.pdf_default_method = default_method
  5129. subdata = data[filter_func(data)
  5130. ] if filter_func is not None else data
  5131. msg = "Density calculations experimental for FFT method"
  5132. with warnings.catch_warnings():
  5133. warnings.filterwarnings("ignore", msg, RuntimeWarning)
  5134. # occurs in FFT methods only
  5135. p = stats.levy_stable.pdf(
  5136. subdata['x'],
  5137. subdata['alpha'],
  5138. subdata['beta'],
  5139. scale=1,
  5140. loc=0
  5141. )
  5142. with np.errstate(over="ignore"):
  5143. subdata2 = rec_append_fields(
  5144. subdata,
  5145. ['calc', 'abserr', 'relerr'],
  5146. [
  5147. p,
  5148. np.abs(p - subdata['p']),
  5149. np.abs(p - subdata['p']) / np.abs(subdata['p'])
  5150. ]
  5151. )
  5152. failures = subdata2[
  5153. (subdata2['relerr'] >= rtol) |
  5154. np.isnan(p)
  5155. ]
  5156. message = (
  5157. f"pdf test {ix} failed with method '{default_method}' "
  5158. f"[platform: {platform_desc}]\n{failures.dtype.names}\n{failures}"
  5159. )
  5160. assert_allclose(
  5161. p,
  5162. subdata['p'],
  5163. rtol,
  5164. err_msg=message,
  5165. verbose=False
  5166. )
  5167. @pytest.mark.parametrize(
  5168. "pct_range,alpha_range,beta_range", [
  5169. pytest.param(
  5170. [.01, .5, .99],
  5171. [.1, 1, 2],
  5172. [-1, 0, .8],
  5173. ),
  5174. pytest.param(
  5175. [.01, .05, .5, .95, .99],
  5176. [.1, .5, 1, 1.5, 2],
  5177. [-.9, -.5, 0, .3, .6, 1],
  5178. marks=pytest.mark.slow
  5179. ),
  5180. pytest.param(
  5181. [.01, .05, .1, .25, .35, .5, .65, .75, .9, .95, .99],
  5182. np.linspace(0.1, 2, 20),
  5183. np.linspace(-1, 1, 21),
  5184. marks=pytest.mark.xslow,
  5185. ),
  5186. ]
  5187. )
  5188. def test_cdf_nolan_samples(
  5189. self, nolan_cdf_sample_data, pct_range, alpha_range, beta_range
  5190. ):
  5191. """ Test cdf values against Nolan's stablec.exe output."""
  5192. data = nolan_cdf_sample_data
  5193. tests = [
  5194. # piecewise generally good accuracy
  5195. [
  5196. 'piecewise', 2e-12, lambda r: (
  5197. np.isin(r['pct'], pct_range) &
  5198. np.isin(r['alpha'], alpha_range) &
  5199. np.isin(r['beta'], beta_range) &
  5200. ~(
  5201. (
  5202. (r['alpha'] == 1.) &
  5203. np.isin(r['beta'], [-0.3, -0.2, -0.1]) &
  5204. (r['pct'] == 0.01)
  5205. ) |
  5206. (
  5207. (r['alpha'] == 1.) &
  5208. np.isin(r['beta'], [0.1, 0.2, 0.3]) &
  5209. (r['pct'] == 0.99)
  5210. )
  5211. )
  5212. )
  5213. ],
  5214. # for some points with alpha=1, Nolan's STABLE clearly
  5215. # loses accuracy
  5216. [
  5217. 'piecewise', 5e-2, lambda r: (
  5218. np.isin(r['pct'], pct_range) &
  5219. np.isin(r['alpha'], alpha_range) &
  5220. np.isin(r['beta'], beta_range) &
  5221. (
  5222. (r['alpha'] == 1.) &
  5223. np.isin(r['beta'], [-0.3, -0.2, -0.1]) &
  5224. (r['pct'] == 0.01)
  5225. ) |
  5226. (
  5227. (r['alpha'] == 1.) &
  5228. np.isin(r['beta'], [0.1, 0.2, 0.3]) &
  5229. (r['pct'] == 0.99)
  5230. )
  5231. )
  5232. ],
  5233. # fft accuracy poor, very poor alpha < 1
  5234. [
  5235. 'fft-simpson', 1e-5, lambda r: (
  5236. np.isin(r['pct'], pct_range) &
  5237. np.isin(r['alpha'], alpha_range) &
  5238. np.isin(r['beta'], beta_range) &
  5239. (r['alpha'] > 1.7)
  5240. )
  5241. ],
  5242. [
  5243. 'fft-simpson', 1e-4, lambda r: (
  5244. np.isin(r['pct'], pct_range) &
  5245. np.isin(r['alpha'], alpha_range) &
  5246. np.isin(r['beta'], beta_range) &
  5247. (r['alpha'] > 1.5) &
  5248. (r['alpha'] <= 1.7)
  5249. )
  5250. ],
  5251. [
  5252. 'fft-simpson', 1e-3, lambda r: (
  5253. np.isin(r['pct'], pct_range) &
  5254. np.isin(r['alpha'], alpha_range) &
  5255. np.isin(r['beta'], beta_range) &
  5256. (r['alpha'] > 1.3) &
  5257. (r['alpha'] <= 1.5)
  5258. )
  5259. ],
  5260. [
  5261. 'fft-simpson', 1e-2, lambda r: (
  5262. np.isin(r['pct'], pct_range) &
  5263. np.isin(r['alpha'], alpha_range) &
  5264. np.isin(r['beta'], beta_range) &
  5265. (r['alpha'] > 1.0) &
  5266. (r['alpha'] <= 1.3)
  5267. )
  5268. ],
  5269. ]
  5270. for ix, (default_method, rtol,
  5271. filter_func) in enumerate(tests):
  5272. stats.levy_stable.cdf_default_method = default_method
  5273. subdata = data[filter_func(data)
  5274. ] if filter_func is not None else data
  5275. with warnings.catch_warnings():
  5276. warnings.filterwarnings(
  5277. 'ignore',
  5278. ('Cumulative density calculations experimental for FFT'
  5279. ' method. Use piecewise method instead.'),
  5280. RuntimeWarning)
  5281. p = stats.levy_stable.cdf(
  5282. subdata['x'],
  5283. subdata['alpha'],
  5284. subdata['beta'],
  5285. scale=1,
  5286. loc=0
  5287. )
  5288. with np.errstate(over="ignore"):
  5289. subdata2 = rec_append_fields(
  5290. subdata,
  5291. ['calc', 'abserr', 'relerr'],
  5292. [
  5293. p,
  5294. np.abs(p - subdata['p']),
  5295. np.abs(p - subdata['p']) / np.abs(subdata['p'])
  5296. ]
  5297. )
  5298. failures = subdata2[
  5299. (subdata2['relerr'] >= rtol) |
  5300. np.isnan(p)
  5301. ]
  5302. message = (f"cdf test {ix} failed with method '{default_method}'\n"
  5303. f"{failures.dtype.names}\n{failures}")
  5304. assert_allclose(
  5305. p,
  5306. subdata['p'],
  5307. rtol,
  5308. err_msg=message,
  5309. verbose=False
  5310. )
  5311. @pytest.mark.parametrize("param", [0, 1])
  5312. @pytest.mark.parametrize("case", ["pdf", "cdf"])
  5313. def test_location_scale(
  5314. self, nolan_loc_scale_sample_data, param, case
  5315. ):
  5316. """Tests for pdf and cdf where loc, scale are different from 0, 1
  5317. """
  5318. uname = platform.uname()
  5319. is_linux_32 = uname.system == 'Linux' and "32bit" in platform.architecture()[0]
  5320. # Test seems to be unstable (see gh-17839 for a bug report on Debian
  5321. # i386), so skip it.
  5322. if is_linux_32 and case == 'pdf':
  5323. pytest.skip("Test unstable on some platforms; see gh-17839, 17859")
  5324. data = nolan_loc_scale_sample_data
  5325. # We only test against piecewise as location/scale transforms
  5326. # are same for other methods.
  5327. stats.levy_stable.cdf_default_method = "piecewise"
  5328. stats.levy_stable.pdf_default_method = "piecewise"
  5329. subdata = data[data["param"] == param]
  5330. stats.levy_stable.parameterization = f"S{param}"
  5331. assert case in ["pdf", "cdf"]
  5332. function = (
  5333. stats.levy_stable.pdf if case == "pdf" else stats.levy_stable.cdf
  5334. )
  5335. v1 = function(
  5336. subdata['x'], subdata['alpha'], subdata['beta'], scale=2, loc=3
  5337. )
  5338. assert_allclose(v1, subdata[case], 1e-5)
  5339. @pytest.mark.parametrize(
  5340. "method,decimal_places",
  5341. [
  5342. ['dni', 4],
  5343. ['piecewise', 4],
  5344. ]
  5345. )
  5346. def test_pdf_alpha_equals_one_beta_non_zero(self, method, decimal_places):
  5347. """ sample points extracted from Tables and Graphs of Stable
  5348. Probability Density Functions - Donald R Holt - 1973 - p 187.
  5349. """
  5350. xs = np.array(
  5351. [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4]
  5352. )
  5353. density = np.array(
  5354. [
  5355. .3183, .3096, .2925, .2622, .1591, .1587, .1599, .1635, .0637,
  5356. .0729, .0812, .0955, .0318, .0390, .0458, .0586, .0187, .0236,
  5357. .0285, .0384
  5358. ]
  5359. )
  5360. betas = np.array(
  5361. [
  5362. 0, .25, .5, 1, 0, .25, .5, 1, 0, .25, .5, 1, 0, .25, .5, 1, 0,
  5363. .25, .5, 1
  5364. ]
  5365. )
  5366. with np.errstate(all='ignore'), warnings.catch_warnings():
  5367. warnings.filterwarnings("ignore",
  5368. category=RuntimeWarning,
  5369. message="Density calculation unstable.*"
  5370. )
  5371. stats.levy_stable.pdf_default_method = method
  5372. # stats.levy_stable.fft_grid_spacing = 0.0001
  5373. pdf = stats.levy_stable.pdf(xs, 1, betas, scale=1, loc=0)
  5374. assert_almost_equal(
  5375. pdf, density, decimal_places, method
  5376. )
  5377. @pytest.mark.parametrize(
  5378. "params,expected",
  5379. [
  5380. [(1.48, -.22, 0, 1), (0, np.inf, np.nan, np.nan)],
  5381. [(2, .9, 10, 1.5), (10, 4.5, 0, 0)]
  5382. ]
  5383. )
  5384. def test_stats(self, params, expected):
  5385. observed = stats.levy_stable.stats(
  5386. params[0], params[1], loc=params[2], scale=params[3],
  5387. moments='mvsk'
  5388. )
  5389. assert_almost_equal(observed, expected)
  5390. @pytest.mark.parametrize('alpha', [0.25, 0.5, 0.75])
  5391. @pytest.mark.parametrize(
  5392. 'function,beta,points,expected',
  5393. [
  5394. (
  5395. stats.levy_stable.cdf,
  5396. 1.0,
  5397. np.linspace(-25, 0, 10),
  5398. 0.0,
  5399. ),
  5400. (
  5401. stats.levy_stable.pdf,
  5402. 1.0,
  5403. np.linspace(-25, 0, 10),
  5404. 0.0,
  5405. ),
  5406. (
  5407. stats.levy_stable.cdf,
  5408. -1.0,
  5409. np.linspace(0, 25, 10),
  5410. 1.0,
  5411. ),
  5412. (
  5413. stats.levy_stable.pdf,
  5414. -1.0,
  5415. np.linspace(0, 25, 10),
  5416. 0.0,
  5417. )
  5418. ]
  5419. )
  5420. def test_distribution_outside_support(
  5421. self, alpha, function, beta, points, expected
  5422. ):
  5423. """Ensure the pdf/cdf routines do not return nan outside support.
  5424. This distribution's support becomes truncated in a few special cases:
  5425. support is [mu, infty) if alpha < 1 and beta = 1
  5426. support is (-infty, mu] if alpha < 1 and beta = -1
  5427. Otherwise, the support is all reals. Here, mu is zero by default.
  5428. """
  5429. assert 0 < alpha < 1
  5430. assert_almost_equal(
  5431. function(points, alpha=alpha, beta=beta),
  5432. np.full(len(points), expected)
  5433. )
  5434. @pytest.mark.parametrize(
  5435. 'x,alpha,beta,expected',
  5436. # Reference values from Matlab
  5437. # format long
  5438. # alphas = [1.7720732804618808, 1.9217001522410235, 1.5654806051633634,
  5439. # 1.7420803447784388, 1.5748002527689913];
  5440. # betas = [0.5059373136902996, -0.8779442746685926, -0.4016220341911392,
  5441. # -0.38180029468259247, -0.25200194914153684];
  5442. # x0s = [0, 1e-4, -1e-4];
  5443. # for x0 = x0s
  5444. # disp("x0 = " + x0)
  5445. # for ii = 1:5
  5446. # alpha = alphas(ii);
  5447. # beta = betas(ii);
  5448. # pd = makedist('Stable','alpha',alpha,'beta',beta,'gam',1,'delta',0);
  5449. # % we need to adjust x. It is the same as x = 0 In scipy.
  5450. # x = x0 - beta * tan(pi * alpha / 2);
  5451. # disp(pd.pdf(x))
  5452. # end
  5453. # end
  5454. [
  5455. (0, 1.7720732804618808, 0.5059373136902996, 0.278932636798268),
  5456. (0, 1.9217001522410235, -0.8779442746685926, 0.281054757202316),
  5457. (0, 1.5654806051633634, -0.4016220341911392, 0.271282133194204),
  5458. (0, 1.7420803447784388, -0.38180029468259247, 0.280202199244247),
  5459. (0, 1.5748002527689913, -0.25200194914153684, 0.280136576218665),
  5460. ]
  5461. )
  5462. def test_x_equal_zeta(
  5463. self, x, alpha, beta, expected
  5464. ):
  5465. """Test pdf for x equal to zeta.
  5466. With S1 parametrization: x0 = x + zeta if alpha != 1 So, for x = 0, x0
  5467. will be close to zeta.
  5468. When case "x equal zeta" is not handled properly and quad_eps is not
  5469. low enough: - pdf may be less than 0 - logpdf is nan
  5470. The points from the parametrize block are found randomly so that PDF is
  5471. less than 0.
  5472. Reference values taken from MATLAB
  5473. https://www.mathworks.com/help/stats/stable-distribution.html
  5474. """
  5475. stats.levy_stable.quad_eps = 1.2e-11
  5476. assert_almost_equal(
  5477. stats.levy_stable.pdf(x, alpha=alpha, beta=beta),
  5478. expected,
  5479. )
  5480. @pytest.mark.xfail
  5481. @pytest.mark.parametrize(
  5482. # See comment for test_x_equal_zeta for script for reference values
  5483. 'x,alpha,beta,expected',
  5484. [
  5485. (1e-4, 1.7720732804618808, 0.5059373136902996, 0.278929165340670),
  5486. (1e-4, 1.9217001522410235, -0.8779442746685926, 0.281056564327953),
  5487. (1e-4, 1.5654806051633634, -0.4016220341911392, 0.271252432161167),
  5488. (1e-4, 1.7420803447784388, -0.38180029468259247, 0.280205311264134),
  5489. (1e-4, 1.5748002527689913, -0.25200194914153684, 0.280140965235426),
  5490. (-1e-4, 1.7720732804618808, 0.5059373136902996, 0.278936106741754),
  5491. (-1e-4, 1.9217001522410235, -0.8779442746685926, 0.281052948629429),
  5492. (-1e-4, 1.5654806051633634, -0.4016220341911392, 0.271275394392385),
  5493. (-1e-4, 1.7420803447784388, -0.38180029468259247, 0.280199085645099),
  5494. (-1e-4, 1.5748002527689913, -0.25200194914153684, 0.280132185432842),
  5495. ]
  5496. )
  5497. def test_x_near_zeta(
  5498. self, x, alpha, beta, expected
  5499. ):
  5500. """Test pdf for x near zeta.
  5501. With S1 parametrization: x0 = x + zeta if alpha != 1 So, for x = 0, x0
  5502. will be close to zeta.
  5503. When case "x near zeta" is not handled properly and quad_eps is not
  5504. low enough: - pdf may be less than 0 - logpdf is nan
  5505. The points from the parametrize block are found randomly so that PDF is
  5506. less than 0.
  5507. Reference values taken from MATLAB
  5508. https://www.mathworks.com/help/stats/stable-distribution.html
  5509. """
  5510. stats.levy_stable.quad_eps = 1.2e-11
  5511. assert_almost_equal(
  5512. stats.levy_stable.pdf(x, alpha=alpha, beta=beta),
  5513. expected,
  5514. )
  5515. @pytest.fixture
  5516. def levy_stable_lock(self):
  5517. return threading.Lock()
  5518. def test_frozen_parameterization_gh20821(self, levy_stable_lock):
  5519. # gh-20821 reported that frozen distributions ignore the parameterization.
  5520. # Check that this is resolved and that the frozen distribution's
  5521. # parameterization can be changed independently of stats.levy_stable
  5522. rng = np.random.default_rng
  5523. shapes = dict(alpha=1.9, beta=0.1, loc=0.0, scale=1.0)
  5524. unfrozen = stats.levy_stable
  5525. frozen = stats.levy_stable(**shapes)
  5526. with levy_stable_lock:
  5527. unfrozen.parameterization = "S0"
  5528. frozen.parameterization = "S1"
  5529. unfrozen_a = unfrozen.rvs(**shapes, size=10, random_state=rng(329823498))
  5530. frozen_a = frozen.rvs(size=10, random_state=rng(329823498))
  5531. assert not np.any(frozen_a == unfrozen_a)
  5532. unfrozen.parameterization = "S1"
  5533. frozen.parameterization = "S0"
  5534. unfrozen_b = unfrozen.rvs(**shapes, size=10, random_state=rng(329823498))
  5535. frozen_b = frozen.rvs(size=10, random_state=rng(329823498))
  5536. assert_equal(frozen_b, unfrozen_a)
  5537. assert_equal(unfrozen_b, frozen_a)
  5538. def test_frozen_parameterization_gh20821b(self, levy_stable_lock):
  5539. # Check that the parameterization of the frozen distribution is that of
  5540. # the unfrozen distribution at the time of freezing
  5541. rng = np.random.default_rng
  5542. shapes = dict(alpha=1.9, beta=0.1, loc=0.0, scale=1.0)
  5543. unfrozen = stats.levy_stable
  5544. with levy_stable_lock:
  5545. unfrozen.parameterization = "S0"
  5546. frozen = stats.levy_stable(**shapes)
  5547. unfrozen_a = unfrozen.rvs(**shapes, size=10, random_state=rng(329823498))
  5548. frozen_a = frozen.rvs(size=10, random_state=rng(329823498))
  5549. assert_equal(frozen_a, unfrozen_a)
  5550. unfrozen.parameterization = "S1"
  5551. frozen = stats.levy_stable(**shapes)
  5552. unfrozen_b = unfrozen.rvs(**shapes, size=10, random_state=rng(329823498))
  5553. frozen_b = frozen.rvs(size=10, random_state=rng(329823498))
  5554. assert_equal(frozen_b, unfrozen_b)
  5555. class TestArrayArgument: # test for ticket:992
  5556. def setup_method(self):
  5557. self.rng = np.random.default_rng(7556981556)
  5558. def test_noexception(self):
  5559. rvs = stats.norm.rvs(loc=(np.arange(5)), scale=np.ones(5),
  5560. size=(10, 5), random_state=self.rng)
  5561. assert_equal(rvs.shape, (10, 5))
  5562. class TestDocstring:
  5563. def test_docstrings(self):
  5564. # See ticket #761
  5565. if stats.rayleigh.__doc__ is not None:
  5566. assert_("rayleigh" in stats.rayleigh.__doc__.lower())
  5567. if stats.bernoulli.__doc__ is not None:
  5568. assert_("bernoulli" in stats.bernoulli.__doc__.lower())
  5569. def test_no_name_arg(self):
  5570. # If name is not given, construction shouldn't fail. See #1508.
  5571. stats.rv_continuous()
  5572. stats.rv_discrete()
  5573. def test_args_reduce():
  5574. a = array([1, 3, 2, 1, 2, 3, 3])
  5575. b, c = argsreduce(a > 1, a, 2)
  5576. assert_array_equal(b, [3, 2, 2, 3, 3])
  5577. assert_array_equal(c, [2])
  5578. b, c = argsreduce(2 > 1, a, 2)
  5579. assert_array_equal(b, a)
  5580. assert_array_equal(c, [2] * np.size(a))
  5581. b, c = argsreduce(a > 0, a, 2)
  5582. assert_array_equal(b, a)
  5583. assert_array_equal(c, [2] * np.size(a))
  5584. class TestFitMethod:
  5585. # fitting assumes continuous parameters
  5586. skip = ['ncf', 'ksone', 'kstwo', 'irwinhall']
  5587. def setup_method(self):
  5588. self.rng = np.random.default_rng(4522425749)
  5589. # skip these b/c deprecated, or only loc and scale arguments
  5590. fitSkipNonFinite = ['expon', 'norm', 'uniform', 'irwinhall']
  5591. @pytest.mark.parametrize('dist,args', distcont)
  5592. def test_fit_w_non_finite_data_values(self, dist, args):
  5593. """gh-10300"""
  5594. if dist in self.fitSkipNonFinite:
  5595. pytest.skip(f"{dist} fit known to fail or deprecated")
  5596. x = np.array([1.6483, 2.7169, 2.4667, 1.1791, 3.5433, np.nan])
  5597. y = np.array([1.6483, 2.7169, 2.4667, 1.1791, 3.5433, np.inf])
  5598. distfunc = getattr(stats, dist)
  5599. assert_raises(ValueError, distfunc.fit, x, fscale=1)
  5600. assert_raises(ValueError, distfunc.fit, y, fscale=1)
  5601. def test_fix_fit_2args_lognorm(self):
  5602. # Regression test for #1551.
  5603. with np.errstate(all='ignore'):
  5604. x = stats.lognorm.rvs(0.25, 0., 20.0, size=20, random_state=self.rng)
  5605. expected_shape = np.sqrt(((np.log(x) - np.log(20))**2).mean())
  5606. assert_allclose(np.array(stats.lognorm.fit(x, floc=0, fscale=20)),
  5607. [expected_shape, 0, 20], atol=1e-8)
  5608. def test_fix_fit_norm(self):
  5609. x = np.arange(1, 6)
  5610. loc, scale = stats.norm.fit(x)
  5611. assert_almost_equal(loc, 3)
  5612. assert_almost_equal(scale, np.sqrt(2))
  5613. loc, scale = stats.norm.fit(x, floc=2)
  5614. assert_equal(loc, 2)
  5615. assert_equal(scale, np.sqrt(3))
  5616. loc, scale = stats.norm.fit(x, fscale=2)
  5617. assert_almost_equal(loc, 3)
  5618. assert_equal(scale, 2)
  5619. def test_fix_fit_gamma(self):
  5620. x = np.arange(1, 6)
  5621. meanlog = np.log(x).mean()
  5622. # A basic test of gamma.fit with floc=0.
  5623. floc = 0
  5624. a, loc, scale = stats.gamma.fit(x, floc=floc)
  5625. s = np.log(x.mean()) - meanlog
  5626. assert_almost_equal(np.log(a) - special.digamma(a), s, decimal=5)
  5627. assert_equal(loc, floc)
  5628. assert_almost_equal(scale, x.mean()/a, decimal=8)
  5629. # Regression tests for gh-2514.
  5630. # The problem was that if `floc=0` was given, any other fixed
  5631. # parameters were ignored.
  5632. f0 = 1
  5633. floc = 0
  5634. a, loc, scale = stats.gamma.fit(x, f0=f0, floc=floc)
  5635. assert_equal(a, f0)
  5636. assert_equal(loc, floc)
  5637. assert_almost_equal(scale, x.mean()/a, decimal=8)
  5638. f0 = 2
  5639. floc = 0
  5640. a, loc, scale = stats.gamma.fit(x, f0=f0, floc=floc)
  5641. assert_equal(a, f0)
  5642. assert_equal(loc, floc)
  5643. assert_almost_equal(scale, x.mean()/a, decimal=8)
  5644. # loc and scale fixed.
  5645. floc = 0
  5646. fscale = 2
  5647. a, loc, scale = stats.gamma.fit(x, floc=floc, fscale=fscale)
  5648. assert_equal(loc, floc)
  5649. assert_equal(scale, fscale)
  5650. c = meanlog - np.log(fscale)
  5651. assert_almost_equal(special.digamma(a), c)
  5652. def test_fix_fit_beta(self):
  5653. # Test beta.fit when both floc and fscale are given.
  5654. def mlefunc(a, b, x):
  5655. # Zeros of this function are critical points of
  5656. # the maximum likelihood function.
  5657. n = len(x)
  5658. s1 = np.log(x).sum()
  5659. s2 = np.log(1-x).sum()
  5660. psiab = special.psi(a + b)
  5661. func = [s1 - n * (-psiab + special.psi(a)),
  5662. s2 - n * (-psiab + special.psi(b))]
  5663. return func
  5664. # Basic test with floc and fscale given.
  5665. x = np.array([0.125, 0.25, 0.5])
  5666. a, b, loc, scale = stats.beta.fit(x, floc=0, fscale=1)
  5667. assert_equal(loc, 0)
  5668. assert_equal(scale, 1)
  5669. assert_allclose(mlefunc(a, b, x), [0, 0], atol=1e-6)
  5670. # Basic test with f0, floc and fscale given.
  5671. # This is also a regression test for gh-2514.
  5672. x = np.array([0.125, 0.25, 0.5])
  5673. a, b, loc, scale = stats.beta.fit(x, f0=2, floc=0, fscale=1)
  5674. assert_equal(a, 2)
  5675. assert_equal(loc, 0)
  5676. assert_equal(scale, 1)
  5677. da, db = mlefunc(a, b, x)
  5678. assert_allclose(db, 0, atol=1e-5)
  5679. # Same floc and fscale values as above, but reverse the data
  5680. # and fix b (f1).
  5681. x2 = 1 - x
  5682. a2, b2, loc2, scale2 = stats.beta.fit(x2, f1=2, floc=0, fscale=1)
  5683. assert_equal(b2, 2)
  5684. assert_equal(loc2, 0)
  5685. assert_equal(scale2, 1)
  5686. da, db = mlefunc(a2, b2, x2)
  5687. assert_allclose(da, 0, atol=1e-5)
  5688. # a2 of this test should equal b from above.
  5689. assert_almost_equal(a2, b)
  5690. # Check for detection of data out of bounds when floc and fscale
  5691. # are given.
  5692. assert_raises(ValueError, stats.beta.fit, x, floc=0.5, fscale=1)
  5693. y = np.array([0, .5, 1])
  5694. assert_raises(ValueError, stats.beta.fit, y, floc=0, fscale=1)
  5695. assert_raises(ValueError, stats.beta.fit, y, floc=0, fscale=1, f0=2)
  5696. assert_raises(ValueError, stats.beta.fit, y, floc=0, fscale=1, f1=2)
  5697. # Check that attempting to fix all the parameters raises a ValueError.
  5698. assert_raises(ValueError, stats.beta.fit, y, f0=0, f1=1,
  5699. floc=2, fscale=3)
  5700. def test_expon_fit(self):
  5701. x = np.array([2, 2, 4, 4, 4, 4, 4, 8])
  5702. loc, scale = stats.expon.fit(x)
  5703. assert_equal(loc, 2) # x.min()
  5704. assert_equal(scale, 2) # x.mean() - x.min()
  5705. loc, scale = stats.expon.fit(x, fscale=3)
  5706. assert_equal(loc, 2) # x.min()
  5707. assert_equal(scale, 3) # fscale
  5708. loc, scale = stats.expon.fit(x, floc=0)
  5709. assert_equal(loc, 0) # floc
  5710. assert_equal(scale, 4) # x.mean() - loc
  5711. def test_lognorm_fit(self):
  5712. x = np.array([1.5, 3, 10, 15, 23, 59])
  5713. lnxm1 = np.log(x - 1)
  5714. shape, loc, scale = stats.lognorm.fit(x, floc=1)
  5715. assert_allclose(shape, lnxm1.std(), rtol=1e-12)
  5716. assert_equal(loc, 1)
  5717. assert_allclose(scale, np.exp(lnxm1.mean()), rtol=1e-12)
  5718. shape, loc, scale = stats.lognorm.fit(x, floc=1, fscale=6)
  5719. assert_allclose(shape, np.sqrt(((lnxm1 - np.log(6))**2).mean()),
  5720. rtol=1e-12)
  5721. assert_equal(loc, 1)
  5722. assert_equal(scale, 6)
  5723. shape, loc, scale = stats.lognorm.fit(x, floc=1, fix_s=0.75)
  5724. assert_equal(shape, 0.75)
  5725. assert_equal(loc, 1)
  5726. assert_allclose(scale, np.exp(lnxm1.mean()), rtol=1e-12)
  5727. def test_uniform_fit(self):
  5728. x = np.array([1.0, 1.1, 1.2, 9.0])
  5729. loc, scale = stats.uniform.fit(x)
  5730. assert_equal(loc, x.min())
  5731. assert_equal(scale, np.ptp(x))
  5732. loc, scale = stats.uniform.fit(x, floc=0)
  5733. assert_equal(loc, 0)
  5734. assert_equal(scale, x.max())
  5735. loc, scale = stats.uniform.fit(x, fscale=10)
  5736. assert_equal(loc, 0)
  5737. assert_equal(scale, 10)
  5738. assert_raises(ValueError, stats.uniform.fit, x, floc=2.0)
  5739. assert_raises(ValueError, stats.uniform.fit, x, fscale=5.0)
  5740. @pytest.mark.xslow
  5741. @pytest.mark.parametrize("method", ["MLE", "MM"])
  5742. def test_fshapes(self, method):
  5743. # take a beta distribution, with shapes='a, b', and make sure that
  5744. # fa is equivalent to f0, and fb is equivalent to f1
  5745. a, b = 3., 4.
  5746. x = stats.beta.rvs(a, b, size=100, random_state=self.rng)
  5747. res_1 = stats.beta.fit(x, f0=3., method=method)
  5748. res_2 = stats.beta.fit(x, fa=3., method=method)
  5749. assert_allclose(res_1, res_2, atol=1e-12, rtol=1e-12)
  5750. res_2 = stats.beta.fit(x, fix_a=3., method=method)
  5751. assert_allclose(res_1, res_2, atol=1e-12, rtol=1e-12)
  5752. res_3 = stats.beta.fit(x, f1=4., method=method)
  5753. res_4 = stats.beta.fit(x, fb=4., method=method)
  5754. assert_allclose(res_3, res_4, atol=1e-12, rtol=1e-12)
  5755. res_4 = stats.beta.fit(x, fix_b=4., method=method)
  5756. assert_allclose(res_3, res_4, atol=1e-12, rtol=1e-12)
  5757. # cannot specify both positional and named args at the same time
  5758. assert_raises(ValueError, stats.beta.fit, x, fa=1, f0=2, method=method)
  5759. # check that attempting to fix all parameters raises a ValueError
  5760. assert_raises(ValueError, stats.beta.fit, x, fa=0, f1=1,
  5761. floc=2, fscale=3, method=method)
  5762. # check that specifying floc, fscale and fshapes works for
  5763. # beta and gamma which override the generic fit method
  5764. res_5 = stats.beta.fit(x, fa=3., floc=0, fscale=1, method=method)
  5765. aa, bb, ll, ss = res_5
  5766. assert_equal([aa, ll, ss], [3., 0, 1])
  5767. # gamma distribution
  5768. a = 3.
  5769. data = stats.gamma.rvs(a, size=100, random_state=self.rng)
  5770. aa, ll, ss = stats.gamma.fit(data, fa=a, method=method)
  5771. assert_equal(aa, a)
  5772. @pytest.mark.parametrize("method", ["MLE", "MM"])
  5773. def test_extra_params(self, method):
  5774. # unknown parameters should raise rather than be silently ignored
  5775. dist = stats.exponnorm
  5776. data = dist.rvs(K=2, size=100, random_state=self.rng)
  5777. dct = dict(enikibeniki=-101)
  5778. assert_raises(TypeError, dist.fit, data, **dct, method=method)
  5779. class TestFrozen:
  5780. # Test that a frozen distribution gives the same results as the original
  5781. # object.
  5782. #
  5783. # Only tested for the normal distribution (with loc and scale specified)
  5784. # and for the gamma distribution (with a shape parameter specified).
  5785. def test_norm(self):
  5786. dist = stats.norm
  5787. frozen = stats.norm(loc=10.0, scale=3.0)
  5788. result_f = frozen.pdf(20.0)
  5789. result = dist.pdf(20.0, loc=10.0, scale=3.0)
  5790. assert_equal(result_f, result)
  5791. result_f = frozen.cdf(20.0)
  5792. result = dist.cdf(20.0, loc=10.0, scale=3.0)
  5793. assert_equal(result_f, result)
  5794. result_f = frozen.ppf(0.25)
  5795. result = dist.ppf(0.25, loc=10.0, scale=3.0)
  5796. assert_equal(result_f, result)
  5797. result_f = frozen.isf(0.25)
  5798. result = dist.isf(0.25, loc=10.0, scale=3.0)
  5799. assert_equal(result_f, result)
  5800. result_f = frozen.sf(10.0)
  5801. result = dist.sf(10.0, loc=10.0, scale=3.0)
  5802. assert_equal(result_f, result)
  5803. result_f = frozen.median()
  5804. result = dist.median(loc=10.0, scale=3.0)
  5805. assert_equal(result_f, result)
  5806. result_f = frozen.mean()
  5807. result = dist.mean(loc=10.0, scale=3.0)
  5808. assert_equal(result_f, result)
  5809. result_f = frozen.var()
  5810. result = dist.var(loc=10.0, scale=3.0)
  5811. assert_equal(result_f, result)
  5812. result_f = frozen.std()
  5813. result = dist.std(loc=10.0, scale=3.0)
  5814. assert_equal(result_f, result)
  5815. result_f = frozen.entropy()
  5816. result = dist.entropy(loc=10.0, scale=3.0)
  5817. assert_equal(result_f, result)
  5818. result_f = frozen.moment(2)
  5819. result = dist.moment(2, loc=10.0, scale=3.0)
  5820. assert_equal(result_f, result)
  5821. assert_equal(frozen.a, dist.a)
  5822. assert_equal(frozen.b, dist.b)
  5823. def test_gamma(self):
  5824. a = 2.0
  5825. dist = stats.gamma
  5826. frozen = stats.gamma(a)
  5827. result_f = frozen.pdf(20.0)
  5828. result = dist.pdf(20.0, a)
  5829. assert_equal(result_f, result)
  5830. result_f = frozen.cdf(20.0)
  5831. result = dist.cdf(20.0, a)
  5832. assert_equal(result_f, result)
  5833. result_f = frozen.ppf(0.25)
  5834. result = dist.ppf(0.25, a)
  5835. assert_equal(result_f, result)
  5836. result_f = frozen.isf(0.25)
  5837. result = dist.isf(0.25, a)
  5838. assert_equal(result_f, result)
  5839. result_f = frozen.sf(10.0)
  5840. result = dist.sf(10.0, a)
  5841. assert_equal(result_f, result)
  5842. result_f = frozen.median()
  5843. result = dist.median(a)
  5844. assert_equal(result_f, result)
  5845. result_f = frozen.mean()
  5846. result = dist.mean(a)
  5847. assert_equal(result_f, result)
  5848. result_f = frozen.var()
  5849. result = dist.var(a)
  5850. assert_equal(result_f, result)
  5851. result_f = frozen.std()
  5852. result = dist.std(a)
  5853. assert_equal(result_f, result)
  5854. result_f = frozen.entropy()
  5855. result = dist.entropy(a)
  5856. assert_equal(result_f, result)
  5857. result_f = frozen.moment(2)
  5858. result = dist.moment(2, a)
  5859. assert_equal(result_f, result)
  5860. assert_equal(frozen.a, frozen.dist.a)
  5861. assert_equal(frozen.b, frozen.dist.b)
  5862. def test_regression_ticket_1293(self):
  5863. # Create a frozen distribution.
  5864. frozen = stats.lognorm(1)
  5865. # Call one of its methods that does not take any keyword arguments.
  5866. m1 = frozen.moment(2)
  5867. # Now call a method that takes a keyword argument.
  5868. frozen.stats(moments='mvsk')
  5869. # Call moment(2) again.
  5870. # After calling stats(), the following was raising an exception.
  5871. # So this test passes if the following does not raise an exception.
  5872. m2 = frozen.moment(2)
  5873. # The following should also be true, of course. But it is not
  5874. # the focus of this test.
  5875. assert_equal(m1, m2)
  5876. def test_ab(self):
  5877. # test that the support of a frozen distribution
  5878. # (i) remains frozen even if it changes for the original one
  5879. # (ii) is actually correct if the shape parameters are such that
  5880. # the values of [a, b] are not the default [0, inf]
  5881. # take a genpareto as an example where the support
  5882. # depends on the value of the shape parameter:
  5883. # for c > 0: a, b = 0, inf
  5884. # for c < 0: a, b = 0, -1/c
  5885. c = -0.1
  5886. rv = stats.genpareto(c=c)
  5887. a, b = rv.dist._get_support(c)
  5888. assert_equal([a, b], [0., 10.])
  5889. c = 0.1
  5890. stats.genpareto.pdf(0, c=c)
  5891. assert_equal(rv.dist._get_support(c), [0, np.inf])
  5892. c = -0.1
  5893. rv = stats.genpareto(c=c)
  5894. a, b = rv.dist._get_support(c)
  5895. assert_equal([a, b], [0., 10.])
  5896. c = 0.1
  5897. stats.genpareto.pdf(0, c) # this should NOT change genpareto.b
  5898. assert_equal((rv.dist.a, rv.dist.b), stats.genpareto._get_support(c))
  5899. rv1 = stats.genpareto(c=0.1)
  5900. assert_(rv1.dist is not rv.dist)
  5901. # c >= 0: a, b = [0, inf]
  5902. for c in [1., 0.]:
  5903. c = np.asarray(c)
  5904. rv = stats.genpareto(c=c)
  5905. a, b = rv.a, rv.b
  5906. assert_equal(a, 0.)
  5907. assert_(np.isposinf(b))
  5908. # c < 0: a=0, b=1/|c|
  5909. c = np.asarray(-2.)
  5910. a, b = stats.genpareto._get_support(c)
  5911. assert_allclose([a, b], [0., 0.5])
  5912. def test_rv_frozen_in_namespace(self):
  5913. # Regression test for gh-3522
  5914. assert_(hasattr(stats.distributions, 'rv_frozen'))
  5915. def test_random_state(self):
  5916. # only check that the random_state attribute exists,
  5917. frozen = stats.norm()
  5918. assert_(hasattr(frozen, 'random_state'))
  5919. # ... that it can be set,
  5920. frozen.random_state = 42
  5921. assert_equal(frozen.random_state.get_state(),
  5922. np.random.RandomState(42).get_state())
  5923. # ... and that .rvs method accepts it as an argument
  5924. rndm = np.random.RandomState(1234)
  5925. frozen.rvs(size=8, random_state=rndm)
  5926. def test_pickling(self):
  5927. # test that a frozen instance pickles and unpickles
  5928. # (this method is a clone of common_tests.check_pickling)
  5929. beta = stats.beta(2.3098496451481823, 0.62687954300963677)
  5930. poiss = stats.poisson(3.)
  5931. sample = stats.rv_discrete(values=([0, 1, 2, 3],
  5932. [0.1, 0.2, 0.3, 0.4]))
  5933. for distfn in [beta, poiss, sample]:
  5934. distfn.random_state = 1234
  5935. distfn.rvs(size=8)
  5936. s = pickle.dumps(distfn)
  5937. r0 = distfn.rvs(size=8)
  5938. unpickled = pickle.loads(s)
  5939. r1 = unpickled.rvs(size=8)
  5940. assert_equal(r0, r1)
  5941. # also smoke test some methods
  5942. medians = [distfn.ppf(0.5), unpickled.ppf(0.5)]
  5943. assert_equal(medians[0], medians[1])
  5944. assert_equal(distfn.cdf(medians[0]),
  5945. unpickled.cdf(medians[1]))
  5946. def test_expect(self):
  5947. # smoke test the expect method of the frozen distribution
  5948. # only take a gamma w/loc and scale and poisson with loc specified
  5949. def func(x):
  5950. return x
  5951. gm = stats.gamma(a=2, loc=3, scale=4)
  5952. with np.errstate(invalid="ignore", divide="ignore"):
  5953. gm_val = gm.expect(func, lb=1, ub=2, conditional=True)
  5954. gamma_val = stats.gamma.expect(func, args=(2,), loc=3, scale=4,
  5955. lb=1, ub=2, conditional=True)
  5956. assert_allclose(gm_val, gamma_val)
  5957. p = stats.poisson(3, loc=4)
  5958. p_val = p.expect(func)
  5959. poisson_val = stats.poisson.expect(func, args=(3,), loc=4)
  5960. assert_allclose(p_val, poisson_val)
  5961. class TestExpect:
  5962. # Test for expect method.
  5963. #
  5964. # Uses normal distribution and beta distribution for finite bounds, and
  5965. # hypergeom for discrete distribution with finite support
  5966. def test_norm(self):
  5967. v = stats.norm.expect(lambda x: (x-5)*(x-5), loc=5, scale=2)
  5968. assert_almost_equal(v, 4, decimal=14)
  5969. m = stats.norm.expect(lambda x: (x), loc=5, scale=2)
  5970. assert_almost_equal(m, 5, decimal=14)
  5971. lb = stats.norm.ppf(0.05, loc=5, scale=2)
  5972. ub = stats.norm.ppf(0.95, loc=5, scale=2)
  5973. prob90 = stats.norm.expect(lambda x: 1, loc=5, scale=2, lb=lb, ub=ub)
  5974. assert_almost_equal(prob90, 0.9, decimal=14)
  5975. prob90c = stats.norm.expect(lambda x: 1, loc=5, scale=2, lb=lb, ub=ub,
  5976. conditional=True)
  5977. assert_almost_equal(prob90c, 1., decimal=14)
  5978. def test_beta(self):
  5979. # case with finite support interval
  5980. v = stats.beta.expect(lambda x: (x-19/3.)*(x-19/3.), args=(10, 5),
  5981. loc=5, scale=2)
  5982. assert_almost_equal(v, 1./18., decimal=13)
  5983. m = stats.beta.expect(lambda x: x, args=(10, 5), loc=5., scale=2.)
  5984. assert_almost_equal(m, 19/3., decimal=13)
  5985. ub = stats.beta.ppf(0.95, 10, 10, loc=5, scale=2)
  5986. lb = stats.beta.ppf(0.05, 10, 10, loc=5, scale=2)
  5987. prob90 = stats.beta.expect(lambda x: 1., args=(10, 10), loc=5.,
  5988. scale=2., lb=lb, ub=ub, conditional=False)
  5989. assert_almost_equal(prob90, 0.9, decimal=13)
  5990. prob90c = stats.beta.expect(lambda x: 1, args=(10, 10), loc=5,
  5991. scale=2, lb=lb, ub=ub, conditional=True)
  5992. assert_almost_equal(prob90c, 1., decimal=13)
  5993. def test_hypergeom(self):
  5994. # test case with finite bounds
  5995. # without specifying bounds
  5996. m_true, v_true = stats.hypergeom.stats(20, 10, 8, loc=5.)
  5997. m = stats.hypergeom.expect(lambda x: x, args=(20, 10, 8), loc=5.)
  5998. assert_almost_equal(m, m_true, decimal=13)
  5999. v = stats.hypergeom.expect(lambda x: (x-9.)**2, args=(20, 10, 8),
  6000. loc=5.)
  6001. assert_almost_equal(v, v_true, decimal=14)
  6002. # with bounds, bounds equal to shifted support
  6003. v_bounds = stats.hypergeom.expect(lambda x: (x-9.)**2,
  6004. args=(20, 10, 8),
  6005. loc=5., lb=5, ub=13)
  6006. assert_almost_equal(v_bounds, v_true, decimal=14)
  6007. # drop boundary points
  6008. prob_true = 1-stats.hypergeom.pmf([5, 13], 20, 10, 8, loc=5).sum()
  6009. prob_bounds = stats.hypergeom.expect(lambda x: 1, args=(20, 10, 8),
  6010. loc=5., lb=6, ub=12)
  6011. assert_almost_equal(prob_bounds, prob_true, decimal=13)
  6012. # conditional
  6013. prob_bc = stats.hypergeom.expect(lambda x: 1, args=(20, 10, 8), loc=5.,
  6014. lb=6, ub=12, conditional=True)
  6015. assert_almost_equal(prob_bc, 1, decimal=14)
  6016. # check simple integral
  6017. prob_b = stats.hypergeom.expect(lambda x: 1, args=(20, 10, 8),
  6018. lb=0, ub=8)
  6019. assert_almost_equal(prob_b, 1, decimal=13)
  6020. def test_poisson(self):
  6021. # poisson, use lower bound only
  6022. prob_bounds = stats.poisson.expect(lambda x: 1, args=(2,), lb=3,
  6023. conditional=False)
  6024. prob_b_true = 1-stats.poisson.cdf(2, 2)
  6025. assert_almost_equal(prob_bounds, prob_b_true, decimal=14)
  6026. prob_lb = stats.poisson.expect(lambda x: 1, args=(2,), lb=2,
  6027. conditional=True)
  6028. assert_almost_equal(prob_lb, 1, decimal=14)
  6029. def test_genhalflogistic(self):
  6030. # genhalflogistic, changes upper bound of support in _argcheck
  6031. # regression test for gh-2622
  6032. halflog = stats.genhalflogistic
  6033. # check consistency when calling expect twice with the same input
  6034. res1 = halflog.expect(args=(1.5,))
  6035. halflog.expect(args=(0.5,))
  6036. res2 = halflog.expect(args=(1.5,))
  6037. assert_almost_equal(res1, res2, decimal=14)
  6038. def test_rice_overflow(self):
  6039. # rice.pdf(999, 0.74) was inf since special.i0 silently overflows
  6040. # check that using i0e fixes it
  6041. assert_(np.isfinite(stats.rice.pdf(999, 0.74)))
  6042. assert_(np.isfinite(stats.rice.expect(lambda x: 1, args=(0.74,))))
  6043. assert_(np.isfinite(stats.rice.expect(lambda x: 2, args=(0.74,))))
  6044. assert_(np.isfinite(stats.rice.expect(lambda x: 3, args=(0.74,))))
  6045. def test_logser(self):
  6046. # test a discrete distribution with infinite support and loc
  6047. p, loc = 0.3, 3
  6048. res_0 = stats.logser.expect(lambda k: k, args=(p,))
  6049. # check against the correct answer (sum of a geom series)
  6050. assert_allclose(res_0,
  6051. p / (p - 1.) / np.log(1. - p), atol=1e-15)
  6052. # now check it with `loc`
  6053. res_l = stats.logser.expect(lambda k: k, args=(p,), loc=loc)
  6054. assert_allclose(res_l, res_0 + loc, atol=1e-15)
  6055. def test_skellam(self):
  6056. # Use a discrete distribution w/ bi-infinite support. Compute two first
  6057. # moments and compare to known values (cf skellam.stats)
  6058. p1, p2 = 18, 22
  6059. m1 = stats.skellam.expect(lambda x: x, args=(p1, p2))
  6060. m2 = stats.skellam.expect(lambda x: x**2, args=(p1, p2))
  6061. assert_allclose(m1, p1 - p2, atol=1e-12)
  6062. assert_allclose(m2 - m1**2, p1 + p2, atol=1e-12)
  6063. def test_randint(self):
  6064. # Use a discrete distribution w/ parameter-dependent support, which
  6065. # is larger than the default chunksize
  6066. lo, hi = 0, 113
  6067. res = stats.randint.expect(lambda x: x, (lo, hi))
  6068. assert_allclose(res,
  6069. sum(_ for _ in range(lo, hi)) / (hi - lo), atol=1e-15)
  6070. def test_zipf(self):
  6071. # Test that there is no infinite loop even if the sum diverges
  6072. with pytest.warns(RuntimeWarning):
  6073. stats.zipf.expect(lambda x: x**2, (2,))
  6074. def test_discrete_kwds(self):
  6075. # check that discrete expect accepts keywords to control the summation
  6076. n0 = stats.poisson.expect(lambda x: 1, args=(2,))
  6077. n1 = stats.poisson.expect(lambda x: 1, args=(2,),
  6078. maxcount=1001, chunksize=32, tolerance=1e-8)
  6079. assert_almost_equal(n0, n1, decimal=14)
  6080. def test_moment(self):
  6081. # test the .moment() method: compute a higher moment and compare to
  6082. # a known value
  6083. def poiss_moment5(mu):
  6084. return mu**5 + 10*mu**4 + 25*mu**3 + 15*mu**2 + mu
  6085. for mu in [5, 7]:
  6086. m5 = stats.poisson.moment(5, mu)
  6087. assert_allclose(m5, poiss_moment5(mu), rtol=1e-10)
  6088. def test_challenging_cases_gh8928(self):
  6089. # Several cases where `expect` failed to produce a correct result were
  6090. # reported in gh-8928. Check that these cases have been resolved.
  6091. assert_allclose(stats.norm.expect(loc=36, scale=1.0), 36)
  6092. assert_allclose(stats.norm.expect(loc=40, scale=1.0), 40)
  6093. assert_allclose(stats.norm.expect(loc=10, scale=0.1), 10)
  6094. assert_allclose(stats.gamma.expect(args=(148,)), 148)
  6095. assert_allclose(stats.logistic.expect(loc=85), 85)
  6096. def test_lb_ub_gh15855(self):
  6097. # Make sure changes to `expect` made in gh15855 treat lb/ub correctly
  6098. dist = stats.uniform
  6099. ref = dist.mean(loc=10, scale=5) # 12.5
  6100. # moment over whole distribution
  6101. assert_allclose(dist.expect(loc=10, scale=5), ref)
  6102. # moment over whole distribution, lb and ub outside of support
  6103. assert_allclose(dist.expect(loc=10, scale=5, lb=9, ub=16), ref)
  6104. # moment over 60% of distribution, [lb, ub] centered within support
  6105. assert_allclose(dist.expect(loc=10, scale=5, lb=11, ub=14), ref*0.6)
  6106. # moment over truncated distribution, essentially
  6107. assert_allclose(dist.expect(loc=10, scale=5, lb=11, ub=14,
  6108. conditional=True), ref)
  6109. # moment over 40% of distribution, [lb, ub] not centered within support
  6110. assert_allclose(dist.expect(loc=10, scale=5, lb=11, ub=13), 12*0.4)
  6111. # moment with lb > ub
  6112. assert_allclose(dist.expect(loc=10, scale=5, lb=13, ub=11), -12*0.4)
  6113. # moment with lb > ub, conditional
  6114. assert_allclose(dist.expect(loc=10, scale=5, lb=13, ub=11,
  6115. conditional=True), 12)
  6116. class TestNct:
  6117. def test_nc_parameter(self):
  6118. # Parameter values c<=0 were not enabled (gh-2402).
  6119. # For negative values c and for c=0 results of rv.cdf(0) below were nan
  6120. rv = stats.nct(5, 0)
  6121. assert_equal(rv.cdf(0), 0.5)
  6122. rv = stats.nct(5, -1)
  6123. assert_almost_equal(rv.cdf(0), 0.841344746069, decimal=10)
  6124. def test_broadcasting(self):
  6125. res = stats.nct.pdf(5, np.arange(4, 7)[:, None],
  6126. np.linspace(0.1, 1, 4))
  6127. expected = array([[0.00321886, 0.00557466, 0.00918418, 0.01442997],
  6128. [0.00217142, 0.00395366, 0.00683888, 0.01126276],
  6129. [0.00153078, 0.00291093, 0.00525206, 0.00900815]])
  6130. assert_allclose(res, expected, rtol=1e-5)
  6131. def test_variance_gh_issue_2401(self):
  6132. # Computation of the variance of a non-central t-distribution resulted
  6133. # in a TypeError: ufunc 'isinf' not supported for the input types,
  6134. # and the inputs could not be safely coerced to any supported types
  6135. # according to the casting rule 'safe'
  6136. rv = stats.nct(4, 0)
  6137. assert_equal(rv.var(), 2.0)
  6138. def test_nct_inf_moments(self):
  6139. # n-th moment of nct only exists for df > n
  6140. m, v, s, k = stats.nct.stats(df=0.9, nc=0.3, moments='mvsk')
  6141. assert_equal([m, v, s, k], [np.nan, np.nan, np.nan, np.nan])
  6142. m, v, s, k = stats.nct.stats(df=1.9, nc=0.3, moments='mvsk')
  6143. assert_(np.isfinite(m))
  6144. assert_equal([v, s, k], [np.nan, np.nan, np.nan])
  6145. m, v, s, k = stats.nct.stats(df=3.1, nc=0.3, moments='mvsk')
  6146. assert_(np.isfinite([m, v, s]).all())
  6147. assert_equal(k, np.nan)
  6148. def test_nct_stats_large_df_values(self):
  6149. # previously gamma function was used which lost precision at df=345
  6150. # cf. https://github.com/scipy/scipy/issues/12919 for details
  6151. nct_mean_df_1000 = stats.nct.mean(1000, 2)
  6152. nct_stats_df_1000 = stats.nct.stats(1000, 2)
  6153. # These expected values were computed with mpmath. They were also
  6154. # verified with the Wolfram Alpha expressions:
  6155. # Mean[NoncentralStudentTDistribution[1000, 2]]
  6156. # Var[NoncentralStudentTDistribution[1000, 2]]
  6157. expected_stats_df_1000 = [2.0015015641422464, 1.0040115288163005]
  6158. assert_allclose(nct_mean_df_1000, expected_stats_df_1000[0],
  6159. rtol=1e-10)
  6160. assert_allclose(nct_stats_df_1000, expected_stats_df_1000,
  6161. rtol=1e-10)
  6162. # and a bigger df value
  6163. nct_mean = stats.nct.mean(100000, 2)
  6164. nct_stats = stats.nct.stats(100000, 2)
  6165. # These expected values were computed with mpmath.
  6166. expected_stats = [2.0000150001562518, 1.0000400011500288]
  6167. assert_allclose(nct_mean, expected_stats[0], rtol=1e-10)
  6168. assert_allclose(nct_stats, expected_stats, rtol=1e-9)
  6169. def test_cdf_large_nc(self):
  6170. # gh-17916 reported a crash with large `nc` values
  6171. assert_allclose(stats.nct.cdf(2, 2, float(2**16)), 0)
  6172. # PDF reference values were computed with mpmath
  6173. # with 100 digits of precision
  6174. # def nct_pdf(x, df, nc):
  6175. # x = mp.mpf(x)
  6176. # n = mp.mpf(df)
  6177. # nc = mp.mpf(nc)
  6178. # x2 = x*x
  6179. # ncx2 = nc*nc*x2
  6180. # fac1 = n + x2
  6181. # trm1 = (n/2.*mp.log(n) + mp.loggamma(n + mp.one)
  6182. # - (n * mp.log(2.) + nc*nc/2 + (n/2)*mp.log(fac1)
  6183. # + mp.loggamma(n/2)))
  6184. # Px = mp.exp(trm1)
  6185. # valF = ncx2 / (2*fac1)
  6186. # trm1 = (mp.sqrt(2)*nc*x*mp.hyp1f1(n/2+1, 1.5, valF)
  6187. # / (fac1*mp.gamma((n+1)/2)))
  6188. # trm2 = (mp.hyp1f1((n+1)/2, 0.5, valF)
  6189. # / (mp.sqrt(fac1)*mp.gamma(n/2 + mp.one)))
  6190. # Px *= trm1+trm2
  6191. # return float(Px)
  6192. @pytest.mark.parametrize("x, df, nc, expected", [
  6193. (10000, 10, 16, 3.394646922945872e-30),
  6194. (-10, 8, 16, 4.282769500264159e-70)
  6195. ])
  6196. def test_pdf_large_nc(self, x, df, nc, expected):
  6197. # gh-#20693 reported zero values for large `nc` values
  6198. assert_allclose(stats.nct.pdf(x, df, nc), expected, rtol=1e-12)
  6199. class TestRecipInvGauss:
  6200. def test_pdf_endpoint(self):
  6201. p = stats.recipinvgauss.pdf(0, 0.6)
  6202. assert p == 0.0
  6203. def test_logpdf_endpoint(self):
  6204. logp = stats.recipinvgauss.logpdf(0, 0.6)
  6205. assert logp == -np.inf
  6206. def test_cdf_small_x(self):
  6207. # The expected value was computer with mpmath:
  6208. #
  6209. # import mpmath
  6210. #
  6211. # mpmath.mp.dps = 100
  6212. #
  6213. # def recipinvgauss_cdf_mp(x, mu):
  6214. # x = mpmath.mpf(x)
  6215. # mu = mpmath.mpf(mu)
  6216. # trm1 = 1/mu - x
  6217. # trm2 = 1/mu + x
  6218. # isqx = 1/mpmath.sqrt(x)
  6219. # return (mpmath.ncdf(-isqx*trm1)
  6220. # - mpmath.exp(2/mu)*mpmath.ncdf(-isqx*trm2))
  6221. #
  6222. p = stats.recipinvgauss.cdf(0.05, 0.5)
  6223. expected = 6.590396159501331e-20
  6224. assert_allclose(p, expected, rtol=1e-14)
  6225. def test_sf_large_x(self):
  6226. # The expected value was computed with mpmath; see test_cdf_small.
  6227. p = stats.recipinvgauss.sf(80, 0.5)
  6228. expected = 2.699819200556787e-18
  6229. assert_allclose(p, expected, 5e-15)
  6230. class TestRice:
  6231. def setup_method(self):
  6232. self.rng = np.random.default_rng(666822542)
  6233. def test_rice_zero_b(self):
  6234. # rice distribution should work with b=0, cf gh-2164
  6235. x = [0.2, 1., 5.]
  6236. assert_(np.isfinite(stats.rice.pdf(x, b=0.)).all())
  6237. assert_(np.isfinite(stats.rice.logpdf(x, b=0.)).all())
  6238. assert_(np.isfinite(stats.rice.cdf(x, b=0.)).all())
  6239. assert_(np.isfinite(stats.rice.logcdf(x, b=0.)).all())
  6240. q = [0.1, 0.1, 0.5, 0.9]
  6241. assert_(np.isfinite(stats.rice.ppf(q, b=0.)).all())
  6242. mvsk = stats.rice.stats(0, moments='mvsk')
  6243. assert_(np.isfinite(mvsk).all())
  6244. # furthermore, pdf is continuous as b\to 0
  6245. # rice.pdf(x, b\to 0) = x exp(-x^2/2) + O(b^2)
  6246. # see e.g. Abramovich & Stegun 9.6.7 & 9.6.10
  6247. b = 1e-8
  6248. assert_allclose(stats.rice.pdf(x, 0), stats.rice.pdf(x, b),
  6249. atol=b, rtol=0)
  6250. def test_rice_rvs(self):
  6251. rvs = stats.rice.rvs
  6252. assert_equal(rvs(b=3., random_state=self.rng).size, 1)
  6253. assert_equal(rvs(b=3., size=(3, 5), random_state=self.rng).shape, (3, 5))
  6254. def test_rice_gh9836(self):
  6255. # test that gh-9836 is resolved; previously jumped to 1 at the end
  6256. cdf = stats.rice.cdf(np.arange(10, 160, 10), np.arange(10, 160, 10))
  6257. # Generated in R
  6258. # library(VGAM)
  6259. # options(digits=16)
  6260. # x = seq(10, 150, 10)
  6261. # print(price(x, sigma=1, vee=x))
  6262. cdf_exp = [0.4800278103504522, 0.4900233218590353, 0.4933500379379548,
  6263. 0.4950128317658719, 0.4960103776798502, 0.4966753655438764,
  6264. 0.4971503395812474, 0.4975065620443196, 0.4977836197921638,
  6265. 0.4980052636649550, 0.4981866072661382, 0.4983377260666599,
  6266. 0.4984655952615694, 0.4985751970541413, 0.4986701850071265]
  6267. assert_allclose(cdf, cdf_exp)
  6268. probabilities = np.arange(0.1, 1, 0.1)
  6269. ppf = stats.rice.ppf(probabilities, 500/4, scale=4)
  6270. # Generated in R
  6271. # library(VGAM)
  6272. # options(digits=16)
  6273. # p = seq(0.1, .9, by = .1)
  6274. # print(qrice(p, vee = 500, sigma = 4))
  6275. ppf_exp = [494.8898762347361, 496.6495690858350, 497.9184315188069,
  6276. 499.0026277378915, 500.0159999146250, 501.0293721352668,
  6277. 502.1135684981884, 503.3824312270405, 505.1421247157822]
  6278. assert_allclose(ppf, ppf_exp)
  6279. ppf = scipy.stats.rice.ppf(0.5, np.arange(10, 150, 10))
  6280. # Generated in R
  6281. # library(VGAM)
  6282. # options(digits=16)
  6283. # b <- seq(10, 140, 10)
  6284. # print(qrice(0.5, vee = b, sigma = 1))
  6285. ppf_exp = [10.04995862522287, 20.02499480078302, 30.01666512465732,
  6286. 40.01249934924363, 50.00999966676032, 60.00833314046875,
  6287. 70.00714273568241, 80.00624991862573, 90.00555549840364,
  6288. 100.00499995833597, 110.00454542324384, 120.00416664255323,
  6289. 130.00384613488120, 140.00357141338748]
  6290. assert_allclose(ppf, ppf_exp)
  6291. class TestErlang:
  6292. def setup_method(self):
  6293. self.rng = np.random.default_rng(2792245532)
  6294. def test_erlang_runtimewarning(self):
  6295. # erlang should generate a RuntimeWarning if a non-integer
  6296. # shape parameter is used.
  6297. with warnings.catch_warnings():
  6298. warnings.simplefilter("error", RuntimeWarning)
  6299. # The non-integer shape parameter 1.3 should trigger a
  6300. # RuntimeWarning
  6301. assert_raises(RuntimeWarning, stats.erlang.rvs, 1.3, loc=0,
  6302. scale=1, size=4, random_state=self.rng)
  6303. # Calling the fit method with `f0` set to an integer should
  6304. # *not* trigger a RuntimeWarning. It should return the same
  6305. # values as gamma.fit(...).
  6306. data = [0.5, 1.0, 2.0, 4.0]
  6307. result_erlang = stats.erlang.fit(data, f0=1)
  6308. result_gamma = stats.gamma.fit(data, f0=1)
  6309. assert_allclose(result_erlang, result_gamma, rtol=1e-3)
  6310. def test_gh_pr_10949_argcheck(self):
  6311. assert_equal(stats.erlang.pdf(0.5, a=[1, -1]),
  6312. stats.gamma.pdf(0.5, a=[1, -1]))
  6313. class TestRayleigh:
  6314. def setup_method(self):
  6315. self.rng = np.random.default_rng(7186715712)
  6316. # gh-6227
  6317. def test_logpdf(self):
  6318. y = stats.rayleigh.logpdf(50)
  6319. assert_allclose(y, -1246.0879769945718)
  6320. def test_logsf(self):
  6321. y = stats.rayleigh.logsf(50)
  6322. assert_allclose(y, -1250)
  6323. @pytest.mark.parametrize("rvs_loc,rvs_scale", [(0.85373171, 0.86932204),
  6324. (0.20558821, 0.61621008)])
  6325. def test_fit(self, rvs_loc, rvs_scale):
  6326. data = stats.rayleigh.rvs(size=250, loc=rvs_loc,
  6327. scale=rvs_scale, random_state=self.rng)
  6328. def scale_mle(data, floc):
  6329. return (np.sum((data - floc) ** 2) / (2 * len(data))) ** .5
  6330. # when `floc` is provided, `scale` is found with an analytical formula
  6331. scale_expect = scale_mle(data, rvs_loc)
  6332. loc, scale = stats.rayleigh.fit(data, floc=rvs_loc)
  6333. assert_equal(loc, rvs_loc)
  6334. assert_equal(scale, scale_expect)
  6335. # when `fscale` is fixed, superclass fit is used to determine `loc`.
  6336. loc, scale = stats.rayleigh.fit(data, fscale=.6)
  6337. assert_equal(scale, .6)
  6338. # with both parameters free, one dimensional optimization is done
  6339. # over a new function that takes into account the dependent relation
  6340. # of `scale` to `loc`.
  6341. loc, scale = stats.rayleigh.fit(data)
  6342. # test that `scale` is defined by its relation to `loc`
  6343. assert_equal(scale, scale_mle(data, loc))
  6344. @pytest.mark.parametrize("rvs_loc,rvs_scale", [[0.74, 0.01],
  6345. [0.08464463, 0.12069025]])
  6346. def test_fit_comparison_super_method(self, rvs_loc, rvs_scale):
  6347. # test that the objective function result of the analytical MLEs is
  6348. # less than or equal to that of the numerically optimized estimate
  6349. data = stats.rayleigh.rvs(size=250, loc=rvs_loc,
  6350. scale=rvs_scale, random_state=self.rng)
  6351. _assert_less_or_close_loglike(stats.rayleigh, data)
  6352. def test_fit_warnings(self):
  6353. assert_fit_warnings(stats.rayleigh)
  6354. def test_fit_gh17088(self):
  6355. # `rayleigh.fit` could return a location that was inconsistent with
  6356. # the data. See gh-17088.
  6357. rng = np.random.default_rng(456)
  6358. loc, scale, size = 50, 600, 500
  6359. rvs = stats.rayleigh.rvs(loc, scale, size=size, random_state=rng)
  6360. loc_fit, _ = stats.rayleigh.fit(rvs)
  6361. assert loc_fit < np.min(rvs)
  6362. loc_fit, scale_fit = stats.rayleigh.fit(rvs, fscale=scale)
  6363. assert loc_fit < np.min(rvs)
  6364. assert scale_fit == scale
  6365. class TestExponWeib:
  6366. def test_pdf_logpdf(self):
  6367. # Regression test for gh-3508.
  6368. x = 0.1
  6369. a = 1.0
  6370. c = 100.0
  6371. p = stats.exponweib.pdf(x, a, c)
  6372. logp = stats.exponweib.logpdf(x, a, c)
  6373. # Expected values were computed with mpmath.
  6374. assert_allclose([p, logp],
  6375. [1.0000000000000054e-97, -223.35075402042244])
  6376. def test_a_is_1(self):
  6377. # For issue gh-3508.
  6378. # Check that when a=1, the pdf and logpdf methods of exponweib are the
  6379. # same as those of weibull_min.
  6380. x = np.logspace(-4, -1, 4)
  6381. a = 1
  6382. c = 100
  6383. p = stats.exponweib.pdf(x, a, c)
  6384. expected = stats.weibull_min.pdf(x, c)
  6385. assert_allclose(p, expected)
  6386. logp = stats.exponweib.logpdf(x, a, c)
  6387. expected = stats.weibull_min.logpdf(x, c)
  6388. assert_allclose(logp, expected)
  6389. def test_a_is_1_c_is_1(self):
  6390. # When a = 1 and c = 1, the distribution is exponential.
  6391. x = np.logspace(-8, 1, 10)
  6392. a = 1
  6393. c = 1
  6394. p = stats.exponweib.pdf(x, a, c)
  6395. expected = stats.expon.pdf(x)
  6396. assert_allclose(p, expected)
  6397. logp = stats.exponweib.logpdf(x, a, c)
  6398. expected = stats.expon.logpdf(x)
  6399. assert_allclose(logp, expected)
  6400. # Reference values were computed with mpmath, e.g:
  6401. #
  6402. # from mpmath import mp
  6403. #
  6404. # def mp_sf(x, a, c):
  6405. # x = mp.mpf(x)
  6406. # a = mp.mpf(a)
  6407. # c = mp.mpf(c)
  6408. # return -mp.powm1(-mp.expm1(-x**c)), a)
  6409. #
  6410. # mp.dps = 100
  6411. # print(float(mp_sf(1, 2.5, 0.75)))
  6412. #
  6413. # prints
  6414. #
  6415. # 0.6823127476985246
  6416. #
  6417. @pytest.mark.parametrize(
  6418. 'x, a, c, ref',
  6419. [(1, 2.5, 0.75, 0.6823127476985246),
  6420. (50, 2.5, 0.75, 1.7056666054719663e-08),
  6421. (125, 2.5, 0.75, 1.4534393150714602e-16),
  6422. (250, 2.5, 0.75, 1.2391389689773512e-27),
  6423. (250, 0.03125, 0.75, 1.548923711221689e-29),
  6424. (3, 0.03125, 3.0, 5.873527551689983e-14),
  6425. (2e80, 10.0, 0.02, 2.9449084156902135e-17)]
  6426. )
  6427. def test_sf(self, x, a, c, ref):
  6428. sf = stats.exponweib.sf(x, a, c)
  6429. assert_allclose(sf, ref, rtol=1e-14)
  6430. # Reference values were computed with mpmath, e.g.
  6431. #
  6432. # from mpmath import mp
  6433. #
  6434. # def mp_isf(p, a, c):
  6435. # p = mp.mpf(p)
  6436. # a = mp.mpf(a)
  6437. # c = mp.mpf(c)
  6438. # return (-mp.log(-mp.expm1(mp.log1p(-p)/a)))**(1/c)
  6439. #
  6440. # mp.dps = 100
  6441. # print(float(mp_isf(0.25, 2.5, 0.75)))
  6442. #
  6443. # prints
  6444. #
  6445. # 2.8946008178158924
  6446. #
  6447. @pytest.mark.parametrize(
  6448. 'p, a, c, ref',
  6449. [(0.25, 2.5, 0.75, 2.8946008178158924),
  6450. (3e-16, 2.5, 0.75, 121.77966713102938),
  6451. (1e-12, 1, 2, 5.256521769756932),
  6452. (2e-13, 0.03125, 3, 2.953915059484589),
  6453. (5e-14, 10.0, 0.02, 7.57094886384687e+75)]
  6454. )
  6455. def test_isf(self, p, a, c, ref):
  6456. isf = stats.exponweib.isf(p, a, c)
  6457. assert_allclose(isf, ref, rtol=5e-14)
  6458. # Reference values computed with mpmath.
  6459. @pytest.mark.parametrize('x, a, c, ref',
  6460. [(2, 3, 8, -1.9848783170128456e-111),
  6461. (1000, 0.5, 0.75, -2.946296827524972e-78)])
  6462. def test_logcdf(self, x, a, c, ref):
  6463. logcdf = stats.exponweib.logcdf(x, a, c)
  6464. assert_allclose(logcdf, ref, rtol=5e-15)
  6465. # Reference values computed with mpmath.
  6466. @pytest.mark.parametrize('x, a, c, ref',
  6467. [(1e-65, 1.5, 1.25, -1.333521432163324e-122),
  6468. (2e-10, 2, 10, -1.0485760000000007e-194)])
  6469. def test_logsf(self, x, a, c, ref):
  6470. logsf = stats.exponweib.logsf(x, a, c)
  6471. assert_allclose(logsf, ref, rtol=5e-15)
  6472. class TestFatigueLife:
  6473. def test_sf_tail(self):
  6474. # Expected value computed with mpmath:
  6475. # import mpmath
  6476. # mpmath.mp.dps = 80
  6477. # x = mpmath.mpf(800.0)
  6478. # c = mpmath.mpf(2.5)
  6479. # s = float(1 - mpmath.ncdf(1/c * (mpmath.sqrt(x)
  6480. # - 1/mpmath.sqrt(x))))
  6481. # print(s)
  6482. # Output:
  6483. # 6.593376447038406e-30
  6484. s = stats.fatiguelife.sf(800.0, 2.5)
  6485. assert_allclose(s, 6.593376447038406e-30, rtol=1e-13)
  6486. def test_isf_tail(self):
  6487. # See test_sf_tail for the mpmath code.
  6488. p = 6.593376447038406e-30
  6489. q = stats.fatiguelife.isf(p, 2.5)
  6490. assert_allclose(q, 800.0, rtol=1e-13)
  6491. class TestWeibull:
  6492. def test_logpdf(self):
  6493. # gh-6217
  6494. y = stats.weibull_min.logpdf(0, 1)
  6495. assert_equal(y, 0)
  6496. def test_with_maxima_distrib(self):
  6497. # Tests for weibull_min and weibull_max.
  6498. # The expected values were computed using the symbolic algebra
  6499. # program 'maxima' with the package 'distrib', which has
  6500. # 'pdf_weibull' and 'cdf_weibull'. The mapping between the
  6501. # scipy and maxima functions is as follows:
  6502. # -----------------------------------------------------------------
  6503. # scipy maxima
  6504. # --------------------------------- ------------------------------
  6505. # weibull_min.pdf(x, a, scale=b) pdf_weibull(x, a, b)
  6506. # weibull_min.logpdf(x, a, scale=b) log(pdf_weibull(x, a, b))
  6507. # weibull_min.cdf(x, a, scale=b) cdf_weibull(x, a, b)
  6508. # weibull_min.logcdf(x, a, scale=b) log(cdf_weibull(x, a, b))
  6509. # weibull_min.sf(x, a, scale=b) 1 - cdf_weibull(x, a, b)
  6510. # weibull_min.logsf(x, a, scale=b) log(1 - cdf_weibull(x, a, b))
  6511. #
  6512. # weibull_max.pdf(x, a, scale=b) pdf_weibull(-x, a, b)
  6513. # weibull_max.logpdf(x, a, scale=b) log(pdf_weibull(-x, a, b))
  6514. # weibull_max.cdf(x, a, scale=b) 1 - cdf_weibull(-x, a, b)
  6515. # weibull_max.logcdf(x, a, scale=b) log(1 - cdf_weibull(-x, a, b))
  6516. # weibull_max.sf(x, a, scale=b) cdf_weibull(-x, a, b)
  6517. # weibull_max.logsf(x, a, scale=b) log(cdf_weibull(-x, a, b))
  6518. # -----------------------------------------------------------------
  6519. x = 1.5
  6520. a = 2.0
  6521. b = 3.0
  6522. # weibull_min
  6523. p = stats.weibull_min.pdf(x, a, scale=b)
  6524. assert_allclose(p, np.exp(-0.25)/3)
  6525. lp = stats.weibull_min.logpdf(x, a, scale=b)
  6526. assert_allclose(lp, -0.25 - np.log(3))
  6527. c = stats.weibull_min.cdf(x, a, scale=b)
  6528. assert_allclose(c, -special.expm1(-0.25))
  6529. lc = stats.weibull_min.logcdf(x, a, scale=b)
  6530. assert_allclose(lc, np.log(-special.expm1(-0.25)))
  6531. s = stats.weibull_min.sf(x, a, scale=b)
  6532. assert_allclose(s, np.exp(-0.25))
  6533. ls = stats.weibull_min.logsf(x, a, scale=b)
  6534. assert_allclose(ls, -0.25)
  6535. # Also test using a large value x, for which computing the survival
  6536. # function using the CDF would result in 0.
  6537. s = stats.weibull_min.sf(30, 2, scale=3)
  6538. assert_allclose(s, np.exp(-100))
  6539. ls = stats.weibull_min.logsf(30, 2, scale=3)
  6540. assert_allclose(ls, -100)
  6541. # weibull_max
  6542. x = -1.5
  6543. p = stats.weibull_max.pdf(x, a, scale=b)
  6544. assert_allclose(p, np.exp(-0.25)/3)
  6545. lp = stats.weibull_max.logpdf(x, a, scale=b)
  6546. assert_allclose(lp, -0.25 - np.log(3))
  6547. c = stats.weibull_max.cdf(x, a, scale=b)
  6548. assert_allclose(c, np.exp(-0.25))
  6549. lc = stats.weibull_max.logcdf(x, a, scale=b)
  6550. assert_allclose(lc, -0.25)
  6551. s = stats.weibull_max.sf(x, a, scale=b)
  6552. assert_allclose(s, -special.expm1(-0.25))
  6553. ls = stats.weibull_max.logsf(x, a, scale=b)
  6554. assert_allclose(ls, np.log(-special.expm1(-0.25)))
  6555. # Also test using a value of x close to 0, for which computing the
  6556. # survival function using the CDF would result in 0.
  6557. s = stats.weibull_max.sf(-1e-9, 2, scale=3)
  6558. assert_allclose(s, -special.expm1(-1/9000000000000000000))
  6559. ls = stats.weibull_max.logsf(-1e-9, 2, scale=3)
  6560. assert_allclose(ls, np.log(-special.expm1(-1/9000000000000000000)))
  6561. @pytest.mark.parametrize('scale', [1.0, 0.1])
  6562. def test_delta_cdf(self, scale):
  6563. # Expected value computed with mpmath:
  6564. #
  6565. # def weibull_min_sf(x, k, scale):
  6566. # x = mpmath.mpf(x)
  6567. # k = mpmath.mpf(k)
  6568. # scale =mpmath.mpf(scale)
  6569. # return mpmath.exp(-(x/scale)**k)
  6570. #
  6571. # >>> import mpmath
  6572. # >>> mpmath.mp.dps = 60
  6573. # >>> sf1 = weibull_min_sf(7.5, 3, 1)
  6574. # >>> sf2 = weibull_min_sf(8.0, 3, 1)
  6575. # >>> float(sf1 - sf2)
  6576. # 6.053624060118734e-184
  6577. #
  6578. delta = stats.weibull_min._delta_cdf(scale*7.5, scale*8, 3,
  6579. scale=scale)
  6580. assert_allclose(delta, 6.053624060118734e-184)
  6581. def test_fit_min(self):
  6582. rng = np.random.default_rng(5985959307161735394)
  6583. c, loc, scale = 2, 3.5, 0.5 # arbitrary, valid parameters
  6584. dist = stats.weibull_min(c, loc, scale)
  6585. rvs = dist.rvs(size=100, random_state=rng)
  6586. # test that MLE still honors guesses and fixed parameters
  6587. c2, loc2, scale2 = stats.weibull_min.fit(rvs, 1.5, floc=3)
  6588. c3, loc3, scale3 = stats.weibull_min.fit(rvs, 1.6, floc=3)
  6589. assert loc2 == loc3 == 3 # fixed parameter is respected
  6590. assert c2 != c3 # different guess -> (slightly) different outcome
  6591. # quality of fit is tested elsewhere
  6592. # test that MoM honors fixed parameters, accepts (but ignores) guesses
  6593. c4, loc4, scale4 = stats.weibull_min.fit(rvs, 3, fscale=3, method='mm')
  6594. assert scale4 == 3
  6595. # because scale was fixed, only the mean and skewness will be matched
  6596. dist4 = stats.weibull_min(c4, loc4, scale4)
  6597. res = dist4.stats(moments='ms')
  6598. ref = np.mean(rvs), stats.skew(rvs)
  6599. assert_allclose(res, ref)
  6600. # reference values were computed via mpmath
  6601. # from mpmath import mp
  6602. # def weibull_sf_mpmath(x, c):
  6603. # x = mp.mpf(x)
  6604. # c = mp.mpf(c)
  6605. # return float(mp.exp(-x**c))
  6606. @pytest.mark.parametrize('x, c, ref', [(50, 1, 1.9287498479639178e-22),
  6607. (1000, 0.8,
  6608. 8.131269637872743e-110)])
  6609. def test_sf_isf(self, x, c, ref):
  6610. assert_allclose(stats.weibull_min.sf(x, c), ref, rtol=5e-14)
  6611. assert_allclose(stats.weibull_min.isf(ref, c), x, rtol=5e-14)
  6612. class TestDweibull:
  6613. def test_entropy(self):
  6614. # Test that dweibull entropy follows that of weibull_min.
  6615. # (Generic tests check that the dweibull entropy is consistent
  6616. # with its PDF. As for accuracy, dweibull entropy should be just
  6617. # as accurate as weibull_min entropy. Checks of accuracy against
  6618. # a reference need only be applied to the fundamental distribution -
  6619. # weibull_min.)
  6620. rng = np.random.default_rng(8486259129157041777)
  6621. c = 10**rng.normal(scale=100, size=10)
  6622. res = stats.dweibull.entropy(c)
  6623. ref = stats.weibull_min.entropy(c) - np.log(0.5)
  6624. assert_allclose(res, ref, rtol=1e-15)
  6625. def test_sf(self):
  6626. # test that for positive values the dweibull survival function is half
  6627. # the weibull_min survival function
  6628. rng = np.random.default_rng(8486259129157041777)
  6629. c = 10**rng.normal(scale=1, size=10)
  6630. x = 10 * rng.uniform()
  6631. res = stats.dweibull.sf(x, c)
  6632. ref = 0.5 * stats.weibull_min.sf(x, c)
  6633. assert_allclose(res, ref, rtol=1e-15)
  6634. class TestTruncWeibull:
  6635. def test_pdf_bounds(self):
  6636. # test bounds
  6637. y = stats.truncweibull_min.pdf([0.1, 2.0], 2.0, 0.11, 1.99)
  6638. assert_equal(y, [0.0, 0.0])
  6639. def test_logpdf(self):
  6640. y = stats.truncweibull_min.logpdf(2.0, 1.0, 2.0, np.inf)
  6641. assert_equal(y, 0.0)
  6642. # hand calculation
  6643. y = stats.truncweibull_min.logpdf(2.0, 1.0, 2.0, 4.0)
  6644. assert_allclose(y, 0.14541345786885884)
  6645. def test_ppf_bounds(self):
  6646. # test bounds
  6647. y = stats.truncweibull_min.ppf([0.0, 1.0], 2.0, 0.1, 2.0)
  6648. assert_equal(y, [0.1, 2.0])
  6649. def test_cdf_to_ppf(self):
  6650. q = [0., 0.1, .25, 0.50, 0.75, 0.90, 1.]
  6651. x = stats.truncweibull_min.ppf(q, 2., 0., 3.)
  6652. q_out = stats.truncweibull_min.cdf(x, 2., 0., 3.)
  6653. assert_allclose(q, q_out)
  6654. def test_sf_to_isf(self):
  6655. q = [0., 0.1, .25, 0.50, 0.75, 0.90, 1.]
  6656. x = stats.truncweibull_min.isf(q, 2., 0., 3.)
  6657. q_out = stats.truncweibull_min.sf(x, 2., 0., 3.)
  6658. assert_allclose(q, q_out)
  6659. def test_munp(self):
  6660. c = 2.
  6661. a = 1.
  6662. b = 3.
  6663. def xnpdf(x, n):
  6664. return x**n*stats.truncweibull_min.pdf(x, c, a, b)
  6665. m0 = stats.truncweibull_min.moment(0, c, a, b)
  6666. assert_equal(m0, 1.)
  6667. m1 = stats.truncweibull_min.moment(1, c, a, b)
  6668. m1_expected, _ = quad(lambda x: xnpdf(x, 1), a, b)
  6669. assert_allclose(m1, m1_expected)
  6670. m2 = stats.truncweibull_min.moment(2, c, a, b)
  6671. m2_expected, _ = quad(lambda x: xnpdf(x, 2), a, b)
  6672. assert_allclose(m2, m2_expected)
  6673. m3 = stats.truncweibull_min.moment(3, c, a, b)
  6674. m3_expected, _ = quad(lambda x: xnpdf(x, 3), a, b)
  6675. assert_allclose(m3, m3_expected)
  6676. m4 = stats.truncweibull_min.moment(4, c, a, b)
  6677. m4_expected, _ = quad(lambda x: xnpdf(x, 4), a, b)
  6678. assert_allclose(m4, m4_expected)
  6679. def test_reference_values(self):
  6680. a = 1.
  6681. b = 3.
  6682. c = 2.
  6683. x_med = np.sqrt(1 - np.log(0.5 + np.exp(-(8. + np.log(2.)))))
  6684. cdf = stats.truncweibull_min.cdf(x_med, c, a, b)
  6685. assert_allclose(cdf, 0.5)
  6686. lc = stats.truncweibull_min.logcdf(x_med, c, a, b)
  6687. assert_allclose(lc, -np.log(2.))
  6688. ppf = stats.truncweibull_min.ppf(0.5, c, a, b)
  6689. assert_allclose(ppf, x_med)
  6690. sf = stats.truncweibull_min.sf(x_med, c, a, b)
  6691. assert_allclose(sf, 0.5)
  6692. ls = stats.truncweibull_min.logsf(x_med, c, a, b)
  6693. assert_allclose(ls, -np.log(2.))
  6694. isf = stats.truncweibull_min.isf(0.5, c, a, b)
  6695. assert_allclose(isf, x_med)
  6696. def test_compare_weibull_min(self):
  6697. # Verify that the truncweibull_min distribution gives the same results
  6698. # as the original weibull_min
  6699. x = 1.5
  6700. c = 2.0
  6701. a = 0.0
  6702. b = np.inf
  6703. scale = 3.0
  6704. p = stats.weibull_min.pdf(x, c, scale=scale)
  6705. p_trunc = stats.truncweibull_min.pdf(x, c, a, b, scale=scale)
  6706. assert_allclose(p, p_trunc)
  6707. lp = stats.weibull_min.logpdf(x, c, scale=scale)
  6708. lp_trunc = stats.truncweibull_min.logpdf(x, c, a, b, scale=scale)
  6709. assert_allclose(lp, lp_trunc)
  6710. cdf = stats.weibull_min.cdf(x, c, scale=scale)
  6711. cdf_trunc = stats.truncweibull_min.cdf(x, c, a, b, scale=scale)
  6712. assert_allclose(cdf, cdf_trunc)
  6713. lc = stats.weibull_min.logcdf(x, c, scale=scale)
  6714. lc_trunc = stats.truncweibull_min.logcdf(x, c, a, b, scale=scale)
  6715. assert_allclose(lc, lc_trunc)
  6716. s = stats.weibull_min.sf(x, c, scale=scale)
  6717. s_trunc = stats.truncweibull_min.sf(x, c, a, b, scale=scale)
  6718. assert_allclose(s, s_trunc)
  6719. ls = stats.weibull_min.logsf(x, c, scale=scale)
  6720. ls_trunc = stats.truncweibull_min.logsf(x, c, a, b, scale=scale)
  6721. assert_allclose(ls, ls_trunc)
  6722. # # Also test using a large value x, for which computing the survival
  6723. # # function using the CDF would result in 0.
  6724. s = stats.truncweibull_min.sf(30, 2, a, b, scale=3)
  6725. assert_allclose(s, np.exp(-100))
  6726. ls = stats.truncweibull_min.logsf(30, 2, a, b, scale=3)
  6727. assert_allclose(ls, -100)
  6728. def test_compare_weibull_min2(self):
  6729. # Verify that the truncweibull_min distribution PDF and CDF results
  6730. # are the same as those calculated from truncating weibull_min
  6731. c, a, b = 2.5, 0.25, 1.25
  6732. x = np.linspace(a, b, 100)
  6733. pdf1 = stats.truncweibull_min.pdf(x, c, a, b)
  6734. cdf1 = stats.truncweibull_min.cdf(x, c, a, b)
  6735. norm = stats.weibull_min.cdf(b, c) - stats.weibull_min.cdf(a, c)
  6736. pdf2 = stats.weibull_min.pdf(x, c) / norm
  6737. cdf2 = (stats.weibull_min.cdf(x, c) - stats.weibull_min.cdf(a, c))/norm
  6738. np.testing.assert_allclose(pdf1, pdf2)
  6739. np.testing.assert_allclose(cdf1, cdf2)
  6740. class TestRdist:
  6741. def test_rdist_cdf_gh1285(self):
  6742. # check workaround in rdist._cdf for issue gh-1285.
  6743. distfn = stats.rdist
  6744. values = [0.001, 0.5, 0.999]
  6745. assert_almost_equal(distfn.cdf(distfn.ppf(values, 541.0), 541.0),
  6746. values, decimal=5)
  6747. def test_rdist_beta(self):
  6748. # rdist is a special case of stats.beta
  6749. x = np.linspace(-0.99, 0.99, 10)
  6750. c = 2.7
  6751. assert_almost_equal(0.5*stats.beta(c/2, c/2).pdf((x + 1)/2),
  6752. stats.rdist(c).pdf(x))
  6753. # reference values were computed via mpmath
  6754. # from mpmath import mp
  6755. # mp.dps = 200
  6756. # def rdist_sf_mpmath(x, c):
  6757. # x = mp.mpf(x)
  6758. # c = mp.mpf(c)
  6759. # return float(mp.betainc(c/2, c/2, (x+1)/2, mp.one, regularized=True))
  6760. @pytest.mark.parametrize(
  6761. "x, c, ref",
  6762. [
  6763. (0.0001, 541, 0.49907251345565845),
  6764. (0.1, 241, 0.06000788166249205),
  6765. (0.5, 441, 1.0655898106047832e-29),
  6766. (0.8, 341, 6.025478373732215e-78),
  6767. ]
  6768. )
  6769. def test_rdist_sf(self, x, c, ref):
  6770. assert_allclose(stats.rdist.sf(x, c), ref, rtol=5e-14)
  6771. class TestTrapezoid:
  6772. def test_reduces_to_triang(self):
  6773. modes = [0, 0.3, 0.5, 1]
  6774. for mode in modes:
  6775. x = [0, mode, 1]
  6776. assert_almost_equal(stats.trapezoid.pdf(x, mode, mode),
  6777. stats.triang.pdf(x, mode))
  6778. assert_almost_equal(stats.trapezoid.cdf(x, mode, mode),
  6779. stats.triang.cdf(x, mode))
  6780. def test_reduces_to_uniform(self):
  6781. x = np.linspace(0, 1, 10)
  6782. assert_almost_equal(stats.trapezoid.pdf(x, 0, 1), stats.uniform.pdf(x))
  6783. assert_almost_equal(stats.trapezoid.cdf(x, 0, 1), stats.uniform.cdf(x))
  6784. def test_cases(self):
  6785. # edge cases
  6786. assert_almost_equal(stats.trapezoid.pdf(0, 0, 0), 2)
  6787. assert_almost_equal(stats.trapezoid.pdf(1, 1, 1), 2)
  6788. assert_almost_equal(stats.trapezoid.pdf(0.5, 0, 0.8),
  6789. 1.11111111111111111)
  6790. assert_almost_equal(stats.trapezoid.pdf(0.5, 0.2, 1.0),
  6791. 1.11111111111111111)
  6792. # straightforward case
  6793. assert_almost_equal(stats.trapezoid.pdf(0.1, 0.2, 0.8), 0.625)
  6794. assert_almost_equal(stats.trapezoid.pdf(0.5, 0.2, 0.8), 1.25)
  6795. assert_almost_equal(stats.trapezoid.pdf(0.9, 0.2, 0.8), 0.625)
  6796. assert_almost_equal(stats.trapezoid.cdf(0.1, 0.2, 0.8), 0.03125)
  6797. assert_almost_equal(stats.trapezoid.cdf(0.2, 0.2, 0.8), 0.125)
  6798. assert_almost_equal(stats.trapezoid.cdf(0.5, 0.2, 0.8), 0.5)
  6799. assert_almost_equal(stats.trapezoid.cdf(0.9, 0.2, 0.8), 0.96875)
  6800. assert_almost_equal(stats.trapezoid.cdf(1.0, 0.2, 0.8), 1.0)
  6801. def test_moments_and_entropy(self):
  6802. # issue #11795: improve precision of trapezoid stats
  6803. # Apply formulas from Wikipedia for the following parameters:
  6804. a, b, c, d = -3, -1, 2, 3 # => 1/3, 5/6, -3, 6
  6805. p1, p2, loc, scale = (b-a) / (d-a), (c-a) / (d-a), a, d-a
  6806. h = 2 / (d+c-b-a)
  6807. def moment(n):
  6808. return (h * ((d**(n+2) - c**(n+2)) / (d-c)
  6809. - (b**(n+2) - a**(n+2)) / (b-a)) /
  6810. (n+1) / (n+2))
  6811. mean = moment(1)
  6812. var = moment(2) - mean**2
  6813. entropy = 0.5 * (d-c+b-a) / (d+c-b-a) + np.log(0.5 * (d+c-b-a))
  6814. assert_almost_equal(stats.trapezoid.mean(p1, p2, loc, scale),
  6815. mean, decimal=13)
  6816. assert_almost_equal(stats.trapezoid.var(p1, p2, loc, scale),
  6817. var, decimal=13)
  6818. assert_almost_equal(stats.trapezoid.entropy(p1, p2, loc, scale),
  6819. entropy, decimal=13)
  6820. # Check boundary cases where scipy d=0 or d=1.
  6821. assert_almost_equal(stats.trapezoid.mean(0, 0, -3, 6), -1, decimal=13)
  6822. assert_almost_equal(stats.trapezoid.mean(0, 1, -3, 6), 0, decimal=13)
  6823. assert_almost_equal(stats.trapezoid.var(0, 1, -3, 6), 3, decimal=13)
  6824. def test_trapezoid_vect(self):
  6825. # test that array-valued shapes and arguments are handled
  6826. c = np.array([0.1, 0.2, 0.3])
  6827. d = np.array([0.5, 0.6])[:, None]
  6828. x = np.array([0.15, 0.25, 0.9])
  6829. v = stats.trapezoid.pdf(x, c, d)
  6830. cc, dd, xx = np.broadcast_arrays(c, d, x)
  6831. res = np.empty(xx.size, dtype=xx.dtype)
  6832. ind = np.arange(xx.size)
  6833. for i, x1, c1, d1 in zip(ind, xx.ravel(), cc.ravel(), dd.ravel()):
  6834. res[i] = stats.trapezoid.pdf(x1, c1, d1)
  6835. assert_allclose(v, res.reshape(v.shape), atol=1e-15)
  6836. # Check that the stats() method supports vector arguments.
  6837. v = np.asarray(stats.trapezoid.stats(c, d, moments="mvsk"))
  6838. cc, dd = np.broadcast_arrays(c, d)
  6839. res = np.empty((cc.size, 4)) # 4 stats returned per value
  6840. ind = np.arange(cc.size)
  6841. for i, c1, d1 in zip(ind, cc.ravel(), dd.ravel()):
  6842. res[i] = stats.trapezoid.stats(c1, d1, moments="mvsk")
  6843. assert_allclose(v, res.T.reshape(v.shape), atol=1e-15)
  6844. def test_trapezoid_fit_convergence_gh23503(self):
  6845. # gh-23503 reported that trapezoid.fit would consistently converge to a
  6846. # triangular distribution unless starting values were provided. Check that this
  6847. # is resolved.
  6848. # Generate test data from a trapezoidal distribution
  6849. rng = np.random.default_rng(23842359234598263956)
  6850. true_args = 0.3, 0.7, -1, 2
  6851. true_dist = stats.trapezoid(*true_args)
  6852. x = true_dist.rvs(1000, random_state=rng)
  6853. # fit to data
  6854. fitted_args = stats.trapezoid.fit(x)
  6855. # Should not converge to triangular distribution (c=d=1)
  6856. fitted_c, fitted_d = fitted_args[:2]
  6857. assert not np.allclose(fitted_c, 1, atol=0.1)
  6858. assert not np.allclose(fitted_d, 1, atol=0.1)
  6859. # objective function is better than with true values of parameters
  6860. true_llf = stats.trapezoid.nnlf(true_args, x)
  6861. fitted_llf = stats.trapezoid.nnlf(fitted_args, x)
  6862. assert fitted_llf < true_llf
  6863. class TestTriang:
  6864. def test_edge_cases(self):
  6865. with np.errstate(all='raise'):
  6866. assert_equal(stats.triang.pdf(0, 0), 2.)
  6867. assert_equal(stats.triang.pdf(0.5, 0), 1.)
  6868. assert_equal(stats.triang.pdf(1, 0), 0.)
  6869. assert_equal(stats.triang.pdf(0, 1), 0)
  6870. assert_equal(stats.triang.pdf(0.5, 1), 1.)
  6871. assert_equal(stats.triang.pdf(1, 1), 2)
  6872. assert_equal(stats.triang.cdf(0., 0.), 0.)
  6873. assert_equal(stats.triang.cdf(0.5, 0.), 0.75)
  6874. assert_equal(stats.triang.cdf(1.0, 0.), 1.0)
  6875. assert_equal(stats.triang.cdf(0., 1.), 0.)
  6876. assert_equal(stats.triang.cdf(0.5, 1.), 0.25)
  6877. assert_equal(stats.triang.cdf(1., 1.), 1)
  6878. class TestMaxwell:
  6879. # reference values were computed with wolfram alpha
  6880. # erfc(x/sqrt(2)) + sqrt(2/pi) * x * e^(-x^2/2)
  6881. @pytest.mark.parametrize("x, ref",
  6882. [(20, 2.2138865931011177e-86),
  6883. (0.01, 0.999999734046458435)])
  6884. def test_sf(self, x, ref):
  6885. assert_allclose(stats.maxwell.sf(x), ref, rtol=1e-14)
  6886. # reference values were computed with wolfram alpha
  6887. # sqrt(2) * sqrt(Q^(-1)(3/2, q))
  6888. @pytest.mark.parametrize("q, ref",
  6889. [(0.001, 4.033142223656157022),
  6890. (0.9999847412109375, 0.0385743284050381),
  6891. (2**-55, 8.95564974719481)])
  6892. def test_isf(self, q, ref):
  6893. assert_allclose(stats.maxwell.isf(q), ref, rtol=1e-15)
  6894. def test_logcdf(self):
  6895. # Reference value computed with mpmath.
  6896. ref = -1.8729310110194814e-17
  6897. logcdf = stats.maxwell.logcdf(9)
  6898. assert_allclose(logcdf, ref, rtol=5e-15)
  6899. def test_logsf(self):
  6900. # Reference value computed with mpmath.
  6901. ref = -2.6596152026762177e-25
  6902. logsf = stats.maxwell.logsf(1e-8)
  6903. assert_allclose(logsf, ref, rtol=5e-15)
  6904. class TestMielke:
  6905. def test_moments(self):
  6906. k, s = 4.642, 0.597
  6907. # n-th moment exists only if n < s
  6908. assert_equal(stats.mielke(k, s).moment(1), np.inf)
  6909. assert_equal(stats.mielke(k, 1.0).moment(1), np.inf)
  6910. assert_(np.isfinite(stats.mielke(k, 1.01).moment(1)))
  6911. def test_burr_equivalence(self):
  6912. x = np.linspace(0.01, 100, 50)
  6913. k, s = 2.45, 5.32
  6914. assert_allclose(stats.burr.pdf(x, s, k/s), stats.mielke.pdf(x, k, s))
  6915. class TestBurr:
  6916. def test_endpoints_7491(self):
  6917. # gh-7491
  6918. # Compute the pdf at the left endpoint dst.a.
  6919. data = [
  6920. [stats.fisk, (1,), 1],
  6921. [stats.burr, (0.5, 2), 1],
  6922. [stats.burr, (1, 1), 1],
  6923. [stats.burr, (2, 0.5), 1],
  6924. [stats.burr12, (1, 0.5), 0.5],
  6925. [stats.burr12, (1, 1), 1.0],
  6926. [stats.burr12, (1, 2), 2.0]]
  6927. ans = [_f.pdf(_f.a, *_args) for _f, _args, _ in data]
  6928. correct = [_correct_ for _f, _args, _correct_ in data]
  6929. assert_array_almost_equal(ans, correct)
  6930. ans = [_f.logpdf(_f.a, *_args) for _f, _args, _ in data]
  6931. correct = [np.log(_correct_) for _f, _args, _correct_ in data]
  6932. assert_array_almost_equal(ans, correct)
  6933. def test_burr_stats_9544(self):
  6934. # gh-9544. Test from gh-9978
  6935. c, d = 5.0, 3
  6936. mean, variance = stats.burr(c, d).stats()
  6937. # mean = sc.beta(3 + 1/5, 1. - 1/5) * 3 = 1.4110263...
  6938. # var = sc.beta(3 + 2 / 5, 1. - 2 / 5) * 3 -
  6939. # (sc.beta(3 + 1 / 5, 1. - 1 / 5) * 3) ** 2
  6940. mean_hc, variance_hc = 1.4110263183925857, 0.22879948026191643
  6941. assert_allclose(mean, mean_hc)
  6942. assert_allclose(variance, variance_hc)
  6943. def test_burr_nan_mean_var_9544(self):
  6944. # gh-9544. Test from gh-9978
  6945. c, d = 0.5, 3
  6946. mean, variance = stats.burr(c, d).stats()
  6947. assert_(np.isnan(mean))
  6948. assert_(np.isnan(variance))
  6949. c, d = 1.5, 3
  6950. mean, variance = stats.burr(c, d).stats()
  6951. assert_(np.isfinite(mean))
  6952. assert_(np.isnan(variance))
  6953. c, d = 0.5, 3
  6954. e1, e2, e3, e4 = stats.burr._munp(np.array([1, 2, 3, 4]), c, d)
  6955. assert_(np.isnan(e1))
  6956. assert_(np.isnan(e2))
  6957. assert_(np.isnan(e3))
  6958. assert_(np.isnan(e4))
  6959. c, d = 1.5, 3
  6960. e1, e2, e3, e4 = stats.burr._munp([1, 2, 3, 4], c, d)
  6961. assert_(np.isfinite(e1))
  6962. assert_(np.isnan(e2))
  6963. assert_(np.isnan(e3))
  6964. assert_(np.isnan(e4))
  6965. c, d = 2.5, 3
  6966. e1, e2, e3, e4 = stats.burr._munp([1, 2, 3, 4], c, d)
  6967. assert_(np.isfinite(e1))
  6968. assert_(np.isfinite(e2))
  6969. assert_(np.isnan(e3))
  6970. assert_(np.isnan(e4))
  6971. c, d = 3.5, 3
  6972. e1, e2, e3, e4 = stats.burr._munp([1, 2, 3, 4], c, d)
  6973. assert_(np.isfinite(e1))
  6974. assert_(np.isfinite(e2))
  6975. assert_(np.isfinite(e3))
  6976. assert_(np.isnan(e4))
  6977. c, d = 4.5, 3
  6978. e1, e2, e3, e4 = stats.burr._munp([1, 2, 3, 4], c, d)
  6979. assert_(np.isfinite(e1))
  6980. assert_(np.isfinite(e2))
  6981. assert_(np.isfinite(e3))
  6982. assert_(np.isfinite(e4))
  6983. def test_burr_isf(self):
  6984. # reference values were computed via the reference distribution, e.g.
  6985. # mp.dps = 100
  6986. # Burr(c=5, d=3).isf([0.1, 1e-10, 1e-20, 1e-40])
  6987. c, d = 5.0, 3.0
  6988. q = [0.1, 1e-10, 1e-20, 1e-40]
  6989. ref = [1.9469686558286508, 124.57309395989076, 12457.309396155173,
  6990. 124573093.96155174]
  6991. assert_allclose(stats.burr.isf(q, c, d), ref, rtol=1e-14)
  6992. class TestBurr12:
  6993. @pytest.mark.parametrize('scale, expected',
  6994. [(1.0, 2.3283064359965952e-170),
  6995. (3.5, 5.987114417447875e-153)])
  6996. def test_delta_cdf(self, scale, expected):
  6997. # Expected value computed with mpmath:
  6998. #
  6999. # def burr12sf(x, c, d, scale):
  7000. # x = mpmath.mpf(x)
  7001. # c = mpmath.mpf(c)
  7002. # d = mpmath.mpf(d)
  7003. # scale = mpmath.mpf(scale)
  7004. # return (mpmath.mp.one + (x/scale)**c)**(-d)
  7005. #
  7006. # >>> import mpmath
  7007. # >>> mpmath.mp.dps = 60
  7008. # >>> float(burr12sf(2e5, 4, 8, 1) - burr12sf(4e5, 4, 8, 1))
  7009. # 2.3283064359965952e-170
  7010. # >>> float(burr12sf(2e5, 4, 8, 3.5) - burr12sf(4e5, 4, 8, 3.5))
  7011. # 5.987114417447875e-153
  7012. #
  7013. delta = stats.burr12._delta_cdf(2e5, 4e5, 4, 8, scale=scale)
  7014. assert_allclose(delta, expected, rtol=1e-13)
  7015. def test_moments_edge(self):
  7016. # gh-18838 reported that burr12 moments could be invalid; see above.
  7017. # Check that this is resolved in an edge case where c*d == n, and
  7018. # compare the results against those produced by Mathematica, e.g.
  7019. # `SinghMaddalaDistribution[2, 2, 1]` at Wolfram Alpha.
  7020. c, d = 2, 2
  7021. mean = np.pi/4
  7022. var = 1 - np.pi**2/16
  7023. skew = np.pi**3/(32*var**1.5)
  7024. kurtosis = np.nan
  7025. ref = [mean, var, skew, kurtosis]
  7026. res = stats.burr12(c, d).stats('mvsk')
  7027. assert_allclose(res, ref, rtol=1e-14)
  7028. # Reference values were computed with mpmath using mp.dps = 80
  7029. # and then cast to float.
  7030. @pytest.mark.parametrize(
  7031. 'p, c, d, ref',
  7032. [(1e-12, 20, 0.5, 15.848931924611135),
  7033. (1e-19, 20, 0.5, 79.43282347242815),
  7034. (1e-12, 0.25, 35, 2.0888618213462466),
  7035. (1e-80, 0.25, 35, 1360930951.7972188)]
  7036. )
  7037. def test_isf_near_zero(self, p, c, d, ref):
  7038. x = stats.burr12.isf(p, c, d)
  7039. assert_allclose(x, ref, rtol=1e-14)
  7040. class TestStudentizedRange:
  7041. # For alpha = .05, .01, and .001, and for each value of
  7042. # v = [1, 3, 10, 20, 120, inf], a Q was picked from each table for
  7043. # k = [2, 8, 14, 20].
  7044. # these arrays are written with `k` as column, and `v` as rows.
  7045. # Q values are taken from table 3:
  7046. # https://www.jstor.org/stable/2237810
  7047. q05 = [17.97, 45.40, 54.33, 59.56,
  7048. 4.501, 8.853, 10.35, 11.24,
  7049. 3.151, 5.305, 6.028, 6.467,
  7050. 2.950, 4.768, 5.357, 5.714,
  7051. 2.800, 4.363, 4.842, 5.126,
  7052. 2.772, 4.286, 4.743, 5.012]
  7053. q01 = [90.03, 227.2, 271.8, 298.0,
  7054. 8.261, 15.64, 18.22, 19.77,
  7055. 4.482, 6.875, 7.712, 8.226,
  7056. 4.024, 5.839, 6.450, 6.823,
  7057. 3.702, 5.118, 5.562, 5.827,
  7058. 3.643, 4.987, 5.400, 5.645]
  7059. q001 = [900.3, 2272, 2718, 2980,
  7060. 18.28, 34.12, 39.69, 43.05,
  7061. 6.487, 9.352, 10.39, 11.03,
  7062. 5.444, 7.313, 7.966, 8.370,
  7063. 4.772, 6.039, 6.448, 6.695,
  7064. 4.654, 5.823, 6.191, 6.411]
  7065. qs = np.concatenate((q05, q01, q001))
  7066. ps = [.95, .99, .999]
  7067. vs = [1, 3, 10, 20, 120, np.inf]
  7068. ks = [2, 8, 14, 20]
  7069. data = list(zip(product(ps, vs, ks), qs))
  7070. # A small selection of large-v cases generated with R's `ptukey`
  7071. # Each case is in the format (q, k, v, r_result)
  7072. r_data = [
  7073. (0.1, 3, 9001, 0.002752818526842),
  7074. (1, 10, 1000, 0.000526142388912),
  7075. (1, 3, np.inf, 0.240712641229283),
  7076. (4, 3, np.inf, 0.987012338626815),
  7077. (1, 10, np.inf, 0.000519869467083),
  7078. ]
  7079. @pytest.mark.slow
  7080. def test_cdf_against_tables(self):
  7081. for pvk, q in self.data:
  7082. p_expected, v, k = pvk
  7083. res_p = stats.studentized_range.cdf(q, k, v)
  7084. assert_allclose(res_p, p_expected, rtol=1e-4)
  7085. @pytest.mark.xslow
  7086. def test_ppf_against_tables(self):
  7087. for pvk, q_expected in self.data:
  7088. p, v, k = pvk
  7089. res_q = stats.studentized_range.ppf(p, k, v)
  7090. assert_allclose(res_q, q_expected, rtol=5e-4)
  7091. path_prefix = os.path.dirname(__file__)
  7092. relative_path = "data/studentized_range_mpmath_ref.json"
  7093. with open(os.path.join(path_prefix, relative_path)) as file:
  7094. pregenerated_data = json.load(file)
  7095. @pytest.mark.parametrize("case_result", pregenerated_data["cdf_data"])
  7096. def test_cdf_against_mp(self, case_result):
  7097. src_case = case_result["src_case"]
  7098. mp_result = case_result["mp_result"]
  7099. qkv = src_case["q"], src_case["k"], src_case["v"]
  7100. res = stats.studentized_range.cdf(*qkv)
  7101. assert_allclose(res, mp_result,
  7102. atol=src_case["expected_atol"],
  7103. rtol=src_case["expected_rtol"])
  7104. @pytest.mark.parametrize("case_result", pregenerated_data["pdf_data"])
  7105. def test_pdf_against_mp(self, case_result):
  7106. src_case = case_result["src_case"]
  7107. mp_result = case_result["mp_result"]
  7108. qkv = src_case["q"], src_case["k"], src_case["v"]
  7109. res = stats.studentized_range.pdf(*qkv)
  7110. assert_allclose(res, mp_result,
  7111. atol=src_case["expected_atol"],
  7112. rtol=src_case["expected_rtol"])
  7113. @pytest.mark.xslow
  7114. @pytest.mark.xfail_on_32bit("intermittent RuntimeWarning: invalid value.")
  7115. @pytest.mark.parametrize("case_result", pregenerated_data["moment_data"])
  7116. def test_moment_against_mp(self, case_result):
  7117. src_case = case_result["src_case"]
  7118. mp_result = case_result["mp_result"]
  7119. mkv = src_case["m"], src_case["k"], src_case["v"]
  7120. # Silence invalid value encountered warnings. Actual problems will be
  7121. # caught by the result comparison.
  7122. with np.errstate(invalid='ignore'):
  7123. res = stats.studentized_range.moment(*mkv)
  7124. assert_allclose(res, mp_result,
  7125. atol=src_case["expected_atol"],
  7126. rtol=src_case["expected_rtol"])
  7127. @pytest.mark.slow
  7128. def test_pdf_integration(self):
  7129. k, v = 3, 10
  7130. # Test whether PDF integration is 1 like it should be.
  7131. res = quad(stats.studentized_range.pdf, 0, np.inf, args=(k, v))
  7132. assert_allclose(res[0], 1)
  7133. @pytest.mark.xslow
  7134. def test_pdf_against_cdf(self):
  7135. k, v = 3, 10
  7136. # Test whether the integrated PDF matches the CDF using cumulative
  7137. # integration. Use a small step size to reduce error due to the
  7138. # summation. This is slow, but tests the results well.
  7139. x = np.arange(0, 10, step=0.01)
  7140. y_cdf = stats.studentized_range.cdf(x, k, v)[1:]
  7141. y_pdf_raw = stats.studentized_range.pdf(x, k, v)
  7142. y_pdf_cumulative = cumulative_trapezoid(y_pdf_raw, x)
  7143. # Because of error caused by the summation, use a relatively large rtol
  7144. assert_allclose(y_pdf_cumulative, y_cdf, rtol=1e-4)
  7145. @pytest.mark.parametrize("r_case_result", r_data)
  7146. def test_cdf_against_r(self, r_case_result):
  7147. # Test large `v` values using R
  7148. q, k, v, r_res = r_case_result
  7149. with np.errstate(invalid='ignore'):
  7150. res = stats.studentized_range.cdf(q, k, v)
  7151. assert_allclose(res, r_res)
  7152. @pytest.mark.xslow
  7153. @pytest.mark.xfail_on_32bit("intermittent RuntimeWarning: invalid value.")
  7154. def test_moment_vectorization(self):
  7155. # Test moment broadcasting. Calls `_munp` directly because
  7156. # `rv_continuous.moment` is broken at time of writing. See gh-12192
  7157. # Silence invalid value encountered warnings. Actual problems will be
  7158. # caught by the result comparison.
  7159. with np.errstate(invalid='ignore'):
  7160. m = stats.studentized_range._munp([1, 2], [4, 5], [10, 11])
  7161. assert_allclose(m.shape, (2,))
  7162. with pytest.raises(ValueError, match="...could not be broadcast..."):
  7163. stats.studentized_range._munp(1, [4, 5], [10, 11, 12])
  7164. @pytest.mark.xslow
  7165. def test_fitstart_valid(self):
  7166. with warnings.catch_warnings(), np.errstate(invalid="ignore"):
  7167. # the integration warning message may differ
  7168. warnings.simplefilter("ignore", IntegrationWarning)
  7169. k, df, _, _ = stats.studentized_range._fitstart([1, 2, 3])
  7170. assert_(stats.studentized_range._argcheck(k, df))
  7171. def test_infinite_df(self):
  7172. # Check that the CDF and PDF infinite and normal integrators
  7173. # roughly match for a high df case
  7174. res = stats.studentized_range.pdf(3, 10, np.inf)
  7175. res_finite = stats.studentized_range.pdf(3, 10, 99999)
  7176. assert_allclose(res, res_finite, atol=1e-4, rtol=1e-4)
  7177. res = stats.studentized_range.cdf(3, 10, np.inf)
  7178. res_finite = stats.studentized_range.cdf(3, 10, 99999)
  7179. assert_allclose(res, res_finite, atol=1e-4, rtol=1e-4)
  7180. def test_df_cutoff(self):
  7181. # Test that the CDF and PDF properly switch integrators at df=100,000.
  7182. # The infinite integrator should be different enough that it fails
  7183. # an allclose assertion. Also sanity check that using the same
  7184. # integrator does pass the allclose with a 1-df difference, which
  7185. # should be tiny.
  7186. res = stats.studentized_range.pdf(3, 10, 100000)
  7187. res_finite = stats.studentized_range.pdf(3, 10, 99999)
  7188. res_sanity = stats.studentized_range.pdf(3, 10, 99998)
  7189. assert_raises(AssertionError, assert_allclose, res, res_finite,
  7190. atol=1e-6, rtol=1e-6)
  7191. assert_allclose(res_finite, res_sanity, atol=1e-6, rtol=1e-6)
  7192. res = stats.studentized_range.cdf(3, 10, 100000)
  7193. res_finite = stats.studentized_range.cdf(3, 10, 99999)
  7194. res_sanity = stats.studentized_range.cdf(3, 10, 99998)
  7195. assert_raises(AssertionError, assert_allclose, res, res_finite,
  7196. atol=1e-6, rtol=1e-6)
  7197. assert_allclose(res_finite, res_sanity, atol=1e-6, rtol=1e-6)
  7198. def test_clipping(self):
  7199. # The result of this computation was -9.9253938401489e-14 on some
  7200. # systems. The correct result is very nearly zero, but should not be
  7201. # negative.
  7202. q, k, v = 34.6413996195345746, 3, 339
  7203. p = stats.studentized_range.sf(q, k, v)
  7204. assert_allclose(p, 0, atol=1e-10)
  7205. assert p >= 0
  7206. class TestTukeyLambda:
  7207. @pytest.mark.parametrize(
  7208. 'lam',
  7209. [0.0, -1.0, -2.0, np.array([[-1.0], [0.0], [-2.0]])]
  7210. )
  7211. def test_pdf_nonpositive_lambda(self, lam):
  7212. # Make sure that Tukey-Lambda distribution correctly handles
  7213. # non-positive lambdas.
  7214. # This is a crude test--it just checks that all the PDF values
  7215. # are finite and greater than 0.
  7216. x = np.linspace(-5.0, 5.0, 101)
  7217. p = stats.tukeylambda.pdf(x, lam)
  7218. assert np.isfinite(p).all()
  7219. assert (p > 0.0).all()
  7220. def test_pdf_mixed_lambda(self):
  7221. # Another crude test of the behavior of the PDF method.
  7222. x = np.linspace(-5.0, 5.0, 101)
  7223. lam = np.array([[-1.0], [0.0], [2.0]])
  7224. p = stats.tukeylambda.pdf(x, lam)
  7225. assert np.isfinite(p).all()
  7226. # For p[0] and p[1], where lam <= 0, the support is (-inf, inf),
  7227. # so the PDF should be nonzero everywhere (assuming we aren't so
  7228. # far in the tails that we get underflow).
  7229. assert (p[:2] > 0.0).all()
  7230. # For p[2], where lam=2.0, the support is [-0.5, 0.5], so in pdf(x),
  7231. # some values should be positive and some should be 0.
  7232. assert (p[2] > 0.0).any()
  7233. assert (p[2] == 0.0).any()
  7234. def test_support(self):
  7235. lam = np.array([-1.75, -0.5, 0.0, 0.25, 0.5, 2.0])
  7236. a, b = stats.tukeylambda.support(lam)
  7237. expected_b = np.array([np.inf, np.inf, np.inf, 4, 2, 0.5])
  7238. assert_equal(b, expected_b)
  7239. assert_equal(a, -expected_b)
  7240. def test_pdf_support_boundary(self):
  7241. # Verify that tukeylambda.pdf() doesn't generate a
  7242. # warning when evaluated at the bounds of the support.
  7243. # For lam=0.5, the support is (-2, 2).
  7244. p = stats.tukeylambda.pdf([-2.0, 2.0], 0.5)
  7245. assert_equal(p, [0.0, 0.0])
  7246. def test_tukeylambda_stats_ticket_1545(self):
  7247. # Some test for the variance and kurtosis of the Tukey Lambda distr.
  7248. # See test_tukeylamdba_stats.py for more tests.
  7249. mv = stats.tukeylambda.stats(0, moments='mvsk')
  7250. # Known exact values:
  7251. expected = [0, np.pi**2/3, 0, 1.2]
  7252. assert_almost_equal(mv, expected, decimal=10)
  7253. mv = stats.tukeylambda.stats(3.13, moments='mvsk')
  7254. # 'expected' computed with mpmath.
  7255. expected = [0, 0.0269220858861465102, 0, -0.898062386219224104]
  7256. assert_almost_equal(mv, expected, decimal=10)
  7257. mv = stats.tukeylambda.stats(0.14, moments='mvsk')
  7258. # 'expected' computed with mpmath.
  7259. expected = [0, 2.11029702221450250, 0, -0.02708377353223019456]
  7260. assert_almost_equal(mv, expected, decimal=10)
  7261. class TestLevy:
  7262. def test_levy_cdf_ppf(self):
  7263. # Test levy.cdf, including small arguments.
  7264. x = np.array([1000, 1.0, 0.5, 0.1, 0.01, 0.001])
  7265. # Expected values were calculated separately with mpmath.
  7266. # E.g.
  7267. # >>> mpmath.mp.dps = 100
  7268. # >>> x = mpmath.mp.mpf('0.01')
  7269. # >>> cdf = mpmath.erfc(mpmath.sqrt(1/(2*x)))
  7270. expected = np.array([0.9747728793699604,
  7271. 0.3173105078629141,
  7272. 0.1572992070502851,
  7273. 0.0015654022580025495,
  7274. 1.523970604832105e-23,
  7275. 1.795832784800726e-219])
  7276. y = stats.levy.cdf(x)
  7277. assert_allclose(y, expected, rtol=1e-10)
  7278. # ppf(expected) should get us back to x.
  7279. xx = stats.levy.ppf(expected)
  7280. assert_allclose(xx, x, rtol=1e-13)
  7281. def test_levy_sf(self):
  7282. # Large values, far into the tail of the distribution.
  7283. x = np.array([1e15, 1e25, 1e35, 1e50])
  7284. # Expected values were calculated with mpmath.
  7285. expected = np.array([2.5231325220201597e-08,
  7286. 2.52313252202016e-13,
  7287. 2.52313252202016e-18,
  7288. 7.978845608028653e-26])
  7289. y = stats.levy.sf(x)
  7290. assert_allclose(y, expected, rtol=1e-14)
  7291. # The expected values for levy.isf(p) were calculated with mpmath.
  7292. # For loc=0 and scale=1, the inverse SF can be computed with
  7293. #
  7294. # import mpmath
  7295. #
  7296. # def levy_invsf(p):
  7297. # return 1/(2*mpmath.erfinv(p)**2)
  7298. #
  7299. # For example, with mpmath.mp.dps set to 60, float(levy_invsf(1e-20))
  7300. # returns 6.366197723675814e+39.
  7301. #
  7302. @pytest.mark.parametrize('p, expected_isf',
  7303. [(1e-20, 6.366197723675814e+39),
  7304. (1e-8, 6366197723675813.0),
  7305. (0.375, 4.185810119346273),
  7306. (0.875, 0.42489442055310134),
  7307. (0.999, 0.09235685880262713),
  7308. (0.9999999962747097, 0.028766845244146945)])
  7309. def test_levy_isf(self, p, expected_isf):
  7310. x = stats.levy.isf(p)
  7311. assert_allclose(x, expected_isf, atol=5e-15)
  7312. def test_levy_logcdf(self):
  7313. x = 1e50
  7314. ref = -7.978845608028653e-26
  7315. logcdf = stats.levy.logcdf(x)
  7316. assert_allclose(logcdf, ref, rtol=5e-15)
  7317. def test_levy_logsf(self):
  7318. x = 5e-3
  7319. ref = -2.0884875837625492e-45
  7320. logsf = stats.levy.logsf(x)
  7321. assert_allclose(logsf, ref, rtol=5e-15)
  7322. def test_540_567():
  7323. # test for nan returned in tickets 540, 567
  7324. assert_almost_equal(stats.norm.cdf(-1.7624320982), 0.03899815971089126,
  7325. decimal=10, err_msg='test_540_567')
  7326. assert_almost_equal(stats.norm.cdf(-1.7624320983), 0.038998159702449846,
  7327. decimal=10, err_msg='test_540_567')
  7328. assert_almost_equal(stats.norm.cdf(1.38629436112, loc=0.950273420309,
  7329. scale=0.204423758009),
  7330. 0.98353464004309321,
  7331. decimal=10, err_msg='test_540_567')
  7332. @pytest.mark.skipif(DOCSTRINGS_STRIPPED, reason="docstrings stripped")
  7333. def test_regression_ticket_1421():
  7334. assert_('pdf(x, mu, loc=0, scale=1)' not in stats.poisson.__doc__)
  7335. assert_('pmf(x,' in stats.poisson.__doc__)
  7336. def test_nan_arguments_gh_issue_1362():
  7337. with np.errstate(invalid='ignore'):
  7338. assert_(np.isnan(stats.t.logcdf(1, np.nan)))
  7339. assert_(np.isnan(stats.t.cdf(1, np.nan)))
  7340. assert_(np.isnan(stats.t.logsf(1, np.nan)))
  7341. assert_(np.isnan(stats.t.sf(1, np.nan)))
  7342. assert_(np.isnan(stats.t.pdf(1, np.nan)))
  7343. assert_(np.isnan(stats.t.logpdf(1, np.nan)))
  7344. assert_(np.isnan(stats.t.ppf(1, np.nan)))
  7345. assert_(np.isnan(stats.t.isf(1, np.nan)))
  7346. assert_(np.isnan(stats.bernoulli.logcdf(np.nan, 0.5)))
  7347. assert_(np.isnan(stats.bernoulli.cdf(np.nan, 0.5)))
  7348. assert_(np.isnan(stats.bernoulli.logsf(np.nan, 0.5)))
  7349. assert_(np.isnan(stats.bernoulli.sf(np.nan, 0.5)))
  7350. assert_(np.isnan(stats.bernoulli.pmf(np.nan, 0.5)))
  7351. assert_(np.isnan(stats.bernoulli.logpmf(np.nan, 0.5)))
  7352. assert_(np.isnan(stats.bernoulli.ppf(np.nan, 0.5)))
  7353. assert_(np.isnan(stats.bernoulli.isf(np.nan, 0.5)))
  7354. def test_frozen_fit_ticket_1536():
  7355. rng = np.random.default_rng(5678)
  7356. true = np.array([0.25, 0., 0.5])
  7357. x = stats.lognorm.rvs(true[0], true[1], true[2], size=100, random_state=rng)
  7358. with np.errstate(divide='ignore'):
  7359. params = np.array(stats.lognorm.fit(x, floc=0.))
  7360. assert_almost_equal(params, true, decimal=2)
  7361. params = np.array(stats.lognorm.fit(x, fscale=0.5, loc=0))
  7362. assert_almost_equal(params, true, decimal=2)
  7363. params = np.array(stats.lognorm.fit(x, f0=0.25, loc=0))
  7364. assert_almost_equal(params, true, decimal=2)
  7365. params = np.array(stats.lognorm.fit(x, f0=0.25, floc=0))
  7366. assert_almost_equal(params, true, decimal=2)
  7367. rng = np.random.default_rng(5678)
  7368. loc = 1
  7369. floc = 0.9
  7370. x = stats.norm.rvs(loc, 2., size=100, random_state=rng)
  7371. params = np.array(stats.norm.fit(x, floc=floc))
  7372. expected = np.array([floc, np.sqrt(((x-floc)**2).mean())])
  7373. assert_almost_equal(params, expected, decimal=4)
  7374. def test_regression_ticket_1530():
  7375. # Check the starting value works for Cauchy distribution fit.
  7376. rng = np.random.default_rng(654321)
  7377. rvs = stats.cauchy.rvs(size=100, random_state=rng)
  7378. params = stats.cauchy.fit(rvs)
  7379. expected = (0.045, 1.142)
  7380. assert_almost_equal(params, expected, decimal=1)
  7381. def test_gh_pr_4806():
  7382. # Check starting values for Cauchy distribution fit.
  7383. rng = np.random.RandomState(1234)
  7384. x = rng.randn(42)
  7385. for offset in 10000.0, 1222333444.0:
  7386. loc, scale = stats.cauchy.fit(x + offset)
  7387. assert_allclose(loc, offset, atol=1.0)
  7388. assert_allclose(scale, 0.6, atol=1.0)
  7389. def test_poisson_logpmf_ticket_1436():
  7390. assert_(np.isfinite(stats.poisson.logpmf(1500, 200)))
  7391. def test_powerlaw_stats():
  7392. """Test the powerlaw stats function.
  7393. This unit test is also a regression test for ticket 1548.
  7394. The exact values are:
  7395. mean:
  7396. mu = a / (a + 1)
  7397. variance:
  7398. sigma**2 = a / ((a + 2) * (a + 1) ** 2)
  7399. skewness:
  7400. One formula (see https://en.wikipedia.org/wiki/Skewness) is
  7401. gamma_1 = (E[X**3] - 3*mu*E[X**2] + 2*mu**3) / sigma**3
  7402. A short calculation shows that E[X**k] is a / (a + k), so gamma_1
  7403. can be implemented as
  7404. n = a/(a+3) - 3*(a/(a+1))*a/(a+2) + 2*(a/(a+1))**3
  7405. d = sqrt(a/((a+2)*(a+1)**2)) ** 3
  7406. gamma_1 = n/d
  7407. Either by simplifying, or by a direct calculation of mu_3 / sigma**3,
  7408. one gets the more concise formula:
  7409. gamma_1 = -2.0 * ((a - 1) / (a + 3)) * sqrt((a + 2) / a)
  7410. kurtosis: (See https://en.wikipedia.org/wiki/Kurtosis)
  7411. The excess kurtosis is
  7412. gamma_2 = mu_4 / sigma**4 - 3
  7413. A bit of calculus and algebra (sympy helps) shows that
  7414. mu_4 = 3*a*(3*a**2 - a + 2) / ((a+1)**4 * (a+2) * (a+3) * (a+4))
  7415. so
  7416. gamma_2 = 3*(3*a**2 - a + 2) * (a+2) / (a*(a+3)*(a+4)) - 3
  7417. which can be rearranged to
  7418. gamma_2 = 6 * (a**3 - a**2 - 6*a + 2) / (a*(a+3)*(a+4))
  7419. """
  7420. cases = [(1.0, (0.5, 1./12, 0.0, -1.2)),
  7421. (2.0, (2./3, 2./36, -0.56568542494924734, -0.6))]
  7422. for a, exact_mvsk in cases:
  7423. mvsk = stats.powerlaw.stats(a, moments="mvsk")
  7424. assert_array_almost_equal(mvsk, exact_mvsk)
  7425. def test_powerlaw_edge():
  7426. # Regression test for gh-3986.
  7427. p = stats.powerlaw.logpdf(0, 1)
  7428. assert_equal(p, 0.0)
  7429. def test_exponpow_edge():
  7430. # Regression test for gh-3982.
  7431. p = stats.exponpow.logpdf(0, 1)
  7432. assert_equal(p, 0.0)
  7433. # Check pdf and logpdf at x = 0 for other values of b.
  7434. p = stats.exponpow.pdf(0, [0.25, 1.0, 1.5])
  7435. assert_equal(p, [np.inf, 1.0, 0.0])
  7436. p = stats.exponpow.logpdf(0, [0.25, 1.0, 1.5])
  7437. assert_equal(p, [np.inf, 0.0, -np.inf])
  7438. class TestGenGamma:
  7439. def test_gengamma_edge(self):
  7440. # Regression test for gh-3985.
  7441. p = stats.gengamma.pdf(0, 1, 1)
  7442. assert_equal(p, 1.0)
  7443. @pytest.mark.parametrize("a, c, ref, tol",
  7444. [(1500000.0, 1, 8.529426144018633, 1e-15),
  7445. (1e+30, 1, 35.95771492811536, 1e-15),
  7446. (1e+100, 1, 116.54819318290696, 1e-15),
  7447. (3e3, 1, 5.422011196659015, 1e-13),
  7448. (3e6, -1e100, -236.29663213396054, 1e-15),
  7449. (3e60, 1e-100, 1.3925371786831085e+102, 1e-15)])
  7450. def test_gengamma_extreme_entropy(self, a, c, ref, tol):
  7451. # The reference values were calculated with mpmath:
  7452. # from mpmath import mp
  7453. # mp.dps = 500
  7454. #
  7455. # def gen_entropy(a, c):
  7456. # a, c = mp.mpf(a), mp.mpf(c)
  7457. # val = mp.digamma(a)
  7458. # h = (a * (mp.one - val) + val/c + mp.loggamma(a) - mp.log(abs(c)))
  7459. # return float(h)
  7460. assert_allclose(stats.gengamma.entropy(a, c), ref, rtol=tol)
  7461. def test_gengamma_endpoint_with_neg_c(self):
  7462. p = stats.gengamma.pdf(0, 1, -1)
  7463. assert p == 0.0
  7464. logp = stats.gengamma.logpdf(0, 1, -1)
  7465. assert logp == -np.inf
  7466. def test_gengamma_munp(self):
  7467. # Regression tests for gh-4724.
  7468. p = stats.gengamma._munp(-2, 200, 1.)
  7469. assert_almost_equal(p, 1./199/198)
  7470. p = stats.gengamma._munp(-2, 10, 1.)
  7471. assert_almost_equal(p, 1./9/8)
  7472. def test_gengamma_logpdf_broadcasting_gh24574(self):
  7473. # gh-24574 reported a broadcasting error when `x` included 0s.
  7474. assert_allclose(stats.gengamma.logpdf([0, 1, 1], 1, -1), [-np.inf, -1, -1])
  7475. def test_ksone_fit_freeze():
  7476. # Regression test for ticket #1638.
  7477. d = np.array(
  7478. [-0.18879233, 0.15734249, 0.18695107, 0.27908787, -0.248649,
  7479. -0.2171497, 0.12233512, 0.15126419, 0.03119282, 0.4365294,
  7480. 0.08930393, -0.23509903, 0.28231224, -0.09974875, -0.25196048,
  7481. 0.11102028, 0.1427649, 0.10176452, 0.18754054, 0.25826724,
  7482. 0.05988819, 0.0531668, 0.21906056, 0.32106729, 0.2117662,
  7483. 0.10886442, 0.09375789, 0.24583286, -0.22968366, -0.07842391,
  7484. -0.31195432, -0.21271196, 0.1114243, -0.13293002, 0.01331725,
  7485. -0.04330977, -0.09485776, -0.28434547, 0.22245721, -0.18518199,
  7486. -0.10943985, -0.35243174, 0.06897665, -0.03553363, -0.0701746,
  7487. -0.06037974, 0.37670779, -0.21684405])
  7488. with np.errstate(invalid='ignore'):
  7489. with warnings.catch_warnings():
  7490. warnings.filterwarnings(
  7491. "ignore",
  7492. "The maximum number of subdivisions .50. has been achieved.",
  7493. IntegrationWarning,
  7494. )
  7495. warnings.filterwarnings(
  7496. "ignore",
  7497. "floating point number truncated to an integer",
  7498. RuntimeWarning,
  7499. )
  7500. stats.ksone.fit(d)
  7501. def test_norm_logcdf():
  7502. # Test precision of the logcdf of the normal distribution.
  7503. # This precision was enhanced in ticket 1614.
  7504. x = -np.asarray(list(range(0, 120, 4)))
  7505. # Values from R
  7506. expected = [-0.69314718, -10.36010149, -35.01343716, -75.41067300,
  7507. -131.69539607, -203.91715537, -292.09872100, -396.25241451,
  7508. -516.38564863, -652.50322759, -804.60844201, -972.70364403,
  7509. -1156.79057310, -1356.87055173, -1572.94460885, -1805.01356068,
  7510. -2053.07806561, -2317.13866238, -2597.19579746, -2893.24984493,
  7511. -3205.30112136, -3533.34989701, -3877.39640444, -4237.44084522,
  7512. -4613.48339520, -5005.52420869, -5413.56342187, -5837.60115548,
  7513. -6277.63751711, -6733.67260303]
  7514. assert_allclose(stats.norm().logcdf(x), expected, atol=1e-8)
  7515. # also test the complex-valued code path
  7516. assert_allclose(stats.norm().logcdf(x + 1e-14j).real, expected, atol=1e-8)
  7517. # test the accuracy: d(logcdf)/dx = pdf / cdf \equiv exp(logpdf - logcdf)
  7518. deriv = (stats.norm.logcdf(x + 1e-10j)/1e-10).imag
  7519. deriv_expected = np.exp(stats.norm.logpdf(x) - stats.norm.logcdf(x))
  7520. assert_allclose(deriv, deriv_expected, atol=1e-10)
  7521. def test_levy_l_sf():
  7522. # Test levy_l.sf for small arguments.
  7523. x = np.array([-0.016, -0.01, -0.005, -0.0015])
  7524. # Expected values were calculated with mpmath.
  7525. expected = np.array([2.6644463892359302e-15,
  7526. 1.523970604832107e-23,
  7527. 2.0884875837625492e-45,
  7528. 5.302850374626878e-147])
  7529. y = stats.levy_l.sf(x)
  7530. assert_allclose(y, expected, rtol=1e-13)
  7531. def test_levy_l_isf():
  7532. # Test roundtrip sf(isf(p)), including a small input value.
  7533. p = np.array([3.0e-15, 0.25, 0.99])
  7534. x = stats.levy_l.isf(p)
  7535. q = stats.levy_l.sf(x)
  7536. assert_allclose(q, p, rtol=5e-14)
  7537. def test_hypergeom_interval_1802():
  7538. # these two had endless loops
  7539. assert_equal(stats.hypergeom.interval(.95, 187601, 43192, 757),
  7540. (152.0, 197.0))
  7541. assert_equal(stats.hypergeom.interval(.945, 187601, 43192, 757),
  7542. (152.0, 197.0))
  7543. # this was working also before
  7544. assert_equal(stats.hypergeom.interval(.94, 187601, 43192, 757),
  7545. (153.0, 196.0))
  7546. # degenerate case .a == .b
  7547. assert_equal(stats.hypergeom.ppf(0.02, 100, 100, 8), 8)
  7548. assert_equal(stats.hypergeom.ppf(1, 100, 100, 8), 8)
  7549. def test_distribution_too_many_args():
  7550. rng = np.random.default_rng(5976604568)
  7551. # Check that a TypeError is raised when too many args are given to a method
  7552. # Regression test for ticket 1815.
  7553. x = np.linspace(0.1, 0.7, num=5)
  7554. assert_raises(TypeError, stats.gamma.pdf, x, 2, 3, loc=1.0)
  7555. assert_raises(TypeError, stats.gamma.pdf, x, 2, 3, 4, loc=1.0)
  7556. assert_raises(TypeError, stats.gamma.pdf, x, 2, 3, 4, 5)
  7557. assert_raises(TypeError, stats.gamma.pdf, x, 2, 3, loc=1.0, scale=0.5)
  7558. assert_raises(TypeError, stats.gamma.rvs, 2., 3, loc=1.0, scale=0.5,
  7559. random_state=rng)
  7560. assert_raises(TypeError, stats.gamma.cdf, x, 2., 3, loc=1.0, scale=0.5)
  7561. assert_raises(TypeError, stats.gamma.ppf, x, 2., 3, loc=1.0, scale=0.5)
  7562. assert_raises(TypeError, stats.gamma.stats, 2., 3, loc=1.0, scale=0.5)
  7563. assert_raises(TypeError, stats.gamma.entropy, 2., 3, loc=1.0, scale=0.5)
  7564. assert_raises(TypeError, stats.gamma.fit, x, 2., 3, loc=1.0, scale=0.5)
  7565. # These should not give errors
  7566. stats.gamma.pdf(x, 2, 3) # loc=3
  7567. stats.gamma.pdf(x, 2, 3, 4) # loc=3, scale=4
  7568. stats.gamma.stats(2., 3)
  7569. stats.gamma.stats(2., 3, 4)
  7570. stats.gamma.stats(2., 3, 4, 'mv')
  7571. stats.gamma.rvs(2., 3, 4, 5, random_state=rng)
  7572. stats.gamma.fit(stats.gamma.rvs(2., size=7, random_state=rng), 2.)
  7573. # Also for a discrete distribution
  7574. stats.geom.pmf(x, 2, loc=3) # no error, loc=3
  7575. assert_raises(TypeError, stats.geom.pmf, x, 2, 3, 4)
  7576. assert_raises(TypeError, stats.geom.pmf, x, 2, 3, loc=4)
  7577. # And for distributions with 0, 2 and 3 args respectively
  7578. assert_raises(TypeError, stats.expon.pdf, x, 3, loc=1.0)
  7579. assert_raises(TypeError, stats.exponweib.pdf, x, 3, 4, 5, loc=1.0)
  7580. assert_raises(TypeError, stats.exponweib.pdf, x, 3, 4, 5, 0.1, 0.1)
  7581. assert_raises(TypeError, stats.ncf.pdf, x, 3, 4, 5, 6, loc=1.0)
  7582. assert_raises(TypeError, stats.ncf.pdf, x, 3, 4, 5, 6, 1.0, scale=0.5)
  7583. stats.ncf.pdf(x, 3, 4, 5, 6, 1.0) # 3 args, plus loc/scale
  7584. def test_ncx2_tails_ticket_955():
  7585. # Trac #955 -- check that the cdf computed by special functions
  7586. # matches the integrated pdf
  7587. a = stats.ncx2.cdf(np.arange(20, 25, 0.2), 2, 1.07458615e+02)
  7588. b = stats.ncx2._cdfvec(np.arange(20, 25, 0.2), 2, 1.07458615e+02)
  7589. assert_allclose(a, b, rtol=1e-3, atol=0)
  7590. def test_ncx2_tails_pdf():
  7591. # ncx2.pdf does not return nans in extreme tails(example from gh-1577)
  7592. # NB: this is to check that nan_to_num is not needed in ncx2.pdf
  7593. with warnings.catch_warnings():
  7594. warnings.simplefilter('error', RuntimeWarning)
  7595. assert_equal(stats.ncx2.pdf(1, np.arange(340, 350), 2), 0)
  7596. logval = stats.ncx2.logpdf(1, np.arange(340, 350), 2)
  7597. assert_(np.isneginf(logval).all())
  7598. # Verify logpdf has extended precision when pdf underflows to 0
  7599. with warnings.catch_warnings():
  7600. warnings.simplefilter('error', RuntimeWarning)
  7601. assert_equal(stats.ncx2.pdf(10000, 3, 12), 0)
  7602. assert_allclose(stats.ncx2.logpdf(10000, 3, 12), -4662.444377524883)
  7603. @pytest.mark.parametrize('method, expected', [
  7604. ('cdf', np.array([2.497951336e-09, 3.437288941e-10])),
  7605. ('pdf', np.array([1.238579980e-07, 1.710041145e-08])),
  7606. ('logpdf', np.array([-15.90413011, -17.88416331])),
  7607. ('ppf', np.array([4.865182052, 7.017182271]))
  7608. ])
  7609. def test_ncx2_zero_nc(method, expected):
  7610. # gh-5441
  7611. # ncx2 with nc=0 is identical to chi2
  7612. # Comparison to R (v3.5.1)
  7613. # > options(digits=10)
  7614. # > pchisq(0.1, df=10, ncp=c(0,4))
  7615. # > dchisq(0.1, df=10, ncp=c(0,4))
  7616. # > dchisq(0.1, df=10, ncp=c(0,4), log=TRUE)
  7617. # > qchisq(0.1, df=10, ncp=c(0,4))
  7618. result = getattr(stats.ncx2, method)(0.1, nc=[0, 4], df=10)
  7619. assert_allclose(result, expected, atol=1e-15)
  7620. def test_ncx2_zero_nc_rvs():
  7621. # gh-5441
  7622. # ncx2 with nc=0 is identical to chi2
  7623. result = stats.ncx2.rvs(df=10, nc=0, random_state=1)
  7624. expected = stats.chi2.rvs(df=10, random_state=1)
  7625. assert_allclose(result, expected, atol=1e-15)
  7626. def test_ncx2_gh12731():
  7627. # test that gh-12731 is resolved; previously these were all 0.5
  7628. nc = 10**np.arange(5, 10)
  7629. assert_equal(stats.ncx2.cdf(1e4, df=1, nc=nc), 0)
  7630. def test_ncx2_gh8665():
  7631. # test that gh-8665 is resolved; previously this tended to nonzero value
  7632. x = np.array([4.99515382e+00, 1.07617327e+01, 2.31854502e+01,
  7633. 4.99515382e+01, 1.07617327e+02, 2.31854502e+02,
  7634. 4.99515382e+02, 1.07617327e+03, 2.31854502e+03,
  7635. 4.99515382e+03, 1.07617327e+04, 2.31854502e+04,
  7636. 4.99515382e+04])
  7637. nu, lam = 20, 499.51538166556196
  7638. sf = stats.ncx2.sf(x, df=nu, nc=lam)
  7639. # computed in R. Couldn't find a survival function implementation
  7640. # options(digits=16)
  7641. # x <- c(4.99515382e+00, 1.07617327e+01, 2.31854502e+01, 4.99515382e+01,
  7642. # 1.07617327e+02, 2.31854502e+02, 4.99515382e+02, 1.07617327e+03,
  7643. # 2.31854502e+03, 4.99515382e+03, 1.07617327e+04, 2.31854502e+04,
  7644. # 4.99515382e+04)
  7645. # nu <- 20
  7646. # lam <- 499.51538166556196
  7647. # 1 - pchisq(x, df = nu, ncp = lam)
  7648. sf_expected = [1.0000000000000000, 1.0000000000000000, 1.0000000000000000,
  7649. 1.0000000000000000, 1.0000000000000000, 0.9999999999999888,
  7650. 0.6646525582135460, 0.0000000000000000, 0.0000000000000000,
  7651. 0.0000000000000000, 0.0000000000000000, 0.0000000000000000,
  7652. 0.0000000000000000]
  7653. assert_allclose(sf, sf_expected, atol=1e-12)
  7654. def test_ncx2_gh11777():
  7655. # regression test for gh-11777:
  7656. # At high values of degrees of freedom df, ensure the pdf of ncx2 does
  7657. # not get clipped to zero when the non-centrality parameter is
  7658. # sufficiently less than df
  7659. df = 6700
  7660. nc = 5300
  7661. x = np.linspace(stats.ncx2.ppf(0.001, df, nc),
  7662. stats.ncx2.ppf(0.999, df, nc), num=10000)
  7663. ncx2_pdf = stats.ncx2.pdf(x, df, nc)
  7664. gauss_approx = stats.norm.pdf(x, df + nc, np.sqrt(2 * df + 4 * nc))
  7665. # use huge tolerance as we're only looking for obvious discrepancy
  7666. assert_allclose(ncx2_pdf, gauss_approx, atol=1e-4)
  7667. # Expected values for foldnorm.sf were computed with mpmath:
  7668. #
  7669. # from mpmath import mp
  7670. # mp.dps = 60
  7671. # def foldcauchy_sf(x, c):
  7672. # x = mp.mpf(x)
  7673. # c = mp.mpf(c)
  7674. # return mp.one - (mp.atan(x - c) + mp.atan(x + c))/mp.pi
  7675. #
  7676. # E.g.
  7677. #
  7678. # >>> float(foldcauchy_sf(2, 1))
  7679. # 0.35241638234956674
  7680. #
  7681. @pytest.mark.parametrize('x, c, expected',
  7682. [(2, 1, 0.35241638234956674),
  7683. (2, 2, 0.5779791303773694),
  7684. (1e13, 1, 6.366197723675813e-14),
  7685. (2e16, 1, 3.183098861837907e-17),
  7686. (1e13, 2e11, 6.368745221764519e-14),
  7687. (0.125, 200, 0.999998010612169)])
  7688. def test_foldcauchy_sf(x, c, expected):
  7689. sf = stats.foldcauchy.sf(x, c)
  7690. assert_allclose(sf, expected, 2e-15)
  7691. # The same mpmath code shown in the comments above test_foldcauchy_sf()
  7692. # is used to create these expected values.
  7693. @pytest.mark.parametrize('x, expected',
  7694. [(2, 0.2951672353008665),
  7695. (1e13, 6.366197723675813e-14),
  7696. (2e16, 3.183098861837907e-17),
  7697. (5e80, 1.2732395447351629e-81)])
  7698. def test_halfcauchy_sf(x, expected):
  7699. sf = stats.halfcauchy.sf(x)
  7700. assert_allclose(sf, expected, 2e-15)
  7701. # Expected value computed with mpmath:
  7702. # expected = mp.cot(mp.pi*p/2)
  7703. @pytest.mark.parametrize('p, expected',
  7704. [(0.9999995, 7.853981633329977e-07),
  7705. (0.975, 0.039290107007669675),
  7706. (0.5, 1.0),
  7707. (0.01, 63.65674116287158),
  7708. (1e-14, 63661977236758.13),
  7709. (5e-80, 1.2732395447351627e+79)])
  7710. def test_halfcauchy_isf(p, expected):
  7711. x = stats.halfcauchy.isf(p)
  7712. assert_allclose(x, expected)
  7713. def test_foldnorm_zero():
  7714. # Parameter value c=0 was not enabled, see gh-2399.
  7715. rv = stats.foldnorm(0, scale=1)
  7716. assert_equal(rv.cdf(0), 0) # rv.cdf(0) previously resulted in: nan
  7717. # Expected values for foldnorm.sf were computed with mpmath:
  7718. #
  7719. # from mpmath import mp
  7720. # mp.dps = 60
  7721. # def foldnorm_sf(x, c):
  7722. # x = mp.mpf(x)
  7723. # c = mp.mpf(c)
  7724. # return mp.ncdf(-x+c) + mp.ncdf(-x-c)
  7725. #
  7726. # E.g.
  7727. #
  7728. # >>> float(foldnorm_sf(2, 1))
  7729. # 0.16000515196308715
  7730. #
  7731. @pytest.mark.parametrize('x, c, expected',
  7732. [(2, 1, 0.16000515196308715),
  7733. (20, 1, 8.527223952630977e-81),
  7734. (10, 15, 0.9999997133484281),
  7735. (25, 15, 7.619853024160525e-24)])
  7736. def test_foldnorm_sf(x, c, expected):
  7737. sf = stats.foldnorm.sf(x, c)
  7738. assert_allclose(sf, expected, 1e-14)
  7739. def test_stats_shapes_argcheck():
  7740. # stats method was failing for vector shapes if some of the values
  7741. # were outside of the allowed range, see gh-2678
  7742. mv3 = stats.invgamma.stats([0.0, 0.5, 1.0], 1, 0.5) # 0 is not a legal `a`
  7743. mv2 = stats.invgamma.stats([0.5, 1.0], 1, 0.5)
  7744. mv2_augmented = tuple(np.r_[np.nan, _] for _ in mv2)
  7745. assert_equal(mv2_augmented, mv3)
  7746. # -1 is not a legal shape parameter
  7747. mv3 = stats.lognorm.stats([2, 2.4, -1])
  7748. mv2 = stats.lognorm.stats([2, 2.4])
  7749. mv2_augmented = tuple(np.r_[_, np.nan] for _ in mv2)
  7750. assert_equal(mv2_augmented, mv3)
  7751. # FIXME: this is only a quick-and-dirty test of a quick-and-dirty bugfix.
  7752. # stats method with multiple shape parameters is not properly vectorized
  7753. # anyway, so some distributions may or may not fail.
  7754. # Test subclassing distributions w/ explicit shapes
  7755. class _distr_gen(stats.rv_continuous):
  7756. def _pdf(self, x, a):
  7757. return 42
  7758. class _distr2_gen(stats.rv_continuous):
  7759. def _cdf(self, x, a):
  7760. return 42 * a + x
  7761. class _distr3_gen(stats.rv_continuous):
  7762. def _pdf(self, x, a, b):
  7763. return a + b
  7764. def _cdf(self, x, a):
  7765. # Different # of shape params from _pdf, to be able to check that
  7766. # inspection catches the inconsistency.
  7767. return 42 * a + x
  7768. class _distr6_gen(stats.rv_continuous):
  7769. # Two shape parameters (both _pdf and _cdf defined, consistent shapes.)
  7770. def _pdf(self, x, a, b):
  7771. return a*x + b
  7772. def _cdf(self, x, a, b):
  7773. return 42 * a + x
  7774. class TestSubclassingExplicitShapes:
  7775. # Construct a distribution w/ explicit shapes parameter and test it.
  7776. def test_correct_shapes(self):
  7777. dummy_distr = _distr_gen(name='dummy', shapes='a')
  7778. assert_equal(dummy_distr.pdf(1, a=1), 42)
  7779. def test_wrong_shapes_1(self):
  7780. dummy_distr = _distr_gen(name='dummy', shapes='A')
  7781. assert_raises(TypeError, dummy_distr.pdf, 1, **dict(a=1))
  7782. def test_wrong_shapes_2(self):
  7783. dummy_distr = _distr_gen(name='dummy', shapes='a, b, c')
  7784. dct = dict(a=1, b=2, c=3)
  7785. assert_raises(TypeError, dummy_distr.pdf, 1, **dct)
  7786. def test_shapes_string(self):
  7787. # shapes must be a string
  7788. dct = dict(name='dummy', shapes=42)
  7789. assert_raises(TypeError, _distr_gen, **dct)
  7790. def test_shapes_identifiers_1(self):
  7791. # shapes must be a comma-separated list of valid python identifiers
  7792. dct = dict(name='dummy', shapes='(!)')
  7793. assert_raises(SyntaxError, _distr_gen, **dct)
  7794. def test_shapes_identifiers_2(self):
  7795. dct = dict(name='dummy', shapes='4chan')
  7796. assert_raises(SyntaxError, _distr_gen, **dct)
  7797. def test_shapes_identifiers_3(self):
  7798. dct = dict(name='dummy', shapes='m(fti)')
  7799. assert_raises(SyntaxError, _distr_gen, **dct)
  7800. def test_shapes_identifiers_nodefaults(self):
  7801. dct = dict(name='dummy', shapes='a=2')
  7802. assert_raises(SyntaxError, _distr_gen, **dct)
  7803. def test_shapes_args(self):
  7804. dct = dict(name='dummy', shapes='*args')
  7805. assert_raises(SyntaxError, _distr_gen, **dct)
  7806. def test_shapes_kwargs(self):
  7807. dct = dict(name='dummy', shapes='**kwargs')
  7808. assert_raises(SyntaxError, _distr_gen, **dct)
  7809. def test_shapes_keywords(self):
  7810. # python keywords cannot be used for shape parameters
  7811. dct = dict(name='dummy', shapes='a, b, c, lambda')
  7812. assert_raises(SyntaxError, _distr_gen, **dct)
  7813. def test_shapes_signature(self):
  7814. # test explicit shapes which agree w/ the signature of _pdf
  7815. class _dist_gen(stats.rv_continuous):
  7816. def _pdf(self, x, a):
  7817. return stats.norm._pdf(x) * a
  7818. dist = _dist_gen(shapes='a')
  7819. assert_equal(dist.pdf(0.5, a=2), stats.norm.pdf(0.5)*2)
  7820. def test_shapes_signature_inconsistent(self):
  7821. # test explicit shapes which do not agree w/ the signature of _pdf
  7822. class _dist_gen(stats.rv_continuous):
  7823. def _pdf(self, x, a):
  7824. return stats.norm._pdf(x) * a
  7825. dist = _dist_gen(shapes='a, b')
  7826. assert_raises(TypeError, dist.pdf, 0.5, **dict(a=1, b=2))
  7827. def test_star_args(self):
  7828. # test _pdf with only starargs
  7829. # NB: **kwargs of pdf will never reach _pdf
  7830. class _dist_gen(stats.rv_continuous):
  7831. def _pdf(self, x, *args):
  7832. extra_kwarg = args[0]
  7833. return stats.norm._pdf(x) * extra_kwarg
  7834. dist = _dist_gen(shapes='extra_kwarg')
  7835. assert_equal(dist.pdf(0.5, extra_kwarg=33), stats.norm.pdf(0.5)*33)
  7836. assert_equal(dist.pdf(0.5, 33), stats.norm.pdf(0.5)*33)
  7837. assert_raises(TypeError, dist.pdf, 0.5, **dict(xxx=33))
  7838. def test_star_args_2(self):
  7839. # test _pdf with named & starargs
  7840. # NB: **kwargs of pdf will never reach _pdf
  7841. class _dist_gen(stats.rv_continuous):
  7842. def _pdf(self, x, offset, *args):
  7843. extra_kwarg = args[0]
  7844. return stats.norm._pdf(x) * extra_kwarg + offset
  7845. dist = _dist_gen(shapes='offset, extra_kwarg')
  7846. assert_equal(dist.pdf(0.5, offset=111, extra_kwarg=33),
  7847. stats.norm.pdf(0.5)*33 + 111)
  7848. assert_equal(dist.pdf(0.5, 111, 33),
  7849. stats.norm.pdf(0.5)*33 + 111)
  7850. def test_extra_kwarg(self):
  7851. # **kwargs to _pdf are ignored.
  7852. # this is a limitation of the framework (_pdf(x, *goodargs))
  7853. class _distr_gen(stats.rv_continuous):
  7854. def _pdf(self, x, *args, **kwargs):
  7855. # _pdf should handle *args, **kwargs itself. Here "handling"
  7856. # is ignoring *args and looking for ``extra_kwarg`` and using
  7857. # that.
  7858. extra_kwarg = kwargs.pop('extra_kwarg', 1)
  7859. return stats.norm._pdf(x) * extra_kwarg
  7860. dist = _distr_gen(shapes='extra_kwarg')
  7861. assert_equal(dist.pdf(1, extra_kwarg=3), stats.norm.pdf(1))
  7862. def test_shapes_empty_string(self):
  7863. # shapes='' is equivalent to shapes=None
  7864. class _dist_gen(stats.rv_continuous):
  7865. def _pdf(self, x):
  7866. return stats.norm.pdf(x)
  7867. dist = _dist_gen(shapes='')
  7868. assert_equal(dist.pdf(0.5), stats.norm.pdf(0.5))
  7869. class TestSubclassingNoShapes:
  7870. # Construct a distribution w/o explicit shapes parameter and test it.
  7871. def test_only__pdf(self):
  7872. dummy_distr = _distr_gen(name='dummy')
  7873. assert_equal(dummy_distr.pdf(1, a=1), 42)
  7874. def test_only__cdf(self):
  7875. # _pdf is determined from _cdf by taking numerical derivative
  7876. dummy_distr = _distr2_gen(name='dummy')
  7877. assert_almost_equal(dummy_distr.pdf(1, a=1), 1)
  7878. @pytest.mark.skipif(DOCSTRINGS_STRIPPED, reason="docstring stripped")
  7879. def test_signature_inspection(self):
  7880. # check that _pdf signature inspection works correctly, and is used in
  7881. # the class docstring
  7882. dummy_distr = _distr_gen(name='dummy')
  7883. assert_equal(dummy_distr.numargs, 1)
  7884. assert_equal(dummy_distr.shapes, 'a')
  7885. res = re.findall(r'logpdf\(x, a, loc=0, scale=1\)',
  7886. dummy_distr.__doc__)
  7887. assert_(len(res) == 1)
  7888. @pytest.mark.skipif(DOCSTRINGS_STRIPPED, reason="docstring stripped")
  7889. def test_signature_inspection_2args(self):
  7890. # same for 2 shape params and both _pdf and _cdf defined
  7891. dummy_distr = _distr6_gen(name='dummy')
  7892. assert_equal(dummy_distr.numargs, 2)
  7893. assert_equal(dummy_distr.shapes, 'a, b')
  7894. res = re.findall(r'logpdf\(x, a, b, loc=0, scale=1\)',
  7895. dummy_distr.__doc__)
  7896. assert_(len(res) == 1)
  7897. def test_signature_inspection_2args_incorrect_shapes(self):
  7898. # both _pdf and _cdf defined, but shapes are inconsistent: raises
  7899. assert_raises(TypeError, _distr3_gen, name='dummy')
  7900. def test_defaults_raise(self):
  7901. # default arguments should raise
  7902. class _dist_gen(stats.rv_continuous):
  7903. def _pdf(self, x, a=42):
  7904. return 42
  7905. assert_raises(TypeError, _dist_gen, **dict(name='dummy'))
  7906. def test_starargs_raise(self):
  7907. # without explicit shapes, *args are not allowed
  7908. class _dist_gen(stats.rv_continuous):
  7909. def _pdf(self, x, a, *args):
  7910. return 42
  7911. assert_raises(TypeError, _dist_gen, **dict(name='dummy'))
  7912. def test_kwargs_raise(self):
  7913. # without explicit shapes, **kwargs are not allowed
  7914. class _dist_gen(stats.rv_continuous):
  7915. def _pdf(self, x, a, **kwargs):
  7916. return 42
  7917. assert_raises(TypeError, _dist_gen, **dict(name='dummy'))
  7918. @pytest.mark.skipif(DOCSTRINGS_STRIPPED, reason="docstring stripped")
  7919. def test_docstrings():
  7920. badones = [r',\s*,', r'\(\s*,', r'^\s*:']
  7921. for distname in stats.__all__:
  7922. dist = getattr(stats, distname)
  7923. if isinstance(dist, (stats.rv_discrete | stats.rv_continuous)):
  7924. for regex in badones:
  7925. assert_(re.search(regex, dist.__doc__) is None)
  7926. def test_infinite_input():
  7927. assert_almost_equal(stats.skellam.sf(np.inf, 10, 11), 0)
  7928. assert_almost_equal(stats.ncx2._cdf(np.inf, 8, 0.1), 1)
  7929. def test_lomax_accuracy():
  7930. # regression test for gh-4033
  7931. p = stats.lomax.ppf(stats.lomax.cdf(1e-100, 1), 1)
  7932. assert_allclose(p, 1e-100)
  7933. def test_truncexpon_accuracy():
  7934. # regression test for gh-4035
  7935. p = stats.truncexpon.ppf(stats.truncexpon.cdf(1e-100, 1), 1)
  7936. assert_allclose(p, 1e-100)
  7937. def test_rayleigh_accuracy():
  7938. # regression test for gh-4034
  7939. p = stats.rayleigh.isf(stats.rayleigh.sf(9, 1), 1)
  7940. assert_almost_equal(p, 9.0, decimal=15)
  7941. def test_genextreme_give_no_warnings():
  7942. """regression test for gh-6219"""
  7943. with warnings.catch_warnings(record=True) as w:
  7944. warnings.simplefilter("always")
  7945. stats.genextreme.cdf(.5, 0)
  7946. stats.genextreme.pdf(.5, 0)
  7947. stats.genextreme.ppf(.5, 0)
  7948. stats.genextreme.logpdf(-np.inf, 0.0)
  7949. number_of_warnings_thrown = len(w)
  7950. assert_equal(number_of_warnings_thrown, 0)
  7951. def test_moments_gh22400():
  7952. # Regression test for gh-22400
  7953. # Check for correct results at c=0 with no warnings. While we're at it,
  7954. # check that NaN and sufficiently negative input produce NaNs, and output
  7955. # with `c=1` also agrees with reference values.
  7956. res = np.asarray(stats.genextreme.stats([0.0, np.nan, 1, -1.5], moments='mvsk'))
  7957. # Reference values for c=0 (Wikipedia)
  7958. mean = np.euler_gamma
  7959. var = np.pi**2 / 6
  7960. skew = 12 * np.sqrt(6) * special.zeta(3) / np.pi**3
  7961. kurt = 12 / 5
  7962. ref_0 = [mean, var, skew, kurt]
  7963. ref_1 = ref_3 = [np.nan]*4
  7964. ref_2 = [0, 1, -2, 6] # Wolfram Alpha, MaxStableDistribution[0, 1, -1]
  7965. assert_allclose(res[:, 0], ref_0, rtol=1e-14)
  7966. assert_equal(res[:, 1], ref_1)
  7967. assert_allclose(res[:, 2], ref_2, rtol=1e-14)
  7968. assert_equal(res[:, 3], ref_3)
  7969. def test_genextreme_entropy():
  7970. # regression test for gh-5181
  7971. euler_gamma = 0.5772156649015329
  7972. h = stats.genextreme.entropy(-1.0)
  7973. assert_allclose(h, 2*euler_gamma + 1, rtol=1e-14)
  7974. h = stats.genextreme.entropy(0)
  7975. assert_allclose(h, euler_gamma + 1, rtol=1e-14)
  7976. h = stats.genextreme.entropy(1.0)
  7977. assert_equal(h, 1)
  7978. h = stats.genextreme.entropy(-2.0, scale=10)
  7979. assert_allclose(h, euler_gamma*3 + np.log(10) + 1, rtol=1e-14)
  7980. h = stats.genextreme.entropy(10)
  7981. assert_allclose(h, -9*euler_gamma + 1, rtol=1e-14)
  7982. h = stats.genextreme.entropy(-10)
  7983. assert_allclose(h, 11*euler_gamma + 1, rtol=1e-14)
  7984. def test_genextreme_sf_isf():
  7985. # Expected values were computed using mpmath:
  7986. #
  7987. # import mpmath
  7988. #
  7989. # def mp_genextreme_sf(x, xi, mu=0, sigma=1):
  7990. # # Formula from wikipedia, which has a sign convention for xi that
  7991. # # is the opposite of scipy's shape parameter.
  7992. # if xi != 0:
  7993. # t = mpmath.power(1 + ((x - mu)/sigma)*xi, -1/xi)
  7994. # else:
  7995. # t = mpmath.exp(-(x - mu)/sigma)
  7996. # return 1 - mpmath.exp(-t)
  7997. #
  7998. # >>> mpmath.mp.dps = 1000
  7999. # >>> s = mp_genextreme_sf(mpmath.mp.mpf("1e8"), mpmath.mp.mpf("0.125"))
  8000. # >>> float(s)
  8001. # 1.6777205262585625e-57
  8002. # >>> s = mp_genextreme_sf(mpmath.mp.mpf("7.98"), mpmath.mp.mpf("-0.125"))
  8003. # >>> float(s)
  8004. # 1.52587890625e-21
  8005. # >>> s = mp_genextreme_sf(mpmath.mp.mpf("7.98"), mpmath.mp.mpf("0"))
  8006. # >>> float(s)
  8007. # 0.00034218086528426593
  8008. x = 1e8
  8009. s = stats.genextreme.sf(x, -0.125)
  8010. assert_allclose(s, 1.6777205262585625e-57)
  8011. x2 = stats.genextreme.isf(s, -0.125)
  8012. assert_allclose(x2, x)
  8013. x = 7.98
  8014. s = stats.genextreme.sf(x, 0.125)
  8015. assert_allclose(s, 1.52587890625e-21)
  8016. x2 = stats.genextreme.isf(s, 0.125)
  8017. assert_allclose(x2, x)
  8018. x = 7.98
  8019. s = stats.genextreme.sf(x, 0)
  8020. assert_allclose(s, 0.00034218086528426593)
  8021. x2 = stats.genextreme.isf(s, 0)
  8022. assert_allclose(x2, x)
  8023. def test_burr12_ppf_small_arg():
  8024. prob = 1e-16
  8025. quantile = stats.burr12.ppf(prob, 2, 3)
  8026. # The expected quantile was computed using mpmath:
  8027. # >>> import mpmath
  8028. # >>> mpmath.mp.dps = 100
  8029. # >>> prob = mpmath.mpf('1e-16')
  8030. # >>> c = mpmath.mpf(2)
  8031. # >>> d = mpmath.mpf(3)
  8032. # >>> float(((1-prob)**(-1/d) - 1)**(1/c))
  8033. # 5.7735026918962575e-09
  8034. assert_allclose(quantile, 5.7735026918962575e-09)
  8035. def test_invweibull_fit():
  8036. """
  8037. Test fitting invweibull to data.
  8038. Here is a the same calculation in R:
  8039. > library(evd)
  8040. > library(fitdistrplus)
  8041. > x = c(1, 1.25, 2, 2.5, 2.8, 3, 3.8, 4, 5, 8, 10, 12, 64, 99)
  8042. > result = fitdist(x, 'frechet', control=list(reltol=1e-13),
  8043. + fix.arg=list(loc=0), start=list(shape=2, scale=3))
  8044. > result
  8045. Fitting of the distribution ' frechet ' by maximum likelihood
  8046. Parameters:
  8047. estimate Std. Error
  8048. shape 1.048482 0.2261815
  8049. scale 3.099456 0.8292887
  8050. Fixed parameters:
  8051. value
  8052. loc 0
  8053. """
  8054. def optimizer(func, x0, args=(), disp=0):
  8055. return fmin(func, x0, args=args, disp=disp, xtol=1e-12, ftol=1e-12)
  8056. x = np.array([1, 1.25, 2, 2.5, 2.8, 3, 3.8, 4, 5, 8, 10, 12, 64, 99])
  8057. c, loc, scale = stats.invweibull.fit(x, floc=0, optimizer=optimizer)
  8058. assert_allclose(c, 1.048482, rtol=5e-6)
  8059. assert loc == 0
  8060. assert_allclose(scale, 3.099456, rtol=5e-6)
  8061. # Expected values were computed with mpmath.
  8062. @pytest.mark.parametrize('x, c, expected',
  8063. [(3, 1.5, 0.175064510070713299327),
  8064. (2000, 1.5, 1.11802773877318715787e-5),
  8065. (2000, 9.25, 2.92060308832269637092e-31),
  8066. (1e15, 1.5, 3.16227766016837933199884e-23)])
  8067. def test_invweibull_sf(x, c, expected):
  8068. computed = stats.invweibull.sf(x, c)
  8069. assert_allclose(computed, expected, rtol=1e-15)
  8070. # Expected values were computed with mpmath.
  8071. @pytest.mark.parametrize('p, c, expected',
  8072. [(0.5, 2.5, 1.15789669836468183976),
  8073. (3e-18, 5, 3195.77171838060906447)])
  8074. def test_invweibull_isf(p, c, expected):
  8075. computed = stats.invweibull.isf(p, c)
  8076. assert_allclose(computed, expected, rtol=1e-15)
  8077. @pytest.mark.parametrize(
  8078. 'df1,df2,x',
  8079. [(2, 2, [-0.5, 0.2, 1.0, 2.3]),
  8080. (4, 11, [-0.5, 0.2, 1.0, 2.3]),
  8081. (7, 17, [1, 2, 3, 4, 5])]
  8082. )
  8083. def test_ncf_edge_case(df1, df2, x):
  8084. # Test for edge case described in gh-11660.
  8085. # Non-central Fisher distribution when nc = 0
  8086. # should be the same as Fisher distribution.
  8087. nc = 0
  8088. expected_cdf = stats.f.cdf(x, df1, df2)
  8089. calculated_cdf = stats.ncf.cdf(x, df1, df2, nc)
  8090. assert_allclose(expected_cdf, calculated_cdf, rtol=1e-14)
  8091. # when ncf_gen._skip_pdf will be used instead of generic pdf,
  8092. # this additional test will be useful.
  8093. expected_pdf = stats.f.pdf(x, df1, df2)
  8094. calculated_pdf = stats.ncf.pdf(x, df1, df2, nc)
  8095. assert_allclose(expected_pdf, calculated_pdf, rtol=1e-6)
  8096. def test_ncf_variance():
  8097. # Regression test for gh-10658 (incorrect variance formula for ncf).
  8098. # The correct value of ncf.var(2, 6, 4), 42.75, can be verified with, for
  8099. # example, Wolfram Alpha with the expression
  8100. # Variance[NoncentralFRatioDistribution[2, 6, 4]]
  8101. # or with the implementation of the noncentral F distribution in the C++
  8102. # library Boost.
  8103. v = stats.ncf.var(2, 6, 4)
  8104. assert_allclose(v, 42.75, rtol=1e-14)
  8105. def test_ncf_cdf_spotcheck():
  8106. # Regression test for gh-15582 testing against values from R/MATLAB
  8107. # Generate check_val from R or MATLAB as follows:
  8108. # R: pf(20, df1 = 6, df2 = 33, ncp = 30.4) = 0.998921
  8109. # MATLAB: ncfcdf(20, 6, 33, 30.4) = 0.998921
  8110. scipy_val = stats.ncf.cdf(20, 6, 33, 30.4)
  8111. check_val = 0.998921
  8112. assert_allclose(check_val, np.round(scipy_val, decimals=6))
  8113. def test_ncf_ppf_issue_17026():
  8114. # Regression test for gh-17026
  8115. x = np.linspace(0, 1, 600)
  8116. x[0] = 1e-16
  8117. par = (0.1, 2, 5, 0, 1)
  8118. q = stats.ncf.ppf(x, *par)
  8119. q0 = [stats.ncf.ppf(xi, *par) for xi in x]
  8120. assert_allclose(q, q0)
  8121. class TestHistogram:
  8122. def setup_method(self):
  8123. self.rng = np.random.default_rng(6561174822)
  8124. # We have 8 bins
  8125. # [1,2), [2,3), [3,4), [4,5), [5,6), [6,7), [7,8), [8,9)
  8126. # But actually np.histogram will put the last 9 also in the [8,9) bin!
  8127. # Therefore there is a slight difference below for the last bin, from
  8128. # what you might have expected.
  8129. histogram = np.histogram([1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5,
  8130. 6, 6, 6, 6, 7, 7, 7, 8, 8, 9], bins=8)
  8131. self.template = stats.rv_histogram(histogram)
  8132. data = stats.norm.rvs(loc=1.0, scale=2.5, size=10000, random_state=self.rng)
  8133. norm_histogram = np.histogram(data, bins=50)
  8134. self.norm_template = stats.rv_histogram(norm_histogram)
  8135. def test_pdf(self):
  8136. values = np.array([0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5,
  8137. 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5])
  8138. pdf_values = np.asarray([0.0/25.0, 0.0/25.0, 1.0/25.0, 1.0/25.0,
  8139. 2.0/25.0, 2.0/25.0, 3.0/25.0, 3.0/25.0,
  8140. 4.0/25.0, 4.0/25.0, 5.0/25.0, 5.0/25.0,
  8141. 4.0/25.0, 4.0/25.0, 3.0/25.0, 3.0/25.0,
  8142. 3.0/25.0, 3.0/25.0, 0.0/25.0, 0.0/25.0])
  8143. assert_allclose(self.template.pdf(values), pdf_values)
  8144. # Test explicitly the corner cases:
  8145. # As stated above the pdf in the bin [8,9) is greater than
  8146. # one would naively expect because np.histogram putted the 9
  8147. # into the [8,9) bin.
  8148. assert_almost_equal(self.template.pdf(8.0), 3.0/25.0)
  8149. assert_almost_equal(self.template.pdf(8.5), 3.0/25.0)
  8150. # 9 is outside our defined bins [8,9) hence the pdf is already 0
  8151. # for a continuous distribution this is fine, because a single value
  8152. # does not have a finite probability!
  8153. assert_almost_equal(self.template.pdf(9.0), 0.0/25.0)
  8154. assert_almost_equal(self.template.pdf(10.0), 0.0/25.0)
  8155. x = np.linspace(-2, 2, 10)
  8156. assert_allclose(self.norm_template.pdf(x),
  8157. stats.norm.pdf(x, loc=1.0, scale=2.5), rtol=0.1)
  8158. def test_cdf_ppf(self):
  8159. values = np.array([0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5,
  8160. 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5])
  8161. cdf_values = np.asarray([0.0/25.0, 0.0/25.0, 0.0/25.0, 0.5/25.0,
  8162. 1.0/25.0, 2.0/25.0, 3.0/25.0, 4.5/25.0,
  8163. 6.0/25.0, 8.0/25.0, 10.0/25.0, 12.5/25.0,
  8164. 15.0/25.0, 17.0/25.0, 19.0/25.0, 20.5/25.0,
  8165. 22.0/25.0, 23.5/25.0, 25.0/25.0, 25.0/25.0])
  8166. assert_allclose(self.template.cdf(values), cdf_values)
  8167. # First three and last two values in cdf_value are not unique
  8168. assert_allclose(self.template.ppf(cdf_values[2:-1]), values[2:-1])
  8169. # Test of cdf and ppf are inverse functions
  8170. x = np.linspace(1.0, 9.0, 100)
  8171. assert_allclose(self.template.ppf(self.template.cdf(x)), x)
  8172. x = np.linspace(0.0, 1.0, 100)
  8173. assert_allclose(self.template.cdf(self.template.ppf(x)), x)
  8174. x = np.linspace(-2, 2, 10)
  8175. assert_allclose(self.norm_template.cdf(x),
  8176. stats.norm.cdf(x, loc=1.0, scale=2.5), rtol=0.1)
  8177. def test_rvs(self):
  8178. N = 10000
  8179. sample = self.template.rvs(size=N, random_state=self.rng)
  8180. assert_equal(np.sum(sample < 1.0), 0.0)
  8181. assert_allclose(np.sum(sample <= 2.0), 1.0/25.0 * N, rtol=0.2)
  8182. assert_allclose(np.sum(sample <= 2.5), 2.0/25.0 * N, rtol=0.2)
  8183. assert_allclose(np.sum(sample <= 3.0), 3.0/25.0 * N, rtol=0.1)
  8184. assert_allclose(np.sum(sample <= 3.5), 4.5/25.0 * N, rtol=0.1)
  8185. assert_allclose(np.sum(sample <= 4.0), 6.0/25.0 * N, rtol=0.1)
  8186. assert_allclose(np.sum(sample <= 4.5), 8.0/25.0 * N, rtol=0.1)
  8187. assert_allclose(np.sum(sample <= 5.0), 10.0/25.0 * N, rtol=0.05)
  8188. assert_allclose(np.sum(sample <= 5.5), 12.5/25.0 * N, rtol=0.05)
  8189. assert_allclose(np.sum(sample <= 6.0), 15.0/25.0 * N, rtol=0.05)
  8190. assert_allclose(np.sum(sample <= 6.5), 17.0/25.0 * N, rtol=0.05)
  8191. assert_allclose(np.sum(sample <= 7.0), 19.0/25.0 * N, rtol=0.05)
  8192. assert_allclose(np.sum(sample <= 7.5), 20.5/25.0 * N, rtol=0.05)
  8193. assert_allclose(np.sum(sample <= 8.0), 22.0/25.0 * N, rtol=0.05)
  8194. assert_allclose(np.sum(sample <= 8.5), 23.5/25.0 * N, rtol=0.05)
  8195. assert_allclose(np.sum(sample <= 9.0), 25.0/25.0 * N, rtol=0.05)
  8196. assert_allclose(np.sum(sample <= 9.0), 25.0/25.0 * N, rtol=0.05)
  8197. assert_equal(np.sum(sample > 9.0), 0.0)
  8198. def test_munp(self):
  8199. for n in range(4):
  8200. assert_allclose(self.norm_template._munp(n),
  8201. stats.norm(1.0, 2.5).moment(n), rtol=0.05)
  8202. def test_entropy(self):
  8203. assert_allclose(self.norm_template.entropy(),
  8204. stats.norm.entropy(loc=1.0, scale=2.5), rtol=0.05)
  8205. def test_histogram_non_uniform():
  8206. # Tests rv_histogram works even for non-uniform bin widths
  8207. counts, bins = ([1, 1], [0, 1, 1001])
  8208. dist = stats.rv_histogram((counts, bins), density=False)
  8209. np.testing.assert_allclose(dist.pdf([0.5, 200]), [0.5, 0.0005])
  8210. assert dist.median() == 1
  8211. dist = stats.rv_histogram((counts, bins), density=True)
  8212. np.testing.assert_allclose(dist.pdf([0.5, 200]), 1/1001)
  8213. assert dist.median() == 1001/2
  8214. # Omitting density produces a warning for non-uniform bins...
  8215. message = "Bin widths are not constant. Assuming..."
  8216. with pytest.warns(RuntimeWarning, match=message):
  8217. dist = stats.rv_histogram((counts, bins))
  8218. assert dist.median() == 1001/2 # default is like `density=True`
  8219. # ... but not for uniform bins
  8220. dist = stats.rv_histogram((counts, [0, 1, 2]))
  8221. assert dist.median() == 1
  8222. class TestLogUniform:
  8223. def test_alias(self):
  8224. # This test makes sure that "reciprocal" and "loguniform" are
  8225. # aliases of the same distribution and that both are log-uniform
  8226. rng = np.random.default_rng(98643218961)
  8227. rv = stats.loguniform(10 ** -3, 10 ** 0)
  8228. rvs = rv.rvs(size=10000, random_state=rng)
  8229. rng = np.random.default_rng(98643218961)
  8230. rv2 = stats.reciprocal(10 ** -3, 10 ** 0)
  8231. rvs2 = rv2.rvs(size=10000, random_state=rng)
  8232. assert_allclose(rvs2, rvs)
  8233. vals, _ = np.histogram(np.log10(rvs), bins=10)
  8234. assert 900 <= vals.min() <= vals.max() <= 1100
  8235. assert np.abs(np.median(vals) - 1000) <= 10
  8236. @pytest.mark.parametrize("method", ['mle', 'mm'])
  8237. def test_fit_override(self, method):
  8238. # loguniform is overparameterized, so check that fit override enforces
  8239. # scale=1 unless fscale is provided by the user
  8240. rng = np.random.default_rng(98643218961)
  8241. rvs = stats.loguniform.rvs(0.1, 1, size=1000, random_state=rng)
  8242. a, b, loc, scale = stats.loguniform.fit(rvs, method=method)
  8243. assert scale == 1
  8244. a, b, loc, scale = stats.loguniform.fit(rvs, fscale=2, method=method)
  8245. assert scale == 2
  8246. def test_overflow(self):
  8247. # original formulation had overflow issues; check that this is resolved
  8248. # Extensive accuracy tests elsewhere, no need to test all methods
  8249. rng = np.random.default_rng(7136519550773909093)
  8250. a, b = 1e-200, 1e200
  8251. dist = stats.loguniform(a, b)
  8252. # test roundtrip error
  8253. cdf = rng.uniform(0, 1, size=1000)
  8254. assert_allclose(dist.cdf(dist.ppf(cdf)), cdf)
  8255. rvs = dist.rvs(size=1000, random_state=rng)
  8256. assert_allclose(dist.ppf(dist.cdf(rvs)), rvs)
  8257. # test a property of the pdf (and that there is no overflow)
  8258. x = 10.**np.arange(-200, 200)
  8259. pdf = dist.pdf(x) # no overflow
  8260. assert_allclose(pdf[:-1]/pdf[1:], 10)
  8261. # check munp against wikipedia reference
  8262. mean = (b - a)/(np.log(b) - np.log(a))
  8263. assert_allclose(dist.mean(), mean)
  8264. class TestArgus:
  8265. def test_argus_rvs_large_chi(self):
  8266. # test that the algorithm can handle large values of chi
  8267. x = stats.argus.rvs(50, size=500, random_state=325)
  8268. assert_almost_equal(stats.argus(50).mean(), x.mean(), decimal=4)
  8269. @pytest.mark.parametrize('chi, random_state', [
  8270. [0.1, 325], # chi <= 0.5: rejection method case 1
  8271. [1.3, 155], # 0.5 < chi <= 1.8: rejection method case 2
  8272. [3.5, 135] # chi > 1.8: transform conditional Gamma distribution
  8273. ])
  8274. def test_rvs(self, chi, random_state):
  8275. x = stats.argus.rvs(chi, size=500, random_state=random_state)
  8276. _, p = stats.kstest(x, "argus", (chi, ))
  8277. assert_(p > 0.05)
  8278. @pytest.mark.parametrize('chi', [1e-9, 1e-6])
  8279. def test_rvs_small_chi(self, chi):
  8280. # test for gh-11699 => rejection method case 1 can even handle chi=0
  8281. # the CDF of the distribution for chi=0 is 1 - (1 - x**2)**(3/2)
  8282. # test rvs against distribution of limit chi=0
  8283. r = stats.argus.rvs(chi, size=500, random_state=890981)
  8284. _, p = stats.kstest(r, lambda x: 1 - (1 - x**2)**(3/2))
  8285. assert_(p > 0.05)
  8286. # Expected values were computed with mpmath.
  8287. @pytest.mark.parametrize('chi, expected_mean',
  8288. [(1, 0.6187026683551835),
  8289. (10, 0.984805536783744),
  8290. (40, 0.9990617659702923),
  8291. (60, 0.9995831885165300),
  8292. (99, 0.9998469348663028)])
  8293. def test_mean(self, chi, expected_mean):
  8294. m = stats.argus.mean(chi, scale=1)
  8295. assert_allclose(m, expected_mean, rtol=1e-13)
  8296. # Expected values were computed with mpmath.
  8297. @pytest.mark.parametrize('chi, expected_var, rtol',
  8298. [(1, 0.05215651254197807, 1e-13),
  8299. (10, 0.00015805472008165595, 1e-11),
  8300. (40, 5.877763210262901e-07, 1e-8),
  8301. (60, 1.1590179389611416e-07, 1e-8),
  8302. (99, 1.5623277006064666e-08, 1e-8)])
  8303. def test_var(self, chi, expected_var, rtol):
  8304. v = stats.argus.var(chi, scale=1)
  8305. assert_allclose(v, expected_var, rtol=rtol)
  8306. # Expected values were computed with mpmath (code: see gh-13370).
  8307. @pytest.mark.parametrize('chi, expected, rtol',
  8308. [(0.9, 0.07646314974436118, 1e-14),
  8309. (0.5, 0.015429797891863365, 1e-14),
  8310. (0.1, 0.0001325825293278049, 1e-14),
  8311. (0.01, 1.3297677078224565e-07, 1e-15),
  8312. (1e-3, 1.3298072023958999e-10, 1e-14),
  8313. (1e-4, 1.3298075973486862e-13, 1e-14),
  8314. (1e-6, 1.32980760133771e-19, 1e-14),
  8315. (1e-9, 1.329807601338109e-28, 1e-15)])
  8316. def test_argus_phi_small_chi(self, chi, expected, rtol):
  8317. assert_allclose(_argus_phi(chi), expected, rtol=rtol)
  8318. # Expected values were computed with mpmath (code: see gh-13370).
  8319. @pytest.mark.parametrize(
  8320. 'chi, expected',
  8321. [(0.5, (0.28414073302940573, 1.2742227939992954, 1.2381254688255896)),
  8322. (0.2, (0.296172952995264, 1.2951290588110516, 1.1865767100877576)),
  8323. (0.1, (0.29791447523536274, 1.29806307956989, 1.1793168289857412)),
  8324. (0.01, (0.2984904104866452, 1.2990283628160553, 1.1769268414080531)),
  8325. (1e-3, (0.298496172925224, 1.2990380082487925, 1.176902956021053)),
  8326. (1e-4, (0.29849623054991836, 1.2990381047023793, 1.1769027171686324)),
  8327. (1e-6, (0.2984962311319278, 1.2990381056765605, 1.1769027147562232)),
  8328. (1e-9, (0.298496231131986, 1.299038105676658, 1.1769027147559818))])
  8329. def test_pdf_small_chi(self, chi, expected):
  8330. x = np.array([0.1, 0.5, 0.9])
  8331. assert_allclose(stats.argus.pdf(x, chi), expected, rtol=1e-13)
  8332. # Expected values were computed with mpmath (code: see gh-13370).
  8333. @pytest.mark.parametrize(
  8334. 'chi, expected',
  8335. [(0.5, (0.9857660526895221, 0.6616565930168475, 0.08796070398429937)),
  8336. (0.2, (0.9851555052359501, 0.6514666238985464, 0.08362690023746594)),
  8337. (0.1, (0.9850670974995661, 0.6500061310508574, 0.08302050640683846)),
  8338. (0.01, (0.9850378582451867, 0.6495239242251358, 0.08282109244852445)),
  8339. (1e-3, (0.9850375656906663, 0.6495191015522573, 0.08281910005231098)),
  8340. (1e-4, (0.9850375627651049, 0.6495190533254682, 0.08281908012852317)),
  8341. (1e-6, (0.9850375627355568, 0.6495190528383777, 0.08281907992729293)),
  8342. (1e-9, (0.9850375627355538, 0.649519052838329, 0.0828190799272728))])
  8343. def test_sf_small_chi(self, chi, expected):
  8344. x = np.array([0.1, 0.5, 0.9])
  8345. assert_allclose(stats.argus.sf(x, chi), expected, rtol=1e-14)
  8346. # Expected values were computed with mpmath.
  8347. @pytest.mark.parametrize(
  8348. 'x, chi, expected',
  8349. [(0.9999999, 0.25, 9.113252974162428e-11),
  8350. (0.9999999, 3.0, 6.616650419714568e-10),
  8351. (0.999999999, 2.5, 4.130195911418939e-13),
  8352. (0.999999999, 10.0, 2.3788319094393724e-11)])
  8353. def test_sf_near_1(self, x, chi, expected):
  8354. sf = stats.argus.sf(x, chi)
  8355. assert_allclose(sf, expected, rtol=5e-15)
  8356. # Expected values were computed with mpmath (code: see gh-13370).
  8357. @pytest.mark.parametrize(
  8358. 'chi, expected',
  8359. [(0.5, (0.0142339473104779, 0.3383434069831524, 0.9120392960157007)),
  8360. (0.2, (0.014844494764049919, 0.34853337610145363, 0.916373099762534)),
  8361. (0.1, (0.014932902500433911, 0.34999386894914264, 0.9169794935931616)),
  8362. (0.01, (0.014962141754813293, 0.35047607577486417, 0.9171789075514756)),
  8363. (1e-3, (0.01496243430933372, 0.35048089844774266, 0.917180899947689)),
  8364. (1e-4, (0.014962437234895118, 0.3504809466745317, 0.9171809198714769)),
  8365. (1e-6, (0.01496243726444329, 0.3504809471616223, 0.9171809200727071)),
  8366. (1e-9, (0.014962437264446245, 0.350480947161671, 0.9171809200727272))])
  8367. def test_cdf_small_chi(self, chi, expected):
  8368. x = np.array([0.1, 0.5, 0.9])
  8369. assert_allclose(stats.argus.cdf(x, chi), expected, rtol=1e-12)
  8370. # Expected values were computed with mpmath (code: see gh-13370).
  8371. @pytest.mark.parametrize(
  8372. 'chi, expected, rtol',
  8373. [(0.5, (0.5964284712757741, 0.052890651988588604), 1e-12),
  8374. (0.101, (0.5893490968089076, 0.053017469847275685), 1e-11),
  8375. (0.1, (0.5893431757009437, 0.05301755449499372), 1e-13),
  8376. (0.01, (0.5890515677940915, 0.05302167905837031), 1e-13),
  8377. (1e-3, (0.5890486520005177, 0.053021719862088104), 1e-13),
  8378. (1e-4, (0.5890486228426105, 0.0530217202700811), 1e-13),
  8379. (1e-6, (0.5890486225481156, 0.05302172027420182), 1e-13),
  8380. (1e-9, (0.5890486225480862, 0.05302172027420224), 1e-13)])
  8381. def test_stats_small_chi(self, chi, expected, rtol):
  8382. val = stats.argus.stats(chi, moments='mv')
  8383. assert_allclose(val, expected, rtol=rtol)
  8384. class TestNakagami:
  8385. def setup_method(self):
  8386. self.rng = np.random.default_rng(9626839526)
  8387. def test_logpdf(self):
  8388. # Test nakagami logpdf for an input where the PDF is smaller
  8389. # than can be represented with 64 bit floating point.
  8390. # The expected value of logpdf was computed with mpmath:
  8391. #
  8392. # def logpdf(x, nu):
  8393. # x = mpmath.mpf(x)
  8394. # nu = mpmath.mpf(nu)
  8395. # return (mpmath.log(2) + nu*mpmath.log(nu) -
  8396. # mpmath.loggamma(nu) + (2*nu - 1)*mpmath.log(x) -
  8397. # nu*x**2)
  8398. #
  8399. nu = 2.5
  8400. x = 25
  8401. logp = stats.nakagami.logpdf(x, nu)
  8402. assert_allclose(logp, -1546.9253055607549)
  8403. def test_sf_isf(self):
  8404. # Test nakagami sf and isf when the survival function
  8405. # value is very small.
  8406. # The expected value of the survival function was computed
  8407. # with mpmath:
  8408. #
  8409. # def sf(x, nu):
  8410. # x = mpmath.mpf(x)
  8411. # nu = mpmath.mpf(nu)
  8412. # return mpmath.gammainc(nu, nu*x*x, regularized=True)
  8413. #
  8414. nu = 2.5
  8415. x0 = 5.0
  8416. sf = stats.nakagami.sf(x0, nu)
  8417. assert_allclose(sf, 2.736273158588307e-25, rtol=1e-13)
  8418. # Check round trip back to x0.
  8419. x1 = stats.nakagami.isf(sf, nu)
  8420. assert_allclose(x1, x0, rtol=1e-13)
  8421. def test_logcdf(self):
  8422. x = 8
  8423. nu = 0.5
  8424. # Reference value computed with mpmath.
  8425. ref = -1.2441921148543576e-15
  8426. logcdf = stats.nakagami.logcdf(x, nu)
  8427. assert_allclose(logcdf, ref, rtol=5e-15)
  8428. def test_logsf(self):
  8429. x = 0.05
  8430. nu = 12
  8431. # Reference value computed with mpmath.
  8432. ref = -1.0791764722337046e-27
  8433. logsf = stats.nakagami.logsf(x, nu)
  8434. assert_allclose(logsf, ref, rtol=5e-15)
  8435. @pytest.mark.parametrize("m, ref",
  8436. [(5, -0.097341814372152),
  8437. (0.5, 0.7257913526447274),
  8438. (10, -0.43426184310934907)])
  8439. def test_entropy(self, m, ref):
  8440. # from sympy import *
  8441. # from mpmath import mp
  8442. # import numpy as np
  8443. # v, x = symbols('v, x', real=True, positive=True)
  8444. # pdf = 2 * v ** v / gamma(v) * x ** (2 * v - 1) * exp(-v * x ** 2)
  8445. # h = simplify(simplify(integrate(-pdf * log(pdf), (x, 0, oo))))
  8446. # entropy = lambdify(v, h, 'mpmath')
  8447. # mp.dps = 200
  8448. # nu = 5
  8449. # ref = np.float64(entropy(mp.mpf(nu)))
  8450. # print(ref)
  8451. assert_allclose(stats.nakagami.entropy(m), ref, rtol=1.1e-14)
  8452. @pytest.mark.parametrize("m, ref",
  8453. [(1e-100, -5.0e+99), (1e-10, -4999999965.442979),
  8454. (9.999e6, -7.333206478668433), (1.001e7, -7.3337562313259825),
  8455. (1e10, -10.787134112333835), (1e100, -114.40346329705756)])
  8456. def test_extreme_nu(self, m, ref):
  8457. assert_allclose(stats.nakagami.entropy(m), ref)
  8458. def test_entropy_overflow(self):
  8459. assert np.isfinite(stats.nakagami._entropy(1e100))
  8460. assert np.isfinite(stats.nakagami._entropy(1e-100))
  8461. @pytest.mark.parametrize("nu, ref",
  8462. [(1e10, 0.9999999999875),
  8463. (1e3, 0.9998750078173821),
  8464. (1e-10, 1.772453850659802e-05)])
  8465. def test_mean(self, nu, ref):
  8466. # reference values were computed with mpmath
  8467. # from mpmath import mp
  8468. # mp.dps = 500
  8469. # nu = mp.mpf(1e10)
  8470. # float(mp.rf(nu, mp.mpf(0.5))/mp.sqrt(nu))
  8471. assert_allclose(stats.nakagami.mean(nu), ref, rtol=1e-12)
  8472. @pytest.mark.xfail(reason="Fit of nakagami not reliable, see gh-10908.")
  8473. @pytest.mark.parametrize('nu', [1.6, 2.5, 3.9])
  8474. @pytest.mark.parametrize('loc', [25.0, 10, 35])
  8475. @pytest.mark.parametrize('scale', [13, 5, 20])
  8476. def test_fit(self, nu, loc, scale):
  8477. # Regression test for gh-13396 (21/27 cases failed previously)
  8478. # The first tuple of the parameters' values is discussed in gh-10908
  8479. N = 100
  8480. samples = stats.nakagami.rvs(size=N, nu=nu, loc=loc,
  8481. scale=scale, random_state=self.rng)
  8482. nu_est, loc_est, scale_est = stats.nakagami.fit(samples)
  8483. assert_allclose(nu_est, nu, rtol=0.2)
  8484. assert_allclose(loc_est, loc, rtol=0.2)
  8485. assert_allclose(scale_est, scale, rtol=0.2)
  8486. def dlogl_dnu(nu, loc, scale):
  8487. return ((-2*nu + 1) * np.sum(1/(samples - loc))
  8488. + 2*nu/scale**2 * np.sum(samples - loc))
  8489. def dlogl_dloc(nu, loc, scale):
  8490. return (N * (1 + np.log(nu) - polygamma(0, nu)) +
  8491. 2 * np.sum(np.log((samples - loc) / scale))
  8492. - np.sum(((samples - loc) / scale)**2))
  8493. def dlogl_dscale(nu, loc, scale):
  8494. return (- 2 * N * nu / scale
  8495. + 2 * nu / scale ** 3 * np.sum((samples - loc) ** 2))
  8496. assert_allclose(dlogl_dnu(nu_est, loc_est, scale_est), 0, atol=1e-3)
  8497. assert_allclose(dlogl_dloc(nu_est, loc_est, scale_est), 0, atol=1e-3)
  8498. assert_allclose(dlogl_dscale(nu_est, loc_est, scale_est), 0, atol=1e-3)
  8499. @pytest.mark.parametrize('loc', [25.0, 10, 35])
  8500. @pytest.mark.parametrize('scale', [13, 5, 20])
  8501. def test_fit_nu(self, loc, scale):
  8502. # For nu = 0.5, we have analytical values for
  8503. # the MLE of the loc and the scale
  8504. nu = 0.5
  8505. n = 100
  8506. samples = stats.nakagami.rvs(size=n, nu=nu, loc=loc,
  8507. scale=scale, random_state=self.rng)
  8508. nu_est, loc_est, scale_est = stats.nakagami.fit(samples, f0=nu)
  8509. # Analytical values
  8510. loc_theo = np.min(samples)
  8511. scale_theo = np.sqrt(np.mean((samples - loc_est) ** 2))
  8512. assert_allclose(nu_est, nu, rtol=1e-7)
  8513. assert_allclose(loc_est, loc_theo, rtol=1e-7)
  8514. assert_allclose(scale_est, scale_theo, rtol=1e-7)
  8515. class TestWrapCauchy:
  8516. def setup_method(self):
  8517. self.rng = np.random.default_rng(2439107123)
  8518. def test_cdf_shape_broadcasting(self):
  8519. # Regression test for gh-13791.
  8520. # Check that wrapcauchy.cdf broadcasts the shape parameter
  8521. # correctly.
  8522. c = np.array([[0.03, 0.25], [0.5, 0.75]])
  8523. x = np.array([[1.0], [4.0]])
  8524. p = stats.wrapcauchy.cdf(x, c)
  8525. assert p.shape == (2, 2)
  8526. scalar_values = [stats.wrapcauchy.cdf(x1, c1)
  8527. for (x1, c1) in np.nditer((x, c))]
  8528. assert_allclose(p.ravel(), scalar_values, rtol=1e-13)
  8529. def test_cdf_center(self):
  8530. p = stats.wrapcauchy.cdf(np.pi, 0.03)
  8531. assert_allclose(p, 0.5, rtol=1e-14)
  8532. def test_cdf(self):
  8533. x1 = 1.0 # less than pi
  8534. x2 = 4.0 # greater than pi
  8535. c = 0.75
  8536. p = stats.wrapcauchy.cdf([x1, x2], c)
  8537. cr = (1 + c)/(1 - c)
  8538. assert_allclose(p[0], np.arctan(cr*np.tan(x1/2))/np.pi)
  8539. assert_allclose(p[1], 1 - np.arctan(cr*np.tan(np.pi - x2/2))/np.pi)
  8540. @pytest.mark.parametrize('c', [1e-10, 1e-1])
  8541. @pytest.mark.parametrize('loc', [-100, -2*np.pi, -np.pi, 0, np.pi, 2*np.pi, 100])
  8542. @pytest.mark.parametrize('scale', [1e-10, 1, 1e10])
  8543. def test_rvs_lie_on_circle(self, c, loc, scale):
  8544. # Check that the random variates lie in range [0, 2*pi]
  8545. x = stats.wrapcauchy.rvs(c=c, loc=loc, scale=scale,
  8546. size=1000, random_state=self.rng)
  8547. assert np.all(x >= 0)
  8548. assert np.all(x <= 2 * np.pi)
  8549. def test_rvs_no_size_error():
  8550. # _rvs methods must have parameter `size`; see gh-11394
  8551. class rvs_no_size_gen(stats.rv_continuous):
  8552. def _rvs(self):
  8553. return 1
  8554. rvs_no_size = rvs_no_size_gen(name='rvs_no_size')
  8555. rng = np.random.default_rng(1334886239)
  8556. with assert_raises(TypeError, match=r"_rvs\(\) got (an|\d) unexpected"):
  8557. rvs_no_size.rvs(random_state=rng)
  8558. @pytest.mark.parametrize('distname, args', invdistdiscrete + invdistcont)
  8559. def test_support_gh13294_regression(distname, args):
  8560. if distname in skip_test_support_gh13294_regression:
  8561. pytest.skip(f"skipping test for the support method for "
  8562. f"distribution {distname}.")
  8563. dist = getattr(stats, distname)
  8564. # test support method with invalid arguments
  8565. if isinstance(dist, stats.rv_continuous):
  8566. # test with valid scale
  8567. if len(args) != 0:
  8568. a0, b0 = dist.support(*args)
  8569. assert_equal(a0, np.nan)
  8570. assert_equal(b0, np.nan)
  8571. # test with invalid scale
  8572. # For some distributions, that take no parameters,
  8573. # the case of only invalid scale occurs and hence,
  8574. # it is implicitly tested in this test case.
  8575. loc1, scale1 = 0, -1
  8576. a1, b1 = dist.support(*args, loc1, scale1)
  8577. assert_equal(a1, np.nan)
  8578. assert_equal(b1, np.nan)
  8579. else:
  8580. a, b = dist.support(*args)
  8581. assert_equal(a, np.nan)
  8582. assert_equal(b, np.nan)
  8583. def test_support_broadcasting_gh13294_regression():
  8584. a0, b0 = stats.norm.support([0, 0, 0, 1], [1, 1, 1, -1])
  8585. ex_a0 = np.array([-np.inf, -np.inf, -np.inf, np.nan])
  8586. ex_b0 = np.array([np.inf, np.inf, np.inf, np.nan])
  8587. assert_equal(a0, ex_a0)
  8588. assert_equal(b0, ex_b0)
  8589. assert a0.shape == ex_a0.shape
  8590. assert b0.shape == ex_b0.shape
  8591. a1, b1 = stats.norm.support([], [])
  8592. ex_a1, ex_b1 = np.array([]), np.array([])
  8593. assert_equal(a1, ex_a1)
  8594. assert_equal(b1, ex_b1)
  8595. assert a1.shape == ex_a1.shape
  8596. assert b1.shape == ex_b1.shape
  8597. a2, b2 = stats.norm.support([0, 0, 0, 1], [-1])
  8598. ex_a2 = np.array(4*[np.nan])
  8599. ex_b2 = np.array(4*[np.nan])
  8600. assert_equal(a2, ex_a2)
  8601. assert_equal(b2, ex_b2)
  8602. assert a2.shape == ex_a2.shape
  8603. assert b2.shape == ex_b2.shape
  8604. def test_stats_broadcasting_gh14953_regression():
  8605. # test case in gh14953
  8606. loc = [0., 0.]
  8607. scale = [[1.], [2.], [3.]]
  8608. assert_equal(stats.norm.var(loc, scale), [[1., 1.], [4., 4.], [9., 9.]])
  8609. # test some edge cases
  8610. loc = np.empty((0, ))
  8611. scale = np.empty((1, 0))
  8612. assert stats.norm.var(loc, scale).shape == (1, 0)
  8613. # Check a few values of the cosine distribution's cdf, sf, ppf and
  8614. # isf methods. Expected values were computed with mpmath.
  8615. @pytest.mark.parametrize('x, expected',
  8616. [(-3.14159, 4.956444476505336e-19),
  8617. (3.14, 0.9999999998928399)])
  8618. def test_cosine_cdf_sf(x, expected):
  8619. assert_allclose(stats.cosine.cdf(x), expected)
  8620. assert_allclose(stats.cosine.sf(-x), expected)
  8621. @pytest.mark.parametrize('p, expected',
  8622. [(1e-6, -3.1080612413765905),
  8623. (1e-17, -3.141585429601399),
  8624. (0.975, 2.1447547020964923)])
  8625. def test_cosine_ppf_isf(p, expected):
  8626. assert_allclose(stats.cosine.ppf(p), expected)
  8627. assert_allclose(stats.cosine.isf(p), -expected)
  8628. def test_cosine_logpdf_endpoints():
  8629. logp = stats.cosine.logpdf([-np.pi, np.pi])
  8630. # reference value calculated using mpmath assuming `np.cos(-1)` is four
  8631. # floating point numbers too high. See gh-18382.
  8632. assert_array_less(logp, -37.18838327496655)
  8633. def test_distr_params_lists():
  8634. # distribution objects are extra distributions added in
  8635. # test_discrete_basic. All other distributions are strings (names)
  8636. # and so we only choose those to compare whether both lists match.
  8637. discrete_distnames = {name for name, _ in distdiscrete
  8638. if isinstance(name, str)}
  8639. invdiscrete_distnames = {name for name, _ in invdistdiscrete}
  8640. assert discrete_distnames == invdiscrete_distnames
  8641. cont_distnames = {name for name, _ in distcont}
  8642. invcont_distnames = {name for name, _ in invdistcont}
  8643. assert cont_distnames == invcont_distnames
  8644. def test_moment_order_4():
  8645. # gh-13655 reported that if a distribution has a `_stats` method that
  8646. # accepts the `moments` parameter, then if the distribution's `moment`
  8647. # method is called with `order=4`, the faster/more accurate`_stats` gets
  8648. # called, but the results aren't used, and the generic `_munp` method is
  8649. # called to calculate the moment anyway. This tests that the issue has
  8650. # been fixed.
  8651. # stats.skewnorm._stats accepts the `moments` keyword
  8652. stats.skewnorm._stats(a=0, moments='k') # no failure = has `moments`
  8653. # When `moment` is called, `_stats` is used, so the moment is very accurate
  8654. # (exactly equal to Pearson's kurtosis of the normal distribution, 3)
  8655. assert stats.skewnorm.moment(order=4, a=0) == 3.0
  8656. # At the time of gh-13655, skewnorm._munp() used the generic method
  8657. # to compute its result, which was inefficient and not very accurate.
  8658. # At that time, the following assertion would fail. skewnorm._munp()
  8659. # has since been made more accurate and efficient, so now this test
  8660. # is expected to pass.
  8661. assert stats.skewnorm._munp(4, 0) == 3.0
  8662. class TestRelativisticBW:
  8663. @pytest.fixture
  8664. def ROOT_pdf_sample_data(self):
  8665. """Sample data points for pdf computed with CERN's ROOT
  8666. See - https://root.cern/
  8667. Uses ROOT.TMath.BreitWignerRelativistic, available in ROOT
  8668. versions 6.27+
  8669. pdf calculated for Z0 Boson, W Boson, and Higgs Boson for
  8670. x in `np.linspace(0, 200, 401)`.
  8671. """
  8672. data = np.load(
  8673. Path(__file__).parent /
  8674. 'data/rel_breitwigner_pdf_sample_data_ROOT.npy'
  8675. )
  8676. data = np.rec.fromarrays(data.T, names='x,pdf,rho,gamma')
  8677. return data
  8678. @pytest.mark.parametrize(
  8679. "rho,gamma,rtol", [
  8680. (36.545206797050334, 2.4952, 5e-14), # Z0 Boson
  8681. (38.55107913669065, 2.085, 1e-14), # W Boson
  8682. (96292.3076923077, 0.0013, 5e-13), # Higgs Boson
  8683. ]
  8684. )
  8685. def test_pdf_against_ROOT(self, ROOT_pdf_sample_data, rho, gamma, rtol):
  8686. data = ROOT_pdf_sample_data[
  8687. (ROOT_pdf_sample_data['rho'] == rho)
  8688. & (ROOT_pdf_sample_data['gamma'] == gamma)
  8689. ]
  8690. x, pdf = data['x'], data['pdf']
  8691. assert_allclose(
  8692. pdf, stats.rel_breitwigner.pdf(x, rho, scale=gamma), rtol=rtol
  8693. )
  8694. @pytest.mark.parametrize("rho, Gamma, rtol", [
  8695. (36.545206797050334, 2.4952, 5e-13), # Z0 Boson
  8696. (38.55107913669065, 2.085, 5e-13), # W Boson
  8697. (96292.3076923077, 0.0013, 5e-10), # Higgs Boson
  8698. ]
  8699. )
  8700. def test_pdf_against_simple_implementation(self, rho, Gamma, rtol):
  8701. # reference implementation straight from formulas on Wikipedia [1]
  8702. def pdf(E, M, Gamma):
  8703. gamma = np.sqrt(M**2 * (M**2 + Gamma**2))
  8704. k = (2 * np.sqrt(2) * M * Gamma * gamma
  8705. / (np.pi * np.sqrt(M**2 + gamma)))
  8706. return k / ((E**2 - M**2)**2 + M**2*Gamma**2)
  8707. # get reasonable values at which to evaluate the CDF
  8708. p = np.linspace(0.05, 0.95, 10)
  8709. x = stats.rel_breitwigner.ppf(p, rho, scale=Gamma)
  8710. res = stats.rel_breitwigner.pdf(x, rho, scale=Gamma)
  8711. ref = pdf(x, rho*Gamma, Gamma)
  8712. assert_allclose(res, ref, rtol=rtol)
  8713. @pytest.mark.xslow
  8714. @pytest.mark.parametrize(
  8715. "rho,gamma", [
  8716. pytest.param(
  8717. 36.545206797050334, 2.4952, marks=pytest.mark.slow
  8718. ), # Z0 Boson
  8719. pytest.param(
  8720. 38.55107913669065, 2.085, marks=pytest.mark.xslow
  8721. ), # W Boson
  8722. pytest.param(
  8723. 96292.3076923077, 0.0013, marks=pytest.mark.xslow
  8724. ), # Higgs Boson
  8725. ]
  8726. )
  8727. def test_fit_floc(self, rho, gamma):
  8728. """Tests fit for cases where floc is set.
  8729. `rel_breitwigner` has special handling for these cases.
  8730. """
  8731. seed = 6936804688480013683
  8732. rng = np.random.default_rng(seed)
  8733. data = stats.rel_breitwigner.rvs(
  8734. rho, scale=gamma, size=1000, random_state=rng
  8735. )
  8736. fit = stats.rel_breitwigner.fit(data, floc=0)
  8737. assert_allclose((fit[0], fit[2]), (rho, gamma), rtol=2e-1)
  8738. assert fit[1] == 0
  8739. # Check again with fscale set.
  8740. fit = stats.rel_breitwigner.fit(data, floc=0, fscale=gamma)
  8741. assert_allclose(fit[0], rho, rtol=1e-2)
  8742. assert (fit[1], fit[2]) == (0, gamma)
  8743. class TestJohnsonSU:
  8744. @pytest.mark.parametrize("case", [ # a, b, loc, scale, m1, m2, g1, g2
  8745. (-0.01, 1.1, 0.02, 0.0001, 0.02000137427557091,
  8746. 2.1112742956578063e-08, 0.05989781342460999, 20.36324408592951-3),
  8747. (2.554395574161155, 2.2482281679651965, 0, 1, -1.54215386737391,
  8748. 0.7629882028469993, -1.256656139406788, 6.303058419339775-3)])
  8749. def test_moment_gh18071(self, case):
  8750. # gh-18071 reported an IntegrationWarning emitted by johnsonsu.stats
  8751. # Check that the warning is no longer emitted and that the values
  8752. # are accurate compared against results from Mathematica.
  8753. # Reference values from Mathematica, e.g.
  8754. # Mean[JohnsonDistribution["SU",-0.01, 1.1, 0.02, 0.0001]]
  8755. res = stats.johnsonsu.stats(*case[:4], moments='mvsk')
  8756. assert_allclose(res, case[4:], rtol=1e-14)
  8757. class TestTruncPareto:
  8758. def test_pdf(self):
  8759. # PDF is that of the truncated pareto distribution
  8760. b, c = 1.8, 5.3
  8761. x = np.linspace(1.8, 5.3)
  8762. res = stats.truncpareto(b, c).pdf(x)
  8763. ref = stats.pareto(b).pdf(x) / stats.pareto(b).cdf(c)
  8764. assert_allclose(res, ref)
  8765. def test_pdf_negative(self):
  8766. # truncpareto is equivalent to more general powerlaw from gh-23648
  8767. # exponent of truncpareto is negative in this case
  8768. a, xmin, xmax = 4, 3, 5
  8769. x = np.linspace(xmin, xmax)
  8770. # compute reference using PDF from gh-23648
  8771. C = a / (xmax ** a - xmin ** a)
  8772. ref = C * x ** (a - 1)
  8773. # compute using `truncpareto` with negative exponent
  8774. b = -a
  8775. c = xmax / xmin
  8776. scale = xmin
  8777. loc = 0
  8778. X = stats.truncpareto(b, c, loc, scale)
  8779. assert_allclose(X.pdf(x), ref)
  8780. assert_allclose(X.logpdf(x), np.log(X.pdf(x)))
  8781. # indexing avoids RuntimeWarning with `np.log(0)`
  8782. assert_allclose(X.logcdf(x[1:]), np.log(X.cdf(x[1:])))
  8783. assert_allclose(X.logsf(x[:-1]), np.log(X.sf(x[:-1])))
  8784. @pytest.mark.parametrize('fix_loc', [True, False])
  8785. @pytest.mark.parametrize('fix_scale', [True, False])
  8786. @pytest.mark.parametrize('fix_b', [True, False])
  8787. @pytest.mark.parametrize('fix_c', [True, False])
  8788. def test_fit(self, fix_loc, fix_scale, fix_b, fix_c):
  8789. rng = np.random.default_rng(6747363148258237171)
  8790. b, c, loc, scale = 1.8, 5.3, 1, 2.5
  8791. dist = stats.truncpareto(b, c, loc=loc, scale=scale)
  8792. data = dist.rvs(size=500, random_state=rng)
  8793. kwds = {}
  8794. if fix_loc:
  8795. kwds['floc'] = loc
  8796. if fix_scale:
  8797. kwds['fscale'] = scale
  8798. if fix_b:
  8799. kwds['f0'] = b
  8800. if fix_c:
  8801. kwds['f1'] = c
  8802. if fix_loc and fix_scale and fix_b and fix_c:
  8803. message = "All parameters fixed. There is nothing to optimize."
  8804. with pytest.raises(RuntimeError, match=message):
  8805. stats.truncpareto.fit(data, **kwds)
  8806. else:
  8807. _assert_less_or_close_loglike(stats.truncpareto, data, **kwds)
  8808. class TestKappa3:
  8809. def test_sf(self):
  8810. # During development of gh-18822, we found that the override of
  8811. # kappa3.sf could experience overflow where the version in main did
  8812. # not. Check that this does not happen in final implementation.
  8813. sf0 = 1 - stats.kappa3.cdf(0.5, 1e5)
  8814. sf1 = stats.kappa3.sf(0.5, 1e5)
  8815. assert_allclose(sf1, sf0)
  8816. class TestIrwinHall:
  8817. unif = stats.uniform(0, 1)
  8818. ih1 = stats.irwinhall(1)
  8819. ih10 = stats.irwinhall(10)
  8820. def test_stats_ih10(self):
  8821. # from Wolfram Alpha "mean variance skew kurtosis UniformSumDistribution[10]"
  8822. # W|A uses Pearson's definition of kurtosis so subtract 3
  8823. # should be exact integer division converted to fp64, without any further ops
  8824. assert_array_max_ulp(self.ih10.stats('mvsk'), (5, 10/12, 0, -3/25))
  8825. def test_moments_ih10(self):
  8826. # from Wolfram Alpha "values moments UniformSumDistribution[10]"
  8827. # algo should use integer division converted to fp64, without any further ops
  8828. # so these should be precise to the ulpm if not exact
  8829. vals = [5, 155 / 6, 275 / 2, 752, 12650 / 3,
  8830. 677465 / 28, 567325 / 4,
  8831. 15266213 / 18, 10333565 / 2]
  8832. moments = [self.ih10.moment(n+1) for n in range(len(vals))]
  8833. assert_array_max_ulp(moments, vals)
  8834. # also from Wolfram Alpha "50th moment UniformSumDistribution[10]"
  8835. m50 = self.ih10.moment(50)
  8836. m50_exact = 17453002755350010529309685557285098151740985685/4862
  8837. assert_array_max_ulp(m50, m50_exact)
  8838. def test_pdf_ih1_unif(self):
  8839. # IH(1) PDF is by definition U(0,1)
  8840. # we should be too, but differences in floating point eval order happen
  8841. # it's unclear if we can get down to the single ulp for doubles unless
  8842. # quads are used we're within 6-10 ulps otherwise (across sf/cdf/pdf)
  8843. # which is pretty good
  8844. pts = np.linspace(0, 1, 100)
  8845. pdf_unif = self.unif.pdf(pts)
  8846. pdf_ih1 = self.ih1.pdf(pts)
  8847. assert_array_max_ulp(pdf_ih1, pdf_unif, maxulp=10)
  8848. def test_pdf_ih2_triangle(self):
  8849. # IH(2) PDF is a triangle
  8850. ih2 = stats.irwinhall(2)
  8851. npts = 101
  8852. pts = np.linspace(0, 2, npts)
  8853. expected = np.linspace(0, 2, npts)
  8854. expected[(npts + 1) // 2:] = 2 - expected[(npts + 1) // 2:]
  8855. pdf_ih2 = ih2.pdf(pts)
  8856. assert_array_max_ulp(pdf_ih2, expected, maxulp=10)
  8857. def test_cdf_ih1_unif(self):
  8858. # CDF of IH(1) should be identical to uniform
  8859. pts = np.linspace(0, 1, 100)
  8860. cdf_unif = self.unif.cdf(pts)
  8861. cdf_ih1 = self.ih1.cdf(pts)
  8862. assert_array_max_ulp(cdf_ih1, cdf_unif, maxulp=10)
  8863. def test_cdf(self):
  8864. # CDF of IH is symmetric so CDF should be 0.5 at n/2
  8865. n = np.arange(1, 10)
  8866. ih = stats.irwinhall(n)
  8867. ih_cdf = ih.cdf(n / 2)
  8868. exact = np.repeat(1/2, len(n))
  8869. # should be identically 1/2 but fp order of eval differences happen
  8870. assert_array_max_ulp(ih_cdf, exact, maxulp=10)
  8871. def test_cdf_ih10_exact(self):
  8872. # from Wolfram Alpha "values CDF[UniformSumDistribution[10], x] x=0 to x=10"
  8873. # symmetric about n/2, i.e., cdf[n-x] = 1-cdf[x] = sf[x]
  8874. vals = [0, 1 / 3628800, 169 / 604800, 24427 / 1814400,
  8875. 252023 / 1814400, 1 / 2, 1562377 / 1814400,
  8876. 1789973 / 1814400, 604631 / 604800,
  8877. 3628799 / 3628800, 1]
  8878. # essentially a test of bspline evaluation
  8879. # this and the other ones are mostly to detect regressions
  8880. assert_array_max_ulp(self.ih10.cdf(np.arange(11)), vals, maxulp=10)
  8881. assert_array_max_ulp(self.ih10.cdf(1/10), 1/36288000000000000, maxulp=10)
  8882. ref = 36287999999999999/36288000000000000
  8883. assert_array_max_ulp(self.ih10.cdf(99/10), ref, maxulp=10)
  8884. def test_pdf_ih10_exact(self):
  8885. # from Wolfram Alpha "values PDF[UniformSumDistribution[10], x] x=0 to x=10"
  8886. # symmetric about n/2 = 5
  8887. vals = [0, 1 / 362880, 251 / 181440, 913 / 22680, 44117 / 181440]
  8888. vals += [15619 / 36288] + vals[::-1]
  8889. assert_array_max_ulp(self.ih10.pdf(np.arange(11)), vals, maxulp=10)
  8890. def test_sf_ih10_exact(self):
  8891. assert_allclose(self.ih10.sf(np.arange(11)), 1 - self.ih10.cdf(np.arange(11)))
  8892. # from Wolfram Alpha "SurvivalFunction[UniformSumDistribution[10],x] at x=1/10"
  8893. # and symmetry about n/2 = 5
  8894. # W|A returns 1 for CDF @ x=9.9
  8895. ref = 36287999999999999/36288000000000000
  8896. assert_array_max_ulp(self.ih10.sf(1/10), ref, maxulp=10)
  8897. class TestDParetoLognorm:
  8898. def test_against_R(self):
  8899. # Test against R implementation in `distributionsrd`
  8900. # library(distributionsrd)
  8901. # options(digits=16)
  8902. # x = 1.1
  8903. # b = 2
  8904. # a = 1.5
  8905. # m = 3
  8906. # s = 1.2
  8907. # ddoubleparetolognormal(x, b, a, m, s)
  8908. # pdoubleparetolognormal(x, b, a, m, s)
  8909. x, m, s, a, b = 1.1, 3, 1.2, 1.5, 2
  8910. dist = stats.dpareto_lognorm(m, s, a, b)
  8911. np.testing.assert_allclose(dist.pdf(x), 0.02490187219085912)
  8912. np.testing.assert_allclose(dist.cdf(x), 0.01664024173822796)
  8913. # Cases are (distribution name, log10 of smallest probability mass to test,
  8914. # log10 of the complement of the largest probability mass to test, atol,
  8915. # rtol). None uses default values.
  8916. @pytest.mark.parametrize("case", [("kappa3", None, None, None, None),
  8917. ("loglaplace", None, None, None, None),
  8918. ("lognorm", None, None, None, None),
  8919. ("lomax", None, None, None, None),
  8920. ("pareto", None, None, None, None),])
  8921. def test_sf_isf_overrides(case):
  8922. # Test that SF is the inverse of ISF. Supplements
  8923. # `test_continuous_basic.check_sf_isf` for distributions with overridden
  8924. # `sf` and `isf` methods.
  8925. distname, lp1, lp2, atol, rtol = case
  8926. lpm = np.log10(0.5) # log10 of the probability mass at the median
  8927. lp1 = lp1 or -290
  8928. lp2 = lp2 or -14
  8929. atol = atol or 0
  8930. rtol = rtol or 1e-12
  8931. dist = getattr(stats, distname)
  8932. params = dict(distcont)[distname]
  8933. dist_frozen = dist(*params)
  8934. # Test (very deep) right tail to median. We can benchmark with random
  8935. # (loguniform) points, but strictly logspaced points are fine for tests.
  8936. ref = np.logspace(lp1, lpm)
  8937. res = dist_frozen.sf(dist_frozen.isf(ref))
  8938. assert_allclose(res, ref, atol=atol, rtol=rtol)
  8939. # test median to left tail
  8940. ref = 1 - np.logspace(lp2, lpm, 20)
  8941. res = dist_frozen.sf(dist_frozen.isf(ref))
  8942. assert_allclose(res, ref, atol=atol, rtol=rtol)