|
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655 |
- {
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Numpy - 多维数据数组软件库"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "NumPy是Python中科学计算的基本软件包。它是一个Python库,提供多维数组对象、各种派生类(如掩码数组和矩阵)和各种例程。\n",
- "* 用于对数组进行快速操作,包括数学、逻辑、形状操作、排序、选择、I/O、离散傅立叶变换、基本线性代数、基本统计操作、随机模拟等等。\n",
- "* Numpy作为Python数据计算的基础广泛应用到数据处理、信号处理、机器学习等领域。"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 1. 简介"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "`numpy`包(模块)用在几乎所有使用Python的数值计算中,为Python提供高性能向量,矩阵和高维数据结构的模块。它是用C和Fortran语言实现的,因此当计算向量化数据(用向量和矩阵表示)时,性能非常的好。\n",
- "\n",
- "为了使用`numpy`模块,你先要像下面的例子一样导入这个模块:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "# 这一行的作用会在Matplotlib中介绍\n",
- "%matplotlib inline\n",
- "import matplotlib.pyplot as plt"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "# 不建议用这种方式导入库\n",
- "from numpy import *"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "# 建议使用这种方式\n",
- "import numpy as np"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "**建议大家使用第二种导入方法** `import numpy as np`\n"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 2. 创建`numpy`数组"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "有很多种方法去初始化新的numpy数组, 例如从\n",
- "\n",
- "* Python列表或元组\n",
- "* 使用专门用来创建numpy arrays的函数,例如 `arange`, `linspace`等\n",
- "* 从文件中读取数据"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 2.1 从列表中"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "例如,为了从Python列表创建新的向量和矩阵我们可以用`numpy.array`函数。\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[1, 2, 3, 4]\n"
- ]
- },
- {
- "data": {
- "text/plain": [
- "array([1, 2, 3, 4])"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "import numpy as np\n",
- "\n",
- "a = [1, 2, 3, 4]\n",
- "print(a)\n",
- "\n",
- "# a vector: the argument to the array function is a Python list\n",
- "v = np.array(a)\n",
- "\n",
- "v"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[1 2]\n",
- " [3 4]\n",
- " [5 6]]\n",
- "\n",
- "(3, 2)\n"
- ]
- }
- ],
- "source": [
- "# 矩阵:数组函数的参数是一个嵌套的Python列表\n",
- "M = np.array([[1, 2], [3, 4], [5, 6]])\n",
- "\n",
- "print(M)\n",
- "print()\n",
- "print(M.shape)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[[ 1 2]\n",
- " [ 3 4]\n",
- " [ 5 6]]\n",
- "\n",
- " [[ 3 4]\n",
- " [ 5 6]\n",
- " [ 7 8]]\n",
- "\n",
- " [[ 5 6]\n",
- " [ 7 8]\n",
- " [ 9 10]]\n",
- "\n",
- " [[ 7 8]\n",
- " [ 9 10]\n",
- " [11 12]]]\n",
- "\n",
- "(4, 3, 2)\n"
- ]
- }
- ],
- "source": [
- "M = np.array([[[1,2], [3,4], [5,6]], \\\n",
- " [[3,4], [5,6], [7,8]], \\\n",
- " [[5,6], [7,8], [9,10]], \\\n",
- " [[7,8], [9,10], [11,12]]])\n",
- "print(M)\n",
- "print()\n",
- "print(M.shape)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "`v`和`M`两个都是属于`numpy`模块提供的`ndarray`类型。"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(numpy.ndarray, numpy.ndarray)"
- ]
- },
- "execution_count": 7,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "type(v), type(M)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "`v`和`M`之间的区别仅在于他们的形状。我们可以用属性函数`ndarray.shape`得到数组形状的信息。"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(4,)"
- ]
- },
- "execution_count": 8,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v.shape"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(4, 3, 2)"
- ]
- },
- "execution_count": 9,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M.shape"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "通过属性函数`ndarray.size`我们可以得到数组中元素的个数"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "24"
- ]
- },
- "execution_count": 10,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M.size"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "同样,我们可以用函数`numpy.shape`和`numpy.size`"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(4, 3, 2)"
- ]
- },
- "execution_count": 11,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.shape(M)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "24"
- ]
- },
- "execution_count": 12,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.size(M)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "到目前为止`numpy.ndarray`看起来非常像Python列表(或嵌套列表)。为什么不简单地使用Python列表来进行计算,而不是创建一个新的数组类型?\n",
- "\n",
- "下面有几个原因:\n",
- "\n",
- "* Python列表非常普遍。它们可以包含任何类型的对象。它们是动态类型的。它们不支持矩阵和点乘等数学函数。由于动态类型的关系,为Python列表实现这类函数的效率不是很高。\n",
- "* Numpy数组是**静态类型的**和**同构的**。元素的类型是在创建数组时确定的。\n",
- "* Numpy数组是内存高效的。\n",
- "* 由于是静态类型,数学函数的快速实现,比如“numpy”数组的乘法和加法可以用编译语言实现(使用C和Fortran).\n",
- "\n",
- "利用`ndarray`的属性函数`dtype`(数据类型),我们可以看出数组的数据是那种类型。\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 13,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "dtype('int64')"
- ]
- },
- "execution_count": 13,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M.dtype"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "如果我们试图给一个numpy数组中的元素赋一个错误类型的值,我们会得到一个错误:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 14,
- "metadata": {},
- "outputs": [
- {
- "ename": "ValueError",
- "evalue": "invalid literal for int() with base 10: 'hello'",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
- "\u001b[0;32m<ipython-input-14-3eecc5e8509b>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mM\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"hello\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
- "\u001b[0;31mValueError\u001b[0m: invalid literal for int() with base 10: 'hello'"
- ]
- }
- ],
- "source": [
- "M[0,0,0] = \"hello\""
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "如果我们想的话,我们可以利用`dtype`关键字参数显式地定义我们创建的数组数据类型:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 15,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1.+0.j, 2.+0.j],\n",
- " [3.+0.j, 4.+0.j]])"
- ]
- },
- "execution_count": 15,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M = np.array([[1, 2], [3, 4]], dtype=complex)\n",
- "\n",
- "M"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "常规可以伴随`dtype`使用的数据类型是:`int`, `float`, `complex`, `bool`, `object`等\n",
- "\n",
- "我们也可以显式地定义数据类型的大小,例如:`int64`, `int16`, `float128`, `complex128`。"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 2.2 使用数组生成函数"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "对于较大的数组,使用显式的Python列表人为地初始化数据是不切实际的。除此之外我们可以用`numpy`的很多函数得到不同类型的数组。有一些常用的分别是:"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### arange"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 16,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[0 1 2 3 4 5 6 7 8 9]\n",
- "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n"
- ]
- }
- ],
- "source": [
- "# 创建一个范围\n",
- "\n",
- "x = np.arange(0, 10, 1) # 参数:start, stop, step: \n",
- "y = range(0, 10, 1)\n",
- "print(x)\n",
- "print(list(y))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 17,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([-1.00000000e+00, -9.00000000e-01, -8.00000000e-01, -7.00000000e-01,\n",
- " -6.00000000e-01, -5.00000000e-01, -4.00000000e-01, -3.00000000e-01,\n",
- " -2.00000000e-01, -1.00000000e-01, -2.22044605e-16, 1.00000000e-01,\n",
- " 2.00000000e-01, 3.00000000e-01, 4.00000000e-01, 5.00000000e-01,\n",
- " 6.00000000e-01, 7.00000000e-01, 8.00000000e-01, 9.00000000e-01])"
- ]
- },
- "execution_count": 17,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "x = np.arange(-1, 1, 0.1)\n",
- "\n",
- "x"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### linspace and logspace"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 18,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 0. , 2.5, 5. , 7.5, 10. ])"
- ]
- },
- "execution_count": 18,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 使用linspace两边的端点也被包含进去\n",
- "np.linspace(0, 10, 5)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 19,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([1.00000000e+00, 3.03773178e+00, 9.22781435e+00, 2.80316249e+01,\n",
- " 8.51525577e+01, 2.58670631e+02, 7.85771994e+02, 2.38696456e+03,\n",
- " 7.25095809e+03, 2.20264658e+04])"
- ]
- },
- "execution_count": 19,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.logspace(0, 10, 10, base=np.e)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### mgrid"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 20,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "y, x = np.mgrid[0:5, 0:5] # 和MATLAB中的meshgrid类似"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 21,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0, 1, 2, 3, 4],\n",
- " [0, 1, 2, 3, 4],\n",
- " [0, 1, 2, 3, 4],\n",
- " [0, 1, 2, 3, 4],\n",
- " [0, 1, 2, 3, 4]])"
- ]
- },
- "execution_count": 21,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "x"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 22,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0, 0, 0, 0, 0],\n",
- " [1, 1, 1, 1, 1],\n",
- " [2, 2, 2, 2, 2],\n",
- " [3, 3, 3, 3, 3],\n",
- " [4, 4, 4, 4, 4]])"
- ]
- },
- "execution_count": 22,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "y"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### random data"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 23,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "from numpy import random"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 24,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[[0.57397454, 0.12434228],\n",
- " [0.74835474, 0.01034541],\n",
- " [0.91383579, 0.02807574],\n",
- " [0.14217509, 0.64698341]],\n",
- "\n",
- " [[0.65606545, 0.84787378],\n",
- " [0.31064031, 0.70205451],\n",
- " [0.30486756, 0.34702889],\n",
- " [0.47537986, 0.91154076]],\n",
- "\n",
- " [[0.32192343, 0.77700745],\n",
- " [0.80485914, 0.85919158],\n",
- " [0.29751565, 0.27228179],\n",
- " [0.57796668, 0.18255467]],\n",
- "\n",
- " [[0.50020698, 0.58134695],\n",
- " [0.14200095, 0.97556272],\n",
- " [0.32948647, 0.35170435],\n",
- " [0.27768833, 0.75059373]],\n",
- "\n",
- " [[0.23972627, 0.08461662],\n",
- " [0.1929383 , 0.80565903],\n",
- " [0.2627892 , 0.73361884],\n",
- " [0.18415944, 0.44976198]]])"
- ]
- },
- "execution_count": 24,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 均匀随机数在[0,1)区间\n",
- "random.rand(5,4,2)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 25,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[-1.74300737, 1.94689131, 0.18922227, -0.20440928],\n",
- " [ 1.31664152, -0.01176745, -0.43956951, 0.53571291],\n",
- " [ 0.02140654, -0.09635041, -1.84205831, 0.64951045],\n",
- " [ 0.35682903, 0.96657395, -0.50099255, -0.80044681]])"
- ]
- },
- "execution_count": 25,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 标准正态分布随机数\n",
- "random.randn(4,4)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### diag"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 26,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 0, 0],\n",
- " [0, 2, 0],\n",
- " [0, 0, 3]])"
- ]
- },
- "execution_count": 26,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 一个对角矩阵\n",
- "np.diag([1,2,3])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 27,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0, 0, 0, 0],\n",
- " [1, 0, 0, 0],\n",
- " [0, 2, 0, 0],\n",
- " [0, 0, 3, 0]])"
- ]
- },
- "execution_count": 27,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 从主对角线偏移的对角线\n",
- "np.diag([1,2,3], k=-1) "
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### zeros and ones"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 28,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0., 0., 0.],\n",
- " [0., 0., 0.],\n",
- " [0., 0., 0.]])"
- ]
- },
- "execution_count": 28,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.zeros((3,3))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 29,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1., 1., 1.],\n",
- " [1., 1., 1.],\n",
- " [1., 1., 1.]])"
- ]
- },
- "execution_count": 29,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.ones((3,3))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 3. 文件 I/O"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 3.1 逗号分隔值 (CSV)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "对于数据文件来说一种非常常见的文件格式是逗号分割值(CSV),或者有关的格式例如TSV(制表符分隔的值)。为了从这些文件中读取数据到Numpy数组中,我们可以用`numpy.genfromtxt`函数。例如:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "1800 1 1 -6.1 -6.1 -6.1 1\r\n",
- "1800 1 2 -15.4 -15.4 -15.4 1\r\n",
- "1800 1 3 -15.0 -15.0 -15.0 1\r\n",
- "1800 1 4 -19.3 -19.3 -19.3 1\r\n",
- "1800 1 5 -16.8 -16.8 -16.8 1\r\n",
- "1800 1 6 -11.4 -11.4 -11.4 1\r\n",
- "1800 1 7 -7.6 -7.6 -7.6 1\r\n",
- "1800 1 8 -7.1 -7.1 -7.1 1\r\n",
- "1800 1 9 -10.1 -10.1 -10.1 1\r\n",
- "1800 1 10 -9.5 -9.5 -9.5 1\r\n"
- ]
- }
- ],
- "source": [
- "!head stockholm_td_adj.dat"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "import numpy as np\n",
- "\n",
- "data = np.genfromtxt('stockholm_td_adj.dat')"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(77431, 7)"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "data.shape"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAz0AAAEWCAYAAABMnPmpAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsfXfYHkX19j2hSCB06R2RIvyQIoqoGEJXsYEdC6ACFloE\nRSkREKkCItJEQBBpAQUVkdCLIiAdpIoUQYxAUEpC8s73x77zPbPnmTkzZ2b2Kcne15Ur7z47O3N2\ndtrpSmuNFi1atGjRokWLFi1atJhdMabfBLRo0aJFixYtWrRo0aJFk2iZnhYtWrRo0aJFixYtWszW\naJmeFi1atGjRokWLFi1azNZomZ4WLVq0aNGiRYsWLVrM1miZnhYtWrRo0aJFixYtWszWaJmeFi1a\ntGgBAFBKza2UmqffdLRo0aJFixal0TI9LVq0aDEHQym1glLq1tHLnQDsp5Qap5SaoJTaXim1r1Lq\nLKv8Jkqp5a3r+ZRSJ3vqnkcppQLtz+v4bUGl1J+VUssJ32VupdR1Sinv3qaUWlMpdY1N1+g7buko\nu1yI/gA9KyilNk19vkWLFi1alMPc/SagRYsWLVr0B6MHeg3gldGf3gAwC8DbAJwF4AYAzwK4Xym1\n8GjZcwB8VCm1HYB5ACwMYDul1IMAFKp95ada69cAHAHg/5RSsxzNLwfgTQDuB/Bxcm8igCe01s8E\n6N8YwI8B/M/8BOCtAK6z2hwLYB+t9S2j18sCeEXXk9TtDmA7RxNfBLCZUmp7ABcDWADADKutcVrr\ndzAkroiqDzaxaJ5baz2Te68WLVq0aFEeLdPTokWLFnMu/g/AeQBWUErdBmBxVIyMAjBFa72zXVgp\ndRGA47TW9yql5h/9+d0AbgPwZ1TWA/OiYp6gtZ6olPrxaJn/jpZfHcB4AO8BsJTW+ijSxjoAvg3g\nKaXUX0dp0aP/A8AZWuufjP6tAdwOYE8AGwJ4B4CTRun4HoAzAfxTaz1rtO7DAXwewFil1AMATgNw\nB4DlAZw4ygTO0FpvPUr/4Uqph0f75Q1UDNaLo22PAXAQoX05ALcCuGeUXgVghlLq96N/LwTgXgC7\n0Q/RokWLFi2aRcv0tGjRosUcCq31PUqpzQFMAfBDVMzI0wB+B+Bbdlml1NqotBz3KaVOHP37fQBW\nAPAkgEsBPAXgT1rrG+xmAOwD4GZUB/+LATg1HUqpNwO4BMCOWuvJSqmlACyqtf7b6P17AFxlPfL6\naJ1nAvgIgH8CmArg66iYqp0AXANgl9HyiwP4rNb6RqXUJ1FptHYH8BUAV4zWdfNoWysBOAzAAVrr\nfyilDONlmC/7b4NZAB4FsDMqRu9jAA4YLXcNgC0BTHe9e4sWLVq0aBYt09OiRYsWLRTqh/i5AGyh\nlDoP1eH9LlQalF1RMQWfQqWt2AvAJAA7oGKc9gDwBVL3EwAOsa41KubAhbUAnK61njx6vTmAbQF8\nXim1IIALtNYPEbpHAPwElQbpOVQmaJNRaW/uBmD7G42g48uqUJnXKQC/1FrPHPUvehUARhmdSwHs\nC+AbqPbLb6Bu3kaDPowZfb93Ang/gDVQMT4YpevDqBjESzzv36JFixYtGoKqmzW3aNGiRYs5CaPa\nlEcA/A2VJuRUVAzMgVrrj41qV96OikG4FMACWutNlVK7AVgflcnWfwAsAeAlAHdprU8eDQxwIDr+\nNhSLo2IkXgZwitb6Aoumz6LyJ9oQlQbn6wDeqbW+ntD+LlSM2LIAfgpgIwB/QaVRmQXgdAA/APAt\nrfVjowEXtkelbZkPwImofG5uR8WoLAzgIq11UvCBUe3QaVrrrZVS7wVwEaq+VQDW01ovmFJvixYt\nWrTIR6vpadGiRYs5GwrA7VrrCUqpLwJYGsA41IMDKFQmYo8AWE8ptTSAL6Hy03kDFbMAAIsBeAuA\nk7XWVwG4Sik1ARWDYTBLa33laFsun571UGlu3mv9vCKA85RSnyGmcwuhMmm7GZWWaQlUDM9YVAzY\nURhleKxntrfM29bUWs9QSl2LKmjBdQCmWbSMQcUYnYCKGXThIK31jaN/LwjgJaXUoqhM/46xyl2q\nlHq31vpPnnpatGjRokWDaJmeFi1atJhDMcqQHAtgIaXUjagO7WNRmYo9T4qfCmBRAJO11s8B2Fgp\ntQiA1wDsobU+Wim1IioTMxunA/iqaRIVQ7Omh575APwMwNe01g8opd4KAFrrh5RSnwNw0Sjj8Pjo\nI6a911Fpp14AsBWAxwHchMrczGWCZmgxOHr0/+VRMUsG7wEw/2if/B2VP9I7UPkN/Q/AygAWscqv\nCOAfqJivH4z+ZpjHN6HSjLVo0aJFiz6gzdPTokWLFnMotNbXoDLr+gOqkM3XoDrov4LKH8YuOxOV\nT4zJzXMZKpOytQBsr5RaAZU/z0mkmZmoIqmZf+MYkk4DcIvW+ny76dH2r0OlcbnAuvceAPehYkLu\nB/AMKtO1EVTmbSPoZnouUko9iYr5UqN1P621fhoVU2czPZ9GZaI2C/UABvb/tn/SOwA8prV+WGs9\nBsBlqMzpNgBwttb6AebdW7Ro0aJFg2g1PS1atGgxZ+MnAKC1fkkp9RdUQQe2A3Dw6H07wMHco/8+\ngCpK2UKoNBjbAJiAKpzzBkqpVbTWfx99Zl6t9QTTmFLq5FHzrzXQCf9ssB9GNUxKqQ+iCpjwrLk5\nGkL6V6P3FwSwBaq8QfugYnYUKi3VGqgiswHAm5RSu43SMw/q5m1vH61rDCofow+hCjQApdS40euJ\no/WZvqD/z6WUUqN5fz6FygfJ4LsAfoOKKfswWrRo0aJF39AyPS1atGgxh0IptRCqaGXfAgCt9fmj\nCT9/obU2DMncqBibV1ExDfOgk6R0NQA/QhXRbAyAfbXWNU2P1noVcr27UupiVKZhXyH3bNO4lVAx\nQMeTMoaZ2gTAlVrrawFcO/o+7wVwKIAfa60vdbzyfhg1N9NaXzhKB0ZpvwWV1sgweyui0tSsh8pU\nbTqqgAoU7wXwP6XUawD+BeDF0XxAywJYG1VghWUAXKGUuh1V3qBDHPW0aNGiRYsG0UZva9GiRYsW\n/x+jYZuhtZ4RKjtoUEqthSrh6mSTkLTH7S+otf7vaJCGBwH8ddQsEEqpJVCZv80cDfLQokWLFi16\niJbpadGiRYsWLVq0aNGixWyNNpBBixYtWrRo0aJFixYtZmsMhU+PUqpVR7Vo0aJFixYtWrRo0YKF\n1lq5fh8KpgcAWjO8FrMrJk2ahEmTJvWbjBYtGkE7vlvM7mjHeO+x887AmWcC7dGweQzb+FbKye8A\naM3bWrRo0aJFixYtWrRoMZujZXpatGjRokWLFi1atGAwcybwy1/2m4oWOWiZnoL46EeBkZF+U9Fi\n2DB+/Ph+k9CiRWNox3eL2R3tGJ8zcO+9wI479psKHq++Cjz/fNk6Z6fxPRQhqzvJrgcbSlUDbuzY\nflPSokWLFi1atOCgNXDttcCECf2mpIUU/fDpufNOYIMNBtuPaIcdgMmTB5vGpqGU8gYyaDU9hfHC\nC/2moMXsiJde6jcFLVq0aMFj5kzgf//rNxXxePppYPPN/fePOKISZLZoAQwHI/HMM/2mYLDRMj2F\ncckl/aZg9sK99/abgsHAoosC11zTbypatGjRwo+99wYWXLDfVMRj1iz+/v77A3/6U29oadGiBP71\nr35T0DsccghwwQWyZ1qmp8VAY911h0vStvHGwFlnNVP3v//dTL29wCKLAH/+c7+paDEomDYNmDKl\n31S0KI2HH+5Pu7ObL+3s9j5NoB9aFyYS8sDg73/vNwW9w8EHV4yPBC3TM4SY09SXw6BSNrj1VuDy\ny/tNxeBh2jTgttv6TUWLQcFRRwFbbtlvKlrMLphrrsrfIgaDvn9eemn1Pi0GA9OmdUw2h+ksMqgY\nGelvMIiW6SF49lng0Uf7TQWP5ZcH/vnPflPRwodhkAa1aNFPXHttvylo0QT6ufbFMjPLLw9cf318\nvb1+p4ce6m17LXissQYwGwUv6zumTy8b9lvKiLZMD8FWWwFvfWvz7ay0EnDSSenPT59ejpYYTJ4M\nPP54b9scVjS1SQ67lKllBlsYTJvWbwp6h5tuAm65pd9UtLBhxt+wr6mzO155pd8UVD4yRhDe1B72\nxhtzzv7Y7zk3tEzP0083EyUmdZJJP+STTwLXXZfWVj+www6VU2c/0O9JMjvjsMOA3/6231S0mNMw\np2zwAPC+91X/SuOpp6p1uUWFpvaJXo/Vdr/rYNy4iiEYFDT1bWbObKbeHGgN/PrXac+OjPg1lv0e\n30PL9KywQhWnPQaPPAL87W/N0mMg+aA5i+mcdGgYNqR+m3HjejdODQ48UO4IWBo33lgPyb3EEvH2\n+S2GE8O+fh13XP/zsV13XaWBj8Fzz/Wmz4f9u4Yw99zAE0/0m4o5C3NCUId+MwIu3Hor8LGPpZlb\nTp4MrLlmXNmTTwY+9CF5G6kYWqYHAKZOjSu37rrAWmtVf4+MAF/7Wnla+jVoR0b6H9XrhBNm/81O\ngtS+eOWVtBDdV1yRLpEZBGy6aZ3xmjq1DXowu2PMUO88wD77AK+/Hl++3+vjnHBQnzEjvqxkvz7w\nwM7fs2Y1H6FuEA/ALeY8mPVNMq8MJFZY550H/O538jZSMdRbT+ziYKsOX3ut4ix9SN2cDC1Na3ro\nADzzTGDJJeX1AMAyy5RRHd9+e34dsxN6fcD5+McriUwMXn4ZWHXV+m+DsMlSGp56qj90tOCx0kpl\n7OwHkel56SVgtdX6TUUzGIQ5LsW998rSFeyzTzN09DpPzzB+qzkNg2iOVhqhNfpd76oH/brnnup8\nDXSP4dNP77hH9Ht8D+DWE4/YzpMcQmmdSskO9U1/0P/+t/rfvNOXv5xe13PPyTYVH4NE3/n118v2\nQ7+lpL1EyrtK+vqZZ7rj+PeKaZW822GHNUdHi3Q8+WQZzfIgzun77gMee6yZupt439C8//3vq+/l\nKjtrVu99JR55RNYP664rM7017xqDXpmhpyAnyMfNNw9eQu/ddwc+8xn5c6Fv1MvDM23rV79qtv6S\nmDkzjUkLjfu//KUuEHj724Ejj6z+/u5362UPPxw44gh3Pb1mgoaa6UlBSgfff38z9Q4bLr3U/Tt9\n97Fjyy4Kw9a3/Y7eppR/gXFhxRXT6JGiF6FYt9oqnGW9Rf8xiEyPNLP3oOODHwQmTqz+pmvHLrsA\nyy4bV89zz8Wbq3DfNSVpopEc57adg16P1bPPTn/2ve8FttmmHC0l8ItfAOefL39Oaj3Ty1QjvY6e\nm4Px4/lAKr5+ixn39NuY+fqvf0WRBqBi1Dl84QtlU7QMNdMTOxkkEq3UA3avzNvMM6Wc+5pa0Oek\nrMAUgxCgQhJpL/bwk4sLL2y2/kcfBa66Ks0GuUVvkTPOt9mmmbE0iIxYKdD94s47431il1kG+Oxn\nO9ff/z6w995yGmjCzdR6fEix6Bg2gVoMepHD7+674w+2EmsSG5Jv9J//NJtqhNJQetw0OQ5vvhn4\n858719df3/HXefRRf7+VNEG2x6T0Xc85B7jmmnK0zBFMT7/r9CF2kV5ySZnkvgkaOLj6bHY+QNh4\n6aX+2/dKxmw/v1XT7dxzT7P1l8C4ccCPf9zbNidPTu/7//2vW6r517/GPbvqqsABB7jv3XFHPA0v\nv1w3c7ryyuYZ6NJoYuzH1GnK5B7abGnw0UcDxx8f99yFF1ZmMDYtRhN7zDHheiQCjF75iTV9Rohl\nRvuJ9dYDdtyxfL0vvNBh0M3/Mf3d9B48OzHH48dXPjYAsPnm/nKSNSvk55kriDRjYcaMaj+w8eCD\nsrpapqcQmqTl3//uqACptGwY0UQ44unTgQceKF9vCIsu2m13nmPal6LBy11QYpPO/v3v9dDSUjQ9\nX30HvEHCK6/UpW4SpM6bu+5Kew6opPyf/GT9tz33jHv2738vk4vs2muBgw+u/2a+8euvV999mKMX\npiJH2CGdI/bBgnuWHpQ+9Slg112rvw1TYvz1YkzmTjklnsamQN+paeHNsIRobsInbPHFgY03rv4u\nuY7fcAPwxS+mP0+/eek9JjSmbr+9rFDPjDHOD06yn5oyMXM6pe8MvV/7GrDwwvLnbQw109O003eo\nnb/8pRO+cnZTl0+ZUh3om8AGG5TPyH7sscDaa6c9e9llefT84x/pz1L0Y8OLNVNYddW6mcugYXbX\nLm6wQZWUuZf43//yckeVWA+5Ol58sfr/hBPy22kS/R6bTZnnzJwZ/26mXMn1MgZad2sCJOtsv75d\nv1NRhGD7Tl58ccefY2SE96sMaWVMuoLQmUryDc85p/ItKoWmzdumTauPu402qgIFNNWeCzGaU1rP\nT3+aRo+Nc8/1r1ePPJJf/1AzPf3Gu94FbLll/bemfXp6JWH405/ipfopJlOS94hxTDcShhTp00c+\nwksUn3uuecdFE5XP4MQTy9qxlkIJZvW114Dnn8+vh2IYND2An75nnwW+/nX+WWNGMGNGVX7QUZLp\nsdeBWCHTG2/E+zgM+rjJQcl3s+uK0TKbeRk6RIXW2SeflGmZDM44A5hnnvpvO+xQ/R/TL/QdSzBB\nTz0VPrRLnMH7AbvvPvGJjrb14x8H1l/f/cyvf939LUL1+77ROee4aQnRqrUs0h/QvT83jf/8h78f\nmgslEDPOzX6Ua2Jv4/Of754b5vqGG+Lb8WFomB6tu00lfB/liSfSFyapFIqGBJW0G2tW5Kq3lJlb\nvyWQHEyfnnpqfFlfqON77023lV5mGVlggBTcd1/1v/kee+zRTJuhQ7WNV16psjLbuOWWfBp23x1Y\naqn8eigGMffLs8/Ga0quuCIsKTO5SA4+OD4ARek5LtE2UTO0F16Qt2fXQX8LbaBHHQUst1xcO3Sj\nveuujiZpdkNOoBl6gIyFmZ++Z5ZZBvj2t/3Pr7QScNFF/vu+cR5j9iyJ/FViPq24YsevYljh+46/\n+Y0/bLYkJHxT1jO//W01lmLg00qVXlOl77jSSpWFSpPtxbyj5DyRgxh6R0biaB7AY4Ibd90FbLZZ\nXNl+5PgwH0Wick2x0TftzDef/Nnrr6/+xUCyKYYG5FlndZhDo4mRLBrPPVf9f9hhwOqr82V9GoR1\n1wWWWCK+TQPzbr2Sutn9wqn1UxddiY/FMcd07KtL4plnytcJdGt6dt4Z2HbbuGevvRa48ca0dn/z\nG7/fzAc/CKy1Vl2y6PuuMQu70e6YOVEat91W1ofBvJNh5lK+fUy/+BxpczSK668P7LVX2rMnnFDX\niqb63Z14IrD00mnPAn7tZ2pELVqXK6+dDzFCCd+4/sY3qv85rZ2p//nn6wnIY8ZPbHCOkrD3FOqc\nDQyf5lESWCMG5v0l2sRQXYDbgsXV/wBw+eXhtmNxxRV1OjmriZhvn+NfGwOJELGp/GYGMdY+NACG\nD0PD9IRe5LOf7UjLzzijGRquv76z+DaJf/2re7M2Eocc6cf48dW/GJx5Zny9LmmoPbl32qnyuQGA\nz30uvl5zQD/uuOr/q68uY9MpgRl3nNlFCVOtmO/529/Wyzbt/yM5qE2f3vtvE8KllwJ/+ENc2QkT\ngE03TWvnox8FvvIV9z1J3oKSJgKpcEm8c9oyzxphB63LbNyPPlrX5MTWa2D8ACgkhxbXe6b6Aey1\nV2e+UnzjG3UzjY037jAhN91Ul55ef30ZgUtorXjkkTImvK7Dp/F7Tcn7YWC+oxkjzz7r19yffXbl\n8ByqMxWu93jjDWDDDWX1GLquvz7fObsfCDG8ufnSTP0xUeIoLVOn+hlo1/dbeGG3SVnJsUMFY4ss\n0tmfzPw0QW5iNRupKKXpMaCBZnLbzqElJNAZGqYnhF/9qpK4hpAziE87DTjppHL1+j7k2mtXTstc\nO7mTMcUcz/U8APzxj/HlDWMaA7qpce9M791/f2ezLQEuLGLswToG3Pc477zqfyPtLL2Zj4ykR8E6\n4oiwFu5TnwrXE2ObbZdZZJHOgZdKpqgk7O67OyalTz/t72ut5f3gq8sswDEavBg0vWHkmAjSb2N+\n466NhPCtb63ytkjactVHfyupsS6Fk04CfvazzvWtt3Y0eGeemecMnKpFXH114Ic/jCvv0vRwzulU\nC8fV7QtFbnwqzLOrrNKdcDEnwlauudLLL8u1RaZNn9Cs15qeT34S+MEP4tsP3T/33O7fXN8oNGZ9\npnIcNtmkCrzD1UshEbqUMm8zmm8jIDFnnphvPwg+PSmIOcOmvJtZZ44+mi832zA9OSiZzMv+WDvt\nlCbt+M9/uqUUTTlpp9R3553hw5FvoTLPRdleJoxOs/mus45c8sahRDjs730v7EAZ0y8771z9X3os\nPPww8LGPpT0bE+BglVXCZUI+H8cfXx8X06ZV4TwBvu+0rnJLGBNZcxh2SdGfflreDz6ps/neOVJu\nG00Ha5D6Cj7/fEeLc9JJ3XOWRmKisNde3xiSbI6PPy5bN2KT5o2MAF/6Uny9QHg8uvCmN8WVc+H2\n2/3vHlOP7aw9Zoxf8+Niem66KY5GoDNfJaCWDtOnhyX5P/lJ/ZlScH1XF3P/hS/w9Rx1lPvZJpNs\ncrjooo5mc9q08FiimgbaLzEmlPvvDyy2GN9Oyvd77rmOlp3WEcPMNREkxtWuGdcp5qa9Ep5JmMHc\nts29lFx2JhhV6AzRF6ZHKXWWUupPSqlfK6UWUEpdrpS6Uyl1tu+Zpjb5m2+uHF1dkirTpjHNMrly\nXHBJvM46q7ORTJ0KPPSQ+xkXQsxSKU3PpEnyZ6kjs8vvw2glaHsSE6iUYA2lJOol6zA4/HDeEReI\nOxybsZFDmyscKl3cBjHIhYuZjukHOr/Nu/lsuaUIaRSaDrKw5Zb+9UmyobrmHDcOllqqo6G5++74\ndgximOWQNseGJMzvffdVa3/M4eq11yqzqVLwtUX7X8LwcQKVlLXCFwnT/j2l3qeekj/jOmiHDt0m\nuldMH5r/99gjft279dbKLNbXxjnn8G37/NCMBsvHdG68ccdi4oorOpHoSsDQG7NmmLI+BiGmH2+7\nze+b0itNlwl3b+g9//xOkJgYYY2NW27pPPPgg8A73sG3TffymHc2/mop5m0pJqzGvHDSpA6jTiH5\nVjERdidOjK/PILY/es70KKXeA2AurfW7ASwMYGcAT2mt1wewmFJqi/i68ul573ur/y++uPueOciY\npFBcZDfz0Y2kzph8md+33x5Yc836MxL6S0t4TT3HHJNf14ILxrcn8RMJmcaE4NtUZs0qL72Q0kDR\n5ALvosG18MQkFvOhtI2wD65wpzSCTK5Zi3leEl1R0o5Nn1KdjSiGbhP8hJadMsUfwEXi8JrCnB15\npJsmG4bppPPfbs9+/rzzOpJ8yfcMlVWqo93bfvvqf8MsxhyOSzHJvrZKJ0GU7Bu9EnKkvJPrUGi+\nhS84js/Pi8OJJ4bLmHYuv7wKgMLB0HvaaVXEthiYZ4ymiuLWWzvtnnceMHlyXL033VTlFuRghJLm\nHTnhq6HT7KUpgQw4wWaKpiclOaZZNw1tMbno7HXM3l/f856O785NNwF33MHXQ4VxRnDEvXNOviEz\nZ+g6xrVn9sHvf98vJA99o9VW6/xtzB5jvmsT5sn90PT8C4BJJTcDwMEArhq9vgZAZIy2bsQcZH0d\n4zoE5jjimcFu2isRX9yur5SmJwUlNkdf+1tt1VlEKOfO9aGpL+abTZwIjB1b/81+p+eek+Vx8OGu\nu4Bx4+q/2XbzNkw7EjOoWNrGjeuWTLnaMXbFU6bE1cvh4YfLMXJPPNFhDOadt0ydMf38lreUaSvU\nnnm3K6/Ma8MXdnfuuePrcDE9oe8YSjYIdA5TW21V/93XL5/7XHfC0VizohCMKaI5IJk1421v8z9j\n6r300nD9MaB0Nh2UpCmhSq+k8T6TKqDz/XxjKca3M2VPi/F/MUKKgw8Oa7jMQdrQYtYFaiFil5Hg\nfe+Lj4Br8K1vyduRgBOy2KaMsfjd79y/22OghBDFZmbGjaufO8zfMdF5qabnwAPDNErWcx+uuKJ+\nLdEop5Yx4M7ptB4TkMSMd85v2KwNIVp6zvRorR/VWt+ulPoYgHkA3AHAGDm8DMBj4RlGP0JVG/g6\nmvsAKapGnwnDoEXOCsHXL1dd1TGfkxwETH0//3m47P33+5/XusoXESs942BMbex39SUdM86skgWm\ntATMIOQIGIM11ogPj85h+vTKF+igg6rr0r4x0nup4MwuzfUll9R/P/LIsF+Arw0bZpOM6ReJpifl\noC7ROnHjvORh2/RbrCReWq8Lv/pV/dqYUEs0PdSckcvb0RRzQg8aMXMnJdGjMbdyvUcoxLotTKDC\nzZS1lGO+afQtI9WO6Rdq6mnqWHNN//4eopsyAbGmroZely+rjwFN0VJygh7zvCS3l+972nOlhIDB\n0P3FL/ppMOawvnQGHC291sy62nOZ8KWccykk/Z8T0dOHfvn0fBjANwFsB+DfqMzcMPq/0yX4lFMm\nAZiESZMm4brRWMYphyozUCT5SihcnetTpZfebLbe2l2vkRK9+GKczaTLHjx2EqXk8cgxaShdlqOX\nTkhJvdRB17QTk9Bzl126f/MxSCW0fa5njeNnymLq2kxtR9JUGMGAkZLGmJ9wMBsoZ5Lh6huJr8jE\niTL/KN93PO20etbx0DO+zcRlqmK/j1LAd79b/e0yN/EFaTAHvBj43tE2V/Rpa13j3Sf8SZkTJUyH\nd9utCp6SCmPWQvcljiZa1uVzREPiSiBZ140pli9Mt102BxwDHENv02bN7353/dokd6a/u0DHof2u\n1CzUlOW0R9OnAx/6UFrgiBiEvqdL8xyjFY6t34XPfCZcpmTCUc7UzAiQODPLHKY75pznezaGQf3g\nB7vv+egMnXFSfa1j163rrrsO11wzCcAk/Pa3k9iy/fDpWQrAtwB8UGv9CoCrARijhwkAnFayzzwz\nCYbpGR+bbMYB0+F0QkqkiZ/8ZPdvJrIPfSbWRO5vf+MlYHSg03bM/cUWizMBos9LDnUxzscUdKEp\noTJ93/vKabhKSE18Pl8xfj0uCbjPp8SYO+QcIp54ovs3EzFFcogwOO207t9Cz7vMNug7SYJZcP1h\naDEaL0lnKbeRAAAgAElEQVR0tltvBZZcMn6T+dGP+AzvsSZZ0oOqK1+WXb+9Fi25ZH29MWaXrv5+\n4QV3pKzUZK42XCZl1M/Q1Q8lJI60LBdkxJT1HZiuvbZbgyyZP+Ydjf+ogSTEvwuStTplDTT9EorS\nx8El3KGmjbQ9F5oSvqW0Y/CnP4XLxIxlX5sxZvPf/na4DEVKX9K54Zq3++8fT0PTJpmHHhpuL8V8\n1sxhSR9KwtSbepuKOszd85ULafBddaT0t89Udfz48Xj/+ycBmIR//GMSS0s/ND1fBLA0gD8qpW4A\nMDeA5ZRSdwGYqrW+xvUQjRiWi5TBbOAKeuCTRF/jfJturLUWsPfe/vulFwDf+8cctFKi71BzjhJM\nz003dUKlSg6IsdL9GBpsUNOg44/3t2d+p5FvYtozjtg5BzxO+mfKNm0uamtqTV/5JEYx73rVVeEy\nBsaRk34b16HWLOiGMRgZkSdA5jZA38HIxZgauPrDaLG0rkuGfZuMxGfRZYr7ne+EaTLwaaxc/ULX\nehf9JopfyrpIzWUMDRdcEH7W117JnGA2uGAaksO3yQcSA4nzcAlToenTuzV3voN6rqlj0wfp2Otc\nxHx7o2Uqba5rNPjmnYxAhGrRXGOjaU1PzLOGLmMybVCqn2gQK5OLzLXemjI0Kqmdx8sHn2DABk3J\nYPyMPvQhNx0hSAJR+ZAyX2O+zcBGb9NaH6W1Xl1r/T6t9aZa69O11h/WWq+ntf6S7zlbApmiaaCg\nm7irwyTmGwZU2i9Rp3MaAbrxN7V4xyQCM30VI8UykNhxmwGe4tOTihILHq3D51QJdMaFWRANXO8h\n2ShKPJvTF65EtWZcm03GBEpwvatPmxLzfQ3jJIHkXU3W6aeeAr78Zb6sTxPruldiI7Fx7LFVFEkq\nnDHtGhMQ17v7wjL3I3y5mSOlD7UpGs0S6y6nKWy6f82BK8bUNuVgmntApW36/F25PaHpsPAGEqFZ\nDIxglDM5SjEpNyaTKWOLe8as5yZht0/jkBMICug9MxvzXX39wmlDjBDBZrJ8wZoMjI+fK6iQoSHm\nTEUFlyaQzBJL1H9v6jzpgmkrFPnQLitZ10MYmuSktnaBmgD4wKncDj+8fu2aoGbgpeBvf/PX60OO\nelW6sPnqXW+98LMnnVT9/6Mfydrk2nchhukpqeJ1oamF16j5YxIehsyWOMSGzLaRw2S5tIDGGT8m\nTGZTEtJQ6NCU9ny+LtI2Sm845jCy6671+s3/55/vf9ZnlhezvsQEEeHq9WmiSgt6Unx4fDRMnRq/\nxpcQ1qXikEOq/yVJF2O+uRGSUe3c3//e8SeKQey34PaEHPM2LgdfSjsSGNNgWq/9rjmmh/RZmkPP\nBbpvvPhit3WAEdb42uHmRUpo6VKIZWRinrVBE+hy9Zp1NvSOrhDjJc4kpUPjS+AzL5w6tZsOSaCH\n2PV1aJge2yTBlUXdBZcduuks6sNSOmSocXCLOUBy9v8GxnzCLEa5g5Q+z0UYoe9gDuEpGhlf+y5w\n9ZoF94AD4uszcC1Ghx/uzsHRlATJjGFqduIqe/XV7npdtKVEBKSINcl0wabJ+Hz4TGtc9Dcl8fZF\nLYrRtFGYcel6L+OPwjF09EARmj8p2boB3jHavu9CCrOcghgHV65/6DMmsaMLRtNi/jdzMGbM+XL5\nPPWUf37Seu+7r1yeHyli90wpVl3V/fsDD1R5bGyUWEtj/LtSgobkrHmueksINuxn9tuv+t8n3efO\nGdRnKkY4YQSaRli0777ARhvxz8QeWIE4gXJTYdx9wYpyNHhaA7//ff23Ej5mLisA+szMmX5/Yl8w\nIR9tp54qM2+NhX3GNf1PaXC9g+/b5PhyDw3TY8OEgQyBG1BUCtHUBIuRAsbYW4f8aHJzfOy5p/+e\njz4zEI0KNledTcF9EzoxU5ieX/+689u0aZW6ldYTO9ZSQdtzmWhIpB1Gw9gv2DRRbSpX1gfKlNiQ\nMHi+tkI0unD66f46zcbHvRs1AQz1w113+SOacaBjKeZwaJ6hEsammNFemZbZCIXadZkkm+A1Lm2U\nb92j9T75pJ9BisVDD3X7VJRCyjf25Qx5/XXZgTEWrrXQMOhm7Erew5fY1AWJlowe4FK+lf2uhinz\nRZ010Rdd+Otf69cxY9AwUYZhcvkIGvj2J+48QDWDsQLHD34wLgCOuY4xAcsVmBpQzbSBiyE1ZSTh\nuOmz5u955gFWXtldNta9wtS5225xvkI58PU35/NE8wp95Svp7Q8l05OjCvdtoBKmZ4MN4suWYgRC\nkiNJ9DXX8yVQ4hAaWyZHkmbKuqRNdGOTOABzoI7OPhMbl9rZt9C6pDgxNselMDISN298bceYt5kM\n0K6yPrM/CQ0uu+JQX9kmlXTTStG0hdrTupv5jvmeMZK0WPSD6THvyI0xY8oXA1NfSHPmGle+PDEu\n2nwCqhjTmBDWXLNjqtZrSPayY46pv2/InCmHQfrAB6r/Y3x66POnnBLXLiDTuNLIhiYPWyrofkHN\nujnhUNMwZw+XP6cP1FHfNWdsoSQA7LNPJVSSJM/mGA7fNQduL/NZvnBa8xQXChO8ydVWLDjztqZN\n3Uz91MJp5kw/w0hz2MVELfRhKJmeWGgtZwZslIjnHlPWlHGZmEkOjBLEPv/qq/6DOV18UgIPTJvW\nscWkG0XTgQzsxQOoDqy+yFE2DjjALW3y4c1v9jsxh6TOvlw9AHDhhd2/SXIt5Y6h9dcHPvGJ+m+5\nGwiln258qfWWfNZ29vcdBI0TcQxC43xkpPvAFRNBkR60XIn0fMgx9Uj1XaE+mOagzGl6zIFXArpu\nSezbXaaJtLyJuic5XMX6nAEd6XVKks8cUI0B4H8nyuRwTE/ummF861LMicz3HDcunoYUM+gYLRHV\nIHNCIeqgnmIqfNNNneAvdA06+eRw/Qbf+EanvthnYkA1Uscd5y/ra8vVBz7zNmqe5oIvtLTd/qWX\n1n/LEXw3xYBwa15TVk+0LSpQdp2RJOtiLGYLpoeL9BKbid41uFzZiKWQDFqXU77ZaEIRnnwL3Prr\nuw9glC5f/dQuG+hsFFTKLZncRk3/jnd0NGfGP8dAYstfYnF45plwvU8+CfzgB8BZZ8XXu+ii/nsx\nWa1Lqd8pcvvsnnu6NzpJO5L2U/1apOA0axJIIskZbZYEEr8FSf9z4dVjv5dE22W3R79xbo4aCsnB\nyId99w3X6UsA6FpLc2zTXT6rBqFEtRwkEvtYbTynhZGscTE+PVy+JR922ilcxggRvv71MA0pliQm\nBLw5B9h1hL5bjNac4qCDOmkyuCSbdl2zZjWvCaBt5pSVMMIuXxZar88filsHYrRNPoTGTepexTE9\nEk1aCFOmxOXEBLpN2DjkRGqcLZieHPOZFOyyS3zZGObCaBdctPkcLGMPNnfdVc+H4oOPYYkJcWow\nMhJvQ3rZZdX/jz7ayUVBJZclFj0g3nQkZkFfYw1ZnQBfJ13UXH4YnISLopdMT247kvnpyvTue1cq\niZWYKEqZTAojZDH5EGjdLoT8sJoMZ+zT4ub0gYRee4OlbRotvZkjTUsgm8YLL3S/oys6E+B3QAbi\nvo1PGME9a77b5Mnxz8aOk1JMDydYM0yJJJWCAaXPpcHbZJPqf2omGsOI+fw9XKB5XoDOt/GZqHL+\nED7Y92MjUc6c6ffjKr2f5NTHCcl8Z6ec1AFSpqcUQn0Ua+5uX4cSjUpw6aXda5mP5gsuiP/mOXvi\nUDI9vo3aVc53b7PN0ttfeun4sjFMj7HrbOqgkSNpkAyuO+6IP5i42jcHRUNvKU1P7KE3RspvmDpX\n4kiff0GupoZLJErboc8bM7ymBAA5daaYZMS0RSVGzz8fT1cu/bHh9CVt5faTrx7XYdMc/lw5D5pY\nM3bf3d+OSVjJmftIUELTE1NvbqJkwJ0AW5I3jssJZIMzn43p7xJjQtL/IyNxoe99iN03JJrNbbeN\nZzAktNqMjOmjI46If14CLnorAPzylx06fEwPHfcLLZRnLeN7VmJ6KzFvc/WtZI32aU9yzl+5a17s\n3GqK6ZGshVwybgql+LWLw1AyPRQS523zG3Vg7qcJUYkDDOA35aODY9q0cloUG5dcUvYg3QSNHFwb\nnaRen/+Jy/be980lalva3muvxZnUGMS+W+wBStpOU4dY6u8iSRAsQZOah5A5X6k1w9eHRvtqt9cL\nKZyLJtPPkvEiMRvLyVnhWkvNeHMdrmhbvvnuWjMMMx+i77//jTfDcZkQ+uqX+lja9YwZU2aNXmKJ\nbvPJEvXGCAR8cJkD+vYRrePX01VW6fwtNW/TOnwotCPBSaKIxa7nW28tCzZDIfGb9dHk0mDRsrn7\nWwiLLJL+rGRsu4S7KZqekvvlZZflnal8UEomYLQxWzA9PkgW6V6ZTrgGIWdS4hsgv/lNdx3Uyc6Y\nh9CwvE8/3Yyk4cYbywxomvTMhSa0FC5IFkQfTZIkrpIDI3X0PPfc7udvvdXfTmwfcgdw6iwvGcNN\nMT3UydcVjIOrM9Y3TeLD5pLS+2h67LG6AINbM2LgW184DRJdDyVaBsowSUHpMtogyXjZcMNwvQY5\nwW5cIc8NwxLy1/P95noW6ERtM07mPuf7l15ya4qAjtO5gd0nJsKk+S0m7HLsGp3ik+LC294WVy62\nHXOdu/+H6LcZ99/9Lq7OD32o87eRvvvaMUliDZ5+upl8KxxiLXCagM9MdOLE7t++9a36tc+UVJJT\ni7MSWW21+HooJONSIsDIEfRI4PJTL3Gue+ON9PE1dEyPi3Pn/F58qkxX2Vj41LsxcLVjEsdJaKBS\nkLnm6n7eF45TEhErJedBDLh3Nc6V5tt99KPh+kzZbbet//7EE/G5MV57rZsuk2ySQqJiHxnpLh8b\nGVCqVaTlr7rKT1vseJs+vRkmOddsK7Ytl31+CZok9XJ5sCimTq1rAFxtGCmtywGZRkHk6ok9qPzj\nH/HvSsPRxsJIKktpGmLhynGWI/31HaRLj23jX+j6hr7naZJSm7mm+5AxaTIYGelet0oJNCRzmcIn\nmV5rrXA7tgaGwvidpoDWZwQksWH+fTT5+okyqG+80UyOOU4DFuPb1BRoECSDHGZWEjmsqfeUCAtc\nzJuPGczVbuegV2PCh6Fjeh57rLvTfNFaRkbipSqSyZETOcL1wY05jmTRoGUffLC7rE+C2VQEFlec\n9RSYA53ZYBdcMPyMaXeeeeq/v/Zat+reZzv6wx92/+aT5ks1GvSeL8JVjnQsx/yEc5x2He4l39l3\ngGxK05MDSThaSX+7cjVwUjh7HHDv6QpDHWuT7RqXJuiJa41rgvG1YaJM+jRFknrpPDr++Ga0fdwh\nkDIISy7ZrTWNNT/hxhqV8ruej4GZp+Z/15yney337va9kHQ3h+nx7XPzzx92Ir/5Zjd9WgNnnhlH\nk+95GynBOHIEVVLEMvlSpqcJuA7dPlO4Xu0xXDl6BpVYCEjod9VL8wNy9dIoaz5wYyUmhUDL9CSA\ndpqPsRmEaD8SjjpHUiLN2RJbr8QMqjQztc8+/nux7bgCR/gWyFxb1hKbwdixcXVK2gfcm79NF/fu\nro2OatQ43H+/+3eXRiLkUGuQK23yQRJBRqLpAWRzzp67JXIq+ejx1UvtpXtpquJKGAvIEtJRoYJL\nm2NA3y0lS7oLe+xRv15llW6mx875ZIN+G84Ez6VRShkvJmCKiX7mOsjT9TSW6eGQy/T4oFR30k7a\njjno5WopQmU5jZKkTskaIkEJv5bYCHC5oGs/F/0yxyk/x8rC/k7UzFCSJLopBsE1t010QhdsMzWO\nJpfJLS1/zjn+51MDX0jObkPH9Lik9FRlb6A1MO+83b+50FSo3xwJOQeTyIxDTtZaA2m/xL6fK9Gd\nqz5J20A3vVtuGV8HbTMknYz5zfwey/zmjA9XOwYuMz27Le47uw733CGSa8cG9UsD4k0yJCZ3UuYk\nFjlCFW6uKFXXtCglO4j7vqVE2+RCryR0vnboGOZysOVETHJpTlJAgxE89lj3t+G0WiF6ObNLiabK\nB1c0K9qmL7+NywzO7EeLL959LzY3UFOSe4lmLQY0mIqpv1eCWGk/xVqvaC33dYmBlEmzfUl92gzA\nb+obi1RNz623dvppwoT6vVxzax9y9yMu6ERsIuRllgmX4QQ4ku9ljxmJ9mzomB5J0j8X0+PLqHvf\nfc0MRBfTE6sReO65PAmrT2oujcSUI4XzRZCRRGahfXD22X5mkv6e46TMHTTpJJsxwz/xqOkYt2nk\nMj0+XHBBd9lYpmfGjPjkoCn5ImzMNVdcOa27pbhc2VhINiRJ/h8KeiiyQTU9Y8bwiShDMI7vriRx\nkr6JTfScCx9NVMvASXElGnYqQJLOwVjB1kUXydZSW/rump877xxXF4dcYZ8vj5trHpmcTK5v84c/\nxNEgmZ9U6szNIVrnww/7hakxzx96aP3a7I2SYD85mp6moHWVnDu2bFOw10/JgTeEZ58tU08oT1Cp\ns6Z9P8T0SFKASO9z5SRR1iS+r9QaIhZDx/RIJtKDD3ZLMHzOaWeckU5TKdBBKXUIbsKcQDKYXIcQ\nV1LJXLiYudQFNvbgH8KTT/qZGRo4oilTIYl52/zz18tzh/A99+R9fmwcfXRcOR9ig4RoDZx4YnzZ\nWJMCydz47GfjyknbcZm3NQXJmuFzik2tU/p8bFAaoPsgxPX3q6/WzeFC/W3yB4XqjYFPujoyAmy8\nMU+TLxSu6AAwRpY8MbZuauqsdeebGDMo438pyaMlkWbbIZmBqq997bii3d12W3xbIaGQefdHHukN\n0yNdM2LLX3tt/HjplUlsyXZo1MycoBP2PcqcNCFgd2GppTp/25p+KhDQmv+u9noqPdMdeKCsfApm\na6ZHonm4/35g0UXrv3GS5F4MRInJVO6GmkqHDYmfzn//W4b5oKDhcl39IulXG8Z5GqiSztKy9qJh\nwxcu1gc7b4jE16qU2SVdvFdZpV6eY2ouv7w7QIQP9oEwBRJNTyxGRtymXb56+23yte++9WvJGJg1\nS5aQTnLY7Ld5m2TOU4QOL7afQKheXxh4A+7wQOv2aRNmzaoLdziachJAKgX86ldxZXM1pvQbmOhq\nW2wh23tTwrXTvylMAA8DqX/npEn8fXNolGglXEKG1ISMpXDuufHfShLwSVJWYqUgxfzzd7cVSxMX\nlMT2a20qkIFrjfNFAaX7eagd+91OPdUf9KCXmsjUtoaO6dE63r5w7rm7D63c5ErtRIkD3z//Gd+O\nRAIHyDLaxkJiTgikH0y4cpzNroEJ3SuVjtkmM64cEJ/4hPs56VgxJkYAz7jT32+6Kb6NkZH4MbDH\nHrJ3eNOb4svmwBf0IAexjBRQ9SF911KbKpV8+0xtr7mme1OPZdpyIvhxmDixjNQz93nbRKkk0xMb\nLc/1HC2fowH00fDpT7vbBrrzUkmgVLwWN6e/bU2P3TZQje2mBI6ph2MT6j8WIdNPw0RJ6D/88Phv\nQyFds5oQfjQVgGXy5O52SsHeKyT0c+eecePS03nkRvuLjQ5pgpf4YNOhNfDJT8bT1ZQfW+rcHkqm\nJ8c5LSfctAE1leEkf9RsSLKYShc8zhHN9n8YBA1SDlwHQCmD6EMs0yZ9z1gNCK3XFUbbh5ERf1JC\nigce6D6ES+jqN3K0MVzyTK27/QBL0WE7a2sN7LVX3HNKuaMQlqBJUk9TwhoJYgVeFKHDGt0XJNLs\nJjSD9KDAmRY++GD9WjJ+lUpfmzj8+9/d6wt9J1+iUYmpkAQzZ3ZCVIcgbSP2YCc9AHJmxxyaWq9T\n518Iu+xSt7rg8Nhj9UScvYws6cOVV/rp+OpXu38rxeSH9nCfMIeWffppvp1LLuHvczSk7geSd5dE\nxBs6pkcitaW4++4y5m3f/Gb9mlOFU02J1vHO9SUXLpvGJpkeiiba+dnPyh007HvG0Ta3zlD5kuZt\nth9VDk2lyu64Y3obEk1ljqmNL0eSqywQf1AKwT4wSBZ06uMTQuzB6sMfbmYM/P738XVKIPHpoaD+\nHRR2/0o26RJCNBe+971wGd/7S2hafnl+PthYeOGyecRsszr7Xbh8IdI1zqb34ovjo8RJx5qE6bHr\nygmpXBKx/XrFFTJNTyxuuSU+WA5Q10wMgs8jF5xImvNMIowMoUQeMKD7nCERBksEdjYkVh8SE9+h\nY3pyHPT+/vdmzNukH5XTyNgoeYi1+4EuvKGIJU0cjJqCNKJWKr1ad5s0xEZH4aTO9PfQAcZu88or\n68+H7L+b0PScd17ac0BetCQOrjwmknoPOSS+rVjkmlBxiD2A/fnP/nrHjpVvjNJyUtBNsOT6aM+z\nvfeOX0uvu07+LUuhhBZ6rrniyy+4YLqP4cMP89EW7bKcz4PW6aFqc/KwXXEFfz9VgxdKni6ZS/a5\nYhAYAUpDU7nVOM19DmJNioHu3DOlGBf6/SXhwkdG4s12SzH1LqSOxVCbqX08dEyPBC7zDK5zUv0J\npAnT1l8/rZ0ccANPEqWGgprgpZrExEobQ/XG5P9JqddVjjJYsRvw+efHt29vFK6gCnZ5ajrJJW2j\nz5ZienKk8VLE1k2DToSYnlQmXxJWWrRIC518SzjKukxrfWXXWad+LXW2Tt1QSx4m7DHR1OEMKCtY\no4KUFEjM83KYzClT+HFh0y8JrSsROErelQoCqUCGHoib6kPJd43xffWhiXWaCmtiQ11LEdLiSmDT\nyyVHp7j5Zj5vViros5Lxzpm658xlrf3pUEqOo5DlDfUzisVszfRQR2GteVOVVDWcFLESp5IDyJ6Q\nc89drzsUR52jI6SStgcml/SPhnUuCYmEI/Vw7/vNwO7/G2/0q2Mp82fb67s0ITljpMShqZew8yZJ\nogpSZlGq6YlFyag8seaQFHfeKbO7LzE3bPv6XDSpVb766s7fVCAgyeuTS4eBneU8BJcjtH0osPOe\nNSVoOOAAWXmbDhqBkysbYnokwhrbVFEpfr+yGZmTTqrfo+ODStwl+0bq2CqlbcpFKv2hs0JTGoFU\nSLQqFKExagIvhZ4NCRHt6wUWqN977TU/HblMjw3qOsE9K0FIEJ5a79AxPaGJwU0yrWXhRJsAR//E\nifXrsWNlCQFjTTIo02MjJjTxcsv5n7Xr/fe/64wnJwkvGW2G3rvwws7fdiZnV1lJuF96HSvp/8Uv\n/Aee7bePqyMGkrlSStNT6jkXqHQ19ltRNX+orAT2+0k0MqEDjI2QT4/tA7HDDuUO7KkCASA96lQI\nqVHWgMq8uQmkjvFcf46zzsqnQQJfjrsYhBylY9ci6XvagWCU6ja/tbHDDrK6DVZcMd30M7Qu2eWb\nMuMCukN2c+iFQEBS729+E/+cRDBVKvocNcl8/fV4HxRJ+9TE7qWX/CGrab2h8cv1WyjYRqn5XEoD\nP9sxPfQwScs3EXo3JzO7DUrbXHPFBz0A4pmed76zfo9Kw0LYbbdwG0DFqd95Z7i+0rClnkCdBlub\nt9lm4Unni5qUYwblunbR1zQGjekJjT26gKdq5bh2pJJYu24Jk3nRRfFtzD8/X7ctEZNoDyhNJctS\nSXlsvU2NQ2k9vTislWzDrsvWiEqfDUEinKICpliEND0SGkL+qjZSA6k8+WS6eVvo7CDR+KYmNA6Z\nQedAIkSKNXHMARU2UQ0q/T6Sdcwn9Dz11Po1TarNnQ0k/XDJJfXzCt0L7HpfeaU+9kLjlzMls69d\nGqxS6xz3rST9NHRMDwU15ZDYA5fCccc1U2/JiW+bRp13Xr0vQhqKWE59xoz6tUSqUjLMbWy7117b\n/Rs9lOT4O/UCOdL4yy6Lf86+L/F9KznnaDCOWLzySrwWTjrnjjqq83dTTuohiePcc3f+lka3bErT\n0wsmuaSJhqTuUt+55Ppu08tpM7jnAF7IJmU4JPnrUs3bQrAPfjmR9kppzZ95pn7/4IPj65XQIPlO\ne+4ZX1YC+q1CZv0HHdT5OxTsKXUO0nMGx/ApJdNu/uQnnb/t9/7DH+rlZsyI11hLfWRtn2ZuvH/1\nq+kCdW5+vvJK/fz19a83dyZPfXbucJHBAh3sH/5w/LMlD2C2qlmymEqj35Q6BNg21WeeCRx6qPu5\nGE1D7EFJImE/44xwu7E05NRz+umdvyW+HyF1sVSdHIucfrDV0pJDYGzMfqCsSZG9Eb78cvy777UX\nn+fEhsRXCAAeeaTzd2qm+BhwNNGEehLYkrmQhsCmIWTvbjNiJXMMNZEodpDqKoEcenwOykA1l21B\nSUk67LKcuYzW9fEUasP2iSwZXpxb/0P7sJ1TJGQG2gtfS2lIfvv9qDaBjg+7bGiPty00QoLLUkKV\nXgg3QuC+scSnB6iHuh8zhhcU2vtGKU0PUBe6LLBA/NyYa65w5EbuOhZDp+mh5lKcczxQN/0IMRGS\nWN+2qq2pjVi64MU60tO2QoPHjgIiORxLND0S36WSoO9j+//kIDQue2E+E4I9XprKN2IzBSGEQoRO\nmtT5++ij4+uVSJwlyWBzIF0zOOm9zWBI67UZWKoN4zaZEINkS1RDZkP2WtorTQ+NbDToWq0maZD4\nX9k5mCR7QSjYhb0Wcb41Wsv2IxuuYBCpoD5KsfvpyEi35J9DqvmsBDmRU2lSSHudmj5dRpP9fhLB\nmgQXXFC/5uZ9qL9TAx3QoB4cY0PpmzkT2Ggjf932ukz3dNqOvW/Qe9TskmN66LP2WU7r+n0qBOXe\nNRRcZo4xbwsdjqk6ctdd69e+SbjEEjJ7eHtASQ4aCy7ov0eZrhyn6pKQMIOpAzHnAFPyudh6F19c\nxjimtiOFZNG2v88KK8TXm0M7Z8Y4YQL/bKrNt4T5zoFkbNFvQ2m0y4aisdlrkdS8TRJ5TdL/tlZu\nr734sraZRSrTLoWtAeglOMarVL3S+XnKKZ2/JQe9yZPjaQohVlhGBZcuE2UfckIm035ZZpn6dWz4\n3JAwjCJ1D73llvjnpIISyjj46tpjj/S9gppQl2JYOdopQv1iJ0gF4ufg44/Xx61E03PMMfF9GmJ6\nOAr+7UEAACAASURBVBM7Kvy179Nov1xuvpGRerscg92rM9TQMT0h0GzgtkSGqsZtbL65rBNTJeNr\nrum/R6OQSE1tYs3O6LXksCYxuWuS6Tn5ZFn52HZi6Rg/vn5NF8impHKhelLHC/fcuHHlmFmpVDG2\nXg5UGlmybslzXH9zJmDf+U58vdJ1ibOd58bW7bfHtyFJktsrlFoHpLAj7aWuYSE8+WT9uql3keZj\nioXEp0catMEGJ4AJCYE46XwoPLcEdr2SvDFNpoDgYK8/Tz0lz2FoQBnfM8/s/P297w2GeXgpSJie\nZ57hNT02lKrvfRLfGsm5gouIS+crF4FNepaZY/P0SCKaPPSQ36GZSxjpgi8UoAu2s5xUksmVzzEJ\nkzA99gJkb9qhekvmLaG48kpZeYOQyjTWwfBzn+ProRg7tn4dm78oBNquxFTFpsEOfxtqJ/SuofC0\nqShlRkqj+3GQSBhD/ZJqxiX5pjl9JNn4JMEs6GZLQzVLxpYdkKUpyeCyy/K+aDk5fX70o87fErNL\nCWjoWu5w/8c/1q+b9EvjENuHIaEblwtm8cXr15wTu5Qptse47RcKAJdfztfFwa43tA4km/tYZ5mF\nFop/LgSlZGbI9nii664tLJtnnngfYIkFA0cP0B2IoSm3BntdOOec+jlvZKSK5ul7lqMvJh2JC8sv\nL2OY7PWGnmFz1k56nvz+9+vtxGLomZ4QbM5S4qgbgoTpSZWIheqlhzeOyeAkU6EBY5eVxMSX5iRI\nBcc0rLhi/TqUiFUCuy76ragfw7bb1q/t8jSKimQcUs2mRH1/442dv7kcEPSgEaLPTgKZI5GjGhpf\nu/QwE0LIrMhuxz6kAt0aGUneGC4vC7cZSOYN7YumEqbGJlgGZBGItOZN9G66yV+vBKEgJeuvH1/X\nIEiLORq4fjrkkPQ2S2qzU5keiSaZakE5oWGOJpD2N9W8+TC3I6yUZIzbDJ9kzuXkvuLqAtLDYeec\nV2yEcshQcOsu1Whw1h2cMJWCvg/1bbW18ZMnA/PN56/LBh3vdM22aaSh3e17664rGxf2OCy5NlIz\nOts0e45merhODuXGsJ899li+bKp5m5Sz5SRXdIHnPjwnVQwdjOx6f/CD+uDjpMHrrsvXWwoc07PZ\nZvVrGsWLk9iFwmhzORZuuKHz9+qr8/XkHN5++1v/vdChRGL3XQo5+SN8anPOTy4XNmMIdM9HW/pK\nxxIVdkgYRwlsP8Z5563fywkFTzdCydywETL9TDWfbUqrlWMy2i+k0phjovbVr/L3m2J6JOZANqhw\nKce/QHIoj30315zyCXTe977u3378Yz8NXDAR+zAsHUeUoVt55fp16jlJEsWrV6DCmKZC11PBJY1Q\nHGvhQ/ueWnNMmdL5mzO1lazJQHdUOPv9Fl64u24faP9yQsM5yryNgouoIQlU8K1v8fevuabzd6jD\nOQkAtxiNjMjM7riFgvaLvcBKFvhp02TmQbGgUfnoBsCF1eTo32QTvl3u2ZBqniY6s2Enmt14Y76e\nYYDdTyETR99zOW1y96Ubq+tgRJmFWJrsTOb0Hg1AkKpdDaFkWHAb1N/HponOT45eLkke0G2bHdIE\nGTQVcTDU95Tx7fUhzKWFiu0zKXKYon5oekp9i1C9P/95/ZoL8mE/Sw99qXC9Z6r5bKheDqedVr+2\no19KtMEAH145VdNDn5Xco4fuUJCY1D6n73PAAfVrGkb+hBPi6qXrIz0f2gGq6LvROSYxb6PnXds6\nQmI+STVeEkEVh74wPUqpeZRSl43+/Sal1OVKqTuVUmfn1p0TcljScfail7PQ0gggqfQAspDV554b\n304/pC5nk5FgmybON59sk+SuOYTMEjgTx+WX7/z9i1/Icv5QZ79x4+KftVHS5thuh2o/mmrXRYf9\nd8l21lnH3U4saDQ/oHvTSV2kpbm9SoGbO1y0OQqqMeLaGYRIe6F3kzB8TcDVXimmh441Sch5Ci4y\nYCpTT9eiHB8BSZ/Ra6rljz2Uc47cMXRwv9vfKqRt8gmHpWOZE2AAzVjE9GqNo+AYg9CzHHIsPST7\nf+p4pxHYQs/agvycb3XYYfx9n6BhgQX453rO9Cil5gNwO4AtRn/aEcBTWuv1ASymlNrC+7ADw2B6\nkGozu/XWsnYkA9NW7ZdMpBkKY2qDcxLn8iCEJEhcf0sWqpJaCvt65535slTCTk30Pv5x4G1vC9Nw\n223hMj4a6L1eHNhDNEnGoS9giaveEhgzRubDRoUdJfuJAxclLtTfEqYn9fBJfd84SJKe0na4d5UG\nGAiFFC+NXu55TWnTqIkO904bbOAvRyOlNdU3kpwhFDk0+dY8V522X2ZoLfLV++qrZf0AU9e1koLW\n1P6n5pCSMVBqTW4SqdrVUD32OLz00vq9kkIKX3+H8v31nOnRWr+utX47AHOsnQDgqtG/rwGwmfNB\nb30FiWNAO5KbzFzIUE4VSGFn142BvVA89hhf1pZaUM445wDDtSux0aQmJBIzC8nik7NZcQdrCU2h\nw/wWWwCrrlp/PiYfS6wa3EUTd7/UnKPMH9cmvR4zpnPtmkNSk69UzaGLHoNSC3yOwzi9l3Ogsc05\npZnCY8uGssPbph6HH16/9/DD/LM26GH+F7/wlw19t9126/zdC01Vk4c+arLbFNNDESuw07pe9tRT\n4+uh4JjVnMTgTWoiYtvIicpHTdZykMr0cONOmkA6dY/PWeMk/rJHHBFfVgIadEqiFaLPpYa75jSi\nUnDP2gFuQnDEC+k5FgdglL4vA/C4fU+y/h4/+q/sAsN9WHro5rQJNPHdLrv4y3Kwo1fFHHK58JZU\nq2LTH6qbhlvm0JRpE5drpSnzn1DZkpHguHa17ryjuWe+WepClktPLGiy4JxIQXb5Cy4Attuu+vux\nx7qlcl/+sqxu26csZU1xMT2ceVtTKLmp0PXQzpJe8nAvGV+2D5UdvhqQZUin4Vs5AQwF5xv6hz/E\n15MKV//Yvy22WN0cWDImjjmmfi1JdtuUmY5tEhY6gEnASfKlB15qDpSK2Lnwpz/xIaxztAepAkYX\nJEyzXReNUJazrnFBV7j+DgmtKGNj36dMJ0cDXcdKIaQFta+p9Yx9XpwyBdhhB387km9DBVUS/3CO\n/jvvvA7AdVH1DALTMxWAce9bePTagUmNE8LlfsnRCHBhG7mDqWQTB/iDiJ3cC6jTTA8A1PSgFNMj\nCR/ZVPIxafjc1HbsWPpA/VuGNjbXd7eZnlhNj8TsJkbTs+yy1YFPkhvr0EPr9+wNNdQm3dS58vTQ\nyjHJ1O+Pmzf0YORDDNOTeoC0D/ohSLSPEhqAej/ZYckBPhxqCJJ+4Q6Xkja32w741a/kbQL8+M+J\nlheLENND7+ckBJYcWiV546hGL3a9b1JwYJvlhEwcJaZNEnNJyqxw/SIJBy0ZwyUFgxJIrAmWW84f\nPZU+S/egWITWF5qrjKN///397eQIkHK+FbeWUoudUonmr722fh0bzp3Wu9NO9Wh0Sy45HkYRUsFK\n4kPQz+htZtpdDWCr0b8nALjWXbx5lDowlFpQpM+lDsyllqrfo8yJhDHg3p2qIJtaeEv59ORMdNsO\nHaiHhKShI2P8I8zhw9yj1y6UGs+G0TL9msOQmo2CjjkXuEzPIXCh3unBgh5+7XZCIc4NlArPhZCD\npQ1JRnW7XXrwlBx4JXODRp2kGgIuISOtVxLRhzMjCiX5tcvnaOFKCUpScd99/EGa0nDkkelt0X5a\ndFF/WYlQi87tWJi1qAnkMIf2uKQHu5LJp23YEWRz6qHgUjFIkfqtaAANWo8kj5Yk2iiHd76zfs3t\n25Teq66CF/0K3lJqTOSYsIXMmW3Yc2y55dLHVj+ZHkPyLwEsr5S6C8BUrbVgKpcFJx3mOpjbCCT1\nSEEX6WWXjW+HOzw0talINrrf/a5+LaGRW3yakmLRbyF5ljIRNEmdzfTcfHP9uqkF06Z/+vQ605PD\nTJl6XUyChCZ6TZOrSkz7qL/eKafI6ALyfXqo+anEJpyrN5SINbVeCqqdlISrTZ2TlHm1zYhd9XLR\nrWLbdF3b4IKzlAQ1ieGktlKLARuhiFWpSK3nmWfK0SA53IfatKX+NBCNBHQd49qVrHH23rvYYny9\nt99ev+bGdMmzgi31D0UI5fLTpZ4VKGjUVKqV4JgeyfpSyqqlJGggKU4jQxk6rk/pOYkKFTnY9eYw\n5n1jerTWq4/+P0NrvZ3Wej2t9Zek9eQsMBLQD2mbMeTE3qcSUd+Acf3+la/46w3Z5UqYnqZMwKjG\nw8bmm9evUw/atE1JhC36LHcQtZ2ZXc9yoGZorszchs7vfKdet6tsCii91HzJZnpKwMUkhGjiytsh\n2KWgh8IUyWyuT8+kSfXrc87xl6X0SkLVS8Y7R6+dhypEQwipa8itt8rqtRkFSZvU1IPrQ2qzbmOn\nneLbDCGU4NV3T4pe5UKKpfEnPyl3SJREGqVoSjBIzWm5dlK/zZgxfIQr2mZTTI/kO9q+oZIIjyHQ\nd7PfJ7TfDRvTI2EUzPnRJJiX0Mj1WymzOequITmbzHbJSZsCndy2qVbOwZ/6IkjqohGqbOkqzeJL\nsdJKnb/pwJMsvDlMxIkn+stSPyMuooxkwOf49HA+MjQ8tGQyH3hg/ZpqDm2Gw4wXc+CjEVpcmboN\nJOGKXfkkYvs5plwK09PU5rDffvXrFOYu5n04SBInf/vb9etS0mBqniRhpiTfhnPAtuEyB7TfNRTS\nn/aLfUiRfCsq+eae5XIS2RnQXZD4xFDY85Uz7ZSiKSsAzl+sV7j77vRnJf2QE2iHm1eSnISUKeYi\nhkloCPUDl3ydM/misB3eV1gh/jmgm8Y3v7nzN12LJGtEqQSqXJLzECTj0E5GCvC+ooZ+E6ypqb03\n1aeHQhJApmV6CiBk1sKVTW3DBXvyhJzY7TwvtG5JyMpSDm4UoWhKnGSTazNHAkMjkXGQvGsow7tt\nzvbggzIm1IaE6aE+Az/9qX+BsiNFhWAkPca8jaP3pz/laSylgSwBV54eCo6mCy6Ib4uajsUyESEa\naDI4iemHZF7RHEWSb2UOJYstBnzpS/HP0XYovdzmS+mzE1NLEPJ54cJmU9A9xmZ6YhLH2gc/DnQO\ncpAw7hxDOgyQmAw2lYOLS2weArdm0DY5Rj7nMCyJMGcLHnItBPbdtyNYpN/GRAQF+KTgQPeY9SXL\nDKEXwU9c4BIP5wglJOs5NaPjIE3s68MgRG8beki0HaH8ORLnxFImJUcd5b/nuuZoKGUCFQplGBv6\nuKS2gPoZcUg5yBm4Dj+x75v6frROyojRMWKDmoNxDsFm4TKakfPP95elc4Ubl/QQksP0pDBTKZor\nGznmA6HM1bGgNHA0UfO2k06Kbyd2fXH9bn57//u7tcGSdug9zkya9gP1u+DK9grSMRs7P6gTOPfc\nVlv571HkHKokTH4p0PeW7AWp7Wy4YTnhDd0/uHFKD+GcALWpdbbkc/RdbU05rcvWhoSi1lKmLVWT\n3CtIaKI5z5p6H8m855g0CVpNTyS4j05jynMfctdd69f0AEN9KZqC1p0IWqHQwFwAghyJBiddDdkr\np2p67Os11ohvAyjnXE5B+/Cii7rrsscJF9e/VxsJB+4AaZgpo+nhNlRJcIh+ScsMXEwPZRxzojil\nQhJMgY5DSchzitQ5aePVV7vNNw2NMYEw6H07JUGvtIY5YYU55JoXxuZiacq8je6RkgMNp2UZxMNm\nbNh7oP4d77ijut5oo3wa6H4pGe/ceaYpLRaHn/1MVm/q3JbSZ+9BTQk/Vlutfp1zzuBAz4Tm2UUW\nCT/L+YtRSJgeSU4fDi3TEwlucH3zm/Xrn/ykmXZKgh6kORo4Rkwykbg8SBSSLPSceeHee9fv2fSG\nggD0SooVc3izmUDqPxRbF3cvx6mXmsLtu6+/7A9+UP3fVBLbEuDsg3196DqEU4fblKhwpUGZCBuU\nfu7AnmPLL1kzKA05TA93jxuPOSaxe+4Z/6wElF7J4YGGVOYg0f5JkFNPP7RpOQKLUCQyGy4/kRJr\n5S9/2fn7xRe729lvP38CyhyfHg5NnXVovVwgBs7kNEQf7Re7nabeLSf8dok5F8P0SMwuJf1UKolr\ny/REglt4qF2iJNKYxLG+5GIvYXo4UJokiQY5hBZ6ro9L9WG/mB7X9ZJLlm/XBg2AIKknRQKTErKa\n00j2Uljggut9SkmmKCTmPXQenXqqvyw116DJ92zkrEUxPicGvlxNKeOHa5OrS+LXkpMwNQeSg+l9\n98XX25QGtQmmZ+zY5vq7lD9BCK7xUyKCHjU/pf5XCywArLmmmwbqAG8jZ3w09a1olDIuvDUNc29D\nKlSx+2IQNY45MFYXOcFWBgWi6aSUWk8p9TGl1IZNEdRLlBiYq6/eLdWUSGZ+//v6NUfTIYfE1xuC\n1p1FjiJHsimx6y4F+h6cNESi5qfR8SQonQckNmJN6mGCJguV1EPtf2OQEu2Mmhfaz/dKcyRhepra\n+CQaUwqOJsrk0KhlNiTBKygoc8XRREN3N6Xp4YQKkgAmFJJxKcltRCF5V4mmp1RIfIommJ7XXhvM\nOZeDkZFm1jbKrNhCUNqHO+/sr4dbI0Jo6lvRaKipkGp67D4dxMAcOTSZNbup9aCXiGJ6lFJLK6V+\nCGAjAK8C2FAp9WOl1GKNUtcwSky6hx/ulqLk1MtJVXKitVBwEiRJ7qOmND3UT4oD3RQ4+qmzIfet\nchznciIZ0etvfxu46664ulJNEVybYCwkoVMNciX1QH+kab42778/L/y8BJLNS+LT42rnrW9135NE\nXqI49th4mqg/hHn3F18MH7gkGt+cXGuxbYYgiZopMW+j9yThXel6PujmbZJAQBJI1vMcNGXeRuHa\nc0w7/RYgDQpCmnpK/4ordv5++ukqEEXTWExwAi8xd0vn7dp44+r/lVcuWy+H4CsopRYGsAWA72qt\nT9daX6m1Pg3ARADbKzXI1vk8vvGNflPQDc50ReIQGcKMGX5V5XXXxdfTlDmHhHmStGk72f3nP80t\nvD77aBdiFqNYafNf/+q/x42tSy6pX0s2+RTpj2F6Ypk5F2zp6w03pNdDsdBCac9tumn9uqmxJQmX\nK9GqUBgp8x57xD8Tg1gnehcM/VOmAMccw5flNL5NrVu0Hsk8kmhMJYEMcoRlTfnP5EidOZqG3fyG\napT6wfQ8+GD59lxIGVsx54JQuotSoPTb69rrr8vXlC22kNMgMS+UBBjwoTTzb/INSnMv+bD00uEy\nMXzb/Frrc7Wuf0Kt9RsAzgQQ4do0mGhKZd2UyrfkIWr33cMZzWOQk8uGg0QaSUE31Pnn7/xtO3Q+\n/7wsQVpT6JVZFJWwc5DkIkmJ8mWYnlLO/SUPOxMm+O8NunSSgkaLlND/6KPVQZyL3piCHIZDcgDk\noi3SjN6lkOM/IwEVUnAHSHNv1VXl7TTFHOYwPak+m8stl95mr3D88fXrUj49FBzT0ys0tZbmJPuU\ngI5hSVJ3F/7v//LoCeEf/2i2/hSYPiql6YlKjB4qoLX2pqbSWs/UWguMoVqE0KtABqFEebH49a/r\n172SstgIMQ2HHAJ8+tPuZy++uBmaJIhhekKJ0mJw9NHxZSXahBQMq37Y9ikZBtA1IyX6T+lQ24am\nt7yl+l9yOJBINrmyf/5z/brUAazpeWNAtVwxTM+yy8rbod8+x+/IRslAGDH47neBzTZLb7NfaMqn\nJ4bpadrk6IQTmqm3V4Ipeoaic+POO2X1NcHcDirOOKN/bWd3s1JqaD7VTjvVryXOuJIcLTngTMsG\nUcpcymkwByGmYe65gSWWcD/LJdJs0Rz++c/ufESDgph5NohzMQalwn7mwBx4N964Mmv44x+baScn\nEMmgg4aJ55gIwySkHKqaGi+9Dlm91FLDOWeb0sDE+A75/PlKIeVMFdMXvfrOpefGsDM9884bX5Ym\nty6FIpqeqiJ1jlJqLaXUJx2311NKTZKR1nust163pEeilTD5RfqJYVy0+wFXP5UIz90ruPIKDJpm\nYe2108xlDHolEU8BNyZK2EUPG0qPPRNoxNS7115l6zeQMNWlTfh6jRiz6EE6VOUwPZwGzyddX2yx\nwVzrQ2jKvI32/623dvt8DtqeAwwW01MaOd85Jn9O06CJUznQdy011ooxPQDmB7A9gG2UUjsqpfZR\nSn1dKfUmAMsAGHgTt3XWyTtolVLr52BYJ3PToP0isUPnEpf1Cq++Wv3/2c9W/7scSVP8ZlLwxS/G\nlZt7buDxx5ulRQIaRCAHl13mv7fGGuXamdNh/LqacpaX2LBTH5lhgQm6wZl8GW32IB1iR0aARRdN\ne5YzSfaZzVx6KXDeeWnt9RMx5m2SoD8mvQPdE6dMkfl89guDsF83hZz5+alPlaMjFd/7XnxZ867L\nL98MLRximZ4ZAF4B8DqAvQCsDGBHAD8FsCuAPkWxj4dSwO9+l/78IDiB9SMT9TDCMBEGnIlATr4R\nF8aOTX92ECSxb3tbXLm77x4Meg1aM8XhBSeU6FVeCEnC10GC6R+O6TGJnHs9X3ff3R/Fsuk8Jquv\nXr8uFWCn1yht3mZM1lxnCRrpcfHFy7XbIoxBEkqkQMJ8m3c147CUQD9b06OUWkApdSSAhVAxNncA\nMPqS/wC4E8B7tNZ/y6K0ByiRF6TfGAb6ByF3ysSJ3WV6taDktDMIi94FF8SXXWed5uiQokQkwhZu\nNDWnTYJarv5Pugyq+wQ7CuSgwNjRD6JAbOxY4F3vct9rykHfgOZIKdVWrFCoFGKYHkmACnMwpYmI\nXYjV+s9piAmLnIKcMToIAkgJ/ZTpGSTzttcBXItKy3MwgJ0ALD/63LYA5gJwrFJq4xxCewGlBnNj\niIExA3jmmf7SEYOYA5Iv8ehOOwGbby5vc5998mkqhWFnerg8PxS0X9ddtywtKaAS3jkFH/94c3U3\n5XRqNuphEOYAefPzox8tR4eN9dar/o+RspZYXz7/+SpZcix8bR52WL6WXZLAutShUNJmCWy9dWV6\nxmH99ePrM+OEWkO40Cst67CBCj8+9KEy9Q7C/p+DFPqnTav+7+UewC4FWutZWus/AJgF4GQAlwB4\nD4BpAH6ltT4BwE0A3t80obkYZk2PWbB75dfRNHyTY9FFgW23ldcXkvI/8EBncjWNnIVrWMenQS8y\nUIcgSazbIg4+aX0ullwy7NMzSIKqnLndVCSst7+9+n+ZZcJlSxz8tQbmmSe/nhLg3ofe64f/YUqI\n8BRIxmWKCVKLOujYOuyw/tBhY9i+lWGo+2FWHLsMLgxgAQDPAlgRwKkAjPLzSQCFsr40h1JMT4l8\nKVIMguoyFjnRVV5/vRlb7zPOaC4ZIcWwZwSXgB5+BmGcSsJmSiA5LMxuaGpDNQKOYWf2Y9DU+Fl7\n7er/kZGwxL/Ed5w1K76eH/0ovz0OHB2DcAikySolWHDBcnTYkIzDQVjPOfTa1NCAjq1BGGvDRkOO\n7zOHmDEbO6yvArAugFUAfATA3gAuVkpdj8rkLaCA7T+GRdPjysobGkzjxwPve19+2yWkkYcfnv7s\nT38qM52Y3TAIC5cEe+xRvx4E+puioddmLbnolZQ5B0pVASg4bc4gjCmDnENgU+8xYUL1f4zvR4lD\n7MiIrB7pezcltCgFyRkiJ9LYYovFl5XQJKl30JmefoEyjpygkwoGt9/eX5bOFc5sbrnl/Pf6hUFa\nqzlEDWut9XFa6x9qrQ/XWh+ktd5ba/0xABMAPBJbTz/x+OPuUMBScB+2hN226wAQGkxTpwI33pjf\n9jCErJydMSyLhsEgOnY31YdN1bvddvFlJWZmJQ8s3KEqx5dIKeA//+HLpETd2nrr+LKf+IS8/hRI\nvkdK2UMOCfvjlWJ6QnMhxtTOB8k868ehXKKB+eY309v56lfjy0r67OCDm6l3TgJlemjUOxsf+Uj9\n+vOfj29ngQX891ZYIb6eQQQdW9xc3nvvsm2Llg2l1HzW33MBWFJrfa7W+rmyZJXHdddVWeCbhMmZ\nUBp0QBjnVYNS9sqpm8hKK8nKr7xyWjuzO4ZBE2mjV2r+QRgvOe/GSa8lYWHp/LQT0oU2kRxnW4nJ\nqSToQUyfPvxwfH0GCy8cX7ZX0eEka+uWW8aXNX0YI9ArMT8vugi47Ta+zHe+k15/KaanqbVI4tz/\n3vfy9zlzxKZ8wJo6o0iQIyh585vL0ZEKyVym7hCceSFdtyTmm6XG+1pr1a8lFg4SGuhZh3vW5C+M\nQRHzNqXUgkqpJUYvb7FuvQfAjUopAe86/GjqYGpyCLkOGPRD0ghnUqbDh5QDBiDPYdRKkNwYNqaH\ngosIlMO4SA4ag6jpKSWRlkjHJGVDOO20uHbmmUcmCR/Eb8UhZ36WGgN0re+HZiS03tsmPb/9bXy9\nX/5yWthb6b0cLLlkfNkQDT4BwVJLNRc5rVT/Uqy4YnzZnISU9hgO0feOd6S3w2H8+Piy++1Xv+bm\nIGVIJYE6SiVtpb42q65apt4clJ7LMcvgoQDMMfv/H2u01jcAOBrARmVJGmw0ZX/+7nf766f1cmrP\nHLzySv26yTC4/cYg2isPGzNID4HcwpsT8Wnq1PRnS2EQmB4KO+QvFZbQNnvBYChVrp2c0ONNmZLN\nnCmnpTRyJLylgimE2rTvX3ttfL1rrjn4a2BJc0jbQsNmBGbM6O6HQw4p124smmKQcsah3U5ICCHR\non/60/Fl11jDTxMFZSK4spI1m96jZ7dUUBo22yz+2abmbun9M6a6mwEsNfr3CAAopRZSSh0A4BOo\n8vf0HZJY9YMIM2BcE/nll91lfdepoIvRIHD5TSGnz1ZZpRwdNiQ05dDwsY+lP5uKnP5+6aX4shJp\n/HveE182Z+HlfJ9Kmc39+tf1e5ReCf0HHRRf1jZ/4GzbXeDePcdfrKnNNyeyZFPJ9wad6ZFgzJhy\nQRJ6pUV0BR6KpcFmou33nj5dRpOk/CDk3slZSyXPnnVWfNn9948vK0nKncM4Ssa3JLQ/t7bSy+dV\niwAAIABJREFU/pUEvshBqblcKnrbYwA+oJSaCGBVpdQfAZwH4HEAW2qtX4wnqTn0ajI3vdDGMD05\nUtwddvDfo/WapKilMQhmXKkL7zbbABdfXJYWAwlNOeO9VJ6NYQ/dKfHnyHk3ibRMQsMmm/jL5jA9\nEnPZ9zeUoY2+q+RQ0pSEOidnEG2HO0xI1sd+mLeF6pHQZEcZlGoKS/n0SPzdlloqXCYWNo32u7jG\nGWc6LAkc0dTckIzZUkxPiL6ll06rNwSJv5Vkj8zR9Ej630R8dIEKRpoaL5JnS9MQ86mnAlgcwMMA\nngfwYa31hwBcpPUgHF8r9MpcSWLeJvFjMM8++mi4bM67GjO6mHqbOigNwqhJlXoq1ZwzaFNSIYqm\noq41JRDoVYQtDr2STr7znf57IY0v12ZTYYZ7FcZ54sRm6pWE+s/R9NA1LzXkbI6vlmTNy/HBS53r\n0udKMT2SwBGcoEFKg33f/javv95d9kVGtPzBD5ajyUZTgmQ6DiV9aj+bI4SglkE562NTWoqmND2c\ne0SvzKL7iZhP/TKAf2utLwfwitbaTMlzlFLMEbq36NXHkRzYt9kmvmzO5Lj//vhnJWjK3GoQmB4a\n8lFi8jUIDthNSVVy0BTTI9E4NiUl7xXTxrVz773xZYdh82qKuZLUK4kGlbNuUUEDR6NEsNaUedt3\nv1u/3mKLzt/0W+y4YzpN9Ll++FqW8jHJQei9Tz01/dlUbES8tSXMFQfa35ygh8IWruakIClppVBq\nH7GjcQIypr7Uvjfs1hsxiJkurwNYVim1CYCFlFKbjP59IYBTlFKCIKXNoVcfR7Ih0UWjFHrlMCZp\nRxL/XwIqbVpiCXc5KX74w/p1bNQpqQmGBJJ6c4JMNMV0cuGKe6URaOrb5EQCmjDBH0Y5Z5Ph+vSZ\nZ+LLhmiSlC21+easRU0dAql25u1vj3+2lCY8Z7xIzLhozh+bftomZepT+3/MGP59Lr88vp1eaTTs\n9BGhCGZcbpVBOFxSUJq+9734shzod+NM7nPakdDQ1B4j0cxSM+imND1cvTfdxJddbbW0eoHuABCS\nZ22cf35ePcHlaVSzcyuAzwC4YfT/zwDYDMA0AAJ9RnMYBPM2iqZoktRLNRicP0fOgiLJpC05GNE4\n92uvHf8sB3pAj/2uTTI9ku9Kw34OwqbZFDM1CEymJPeLqx1fZLsccyWO/pAfYGq9TT5bql76rjnJ\nMm1ceWX9miYe5NCUfwRX7+mn168l0azuuad+zflS0INQjqZHIgmXMM0cJLlIKOz9aYMN6vcofRtu\n6L/fr2iiEv9Orr8lY/ZLX4qvNydEO4ecdZdqbUtpZnOYKUl+tG99K72do4/2l6XCAy7IR6gdDlzI\n8FI+PdBaf1Vr/U3Hv0211r+JpLVRDIKmh2IQDsdHHVW/5qRRknqpxkXybFMmSBKkSqilTI9EdZ8T\napejqakILLTPJPkX3va2srQ0jRyGTineETkVkvEiCQHNjSU673PmpySqXc6BoFSix5x5lHPI4urh\n+oVG33wuI4W4TS+lnZo2S95t4407f4fWVskYkFhZcHNj6635Z3NMhezrUsFlpJDk1ym1F1OfEq7e\nlVeuX5diDqnvtMTEkTLJ3PjJ6bOmzNskAjzazoc/7C9rByVxPZsjDCkJdgipCm+zrldTSs1HygzE\n8aVXkhKaGNSGJMssxSD4c0gid9DIV00xPUceGU+TBNR5kqPJtm+/8cbmpLYSfPSj9WvOyZqatdBn\nbUgcu6kAgMucTMcHF2Kemg0NgnlbDgZB+EF9V7hgHNwBgNaT4w8hia7EgZoN2QdpKSSHQI5xD33z\nVKm5xKyF1lMqZPVf/sLfl4x3WwtHmR7bjwjofh9u/Eu0e5x5m+Q7fuUr8WXpNRWO9Wodk1holIJk\n3dp77/p1qX6hgSG4ekNmrJzPaVOmcDlMjwSUGW/CYmCLLcrt8TFa29ArjAFwrlJqfaXUBgD2AbCp\nUuoepdSPR39jFF69Q68WCc6ulQ48296XoqkIWjmgErtrrvGXzeHiJRN0003T2+EgSfBqq1OnTZPR\n8NWvxpeVgC60NAma5FkbnM0uhYTJpwcujl4u8liOmVkIvcpJwKHU4v/lL/PX3AFYwvhShnrNNeOf\nzZGS26DjZaed4p+lWHfdeJre+97O31/4Al+WO1xSjYw9r444on4vJ2SyxHclxywnNbrlmDF1s8zP\nfKZ+X8L0lAqhHKrHfnfKxMf6iQKy5JgUOQdem6kIHe65MSAxr8qJUpaDq65KaydEr0RIIQFl+jk0\ndZ7cY4/4sqna7NB6IenDCy8Ml2HJ0lrPArAogCMBXAxgeQCbAHgUwJUAbgNweDxJzWEQJbxccs+m\nHLvpYTJn8bc3dQkNIXAqUgo6IZ54Ir1dDpzENCd2PT1s2qBMsWSTpDScdFJ8WW5MSCR/Obbwa62V\n9lyT8zzn4MGhqU1dUi89lHDrD733gQ90/qbzhB6kqYlDKnKYnpLtxiIUIpwzX9pnn/q1PT8pPYcd\nVr+WaIwkgh4JaDvcvsH5czz7bN33jb6bRAOcE864FKhVCDemc7RwOYnZ7cNyTv4lKvzox5oXAjWV\ni623V0wPLcuZxtOyOWOAq5cTToZ8BGm/+cxrQ31EBZ1c+RihUMx28QSAqwH8A8ClAG4C8G5UAQw2\nB/DtiDq8UEq9SSl1uVLqTqXU2bHPUfV1U7lTJJBIvnM2am4g0gGS4z/DbZI5i8/226c/+/jj/ns5\nYaebChPLgdqL5ziVSjQ9HCSmQQ89FF+W0vvFL6Y9m2M2RCHJZZPr02Pjttv89yTMYM76IjmU2GOC\nzpOm5kbOWtoUTRJQmjgtBXX4tcvSeijzKmF6JKHfU6W2IZq4b/OjH/Flm9rjOUY9xChK3pVbbyRa\nuK99rX5NAzxIYM/nnDMJ1ZJz0Qpz2uHGQCjCZup6GaK3KU2PxP9a0g6XXqRkviK6b/uC+Vx2GS9s\n5aIeUsTQH/OK8wAYC2Du0b/nBXAHgIcA7ALgx/EkObEjgKe01usDWEwpFaXUo/bUJ5wQ32DOItFU\nSFYJuLwfIQmXZHLQxTUV221Xv+YkgRQSen/5y/R6uX5rKufJfffVr3M0PaXMoqg5IYdnn40vK6Eh\ntHhyoJsizSHCtcNJW0syPdzcpzQcdFB82dh7IRp6Zb5RaszmJGKVoKT2KZZZCbUp+TbcmKCMF32W\nk5JLwL33rFl8lDhJXRIhEOf/Q/MVSWiQQKLpoY7zpTR4OWM2px3J2nroof57IRM7jn6O6Qzt/9y3\nUwp4//s715L5KtknJChVr3T9tsvbApg33pAFNsrVIgYDGQB4C4AVUZm0fRrAkqPPrQtgaQB3R9Lq\nwwQAxtryGlShsIOgH46GNuaw1VbxZWkncpm0JdJJyeZFkWOPL2mH474lA/7rX48vS8Et6LvvXr/O\nOUTtuqu/LB1rTz/tLyvJLk19pnL8Iezr446Lr4dCcmDMMSEpZUZUEhJJuAQ5izQ3X7l1INRPqf0o\n8XHIgYTBCGk/epEMOUSvxE+KY3okkPjA0LWetttUAB/7sPnqq93PchEhX3ghvp1UlNKgu2D3W84h\nltunQ8EVbJRkerg5JxEi9spEkzPVDs3t0LM0lHkJ0D5MNRcP1cuBWqaEhJX2dU6wGbseqmHMZnpG\n7x+ESpvzFQAHojJzexTAk6i0ND/0Ph2HxVHl+wGAlwF43IknWf+u65nJwpZb1q+58Kc5oQDp5KYO\nrLHgnGJd7aZCcijJaVOi/cgBp0qWaIVKRaQKget/6tQoYaYkix7ns0ZBbW1TGdQm573ESXy//Zqj\nw4ZtskEP9+9+t/85yQHmzDP99+h1SdOxVG0fBefPFnq2FEL00nXMvk/XHluwRuuhB336ne3Ds4Tp\naUqbHWqHajLtKJRK8Ycjex2+4w6+XTsBZoyzcyxyzGltUE1Dqf005GPHmVJKQAVGEqaHAz3M03f/\n/Oc7f4cYx9QxncOQNqU1p2VpYtNUSL7NySfHl91223jhUyi/jz1XOmed6wBMwuGHT0LFI/gRE8hg\nDCpm50uomJyvALgdwFMAtgIQ2HKCmArAsAsLj147MAnnnjsJ1QuND24y3EClh9ZSoTypRkMiwSjF\nnNB3k9hDljI3ySkrQajPOAZVomKXLARnnx1fdsaMeBoo6Lvavk70HmfDSyGZC5KwsCeeGF82x7yN\nwu7TAw/k25F85yWXjC/L0Rzqb1vtT8vm2KHbNOVEBGtqbksSXkqSbpZEzsHUvk/H0jnn+Ou56676\nNWWmaMSzWJpyzOhyLBw4U/OcsUX7tAlpO5C3D9r9JokcGWrTPodINAA5mh7OUkJSDwU1q6RrlX0A\nltAv0bzmCAR6JTzoR72SnG1bbhnfFyEBhq1c6NA7HsAkHHjgJGQxPaN4EcAMAP8DMAXABgDmH72e\nDkDgTePE1aiYJ6AydbvWV9A2YQt9HJpPwgbNaSKRWHPIkdaUYnpoPU2FMiwp8S0FSsNll8WX5SBZ\n9DgzS5rbqKQE6YEH4tvlQGm65BJ/WQmTRs1EuPlLo6jZmqocpofSS+e9REghAVevxEmWSsDWWKN+\nbR92SvrNlTK3kqwZoVDv3OE+B6mSWKlfEVeXbTYi7W8uBxdnlkPp5QKNSBJ/SmGbauUcLmk0K3td\n7teh1a5r+eWBbbbpXFPBVKl5JrE+yRmz9Ozz/e/HtyNZdyVmaFxdkoTFITOufkDCnNx5Z3zZUgoA\nijFj4mmW0JDCkAbJ0FpfiMq87WKt9WQAewO4Wms9efTeN+JJdOKXAJZXSt0FYKrWmskO0wH3cssv\nD0yZ4r9PmR5J5C4OkoMRlU42xfQ0hV6ZcUlA+6xUluvcRc4c2t/1rvrvn/tcuXZKmSBREyouvLjk\n8ENp4KLwUEddmgOlFCShyKnGVKJ54L4HpYGbvzSE6dpr16/tDSAUITFHIMOVzWHw7DWlX7k8JODm\nXKloZy+9FF8WqOf2CO0FRx3lr5dqYOy66PyU5GgJIVWry5Wl86QkJN/ZLjtxIu8vVEqLKCmbE1WV\nghsTOfsRV5eE6eECxFDk+MsMgqZH4gfVVPQ217XvXlMC6f//TEzFWus/aa1njv59hdb6EevePfEk\nOuueobXeTmu9ntb6S1zZ2IPd00/zJhsSB+yc+OfcB6AaGI7pCdk4cvVIIBlskshuknoleWJKOlWX\nOthJ6KBMWa8YVq4dapvNvavEbE4CKoWjEZ3szVnC2EojG9paLupjx/UhlZJzTERIqiUZE5Iw4Knm\nEaGx/53v+O+FwvL+4hfp7ZZCqTnI9e873xn/PjNn1q9z1jT6rG0al8NkSiwcQrDp4IIYAPEaSJqs\nNrQO2H4woXfhfKgo7LpCfpapfWj7uMTAbiekHZbQ9OCD/nslTbPsukLO8Tb9CyxQ32fou40f778n\ngUSAJIHEvFqCnOht9Npm6pWK1+hJ+jslh2Jw+CmlvNamSql5lVINxTzqhm2HmaOGo5oeLmpTTuSx\nnA3KpqmpiFoSyc5ee9Wvm1KDnnZa+rM5i5OE6ZEuOOb5kDR4nXVk9frqasoko1f1cM6rM2YAxx7b\nuaa5PSioVJoDpdG2s5cw4//6l/8elbqV1GhwuTEouPEioYFecwKaq6/mabJNV3KkhoOAUB/G0p/j\nTyCxHnD5i+UkH7Zha4tD9Nvvu+668e/LlVtwwfj9SilZ9MtQSGtaN3edWo+N/fdPqzNUr+s+58dj\nn0OOPz6dphBsmjjtjSs64YQJ/vL2OpabSN6msRTTI1nrJeOMBu7Kqdfe66RjPdZHzMX0hMz5Yj7n\nf5VSOyqlatUrpeYDsIvW+sU48vLBOa2FQm7aoEwPzXLdBKhp07rr1q9LhYfOcYaXqKTpNZVIpkLC\nTIU29ab6TeJ0atMRYnokdsa+NgYVpaRlWstCS6+8cly9QDkJJKcto9LUUEAN+5p7F9pOCLFa81Ab\ndC3lQOnPaXcQkNqHXD0uSBjuUjQoJUuY6avr7LOBPfeMf9Ze/0uZcX3603WfHm6f01q2F6T6zDQ1\nnhdeuF53k7l3uEA2nDkk16YdxKMkqP9jiI5UcytXPZwQLJYeCknaFQlsP7MY2Cb6HP3LLNPM+j5m\nDLDbbrJ6Ynx63gBwOYD9lVITlVKfVUrtA2BPAGelkZoPqrKW5OmhKGV/yj1LN66f/7x+zfk4UIkb\nR1MoK7ENuqlx6uGQxNGXbTcGdruSgyfNQdArpifVvE2pus19r5IoUkiirg3aQTS174Ewk5zjYGuD\nBo6w66HRtkL5Fux2SiULpjRJJbyx96RlB2Gs0Qh/sTTQe+edV4YeLi+cFNz66LrnW59C3+L/tXfm\n0XYU1f7/VhLIRCAJg0SChDCGKRDGECFMMssUosyiMsgoBJCnIgnKEkUcogLPh4KK8edT9CGOiGBE\nmUQFVJYIL6AvPieCCiqTYP3+OLfeqVO3a9g1dPc5d3/Wuuuec7q6qrq6urr2rl1761r+9dfv1ahX\nxTFTpt5XXJFvsqmTErw2Z//Wy91jj3LmzHo9XKEYXOelQlGG6OX+61/AvHnh51IEc7NvuYTQs7Wd\n6qkxZf72t/jzbfhMy01nQKFQ+/uiRWFpDzww/n3q4qKLgMMP734PebZD9/Q8LaW8HMDnATwG4EYp\n5fullM9F1TQDprs8k1yCAQXXpMoUeigPq/kidnUQiknCxRf3atZSPKOknBu7DOozM8s1iPvy8T34\nutCjt5OvD1OgTBYoL8Jc5FIepORFjWUQOxC7hKcJE9yxMVzOIVIimevMmeN+OVAm9660G20EHHJI\nWFrzuK+cXB7lTGKfDbMOLpe4vgmXzpgxtGvVj5tRzl2riFX9IdYsx7XqX7Xv7NlnO/9nzqSthoS2\nS10CM6WNJkwAjjoqrhzK9Ziu31089RStHq7r1QVfypghpT+2kE5s6AAh3PXQnarEChAKmxfZr389\nPs+c+5n1OGcpSkWXgqbUMzh9eq+APWpUgPKBUoCU8vdSyvullE/GVDAnOSdRufBpkm+9NS6vUlGI\np00D7rwzLK1v4HIJkr4HVDf9S1mdqeu+mt8vvNB9vm0y5wtwGSucp2jUc5aTq8xc5/qcklA0wLGO\nL0w32T7lR+yE18XGG7sFDIozC5eyY9tty60oNbHKaOKqg8szl+9cM12sgOebPK5YYc9XCPvG9qo6\n6GOZLvRQBXP9GaQ4KSkl9FBWLHyY44u+6m8Sq9CQkvbM6XVyOR+owpW3GWTWdZ5+rZQ9yZT6UMee\nuuYSoWVSgmFT9vsA4UKmz4udy9TTJ2Sax04+OaxOAHD//eFpAaLQ0ybqmthR8GkwUkzwQstxkWJy\nkbKhVveEUoW+pyp106Dru2uZuqTXu5/9rJtOT+tblcu5qbCfcWnoUoRkSrkmLoHUN7jr9fAJPS5N\nZqk+a9YpNsaJlG6zV9fz2g/je6wwQunDOa/TFCIefbT72RR011kH+MIXut99fU2Pm6RrySl9VMre\n8X/8+PDzqe0UulH6nnvC8/TVIXZlh1pOXcooF66VHhem0Obi4otpdaKs9ORC778UU1V9nwoAnH9+\n7/dcJpqmKaErrRn7MmVVyMR8zjfZJDxPM8i7j4EVepog58Z6SjmhZZgB/SgPfsq1+CZ2el4597nk\nmhDneskIQYtpodfJFbncrAPluikbF5vyrOe6tpwuNil1NGPmUMp1YWrT9Jg/Occ8/TnzPXO6fTv1\nmfrTn8LTlxRgS+SbS+jxpXV9p6BvKL/44l5nOkuNEONCxO/poaw46phCj49QC4GqY1dcEVZGzveR\nK4xGKfRr33PP8LQhuJ4VykpPyvs/ZS9uXcoGxZw59vo+9FDv3MA0s504Ebjttu5336qKji8eVKwC\nxjeOnXNOWL6pUPMeWKGHIlWmTHgpdYjNK+dkQN/X0EbBcaONhmsUchF7vZT+4oPieUwvx7cqFHtt\nLredVFzamVx9zRxozXhXKeXmSpvycnV5BswpfFOuVV8hyDkxMmnDeESpr2ti5yNWSZGrjd7whl6H\nJqYVQsqKqk7O1VWTb387LF2VnX+o6VzOPpkS5JKCrc6+fVs5Nfe6tzTqGPDud9PqEQNVARYak85l\nneFaKTa9+ZrxloRwm0O6ynKZr5USBNdYo1ehalo4pOSdeu7ACj1NkHNzmes8/bvpictXRqypSs4A\ndDrmQGxuvk2hrj5SarIZO2EsNYnyueqOda3rI9eLudTKa124XprUfE44wZ4vpQ6+tBQzlxyT7DpJ\n2e8Ren2jRsXvc/BNYFzCrDlWxa5qxa6chZyvv5Ook7Um+lcTK5lNCNRAryMPqrKmyr10DszxhdJn\nXv/6sDJyBRw3zZopWyMo99FUCORasaZYtKRAnVMBGYQeIUQjglOK1rPUgFdK6KniG9+oLrPUtZmd\nOFc5pqY+54uBMkmsy7yNcn36pnffsn8pb1Y6KQ41cmlyzDb0ab823NB+bPZsezlAOSGulGlWKELU\n49LUjHlSSquYE/Pe6CZhZp1i9y1QJyW5cK1YC5EWR8bWp1P29FDq4UqXc5+oD5e5sK8tcgWDpUCZ\n8KY4V3ChWz+4zLhNqwQpw+M6+QRf31gfu7fM5ZnWVd+Se4xdaXPVyadEoaKbypmYz7cvdlbQcCCE\nuFEIMUsI8bqKw9sLIZaE5JOTUaOAgw4KS2vG9GnK5CLnizH02l1QJrGlVnqqApe58qa44DSJFXqa\nmqTqG19LTQLbthpGzcvnecZlx26+YM0Xnyt2lotcz7lpLhhrckEttxQUJYVv069+nHItVDfxDz/c\n/WyudMaat5mmHq5zTWWTa39kar+76qre4yrNhhsOv3dvelNYORTFgRC0YJ+hE3bqCqnPlbeiyhkC\nxQTJVW5s8Mlp04Zfn3KD75v4u9pQd06Rmxkzup/VSkmVqXSVR69YD3/mtfpiIZrx1ULKAIY/r6Fz\nidQ5R2j/MedbJVf9U945lPbQ+1MVoTqQCQAWADhQCHGCEGKREOIsIcRYANMA/CW8SnkQwu0qWG/g\numxpfRPn0Jtu2rS6BqsUkx2fW1UdyuBC4aKLer/7Hg7d1jXXylpKoLgTTii30qNDiaztKsN0Q9uU\nRl3nwAPDJ6Ml62vm7Ro3XA4UXHX86U/D0/rItQrQVJBc19g1fbr9vGXLwgPsvupVvc/2pZe60+tp\nt97abUKVsqcnFD3wHuAO3LjaauH1qHJtbApi6niVqUponDmKECDlcIcKofiEHoqXqtB0vj0yVPT2\n19t8s81607nGyqo6uRwobLllWN3mz4+3wnjiifDzVBnmHhdf+ph0FEE51LwshzIaSBN6Zs6sjodV\nBWVOQlm9oZrkUuItmVCfudDX3YsA/gHgeQDnAZgB4AQA1wA4HQAhAk08utYoVXLUaUqTb9OCmdfW\ntDkM0KlryiqLDdNWtuTKWq521POZOrUdQo9Zjg2zDagKAVfQRRe+F8wRR4TlExJ8LBaKAiHWZvmb\n3wxPS+2vdYwT1IkP5eUXmvexx8YrsnL2HV2jSM3Xtp/GXL0bPbr3vrpW93KaJ+ljlanwMgUkXz42\nzMm4EPbV1RtvdOftE07M+FiUCS8F89ytt86Tr77PZcGCtDrp6AJUzv6jQ42jElr+7Nm0lROzv8QK\ncS5OOsl9XPfKVsq6RF+xpUIJk+HCjBUkhHv+aLpzN1fVbfcqZk7lnEoJISYKId4PYE10BJufAHhm\n6PBTAB4AME9K+Qit2Dj0iYbvYmOX7EpRVd/Qjm3ue/F5rCrBqafmizOkU0owScn7vPPiy8hJikvc\nUKiaqVLXG7opPOeEJBfmi843LtVl4uCqQ2xbUM+jbPanKA9CXa1T60tp89g9X+uvD7zvfXF5UlYe\nUsxP9M8339wr4FEdDpgcf3zn/733uuugE7sHLYac+yMpAoot3siaaw5X+Lqg7PMNnSe1YQ5lctxx\nvd+pK8uUtKH927Vl4Ktf7QRsDoEyx1PmiwqKoskcM1zeZU1zcNfzWmUu6NqzZuYzenSvIJTT85tP\nf/w8gO+hs8qzGMAbAUwfOu8gAKMBfFAI4Qj7WI6mJw/UcigPUk4tc6gpgou6Nlm+/HL32nX32gq9\nzah2xhTNimlSYCPniqOLpuIX1VVmiRWBuigliJUUekLrkErT99VsQ5djCzN9qXaZPLl3AuGaeFLu\nVe6YVeq3DTboXZWhRnw3cZmlK9SeBHU/fOZJOe9VSh8o8WzleveGCAUuc8RSipKq46mCta8MitKc\nUnYp5WQpLrggfNX8uuuG/7ZqVXXaHNe2ZEl6HlU4p1JSypellN8G8DKAawF8BcA8AE8D+H9SyqUA\nfghgfpnq2aGYudTlCYOaV45JTYhWx2XTa7u+qgehjod0zJjuBN9Xnm9PUsrytcum2Gb77oMqIOlp\nXZofs66lJtJV54ZuPM6phWsb5v4Sihmo67rnE0fVtrk4B3pXenyOU+roA4cd5j5OERx0UifHCt94\nntJGuuLENllRbLmlvazQ/QIp7L5773fKnsYQQsfIqr2stv0HQgyv56mnhpXpgrI6DNBWemLN27bZ\nxp1Wn3PEjC+lFdVUocd0htUmUsaE+fPD3+FVe8n++c+wOlH7cChVz5yP0ORrAZgI4PcAXgXgEwDU\n0Pc/AFbSik2H0mlvvrn3WKnIyLlWeqquzeelalBYfXW3di/2wZkzJzwtxcNTKaHngAN6v3/gA+58\nXd9LQinr3HPT8yi5pycWc9M9xcOWeZ91Qj1kKWJXvksKPS+91P3sM4+ty+TOhcuBQqk6+ATQXCsa\nukBnTlaE6A0KrTtFqBpfTK+bCjOSPAWXs5/cKzku4XbXXbufq7w/mvsP9HzNeq69dvdzyooNZcXU\nfL71mFwmppvy0Pb33Y+S3t5iSelDlKDidVNCmR5Trk6VIGKrly/+n86//RutHlWECj23AdgOwMYA\nDgdwPoCbhBDfR8fk7bu0YtOhXOiTT/Z+P+us3u8p9oK2AdCkakCkdE6bNDtqFLD99uEs3+7IAAAg\nAElEQVT5hFJVt1gtaE5iB65113W/OPTrDTG/KI35onK5zDz9dJrg1QRCuNuVYj7QNqGH6tpav1aK\nMJ6LlJfiW95CS1+HeZvLs2RT8S5iueQSd94+RV/o9ZrjiRC0d5m52pErDERdgq+rz+jukl0e2kKu\nOUe/SNWSq/1vOZ8FvV1C3TnrxAiAVftPQ02zUs3bSpBLOMmlcEk511SC5HK8ZKahhhyoIqhqUsoP\nSymvkFK+V0p5qZTyfCnlkQD2A7AiNJ+cUMxlzLQ5J+96Xr5OnBKl1na9n/0scOWV8flSyvvKV8LP\nj11N0wej1IFHPz90gJk+nR5bglLPRx8NTxtKVayjtpGrTiUH+Ni8qyaAullLbBmlvLeZfZYyLm2x\nhf3aqupz+eXueug89VTv99CJkc99eKwDFl1Lb5K6r8VGlVmtK0CqDlUbH2tKt3JleIR6ClVjf9Nj\nmW/lzfw9pb42z1/U/hs7mY4V8k1TxJB81W+mCa+rDlVmhbrXz5zje5uFHtfKXY56vOtd9Dze/Obe\n7zmsdLbeuuP8QT+3yllL9pUeIcR2Qoithv62FUKsJoT4pBDiWgAfBfB6KeUfaMWmk1Pj63q5hdRD\nIWXXM00VuttJlT6FPfboLMXnilfjO8e3CVinLfuoFFLSHBmUGCCFAL7znfC0oRtqhYg3y6FSQuig\ntnXTEyGTHXYIT0up+3eJ6+ex2vbZs2nlUF6KoV7WgPhn0Oeo5Ywz3Mdt45rL1t0XzNCF2Yd9Kzkz\nZsSV46uD+d3W/ubvzz8/XFBug1KjBBShp+oY5XoOPrj691NOoT3b5gSUQozFQIn5R8z8gaoIp8aS\naQu+PaNVbfe1r4XnHxq7SR8zQuYfru0cVYwaNXwPJvV5rMw3IM3NABYC+DqAywC8EsDmAC4G8G8A\nGuk6lOVJX6Po5mG7FfRDRxlQQtLeeWdHC+SbHMdoOpt8+VCEk1CB1SX0+AQiF6W0R2Z9XGZQQgAL\nF8aVUxLdA54Qdo18W+qrc+SR4WlTAqu5eOYZf5pYrR9lfNTZeedw0wWq5jU04KiJL3Cyb+XW5tzA\nVf8UJYmLqnEo9l65qHrH5PCGGmPypU/izBUeyrgcasGx777heVKoMmGn3K8NNqj+fcwY2gTdpsQI\neR5DFVMUoSfG/DS30FNVf1eb1vFOirE4+vvfuyawaoUtpc+lKBH1PYDHHtt7LMWqyUWKW/7/yyMg\nzW+klJcB+A06AhAAbAHg39Hx6FbTtql6MCPWU8lhp2neSJ/Pdl+ZMTa3qeT2EpaKlPZ20CdbIWXH\nem+jopfj83GvbxylTNaoxF6rWUeT0HhBda30bLVV/LkuIbpKo95G5s6t/p1ii1/S3Fcnh0v+uomd\nDFNN1ij1CT3Xtc8ll1UB9Tp844sORQlIvZ6UCagL5cI7hhz7JV0KCt81uvaKuZxXUKG+95oWelzu\nwW1MnNgVlu66q/M/pK6uNLrwQsE153jHO4anp670VGGaQ8b0nxChp6qqT6PjqvouWnH5yGm/aZ6n\ne5nK1fkp3kzMGzlrVtmJbBWpcWFK1Gn33Yd7saNod3baqTqdLVBgCJRJOLUvhbbh1Kn0zfSx2Opk\nmgItWDDc1tt1/T678JA8ctIGwYSqNc+hqVe4TFlz3YNcworP5WqsJ6m3vz08bcmJ20c/GlaOKbj4\n6qTvS8r1fgmNb2YjRWhw7R+Lpap822S1pEJG9ygXS4gZWmj9P/hBu0cz83fXc15qxbQKc8WUEji5\nBLli77XRKqfqfW6mPfRQenlV4TlKCD1ThBB7ApgMQFn7/QPAL4b+GmGddcIvljJoz5xZLaWGlmOr\nE8Vunmq3aGpMzai/ubRvFErs6fnBD8I2zFUxY4b92Nix9Zi3mUvAuTCvjXrvFi8OS+cyval6ed1w\nQ1idUrWpubDlG2NC9t730sqI5eSTu58pK7ptNCmMfQZ9ZiK2KOg+L4277BJeh5J9WF9dy/kcme6Y\nQ02NXCs9IQ4OQq4hpn9SHNCEIsTw/RDKnLWqvUxnBDmesxTzawqUlZ6xY+3uya+9llZmHVRdW449\nPbnDn+RwkBKztzO3OVrVfTWFYTWOPP98/rJchAg916Gzh+dqdEzcngLwHIAzAbwFQCOvz6lTw18A\nlEZJiQNCHZhsKw8ArQ577+0+N+eLMpQc5m1m3UaNGj7BoQg9FG1mrrQ6PjNFM89Sgph5nBL5mLKq\nRXkGQ/NN8bzoK2PnnavT2mKSuMjhWjPk/usBPydMAG67Lb1cH7kixOtU9feYsUm/hz6U2Zgq13Q0\n46IOxycx59Zh3pabXBrvGEJcsIcKh5MmDR/jc/ULc4IeY7Luq8uzz8blF7M6pyvL9PZUfaF0XxQi\nz17MBx+MPzckLMg55/jzCWnvXC7lfWl1b3omN95Yfe7f/uYvx1X/EkLP7wBsLKX8JIB7pZR/B/Be\nAGcDOB7Az2lF1o8QcUtpIVx2We93SueybVykEivgVaHsb6viRdTN0Ufny8unxXKZwLgGx5ImDSUG\nfj34K5Wq67zllupjpSaBJdvbFgCY2l6uCYlrcmkqQVLjgNgELyGGByWk5EsJJhdK6sTXthczpK+o\n+/65z8WXT+2TsWN/LjO0qnxDtb2ue6XXQTfL85Vtfva15/nnD88jZlzwadYpeVZ51coxDs6YkfZ8\nhK6ArVpFU5AqZav5O0UhYJplq72Esat2trH3ueeG/0ZRQtqomjeEePPcfvtqsz+zrWxuzF3nxJDr\nnep6fn1myDGMGkV/NpzJhRBTACwCsFQIMQPAYiGEADAeHXfVXwfwq4i6FkdvdCnDB3Tqzdfd+7nK\nqXNiZw46lGjCytNKjHbbVYcYQjbYhbaTuQHOxPXyM4+10TQolGXL4s+tuqehjj9yDqptb//YCUpu\nJyjqc5WrfJunNCUA1N3GqbHTbG3nmoCoc17zms5/mxlcSHnUex67n0kI+76ZUaPS+pBtBS82T9s1\n5uhbPo99uWjDeDN7dlpcJIowa7vWKoWQElh87ePar2lOWtXK9Sc+Afz0p9Xn6Ca9JqZy+7TTOv+f\nfTavctjFxhv701xxBW1FLDaNEuxsK1Ip5qSpUMYVm0Jy993pVhXOoVpK+Rcp5Z5Syj8BeAbAubLD\nl6SUxwF4I4AC4RbDoDQa5aVE2QxqYhMWmvKaBQCnn24/lhKjaNEi+7ESXuwomMusFPt8X9n6teX0\nPuMqJxeveIU9XzWwuDYjh15rKY+BVc9xrKvjUELuQ+ievdIvl6q6mr9V9dk77uj8/+EPy9TLxxln\npPV3m2laSHursSEk7Y47Vv9e16ZkIeyTqlJmc6krjpRzTdNmiuexFK67zp+vHtoCyN8urvxy7FcK\nqa9N+Td5cnwbu/aAqbHINONaZx27wuKii+xl7bVX73cVP+Zf/6pvYm+W8+5358srJI05PwE6q3gl\nSPHIRrkfNsV9zHaU4KFaSvlnKeVvjd/+KKW8h1ZkPegNceKJtL0IsZTccJgyeLq0qJtu6tacuDjr\nrPA6UMhhf3rsscM1O3vsUW8dUonVfsfW5wtf8J8f2i4Uj3gUbWpTLy4fIWYICtOMLcWLGcUcxYUy\nVZk8mX5uDqomOJQ6uMaiUCgCkjLrpJyrMCdmFIToaMFtx0qQK181ATX7u25mVCWg18Epp9iPqesv\n5YimLay+uts1don+lTsej4kKFl/ltKCuMU7fd+mDaiZ+9NFpZrlV5aSEa4gts858GtxCWB9Ud76x\nN4PSuUuUr86lDiT68neuyX5IPv/1X/HnKkzbboUQwNNP9/52+OH2tDFlx6SnEOtq17f6VKLOennr\nrhvv+59Sjuu30HNznUfJ2zTNeeml6nQxmuSY/REx51RhmjrWuTG+7s3ws2bFl++aPPv2GQjh9kQZ\n2uZmHrb7/aMfhb0/Q/rLNtt0/purcvoYHhNIm1IHkxA3ziYUhxcUfPU3HRblRnfFbfbvJlaoc+Sj\nLA6EKOPdL6QOVYS2py+vL32pq0yoOsfmFMpVD4qnYVt+ud+ZOelroYfi0SF2pYRynmsfTFU+JVYT\nSgz8MeeZcQX0vU+KHJ3eZusshDvWiA+zbrp5XF3mbbGUHNxt11rXBDdF6HG1iznQ63kuXBiWfwh6\nvh/5iP0Y0GysIDMeQggf+EB8eULkcSFLIcYDm+2e5BK6lOlazMQ6h7mICcUbHmBvn7XX7m5SNydG\nutLNdAaQYj6TA30VWv0vpdDxUTWZzclGG+Vp16q6mYJ+KVNM1zmmQN2293YuVPvvuy9w4IG9v9mo\nqy1MYVrHZYmTs359LfSEQpmYtuFBoJj7mBx8cJkYOVTMwH5XXhmfF8URgyK3ZsdmvpQq9Jx6au93\nl8e6nwf6SZw40a3ZKSHk+vCZYaU8n756Ka32+PH2NC4Ts5A9QyUmC6kaQ4p2zzwWs3E65N6Ygp6O\nGSywDWOxYsGCzn9bnXKvNCmzHAopzzaFqo3Dvnu1ahVw6aXV56g6V7VhqJVGHaZ9+udddum8a0NI\n0ZzrlL63PouPmPFEYRPic5u3hSq79d9DzYsnTw5T7Cjh3oV6F514ojtdTPwc1abf/W7XmqYu01ff\n/XR5rTT3zMXWwceIEHqA/hJ6UkiNcl5qmdls16OOAnbbrfpcU7tovixDeOKJ8LQpGl4qpgBnOg1Q\n3maq6qTMQ3zsvbdda+66VrWfw0WJtqI8c65NsTZCPcyVIMUtvd6Ob3hD2Dm57o/KZ+ut/Wl//3t/\nGjPfKnKs9FBW+CkrPcqBQV1CjxmEOYQ6Vz9s5N7L+aY3haVNia/noyrf++6zm0sDvZPjXHOP1Ocj\nJfBljHIlhDri8VDrYLMQ+ctf/AGNgeFjgZn/r37VXdXwrRpuvXUnfSlc5mglnic9z+OOy59nCH0t\n9ISat6WsnDRFnQOJSwMei7kJ36zTl79sj2asBgJl6hCj7fjZz+jn6LgmT66Ntz7OPjssXUi+J5zQ\n+U+Z6LmehU028Z8fS+zL7de/7v3uEnrqcmNbha3NzFUifZNozMrON74RVq7rWO6Jhtp7ljrxVys9\nKfcxtu9++MNp9W/D+6WulZ5QfC7AVZu5VkxCnbnEuOv+7GeHr7Sb2FZ6fISO8xTMIKlU1PtCYZoS\n+uZJ+jFXW4coptT55v9UKOaQ5kqjK20KZn6bb24vuwpq+JAQD54msdecct9ME+pSgrVJrUKPEGI1\nIcQt2vexQoivCSEeEEJ8Jlc5VcuLoY1WIvCejVIvKDNfnwb/8suBhx7qfFbLra96VVodKJ7SbITE\nzSg92TjssM5/3bW37rAiRPs2c2b3s6++lOuJXdUbN86tpXRh0xaWug+UGEkvvtj7XbmhPe64rnmS\nzXMW5VmkmH6Z+VJcp1ddq6kAoOxrtI1tsRM7X3nUc5XQY+ZjM/W6777uPadMIqo2hJ93XnPXXkVp\nr1alkdK/wqrqW+UAiKy9jZjJnHiiX9Me06ZS9sY8eutbgTPP9J/nM6OleIgM4fOf7/3uEmpKKY5D\n+rn+/qQSUmez7yhz6FzkMMejkGuvuDqmO7goWXbsnPH++2npaxN6hBDjAPwYgN6EJwBYKaXcAcBU\nIQShee0NbO6zECJ8UDz88N6VD2onjHlZmS5Icw8we+wB/O//2o+vsUZX6j700M41xOyj0anbm5IJ\npf3+/OfO/899Drj++t5jS5ZUn6OEwpD7bTPRSCVFaH7Pe4b/ZrZZlbB87bX+vGPM20LvV5Xdr+m9\nRqEm+QcdBNx0U+ezbZ+XWWe16qXqF1JeCGecEXeezQtPSFvX4Qb4jDOGb1KllqMUCKbJhc2L4S67\ndFeFKMqqb34zrn6uc5oe7xRTprhNIV2BIkMpZQoT60AI6Ky+m+ccdFB6nXJc18knA1df7U/n81yX\n+7mlOKmgtENpU6mQibopZFKUQymxC6vyc5VdYizOtdKjzgk1rQ5BL2ettXqPuZwcuLBtk7BR21At\npXxeSjkbgB7rZx8Atw19vgNAhQ7OlWf17+ZkjerIIHTzJEUCpmCasFCpahdbRNsSVE2WKQ93joGA\nMglRk63jjwcOOKD3mK3fKDerUvrLSn1hlMBmWqjXYd684cdspoYpE5YQ7ruv879KYzpnTv7y9t3X\nfixlk6/uxTCHyQHlZR6Cec7HPx523jXXDNfYUyc/tpWekOtQdvjmxPGaa4an1bXwVGwr4KlCjxkr\nLWYMnDy5s/r76U+X9YSXa0/P4sX+NKGmzVXBkKvqGep8oIqmV9JSvbdRxhtK/qZjiyaFHlVv9Yzb\n9qzkWt2ugpJfTqHnkks6/03PuUBzfde1p3W99Xq/x77LqNeWuO3djhDiagDbAVCXcqeU8hIAehXX\nBqCiqTwDwGG9uETTuu819FfN0qX1mGxQNAIuSdrk8cfT6rxgAfDe98afn0qVe+pSxAwasUE/beX6\nzMxc99JcNVCefpp+wVZhi0ZvQn3pVR276qre50vZNYe0y6c+1dkITnnmQvrRZpsBjz3mT5eLkHbU\nV6TM4+YLP8R+3szfJRznxib0UDj99N7vrvrHKGJsyqNUoSdmBc9k6VJ7fjnJYY4GuM2uVX477gj8\n4hf0vH35UtK3cSwuZRrvUt7Y5lSmVUhIe1HMUVOwCT223yikhMSwkVInJURQ5jeu9slBfXsMlwNY\nbrXM0Sm20iOlPEtKuYeUcs+hv0vUIS3ZKgBqkWutoe8WlmDJkiUAlsAl8ADVGscS5ge5J1U6plcv\nSqcM2QuTA8qmwVLmHzHmJvfe2/s9ZUBMdSt8zDG935uKARFCaLBUynNh44ILerXflP7vMidU2jCT\nkM2sqZ4RqYRcMzXwMhB2rTlehrFe/FLKrPseKUaNose0yU1IcOz990+PuO7a75mr/dW1CBHmQTCU\nGKEn9tzc6M9T1QpmU4SMJ+b7WK3gxTgyoAhVlHOoaan9oWp8yBXQHihnRpdTcIl9hvx12AtKRlji\nkXyasETWL/t2APsPfd4HwPdiMlSu73RNdIkNYiZVk0B1c1K1U3PmAH/8Y/f7Koc4aKtDm6CY1+Uw\nhXPd7xhvcLZyU9u66RdpLtR1LFoEXHRR/Pkx6ShtOGNGeFqFuZ8mt6ch5Q0wVYA2j6vP6tmLWelJ\nvVaKUKY2stYlaOV0FrDmmmnOX3SPkEBnjxLVDC+k3RYvBh5+mJYvBYr9f50mR7HUudJD6Y+h4Qts\nxKzGh5q/VSkczRXXt73NXT8XMQJM1b5GdSxGIXvuuV0TdxObEFg1B/Lt46KQMlY3udIT4j04dY+5\nThNCj94MywBMF0I8CGCVlPIOUkZDOSn3kK4AWCVu6vveN/w3ZW5C0U6FTDSefnr4bzZKLLtSSJ2Y\n1rX/5/LL48+llK9fO9X9ZGrZdfPBD4bFMtApoYWjYtpBu/bt6PsllGexnPeiyiQrdM+QXg/lxfJT\nnxp+rIoFC+wT7S99CVi2zH1+FePH99r8u+6fOflIddFbJ4ccktYHTDPFiROB555zn0PZwOta/aQ+\nry5CA0Kfe27XM6YiRiGhE6LoLGXqngNf/5kxwx7bZP789PyF6I4ZFO9tMS6f1QqHOpey+li1f8tH\nlcBx1FGd/zH3denSjsfHVFIsekxye3yMqUuM05yQ1a6FC4Hf/IZenypqF3qklJtrn1+UUr5WSrm9\nlPLk9Ly7n/UbNm1amQGrasXg0EOr07pMfmIj0dqoKxijrU1DglzmImalR53zmtf48/cN9CEbhvU8\ncgXkSsW8rmXLhm/+rEuoopgrpD7HtmuieP/S81B7SHxtRdEmKte1erwam/c2Fzfc0PlvatJsdb3p\npq49uFnO0UfH992qOpsWCFVa/ltuAZlSChNf2pC9T6leoUxyaYlDV+NMz4PvfGf3M/W5XLq0Vzn3\nz3/2Kh58+cWOTf2wp8dW3vjxXcWDmSbU9NjFmDHDx8Ejj+x+Nh0W2IhprzPP7PSBENZbLzytqoup\nzBGiGw7B7Eu617+cKwxV7bJgQfi1+Mi90qN+O/roTlzF0PMoHHhgWEwrIewr6dQ6tMTRZllSojVT\nz4vpeKatZ1uW9n3YrlVplnPnW4VN6FBtmOqiVWkfzTqpcjfe2J9HKbONnHkdd1xz/S51pad0vc38\nq5bjfX22anOpTyume6ULfSb0utoigze5QmgKr/fcY0/TFjfQobR5FSGHRte8Hznr3NReLB+hJl05\nUPmXstTQJ/C+cVTVRb3fhLArhmJWesxzhaD1gVDnQeq/uZLqGltOOaX7OcbpkS3ekq3Nc/X9Aw8M\n9074+OPD62GigtmOH99dFTPx3Xvf8W99q+vFMfb5orqsbulQE4fqyKY5m+shNF2FtoE2mi1RqNIc\nxvpg96HayrQlV/fcpZ0KGZxNX/Lq2lS5IatapSc0MRHsc9Zpn338mka1Kvrkk8NfJBTz0zZM2Kuu\n9bDDOvuZdP7zP9MC6+mmD7aVrpjJbMokhYIZ8T2UuoSdnBvkgbh2DLFnr2KDDYYH88ttquLjtNO6\n42vu/GP6AFUBFULulZ6DD+7GiaoqCxg+juTgqae6Qsvo0f53Rsw7xUXoWEQ514X5jtE9G5q4+lpM\n2a9/PXDssfTzYstTzJoVHu5k4407fUJxyCHAypW9aWzBQseOBV54ofqYT5F35ZX5rV2oSoK+E3q2\n2SbOSYBtcmqL0K7INeBR7NOrVi8mTACefTZPXZrAtyl3nXXszhrmzrXbe6uHytw8n7qHiDK5NNl9\nd+Duu8PTx2LGJKCw9trArbdWH6Oakt1+uz+NerFUeacTwv+SLW3eZivP95vKr8oM4nWvo5VrpqnS\nYPmu31VvV11t5/zjH/60NpSgS12dq8OuvS7zqFL5/va3w3+LbdPQss10G27Y2ZuTm+XL6dpboOvu\nX5H7XuXI79BD7UKPEiBjBD5f3fRVmkcecad/+OHhissQc3FFzs35sSjTS1Vv116z0v2E8u4qpdSr\nylfvE5/9bHhddt0VuPPOuHpsu63du3BdCs0+MyBw4+pUasOxDVcQpRxUBYwK2Vio+Pd/7/y/7rp8\ndUolZj/NxRf78zU1xNtvDzzxhLsO6r+aaLoGmpiHi3Kt5lJwzKCaOhD7vOUJ0XFf2waEyGs7DXS0\nSTmiz+tQXvwhKJvyUtiegXPOCc/DNINIqUdqmjby+98DDz0Uf36/r+orct6/+fPzeNisoumVHp/n\nxFNPte8LNtPGsummw829dLbaanj8OMrY51Mku87NRYyzg5HAIYfkzc93/665Brj22rxlptLXQo9t\nc2/VA2ozr1IagBQzlKo6xfDRj9rzUJov3d60HwkZrN/85vD8zFUx5cozVejxLcfnjiuQm9BAoi7q\nmpClBoutat9ly/IH1jRNG/WyTZfDPp57rrOJVc9PtUNVu9scDJjfQwSp0vsn1EbgefOGH/PZfFel\noVCqz9pWU9dfH9huu7A8zOs67jjgxBOrj+Umx0rPnnsOj6LeFFUKDd91fPObwEc+Qi8r1ypzCP/x\nH2FmenVhG9dc7tlD2kk9T7me1112ia+Li7rf3aXLs5msxeIbzxcsAN7ylri8StF3Qk/IJLbKZt02\nsdpvvzz1ykHoJrS20AZTD5/gG6KhirkOJWxVnRuyghLqLcw02RhEKO5KmxAg1dhRZcqj+hB1b8a4\nccOvxdSu6uywQ1i+M2bY+zVFYE9pZ6Wlt21+LVl2CR54oOthKKdZ3rJlnUluLijxl0KP6Sxc2Bs7\nrklMd9chHHRQ+OqqLuQqJYGrfUO9p+Wa5Pvu2Qc+UB1Sg8o73tH5bwq7VEWVWd+TTur8zzUWKWWn\nuYc3ZB5QerxR19gGxyylrzVlhY3N2yzktsU27d1DMDdiUQJv6rznPV2ztSqmTOm4cuw36tSumCs9\nNsFRzzNkI/dOO9H2Imy4IXDBBZ3PymZ1p506/485Brjsst70offV5gkGYNOYGKht9oc/dG3UFy6M\nywPI90zY8lGrRq5zm+ovIdd+wAG09DFQhGud7bfvCnIuiwBV7xL7XEpx+eVdL02DRp3jikthoVPq\nGdx5515B5MILw0zJfYwf3xF0X/96+rlVK72KnI4Sli7tvnuPPJIumJcWiNqkxCl9PaFxupqk74Se\nKnw3MvdAY3oCiV3ynzOnG+dDR9V3zBjg6qvj8q6DnHtjqCgtsspPPWxqo3yqhuf8890xeMzr+J//\nAa66qvc3ZZv9ylcCl14aXvatt7onsSHk9tnfNK46UWLsUMllIue6HyEB3XxKm1KbZEv1BWUqOGNG\n57/u4CKHeVuV5l1pl1OYO9ffju9+d+c/Ze+U75pLKZLe+c5e70emt8rU/OskRx3UPau6x/vum55/\nLsxrXbQIeOmlMmWtt17cfkZXQNycnHtuV6EhRO98rA3mbZQ8Sj9HoTG5gMHdi9l3Qo/eyKYtdcwE\n1zdpaOKmlt7gXMIlZii52lNpXNWA64tsnKvcOmKd7L9/OzQmda0MpPb3t78dWLEiLK26Jp8yocrL\nnJmH+TkWime3lBeo2rxMMSnJ3QdUvmed1fk/bdrwMlybrEO56aaO4qJOlPCtIoy//e2d/yGejg4+\n2O3KtQ2Tt7aT2leldO+rzbEXLtfzlGsPck5i4gvV9Y5psv+nmNHnJvee8JzhD9i8LYCcEa5zNfik\nScM1/lTaGDuIQurDvf76wAc/6E7jEz5CNkzb0laxxRbV+eVaGo/ZYEsltzezXKT67R87Nn0SYAYI\nLuU9qoqXXw5PW9Wnvvxlt/1+3WZX5v6mqjq7JpB6hO5x46o9X9pQ+c6bB3zoQ73HQhUJekR2Cqaz\nHNeqk8kmm3T2+OTGFZ8kJ22Y0JWmxDXGrlK3yTuZ6udvfas9jc1yIWTedfjhHY9+MaSuVpRWQNeF\nGhdTnQaZ9KOJfd/F6XHhmgDHDljUTjJqVNe+lIqqY24PG7Zy2sro0f7VKHWvbSZorhW8mAd1zpze\nc0OEHko5VO9foegT0NDN9mbbjR/f8TYWS2nTHQrmPbnkks6+hiY33W+2GfDLXx2V9m0AABZ3SURB\nVIalrYqBYau7eR+Vkqj0i+rqq7sboKlss02vkKP3u8mTgb/+1X7u3XfbvTj96EfxXtZCURNY83y1\nKb50P1crTDpqstP2Mb8EKdc8bhzw4ou9v1FMVEN55zs7AZtj2Xvv+HMVhx0G3HJLej6u9qaYVZmk\nKJFThR7TgiSGNnh6tcXGSSVnfUvNgUz6bqXHNYlVbhQpncyXtmqSQVlFoNi1qnxyRwpvilBXhSmE\nrvQ06b0lhNx1qMvsqm7acK90crTRffd19oFccok/z223jfcCdMQR/vwVKdc1ZUrXmxKVn/88fqIx\nd65dSbXzzuVX72zabGX2U3qfnUuoK/3ctO25BIB3vQv48IfjzqWasoVev9kHFi0CrriCVlZuUifE\ntn5depyhEHJ/vvzlsFXqknVoE3W//zfbrDrocm76bqXHdSPqNEkJ5ZBDgOuvb7oWzRC7KTYE30qP\nomrFx1yloZgYmHsdcg1ktnxig3a2UWBpAyFOA0pw5pnACy9UH5s0qTNBc6H3jzlzgB//2F+mTfAP\n8ZyUs130eqQ8L+utBzz7bHp9fMTWsclJTS4taew1uPbA5WSttYCnnw7zrLnTTl0PmlSuvho49tjw\n9KHPSxvH5Vx1atKxkQ3KSs9RRw0fX2Kfh5kzu0Fa2yDsHHtse2Jsudhgg/Jl9N1Kj445oY3ZtzES\nNWAUYjYVq2tesgR49NHeY7kHuc02692rYjNrc2nHq8xCfPiu49hjO+4zU/nEJ4DHH6efl7Pfpd6z\nnB5wcjukqOvcpUvd7ukp/PnP8ef+7GdhZl51OOygctddwK9/3XQt/NjeR028C1SZpd1ST5nSfF/J\nGXQ3d2DjUtTdp6r27aSs9Gy5ZVp9fDTlgWzFCuBTn+p8boN527hxHQV8bnK6Hq+LvlvpqaKUpyFf\neSMdX3uPGxduqkIN7qiYPLkzGTJxTZJTNB7qmm32+4rPfz6+DJ1Jk9q1aTWGpidDOrm9+jVxbTFC\nsCLUlKWNKz11rSb04/juq/Nuu4Xl06ZntW3k6Bc52/eLX8wjNJx5ZndrQJ38/e/1eSmNNW+v27yt\nTc9fSH3nzQPe9jbaOU3Tdys9uTaOK09GpTvZ7Nnhgcva2GHM9tl007T8bNd4113DV4Vc+O6bMgs7\n5phuvBx1XoxrTZM2LBWX6ru5lQg5+7UeKT2G0nudXve69Pxz0Ub3obvvPtwT4qCh2j3nhC72Xs6b\nV16bXidNTQrvuCNPv6XU3+exbOHCPBvUN9igOl5gCPvs0/GuFsPEieVXCtrg6r1NLqtzoF/HuHHA\n+9/fXF1iGIiVnhgmT+79XmoJcuZMYOXK8PQ5yqwzL2B4tGZX/tOmVf+eQxDRWbiw8//II/OYmeWm\nrgGwai9TP5MjhktJSmlMZ8wok2/dbLst8MgjTdeiHtZdF3jiiWbrsN124Z4BgcGZmOUmh5e0QeT2\n27ufB+H9UgL1TIXEDePnL54LLwxLNxBCT8rm5JBONmUK8Je/hJdfgqYGlOOOAx56qPoYZWO0woyH\nEouvPSiDByWtcpaRuuIQy1FHAV/5Snj6XKZFg4LZb+bNGx7v6zWvsZ8/YUK+PhzKiy+maURjNrmH\naCdDN4n3W7/LWd9BEVbbwrrrAs8803QthhP6fj7llP7uE67r9DkV6kdyjgU2d/qDRJNjfWiomBFr\n3vbKV4anvfTS3u9rrFEmInIbNSXveY/dh38b60sh5gFVbn9f+9r4PA4/vBMbIaYuoft7qu5NaBkU\nl+wx+TWVh466pgMPBFat6j221Vb28/7xj65XHle+KZh5pAg8UsbtlwtxZNDvz38p+k3I6yf6vW0n\nTQq3POi3azWFnjaMDyFtePzxaef7aEM75MS1xaHJPhtadt8JPa7JHKVznXpqfB1WW63jnUP/Xpo2\nm7dR8m+Di8oUVByQ2FgpAHDzzcCOO+apjw2znT/zGeDKK8uW2Q/k7n+D9kJjyo0hKfn22wS4FG1s\nhy22cCtCBglX+7dxpSekv+y5Z/Xvo0fHuzyPpY392+Tqqztu4/uVvjFvu+aa+HOrOpKatNqC2VH4\n6leBp55Kz6euDj8IE7Wc5m0p1D1I6ddNuY8nnRSe9pRTuo4+gHLXeOWVvZ5fmPaQc4yYPr2eoHNN\n42uzfhh3zzsPePLJpmvhp02Tw5GyRw3oP/O2UaPi5wovvZS/PoPA6qvX53WPQqgVTN8IPUpIybmK\n8Nhjwx0auLDFt9hggzxBlfrhpZhKG92Kt+EF2ibt8jnn9Ao9g0Q/PGNtqGNIHUL71re+ZQ/M2kba\nMB6Y1KXkWbw4Tz7MyKONQk9dTJ4M/PWvTdciHyedBOy/f9O1CIfyzuwb87YUcyIbum2i2Wgnn9z9\nrF4oNs9juWjDZIeCbV9THZOGptoqd5yXUqj2WbYsPg/liaxUW59yCvC5z5XJuy5yBkRsEzk3W6+1\nVjtcvJempGByzz3AvfdWHxs9Glhzzfi8+4m6xtuNNqqnnH6j31Z6QsjRpy67LD0PoD3zic98Jr9H\n3bYwEEJPG6OHt5mUB2vTTbuey2JMA+sKtFnHyslOO4UH/StdFxuzZsXnX9rL0JQp7k2kJQjxZBY6\njtx7L/DqV8ed23bUs+1y6jAo12rSlomHzk47AbvuWn3s8ceB+++vtz6DzsyZg9u/S3HIIb2rA/3S\nfiqmXwollPKMnUsuiT+3b/SUalWm6oXkc1lt26jWNlyDRFtexF/5SseFbgx/+APwilfkqYetrWLa\nKXZfVxMTjdC4OypdG/oNpQ42V+C5rkNpr3K8kG2T0FTaNFnI9bz2E5deCuy3H/28pp61UrGh+pXY\nQJttow1jt4mrTjvvDNx6a311yUGuOUmbxuyRwEUXAZdfHndu3wg9rujEPu9tIZL8uuvS65Sbflge\nHj/e7wLXNjDmnECttVa+vNqwKS9U2xQ6uK6xRnxdmmT69KZr0M7Jhs4ZZwDf/37TtWh/O8Wyww6d\nPyo88SlPSBsvWFC+HiMVSh/vh+ehtBKWSr+Pqf3gQKrvFuW23RaYOLH3txiX1SY33gisXFl9LEf+\ndXPwwfZj/f5grVgBvOtdzZRdqu1ym/0dc0znf4m4MU2w+up5g4L28zNwzTXAww/XU1Y/t1Pb6Cdn\nDgzDhON6R+bwEMzko++Enuuvt7vUHDs2Pt9Jk3q1zE287NswuewHZs603+s2mXU1yaDZGI8eDfzo\nR/ny42eNyY2vT916K7B8eS1VGVE0ua+SYXxQ4jjeeCPwjW+Uq0tp5s3La4VTgr6bGo0ZM9y8Sr1s\ncsb80F9gdU2kUydiIZu0AeDQQ8sEU2tDvAJKG8bczzYJU/0ycW9Tm4XQdLu+9a0dEzZmsNh1V7eZ\nNuOnaiwxzZP7bbyx0fQ4VAWlTq9+tT3Mx6CR615tt53bSqftnHRSPa67U1bP+mZPTwghk/45c8rX\nI5a6HBnssQfwve/ly08NbFts0fnfhpdOG+rQJG18YY4EcrT7aael55EL23N07bXAllvWWxeGufhi\n4M1v7n7/2MeA7bfvTcNjXzkojgq23hp46KFydWkT3OfqZcIE+3YUHwMl9Cj6tQNSlkHbwssvt0vA\naFNdSuBaOp41C/jlL3t/a8OeHso9acOzO+h9KAdveUvTNWgfbei7g87cub3fzz67mXrUQRvHocce\nSzv/29/OU4+2cdppXaUvUw+xTo/6zrytCeoafDbbDHjwwXrKysWoUb3t0xbtbx1xeprgfe8DHn20\n+ljTdRsUePLKMO1k1iz/O5LHwXLoq2xUpAQOOCBfXWI44ogy+U6c2N9maSOJgRB6zEFOfb/iijz5\nq0lQHYPp7Nl58mnKDfMvf9mOl04p18dNC1MTJnSE49J87GPAySeXL8ekDX2H6cL3g2kbud6RDJ1+\ntEZhGJ2BEHp8wUlDjw0S110HPPBA07WoHzVJGwmD88KFds1Z6sTg7LOBadPS8lC0ceI8UsYBpj64\nTzGDTr/38fXXb7oGTNPUKvQIIT4thLhHCHGzEGKUEGKsEOJrQogHhBCfqbMug8466wzf4DkSGEne\n2444wm4jPXNmvnL6/UVXJ4PWVm0I3MswDJODD38Y+N3vmq4F0yS1CT1CiHkARksp5wJYC8D+AE4A\nsFJKuQOAqUKI/fKWGX/ufvvlnTgyTGle9zpg//2brgUzKLzwQv6guYPMoMXG6lfapJhi2sW4cfks\nGJj+pM5h+o8Alg59fnHo/z4Abhv6fAeAvWusj5PjjwdWrOh8VoNok1pcHsjD6Nd2ylHvxYtpLkVj\nWW+9MnGeBoF+7X9V8CoPjYkTgfvvb7oWzKDQxrFk0FaymZFHMZfVQoirAWwHQD0md0opLxFCHAlg\nNQC3AjgPwNNDx58BsLktvyVLlvzf57322gt7Rc66Uh7alIBIpbnlFmDs2KZrMfi08UXkosRLasUK\n2rPQb22WAk8KRjY77dR0DRiGYUYWy5cvx/Lly4PSFhN6pJRnmb8JIQ4DcA6AQ6WUUgixCh1TNwz9\nX2XLTxd66kZN2q66qrEqYO213cdf+9p66jFIjBtHP6fUBH78+DL55mD6dOC557rf11ijubrkgoUT\nYNEi4EMfaroWDMP0CzxuMm3EXAi57LLLrGlrC04qhFgfwIUADpBSqinU7ejs7fkvdEzdol7Btono\nkUemB9PSmTo1X15U1lyTB5wQKELJrFnAr35Vri6h/OpX9bihjuXHP66n733oQ8CMGeXLYRhmcBlJ\nK8t1w3MQOtxm7aI2oQfASQDWB3Cr6IxK1wNYBuAoIcSDAB6UUt4Rk7HNZfXmmwOf/KQ7LTNYUDcT\nb241qKyPknXIsbnat8qYi/PPD0/7xjcCN9xQri4xfPGLwKtf3XQtwmnz6iLDMAzD5KY2oUdKeSWA\nKysOsWEWk41XvAK4++5y+feTFvHuu4FNN226FmXabJNN8ueZysKFTdeAxjveARx9dNO1YBiGGVz6\nac4wEqhzpYdhamHu3KZr0A4GuR1mzWq6Bv3PhAkjM5YXw/QDbZwss6UMHW6zdjGQQk+Te2+YwaaN\nL6KRyFFHlXmZLF8ObLdd/nwZhqmHQRmjzzgDuP32pmvBMIPFQAg9+iDHUjVTkkF5oY50bOPE/Pn1\n1oNhGKaKiRObrsFweH7F9DsDEUN6TGHRTU10ecI7srnhBtpme6ZDG1/eDMMwbaaNAsa8ecBaa/nT\nMUxbGQihpy7aOAgx9XHyyZ2YNUw4K1YAP/lJ07UYDiswGIZhaLzpTcBf/9p0LRgmnoEwb6PAggvD\n1MfMmU3XoBoeBxiGYRhmZMErPQFMm5Y3P14tYBiGYRjGRpsDVjNMv8JCTwCHH543v3XWyZsfwzAM\nwzCDY7q66aa8Is0wuRlxQk/MIJIjqj3DMAzDMAzDMM3A0/kGGBRNFMMwDMMwDMP0Ayz0MAzDMAzD\nMAwz0LDQwzDMiINt5RmGYRhmZDHihB6e7DAMwzDMYMLm4wzD2BhxQg/DMAxPjBhm8LjoImDHHZuu\nBcMwbWXEBSdlGGZkc/vtwNy5TdeCYZjcXHll0zVgmF522y1/rEcmnr5f6TnggPAgXlOnArNnx5Uz\nfz4wZUrcuQzjYvny5U1XYUSxzz7A+PFN12LkwP2bGXS4jzM2dtwR+N3vmq5FGoPUv/te6Pn2t4E1\n1wxL+7vfAZ/+dFw5y5cDq68ed64Jm9YwOoM0oDCMCfdvZtDhPs4MMoPUv0eUedvYsU3XgGEYhmEY\nhmGYuun7lZ5+hD3IMQzDMAzDMEx9CNkHM3AhRPsryTAMwzAMwzBMo0gpKzeS9IXQwzAMwzAMwzAM\nEwubtzEMwzAMwzAMM9Cw0MMwDMMwDMMwzEDDQg/DMAzDMAzDMANNK4QeIcRqQohbhj5PEELcLIT4\ngRDifUO/jRVCfE0I8YAQ4jO23ximjQT07wOEECuFEHcO/W3G/ZvpF4z+PVkI8b2h/v3Ood94/Gb6\nloD+zeM307cIIT4thLhnaF4yMWSs7uf+3bjQI4QYB+DHAPYb+ul4APdIKfcAsI0QYgsAJwBYKaXc\nAcBUIcR+lt8YplUE9m8AuEZKuefQ32Pg/s30ARX9+zgAvxjq368WQmwEHr+ZPiWwfwM8fjN9iBBi\nHoDRUsq5ANYC8CaEjdV9278bF3qklM9LKWcD+O3QTy8AmCCEEADGAngRwD4Abhs6fsfQd/O3vWur\nNMME4unf49Dp3wBwtBDiPiHEl4a+c/9mWk9F/waASUP/BYAdwOM306cE9O/thz7z+M30I38EsHTo\n84sAFsM/Vvf1+N240KOhfGp/HsDBAB4G8IiU8gkAawN4euj4MwCmDv2ZvzFMW6nq378c6t8rAFwi\npdwVwDQhxHxU93mGaTvLAEwWQtwE4HkA48HjNzM4VPXv/waP30wfIqX8bynlj4UQRwJYDcBPEDZW\n9+343SahRwUMejuAa6WUWwFYWwgxF8AqdJbeMPT/yYrfVtVYV4ahYuvfuwH4M4DvDh3/DYB10enj\n3L+ZfuTNUsqj0dEc/hHD+zKP30w/o/fvPwH4C3j8ZvoUIcRhAM4B8FqEjdV9PX63SehRmvBJ6GhQ\ngI4p0EQAtwPYf+i3fQB8D50lNfM3hmkrtv69BoBFAI4VQowCsA2AX4D7N9NfqP69J4BPCCFWB7Ad\ngHtR3Ze5fzP9hKt/8/jN9CVCiFcAuBDAIVLKfyB8rt23/btNQo/ShF8N4EwhxF3o7Hm4HZ0l5elC\niAcBPCWlvMP4bdXQbwzTVlz9++MA3gjgHgBfllI+Au7fTH+h+ve30OnXdwJ4j5TyWfD4zfQ/rv7N\n4zfTr7wBwPoAviOEuBPAGAAbCCEeQvVY3ffjt5BS+lMxDMMwDMMwDMP0KW1a6WEYhmEYhmEYhskO\nCz0MwzAMwzAMwww0LPQwDMMwDMMwDDPQsNDDMAzDMAzDMMxAw0IPwzAM01qEEBs0XQeGYRim/2Gh\nh2EYhmklQog9ANwshBCONJ8WQuwuhBglhDhGCDF/KKg1wzAMw/wf7LKaYRiGaR1DASDvRyfy/UoA\nEwA8C2A1dGJDvFEIMQnADwFsD2A/AIcD+A8Ab5BSXtBIxRmGYZhWMqbpCjAMwzBMBR8HcKeU8hwA\nEEJ8T0p5oJHmdADflVJKIcRbASySUj4qhNhZCLGGlPLvdVeaYRiGaSds3sYwDMO0CiHEBAA/A/BH\nIcTXhRBfA7CNEOIbQohbhRD7CiGmAjgHwAtCiNcCeFZK+ehQFh8B8CkhxOhmroBhGIZpG2zexjAM\nw7QSIcT1ABZLKVcKIe6QUu6jHTsdwJoANgawB4DvAzgGHWFpNoBbAFwnpby7/pozDMMwbYPN2xiG\nYZi28i8AyolBjzMDKeUnhBA7AlgAYFcAzwPYQEp5pBDiO1LKN9ZbVYZhGKbNsNDDMAzDtAohxP4A\nLkLHicHHh7y3bSOEuAUd4Wc1AFcA+DsASCmfFULMA/DIUBb/qr/WDMMwTJthoYdhGIZpFVLK7wD4\njv6bEGK5lPIw47edAYwSQowC8C4AFwghxoDfbQzDMIwBOzJgGIZh+oFxFb+NBbA6gMUAbgfwJwCP\nA/hBjfViGIZh+gB2ZMAwDMP0NUIIIfllxjAMwzhgoYdhGIZhGIZhmIGGzdsYhmEYhmEYhhloWOhh\nGIZhGIZhGGagYaGHYRiGYRiGYZiBhoUehmEYhmEYhmEGGhZ6GIZhGIZhGIYZaP4/alrHHI1gCsYA\nAAAASUVORK5CYII=\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f973dc386d8>"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": [
- "%matplotlib inline\n",
- "import matplotlib.pyplot as plt\n",
- "import matplotlib as mpl\n",
- "\n",
- "mpl.rcParams['font.family'] = 'SimHei'\n",
- "plt.rcParams['axes.unicode_minus'] = False # 步骤二(解决坐标轴负数的负号显示问题)\n",
- "\n",
- "fig, ax = plt.subplots(figsize=(14,4))\n",
- "ax.plot(data[:,0]+data[:,1]/12.0+data[:,2]/365, data[:,5])\n",
- "ax.axis('tight')\n",
- "ax.set_title('斯德哥尔摩的温度')\n",
- "ax.set_xlabel('年份')\n",
- "ax.set_ylabel('温度(摄氏度)');\n",
- "fig.savefig('fig-res-tempture-stockholm.pdf')"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "使用`numpy.savetxt`我们可以将一个Numpy数组以CSV格式存入:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 34,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.34743109, 0.34666094, 0.67796236],\n",
- " [0.37775535, 0.7452935 , 0.44639271],\n",
- " [0.7097024 , 0.54721637, 0.96400871]])"
- ]
- },
- "execution_count": 34,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M = np.random.rand(3,3)\n",
- "\n",
- "M"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 35,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "np.savetxt(\"random-matrix.csv\", M)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 36,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "3.474310879390657414e-01 3.466609365910759966e-01 6.779623624489031775e-01\r\n",
- "3.777553531256817587e-01 7.452935047749419395e-01 4.463927097637667707e-01\r\n",
- "7.097023968559375007e-01 5.472163711854115542e-01 9.640087120207403437e-01\r\n"
- ]
- }
- ],
- "source": [
- "!cat random-matrix.csv"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 37,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "0.34743 0.34666 0.67796\r\n",
- "0.37776 0.74529 0.44639\r\n",
- "0.70970 0.54722 0.96401\r\n"
- ]
- }
- ],
- "source": [
- "np.savetxt(\"random-matrix.csv\", M, fmt='%.5f') # fmt 确定格式\n",
- "\n",
- "!cat random-matrix.csv"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 3.2 numpy 的本地文件格式"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "当存储和读取numpy数组时非常有用。利用函数`numpy.save`和`numpy.load`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 38,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "random-matrix.npy: NumPy array, version 1.0, header length 118\r\n"
- ]
- }
- ],
- "source": [
- "np.save(\"random-matrix.npy\", M)\n",
- "\n",
- "!file random-matrix.npy"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 39,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.34743109, 0.34666094, 0.67796236],\n",
- " [0.37775535, 0.7452935 , 0.44639271],\n",
- " [0.7097024 , 0.54721637, 0.96400871]])"
- ]
- },
- "execution_count": 39,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.load(\"random-matrix.npy\")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 4. 更多Numpy数组的性质"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 40,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "int64\n",
- "8\n"
- ]
- }
- ],
- "source": [
- "M = np.array([[1, 2], [3, 4], [5, 6]])\n",
- "\n",
- "print(M.dtype)\n",
- "print(M.itemsize) # 每个元素的字节数\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 41,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "48"
- ]
- },
- "execution_count": 41,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M.nbytes # 字节数"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 42,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "2"
- ]
- },
- "execution_count": 42,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M.ndim # 维度"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 5. 操作数组"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 5.1 索引"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "我们可以用方括号和下标索引元素:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 43,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "1"
- ]
- },
- "execution_count": 43,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v = np.array([1, 2, 3, 4, 5])\n",
- "\n",
- "# v 是一个向量,仅仅只有一维,取一个索引\n",
- "v[0]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 44,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "4\n",
- "4\n",
- "[3 4]\n"
- ]
- }
- ],
- "source": [
- "# M 是一个矩阵或者是一个二维的数组,取两个索引 \n",
- "print(M[1,1])\n",
- "print(M[1][1])\n",
- "print(M[1])"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "如果我们省略了一个多维数组的索引,它将会返回整行(或者,总的来说,一个 N-1 维的数组)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 45,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2],\n",
- " [3, 4],\n",
- " [5, 6]])"
- ]
- },
- "execution_count": 45,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 46,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([3, 4])"
- ]
- },
- "execution_count": 46,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M[1]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "相同的事情可以利用`:`而不是索引来实现:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 47,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([3, 4])"
- ]
- },
- "execution_count": 47,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M[1,:] # 行 1"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 48,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([2, 4, 6])"
- ]
- },
- "execution_count": 48,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M[:,1] # 列 1"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "我们可以用索引赋新的值给数组中的元素:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 49,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "M[0,0] = 1"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 50,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2],\n",
- " [3, 4],\n",
- " [5, 6]])"
- ]
- },
- "execution_count": 50,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 51,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "# 对行和列也同样有用\n",
- "M[1,:] = 0\n",
- "M[:,1] = -1"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 52,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[ 1, -1],\n",
- " [ 0, -1],\n",
- " [ 5, -1]])"
- ]
- },
- "execution_count": 52,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 5.2 切片索引"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "切片索引是语法 `M[lower:upper:step]` 的技术名称,用于提取数组的一部分:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 53,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([1, 2, 3, 4, 5])"
- ]
- },
- "execution_count": 53,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A = np.array([1,2,3,4,5])\n",
- "A"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 54,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([2, 3])"
- ]
- },
- "execution_count": 54,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[1:3]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "切片索引到的数据是 *可变的* : 如果它们被分配了一个新值,那么从其中提取切片的原始数组将被修改:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 55,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1, -2, -3, 4, 5])"
- ]
- },
- "execution_count": 55,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[1:3] = [-2,-3] # auto convert type\n",
- "A[1:3] = np.array([-2, -3]) \n",
- "\n",
- "A"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "我们可以省略 `M[lower:upper:step]` 中任意的三个值"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 56,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1, -2, -3, 4, 5])"
- ]
- },
- "execution_count": 56,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[::] # lower, upper, step 都取默认值"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 57,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1, -2, -3, 4, 5])"
- ]
- },
- "execution_count": 57,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[:]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 58,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1, -3, 5])"
- ]
- },
- "execution_count": 58,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[::2] # step is 2, lower and upper 代表数组的开始和结束"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 59,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1, -2, -3])"
- ]
- },
- "execution_count": 59,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[:3] # 前3个元素"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 60,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([4, 5])"
- ]
- },
- "execution_count": 60,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[3:] # 从索引3开始的元素"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "负索引计数从数组的结束(正索引从开始):"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 61,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "A = np.array([1,2,3,4,5])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 62,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "5"
- ]
- },
- "execution_count": 62,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[-1] # 数组中最后一个元素"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 63,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([3, 4, 5])"
- ]
- },
- "execution_count": 63,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[-3:] # 最后三个元素"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "索引切片的工作方式与多维数组完全相同:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 64,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[ 0, 1, 2, 3, 4],\n",
- " [10, 11, 12, 13, 14],\n",
- " [20, 21, 22, 23, 24],\n",
- " [30, 31, 32, 33, 34],\n",
- " [40, 41, 42, 43, 44]])"
- ]
- },
- "execution_count": 64,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A = np.array([[n+m*10 for n in range(5)] for m in range(5)])\n",
- "\n",
- "A"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 65,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[11, 12, 13],\n",
- " [21, 22, 23],\n",
- " [31, 32, 33]])"
- ]
- },
- "execution_count": 65,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 原始数组中的一个块\n",
- "A[1:4, 1:4]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 66,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[ 0, 2, 4],\n",
- " [20, 22, 24],\n",
- " [40, 42, 44]])"
- ]
- },
- "execution_count": 66,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 步长\n",
- "A[::2, ::2]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 5.3 花式索引"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Fancy索引是一个名称时,一个数组或列表被使用在一个索引:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 67,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[10 11 12 13 14]\n",
- " [30 31 32 33 34]\n",
- " [20 21 22 23 24]]\n",
- "[[ 0 1 2 3 4]\n",
- " [10 11 12 13 14]\n",
- " [20 21 22 23 24]\n",
- " [30 31 32 33 34]\n",
- " [40 41 42 43 44]]\n"
- ]
- }
- ],
- "source": [
- "A = np.array([[n+m*10 for n in range(5)] for m in range(5)])\n",
- "\n",
- "row_indices = [1, 3, 2]\n",
- "print(A[row_indices])\n",
- "print(A)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 68,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([11, 31, 24])"
- ]
- },
- "execution_count": 68,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "col_indices = [1, 1, -1] # 索引-1 代表最后一个元素\n",
- "A[row_indices, col_indices]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "我们也可以使用索引掩码:如果索引掩码是一个数据类型`bool`的Numpy数组,那么一个元素被选择(True)或不(False)取决于索引掩码在每个元素位置的值:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 69,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 1, 2, 3, 4])"
- ]
- },
- "execution_count": 69,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "B = np.array([n for n in range(5)])\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 70,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 2])"
- ]
- },
- "execution_count": 70,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "row_mask = np.array([True, False, True, False, False])\n",
- "B[row_mask]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 71,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 2])"
- ]
- },
- "execution_count": 71,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 相同的事情\n",
- "row_mask = np.array([1,0,1,0,0], dtype=bool)\n",
- "B[row_mask]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "这个特性对于有条件地从数组中选择元素非常有用,例如使用比较运算符:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 72,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. , 5.5, 6. ,\n",
- " 6.5, 7. , 7.5, 8. , 8.5, 9. , 9.5])"
- ]
- },
- "execution_count": 72,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "x = np.arange(0, 10, 0.5)\n",
- "x"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 73,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([False, False, False, False, False, False, False, False, False,\n",
- " False, False, True, True, True, True, False, False, False,\n",
- " False, False])"
- ]
- },
- "execution_count": 73,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "mask = (5 < x) * (x < 7.5)\n",
- "\n",
- "mask"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 74,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([5.5, 6. , 6.5, 7. ])"
- ]
- },
- "execution_count": 74,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "x[mask]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 75,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([3.5, 4. , 4.5, 5. , 5.5])"
- ]
- },
- "execution_count": 75,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "x[(3<x) * (x<6)]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 6. 用于从数组中提取数据和创建数组的函数"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 6.1 where"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "索引掩码可以使用`where`函数转换为位置索引"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 76,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(array([11, 12, 13, 14]),)"
- ]
- },
- "execution_count": 76,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "x = np.arange(0, 10, 0.5)\n",
- "mask = (5 < x) * (x < 7.5)\n",
- "\n",
- "indices = np.where(mask)\n",
- "\n",
- "indices"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 77,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([5.5, 6. , 6.5, 7. ])"
- ]
- },
- "execution_count": 77,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "x[indices] # 这个索引等同于花式索引x[mask]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 6.2 diag"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "使用diag函数,我们还可以提取一个数组的对角线和亚对角线:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 78,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 0, 11, 22, 33, 44])"
- ]
- },
- "execution_count": 78,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.diag(A)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 79,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([10, 21, 32, 43])"
- ]
- },
- "execution_count": 79,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.diag(A, -1)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 7. 线性代数"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "向量化代码是使用Python/Numpy编写高效数值计算的关键。这意味着尽可能多的程序应该用矩阵和向量运算来表示,比如矩阵-矩阵乘法。"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 7.1 Scalar-array 操作"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "我们可以使用常用的算术运算符来对标量数组进行乘、加、减和除运算。"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 80,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "import numpy as np\n",
- "\n",
- "v1 = np.arange(0, 5)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 81,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 2, 4, 6, 8])"
- ]
- },
- "execution_count": 81,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v1 * 2"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 82,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([2, 3, 4, 5, 6])"
- ]
- },
- "execution_count": 82,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v1 + 2"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 83,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[ 0 2 4 6 8]\n",
- " [20 22 24 26 28]\n",
- " [40 42 44 46 48]\n",
- " [60 62 64 66 68]\n",
- " [80 82 84 86 88]]\n",
- "[[ 2 3 4 5 6]\n",
- " [12 13 14 15 16]\n",
- " [22 23 24 25 26]\n",
- " [32 33 34 35 36]\n",
- " [42 43 44 45 46]]\n"
- ]
- }
- ],
- "source": [
- "A = np.array([[n+m*10 for n in range(5)] for m in range(5)])\n",
- "\n",
- "print(A * 2)\n",
- "\n",
- "print(A + 2)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 7.2 数组间的元素操作"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "当我们对数组进行加法、减法、乘法和除法时,默认的行为是**element-wise**操作:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 84,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.12684531, 0.88008175, 0.00646408],\n",
- " [0.56140088, 0.06651575, 0.79145154]])"
- ]
- },
- "execution_count": 84,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A = np.random.rand(2, 3)\n",
- "\n",
- "A * A # element-wise 乘法"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 85,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([1., 4.])"
- ]
- },
- "execution_count": 85,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v1 = np.array([1.0, 2.0])\n",
- "v1 * v1"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "如果我们用兼容的形状进行数组的乘法,我们会得到每一行的对位相乘结果:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 86,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "((2, 3), (2,))"
- ]
- },
- "execution_count": 86,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A.shape, v1.shape"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 87,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.35615349, 0.93812672, 0.08039952],\n",
- " [0.74926689, 0.25790647, 0.88963562]])"
- ]
- },
- "execution_count": 87,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 88,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.35615349, 1.49853379],\n",
- " [0.93812672, 0.51581293],\n",
- " [0.08039952, 1.77927125]])"
- ]
- },
- "execution_count": 88,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A.T * v1"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 89,
- "metadata": {},
- "outputs": [
- {
- "ename": "ValueError",
- "evalue": "operands could not be broadcast together with shapes (2,3) (2,) ",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
- "\u001b[0;32m<ipython-input-89-629678c55a83>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mA\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mv1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
- "\u001b[0;31mValueError\u001b[0m: operands could not be broadcast together with shapes (2,3) (2,) "
- ]
- }
- ],
- "source": [
- "A*v1"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 7.4 矩阵代数"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "矩阵的乘法有两种方法,第一种方法是点乘函数,它对两个参数应用矩阵-矩阵、矩阵-向量或内向量乘法"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 90,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[2.59833251, 1.8189686 , 1.32946437, 2.15441681, 1.55219543],\n",
- " [1.4561364 , 1.26875236, 0.97855704, 1.35013248, 1.05524471],\n",
- " [2.38061437, 1.70445667, 1.16297305, 2.27888345, 1.66499116],\n",
- " [1.08602725, 0.76015292, 0.46415646, 1.38753125, 1.00011024],\n",
- " [1.82122991, 1.34175794, 0.92375387, 1.74770416, 1.27559765]])"
- ]
- },
- "execution_count": 90,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A = np.random.rand(5, 5)\n",
- "v1 = np.random.rand(5, 1)\n",
- "\n",
- "np.dot(A, A)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 91,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[2.0139906 ],\n",
- " [1.41657535],\n",
- " [2.09784627],\n",
- " [1.2752073 ],\n",
- " [1.6253844 ]])"
- ]
- },
- "execution_count": 91,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.dot(A, v1)\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 92,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[2.08466462]])"
- ]
- },
- "execution_count": 92,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.dot(v1.T, v1)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "另外,我们可以将数组对象投到`matrix`类型上。这将改变标准算术运算符`+, -, *` 的行为,以使用矩阵代数。"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 93,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "M = np.matrix(A)\n",
- "v = np.matrix(v1).T # make it a column vector"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 94,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[0.45282687, 0.64874757, 0.70028245, 0.91412865, 0.36429705]])"
- ]
- },
- "execution_count": 94,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 95,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[2.59833251, 1.8189686 , 1.32946437, 2.15441681, 1.55219543],\n",
- " [1.4561364 , 1.26875236, 0.97855704, 1.35013248, 1.05524471],\n",
- " [2.38061437, 1.70445667, 1.16297305, 2.27888345, 1.66499116],\n",
- " [1.08602725, 0.76015292, 0.46415646, 1.38753125, 1.00011024],\n",
- " [1.82122991, 1.34175794, 0.92375387, 1.74770416, 1.27559765]])"
- ]
- },
- "execution_count": 95,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M * M"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 96,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[2.0139906 ],\n",
- " [1.41657535],\n",
- " [2.09784627],\n",
- " [1.2752073 ],\n",
- " [1.6253844 ]])"
- ]
- },
- "execution_count": 96,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M * v.T"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 97,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[2.08466462]])"
- ]
- },
- "execution_count": 97,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 內积\n",
- "v * v.T"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "如果我们尝试用不相配的矩阵形状加,减或者乘我们会得到错误:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 98,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "v = np.matrix([1,2,3,4,5,6]).T"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 99,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "((5, 5), (6, 1))"
- ]
- },
- "execution_count": 99,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.shape(M), np.shape(v)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 100,
- "metadata": {},
- "outputs": [
- {
- "ename": "ValueError",
- "evalue": "shapes (5,5) and (6,1) not aligned: 5 (dim 1) != 6 (dim 0)",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
- "\u001b[0;32m<ipython-input-100-e8f88679fe45>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mM\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
- "\u001b[0;32m~/anaconda3/lib/python3.8/site-packages/numpy/matrixlib/defmatrix.py\u001b[0m in \u001b[0;36m__mul__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 218\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mN\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mndarray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 219\u001b[0m \u001b[0;31m# This promotes 1-D vectors to row vectors\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 220\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mN\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0masmatrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 221\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misscalar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mhasattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'__rmul__'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 222\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mN\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;32m<__array_function__ internals>\u001b[0m in \u001b[0;36mdot\u001b[0;34m(*args, **kwargs)\u001b[0m\n",
- "\u001b[0;31mValueError\u001b[0m: shapes (5,5) and (6,1) not aligned: 5 (dim 1) != 6 (dim 0)"
- ]
- }
- ],
- "source": [
- "M * v"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 7.5 矩阵计算与数据处理"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### 求逆"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 101,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[-2. , 1. ],\n",
- " [ 1.5, -0.5]])"
- ]
- },
- "execution_count": 101,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "C = np.array([[1, 2], [3, 4]])\n",
- "np.linalg.inv(C) # equivalent to C.I "
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### 行列式"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 102,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "-2.0000000000000004"
- ]
- },
- "execution_count": 102,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.linalg.det(C)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### 数据统计\n",
- "通常将数据集存储在Numpy数组中是非常有用的。Numpy提供了许多函数用于计算数组中数据集的统计。\n",
- "\n",
- "例如,让我们从上面使用的斯德哥尔摩温度数据集计算一些属性。"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 103,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(77431, 7)"
- ]
- },
- "execution_count": 103,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "import numpy as np\n",
- "data = np.genfromtxt('stockholm_td_adj.dat')\n",
- "\n",
- "# 提醒一下,温度数据集存储在数据变量中:\n",
- "np.shape(data)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### mean"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 104,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "(77431, 7)\n"
- ]
- },
- {
- "data": {
- "text/plain": [
- "6.197109684751585"
- ]
- },
- "execution_count": 104,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 温度数据在第三列中\n",
- "print(data.shape)\n",
- "np.mean(data[:,3])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 105,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "0.4931528475182218"
- ]
- },
- "execution_count": 105,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A = np.random.rand(4, 3)\n",
- "np.mean(A)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "在过去的200年里,斯德哥尔摩每天的平均气温大约是6.2 C。"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### 标准差和方差"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 106,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(8.282271621340573, 68.59602320966341)"
- ]
- },
- "execution_count": 106,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.std(data[:,3]), np.var(data[:,3])"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### 最小值和最大值"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 107,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "-25.8"
- ]
- },
- "execution_count": 107,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 最低日平均温度\n",
- "data[:,3].min()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 108,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "28.3"
- ]
- },
- "execution_count": 108,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 最高日平均温度\n",
- "data[:,3].max()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### sum, prod, and trace"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 109,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
- ]
- },
- "execution_count": 109,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "d = np.arange(0, 10)\n",
- "d"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 110,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "45"
- ]
- },
- "execution_count": 110,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 将所有的元素相加\n",
- "np.sum(d)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 111,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "3628800"
- ]
- },
- "execution_count": 111,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 全元素积分\n",
- "np.prod(d+1)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 112,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 0, 1, 3, 6, 10, 15, 21, 28, 36, 45])"
- ]
- },
- "execution_count": 112,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 累计求和\n",
- "np.cumsum(d)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 113,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1, 2, 6, 24, 120, 720, 5040,\n",
- " 40320, 362880, 3628800])"
- ]
- },
- "execution_count": 113,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 累计乘积\n",
- "np.cumprod(d+1)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 114,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "1.4446600641166332"
- ]
- },
- "execution_count": 114,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 计算对角线元素的和,和diag(A).sum()一样\n",
- "np.trace(A)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 7.6 数组子集的计算"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "我们可以使用索引、花式索引和从数组中提取数据的其他方法(如上所述)来计算数组中的数据子集。\n",
- "\n",
- "例如,让我们回到温度数据集:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 115,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "1800 1 1 -6.1 -6.1 -6.1 1\r\n",
- "1800 1 2 -15.4 -15.4 -15.4 1\r\n",
- "1800 1 3 -15.0 -15.0 -15.0 1\r\n"
- ]
- }
- ],
- "source": [
- "!head -n 3 stockholm_td_adj.dat"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "数据集的格式是:年,月,日,日平均气温,低,高,位置。\n",
- "\n",
- "如果我们对某个特定月份的平均温度感兴趣,比如二月,然后我们可以创建一个索引掩码,使用它来选择当月的数据:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 116,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.])"
- ]
- },
- "execution_count": 116,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.unique(data[:,1]) # 列的值从1到12"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 117,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[False False False ... False False False]\n"
- ]
- }
- ],
- "source": [
- "mask_feb = data[:,1] == 2\n",
- "print(mask_feb)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 118,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "-3.212109570736596\n",
- "5.090390768766271\n"
- ]
- }
- ],
- "source": [
- "# 温度数据实在第三行\n",
- "print(np.mean(data[mask_feb,3]))\n",
- "print(np.std(data[mask_feb,3]))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "有了这些工具,我们就有了非常强大的数据处理能力。例如,提取每年每个月的平均气温只需要几行代码:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 119,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/png": "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\n",
- "text/plain": [
- "<Figure size 432x288 with 1 Axes>"
- ]
- },
- "metadata": {
- "needs_background": "light"
- },
- "output_type": "display_data"
- }
- ],
- "source": [
- "%matplotlib inline\n",
- "import matplotlib.pyplot as plt\n",
- "\n",
- "months = np.unique(data[:,1])\n",
- "monthly_mean = [np.mean(data[data[:,1] == month, 3]) for month in months]\n",
- "\n",
- "fig, ax = plt.subplots()\n",
- "ax.bar(months, monthly_mean)\n",
- "ax.set_xlabel(\"Month\")\n",
- "ax.set_ylabel(\"Monthly avg. temp.\");"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 7.7 高维数据的计算"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "当例如`min`, `max`等函数应用在高维数组上时,有时将计算应用于整个数组是有用的,而且很多时候有时只基于行或列。用`axis`参数我们可以决定这个函数应该怎样表现:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 120,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.85882078, 0.0838741 , 0.4529751 ],\n",
- " [0.32355282, 0.23641565, 0.37693805],\n",
- " [0.06769945, 0.30438005, 0.9780961 ],\n",
- " [0.46162058, 0.42681981, 0.71106984]])"
- ]
- },
- "execution_count": 120,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "import numpy as np\n",
- "\n",
- "m = np.random.rand(4,3)\n",
- "m"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 121,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "0.978096099540799"
- ]
- },
- "execution_count": 121,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# global max\n",
- "m.max()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 122,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0.85882078, 0.42681981, 0.9780961 ])"
- ]
- },
- "execution_count": 122,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# max in each column\n",
- "m.max(axis=0)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 123,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0.85882078, 0.37693805, 0.9780961 , 0.71106984])"
- ]
- },
- "execution_count": 123,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# max in each row\n",
- "m.max(axis=1)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "许多其他的在`array` 和`matrix`类中的函数和方法接受同样(可选的)的关键字参数`axis`"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 8. 阵列的重塑、调整大小和堆叠"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Numpy数组的形状可以被确定而无需复制底层数据,这使得即使对于大型数组也能有较快的操作。"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 124,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[0.58458652 0.95489874 0.76873658]\n",
- " [0.79144906 0.35559767 0.96031963]\n",
- " [0.55942317 0.78723157 0.3650356 ]\n",
- " [0.04685468 0.43444695 0.33839966]]\n"
- ]
- }
- ],
- "source": [
- "import numpy as np\n",
- "\n",
- "A = np.random.rand(4, 3)\n",
- "print(A)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 125,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "4 3\n"
- ]
- }
- ],
- "source": [
- "n, m = A.shape\n",
- "print(n, m)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 126,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.58458652, 0.95489874, 0.76873658, 0.79144906, 0.35559767,\n",
- " 0.96031963, 0.55942317, 0.78723157, 0.3650356 , 0.04685468,\n",
- " 0.43444695, 0.33839966]])"
- ]
- },
- "execution_count": 126,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "B = A.reshape((1,n*m))\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 127,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[0.58458652]\n",
- " [0.95489874]\n",
- " [0.76873658]\n",
- " [0.79144906]\n",
- " [0.35559767]\n",
- " [0.96031963]\n",
- " [0.55942317]\n",
- " [0.78723157]\n",
- " [0.3650356 ]\n",
- " [0.04685468]\n",
- " [0.43444695]\n",
- " [0.33839966]]\n",
- "(12, 1)\n"
- ]
- }
- ],
- "source": [
- "B2 = A.reshape((n*m, 1))\n",
- "print(B2)\n",
- "print(B2.shape)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 128,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[5. , 5. , 5. , 5. , 5. ,\n",
- " 0.96031963, 0.55942317, 0.78723157, 0.3650356 , 0.04685468,\n",
- " 0.43444695, 0.33839966]])"
- ]
- },
- "execution_count": 128,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "B[0,0:5] = 5 # modify the array\n",
- "\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 129,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[5. , 5. , 5. ],\n",
- " [5. , 5. , 0.96031963],\n",
- " [0.55942317, 0.78723157, 0.3650356 ],\n",
- " [0.04685468, 0.43444695, 0.33839966]])"
- ]
- },
- "execution_count": 129,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A # and the original variable is also changed. B is only a different view of the same data"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can also use the function `flatten` to make a higher-dimensional array into a vector. But this function create a copy of the data."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 130,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([5. , 5. , 5. , 5. , 5. ,\n",
- " 0.96031963, 0.55942317, 0.78723157, 0.3650356 , 0.04685468,\n",
- " 0.43444695, 0.33839966])"
- ]
- },
- "execution_count": 130,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "B = A.flatten()\n",
- "\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 131,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "(12,)\n"
- ]
- }
- ],
- "source": [
- "print(B.shape)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 132,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[0.88616566 0.11474399 0.49426839 0.86496944 0.44553257 0.01731081\n",
- " 0.26391484 0.81714822 0.9077824 0.45350327 0.34418481 0.30680307\n",
- " 0.22397584 0.96490185 0.25766897 0.1628303 0.35022665 0.87266285\n",
- " 0.14436895 0.2987234 0.04567582 0.62524215 0.03006832 0.15222984\n",
- " 0.86554462 0.30036796 0.66637188 0.51245662 0.46296801 0.53384373\n",
- " 0.90012971 0.00319531 0.48428543 0.24703543 0.53384405 0.48024175\n",
- " 0.17175873 0.1834814 0.43739033 0.64565657 0.49266811 0.72123815\n",
- " 0.57728476 0.76663343 0.68360823 0.34881945 0.64329004 0.79011718\n",
- " 0.7055079 0.32594224 0.48795517 0.43684614 0.32047664 0.63067622\n",
- " 0.24496431 0.25019593 0.57181523 0.38889906 0.53574819 0.02653888]\n"
- ]
- }
- ],
- "source": [
- "T = np.random.rand(3, 4, 5)\n",
- "T2 = T.flatten()\n",
- "print(T2)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 133,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([10. , 10. , 10. , 10. , 10. ,\n",
- " 0.96031963, 0.55942317, 0.78723157, 0.3650356 , 0.04685468,\n",
- " 0.43444695, 0.33839966])"
- ]
- },
- "execution_count": 133,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "B[0:5] = 10\n",
- "\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 134,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[5. , 5. , 5. ],\n",
- " [5. , 5. , 0.96031963],\n",
- " [0.55942317, 0.78723157, 0.3650356 ],\n",
- " [0.04685468, 0.43444695, 0.33839966]])"
- ]
- },
- "execution_count": 134,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A # 现在A并没有改变,因为B的数值是A的复制,并不指向同样的值。"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 9. 添加、删除维度:newaxis、squeeze"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "当矩阵乘法的时候,需要两个矩阵的对应的纬度保持一致才可以正确执行,有了`newaxis`,我们可以在数组中插入新的维度,例如将一个向量转换为列或行矩阵:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 135,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "v = np.array([1,2,3])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 136,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "(3,)\n",
- "[1 2 3]\n"
- ]
- }
- ],
- "source": [
- "print(np.shape(v))\n",
- "print(v)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 137,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "(3, 1)\n",
- "[[1]\n",
- " [2]\n",
- " [3]]\n"
- ]
- }
- ],
- "source": [
- "v2 = v.reshape(3, 1)\n",
- "print(v2.shape)\n",
- "print(v2)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 138,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "(3,)\n",
- "(3, 1)\n"
- ]
- }
- ],
- "source": [
- "# 做一个向量v的列矩阵\n",
- "v2 = v[:, np.newaxis]\n",
- "print(v.shape)\n",
- "print(v2.shape)\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 139,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(3, 1)"
- ]
- },
- "execution_count": 139,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 列矩阵\n",
- "v[:,np.newaxis].shape"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 140,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(1, 3)"
- ]
- },
- "execution_count": 140,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 行矩阵\n",
- "v[np.newaxis,:].shape"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "也可以通过 `np.expand_dims` 来实现类似的操作"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 141,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "(3, 1)\n",
- "[[1]\n",
- " [2]\n",
- " [3]]\n"
- ]
- }
- ],
- "source": [
- "v = np.array([1,2,3])\n",
- "v3 = np.expand_dims(v, 1)\n",
- "print(v3.shape)\n",
- "print(v3)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "在某些情况,需要将纬度为1的那个纬度删除掉,可以使用`np.squeeze`实现"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 142,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "(1, 2, 3)\n",
- "[[[1 2 3]\n",
- " [2 3 4]]]\n"
- ]
- }
- ],
- "source": [
- "arr = np.array([[[1, 2, 3], [2, 3, 4]]])\n",
- "print(arr.shape)\n",
- "print(arr)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 143,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "(2, 3)\n",
- "[[1 2 3]\n",
- " [2 3 4]]\n"
- ]
- }
- ],
- "source": [
- "# 实际上第一个纬度为`1`,我们不需要\n",
- "arr2 = np.squeeze(arr, 0)\n",
- "print(arr2.shape)\n",
- "print(arr2)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "需要注意:只有数组长度在该纬度上为1,那么该纬度才可以被删除;否则会报错。"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 10. 叠加和重复数组"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "利用函数`repeat`, `tile`, `vstack`, `hstack`, 和`concatenate` 可以用较小的向量和矩阵来创建更大的向量和矩阵。"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 10.1 tile and repeat"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 144,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[1 2]\n",
- " [3 4]]\n"
- ]
- }
- ],
- "source": [
- "a = np.array([[1, 2], [3, 4]])\n",
- "print(a)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 145,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4])"
- ]
- },
- "execution_count": 145,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 重复每一个元素三次\n",
- "np.repeat(a, 3)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 146,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2, 1, 2, 1, 2],\n",
- " [3, 4, 3, 4, 3, 4]])"
- ]
- },
- "execution_count": 146,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# tile the matrix 3 times \n",
- "np.tile(a, 3)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 147,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2, 1, 2, 1, 2],\n",
- " [3, 4, 3, 4, 3, 4]])"
- ]
- },
- "execution_count": 147,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 更好的方案\n",
- "np.tile(a, (1, 3))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 148,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2],\n",
- " [3, 4],\n",
- " [1, 2],\n",
- " [3, 4],\n",
- " [1, 2],\n",
- " [3, 4]])"
- ]
- },
- "execution_count": 148,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.tile(a, (3, 1))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 10.2 concatenate"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 149,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "b = np.array([[5, 6]])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 150,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2],\n",
- " [3, 4],\n",
- " [5, 6]])"
- ]
- },
- "execution_count": 150,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.concatenate((a, b), axis=0)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 151,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2, 5],\n",
- " [3, 4, 6]])"
- ]
- },
- "execution_count": 151,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.concatenate((a, b.T), axis=1)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### 10.3 hstack and vstack"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 152,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2],\n",
- " [3, 4],\n",
- " [5, 6]])"
- ]
- },
- "execution_count": 152,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.vstack((a,b))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 153,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2, 5],\n",
- " [3, 4, 6]])"
- ]
- },
- "execution_count": 153,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.hstack((a,b.T))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 11. 复制和“深度复制”"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "为了获得高性能,Python中的赋值通常不复制底层对象。例如,在函数之间传递对象时,通过引用传递从而避免不必要的大量内存复制。"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 154,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2],\n",
- " [3, 4]])"
- ]
- },
- "execution_count": 154,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A = np.array([[1, 2], [3, 4]])\n",
- "\n",
- "A"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 155,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "# 现在B和A指的是同一个数组数据\n",
- "B = A "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 156,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[10, 2],\n",
- " [ 3, 4]])"
- ]
- },
- "execution_count": 156,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 改变B影响A\n",
- "B[0,0] = 10\n",
- "\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 157,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[10, 2],\n",
- " [ 3, 4]])"
- ]
- },
- "execution_count": 157,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "如果我们想避免这种引用赋值的行为,那么当我们从 `A` 复制一个新的完全独立的对象 `B` 时,我们需要使用函数 `copy` 来做一个所谓的“深度复制”:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 158,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "B = np.copy(A)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 159,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[-5, 2],\n",
- " [ 3, 4]])"
- ]
- },
- "execution_count": 159,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 现在如果我们改变B,A不受影响\n",
- "B[0,0] = -5\n",
- "\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 160,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[10, 2],\n",
- " [ 3, 4]])"
- ]
- },
- "execution_count": 160,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 12. 遍历数组元素"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "通常,我们希望尽可能避免遍历数组元素(不惜一切代价)。原因是在像Python(或MATLAB)这样的解释语言中,迭代与向量化操作相比真的很慢。\n",
- "\n",
- "然而,有时迭代是不可避免的。对于这种情况,Python的For循环是最方便的遍历数组的方法:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 161,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "1\n",
- "2\n",
- "3\n",
- "4\n"
- ]
- }
- ],
- "source": [
- "v = np.array([1,2,3,4])\n",
- "\n",
- "for element in v:\n",
- " print(element)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 162,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "row [1 2]\n",
- "1\n",
- "2\n",
- "row [3 4]\n",
- "3\n",
- "4\n"
- ]
- }
- ],
- "source": [
- "M = np.array([[1,2], [3,4]])\n",
- "\n",
- "for row in M:\n",
- " print(\"row\", row)\n",
- " \n",
- " for element in row:\n",
- " print(element)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "当我们需要去\n",
- "当我们需要遍历一个数组的每个元素并修改它的元素时,使用`enumerate`函数可以方便地在`for`循环中获得元素及其索引:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 163,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "row_idx 0 row [1 2]\n",
- "col_idx 0 element 1\n",
- "col_idx 1 element 2\n",
- "row_idx 1 row [3 4]\n",
- "col_idx 0 element 3\n",
- "col_idx 1 element 4\n"
- ]
- }
- ],
- "source": [
- "for row_idx, row in enumerate(M):\n",
- " print(\"row_idx\", row_idx, \"row\", row)\n",
- " \n",
- " for col_idx, element in enumerate(row):\n",
- " print(\"col_idx\", col_idx, \"element\", element)\n",
- " \n",
- " # 更新矩阵:对每个元素求平方\n",
- " M[row_idx, col_idx] = element ** 2"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 164,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[ 1, 4],\n",
- " [ 9, 16]])"
- ]
- },
- "execution_count": 164,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 现在矩阵里的每一个元素都已经求得平方\n",
- "M"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 13. 向量化功能"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "正如前面多次提到的,为了获得良好的性能,我们应该尽量避免对向量和矩阵中的元素进行循环,而应该使用向量化算法。将标量算法转换为向量化算法的第一步是确保我们编写的函数使用向量输入。"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 165,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "def Theta(x):\n",
- " \"\"\"\n",
- " 阶跃函数的普遍版本\n",
- " \"\"\"\n",
- " if x >= 0:\n",
- " return 1\n",
- " else:\n",
- " return 0"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 166,
- "metadata": {
- "scrolled": true
- },
- "outputs": [
- {
- "ename": "ValueError",
- "evalue": "The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
- "\u001b[0;32m<ipython-input-166-b49266106206>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mTheta\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
- "\u001b[0;32m<ipython-input-165-cb840dbb09da>\u001b[0m in \u001b[0;36mTheta\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0m阶跃函数的普遍版本\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \"\"\"\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m>=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;31mValueError\u001b[0m: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()"
- ]
- }
- ],
- "source": [
- "Theta(np.array([-3,-2,-1,0,1,2,3]))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "这个操作并不可行,因为所实现的 `Theta` 函数不能接收向量输入。\n",
- "\n",
- "为了得到向量化的版本,我们可以使用Numpy函数 `vectorize` 。在许多情况下,它可以自动向量化一个函数:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 167,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "Theta_vec = np.vectorize(Theta)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 168,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 0, 0, 1, 1, 1, 1])"
- ]
- },
- "execution_count": 168,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "Theta_vec(np.array([-3,-2,-1,0,1,2,3]))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "我们也可以实现从一开始就接受矢量输入的函数(需要更多的计算,但可能会有更好的性能):"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 169,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": [
- "def Theta(x):\n",
- " \"\"\"\n",
- " Heaviside阶跃函数的矢量感知实现。\n",
- " \"\"\"\n",
- " return 1 * (x >= 0)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 170,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 0, 0, 1, 1, 1, 1])"
- ]
- },
- "execution_count": 170,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "Theta(np.array([-3,-2,-1,0,1,2,3]))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 171,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[False False False True True True True]\n"
- ]
- },
- {
- "data": {
- "text/plain": [
- "array([0, 0, 0, 1, 1, 1, 1])"
- ]
- },
- "execution_count": 171,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "a = np.array([-3,-2,-1,0,1,2,3])\n",
- "b = a>=0\n",
- "print(b)\n",
- "b*1"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 172,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(0, 1)"
- ]
- },
- "execution_count": 172,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# 同样适用于标量\n",
- "Theta(-1.2), Theta(2.6)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 14. 在条件中使用数组"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "当在条件中使用数组时,例如`if`语句和其他布尔表达,一个需要用`any`或者`all`,这让数组任何或者所有元素都等于`True`。"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 173,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2],\n",
- " [3, 4]])"
- ]
- },
- "execution_count": 173,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M = np.array([[1, 2], [3, 4]])\n",
- "M"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 174,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 174,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "(M > 2).any()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 175,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "at least one element in M is larger than 2\n"
- ]
- }
- ],
- "source": [
- "if (M > 2).any():\n",
- " print(\"at least one element in M is larger than 2\")\n",
- "else:\n",
- " print(\"no element in M is larger than 2\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 176,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "all elements in M are not larger than 5\n"
- ]
- }
- ],
- "source": [
- "if (M > 5).all():\n",
- " print(\"all elements in M are larger than 5\")\n",
- "else:\n",
- " print(\"all elements in M are not larger than 5\")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 15. 类型转换"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "因为Numpy数组是*静态类型*,数组的类型一旦创建就不会改变。但是我们可以用`astype`函数(参见类似的“asarray”函数)显式地转换一个数组的类型到其他的类型,这总是创建一个新类型的新数组。"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 177,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "dtype('int64')"
- ]
- },
- "execution_count": 177,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M.dtype\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 178,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1., 2.],\n",
- " [3., 4.]])"
- ]
- },
- "execution_count": 178,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M2 = M.astype(float)\n",
- "\n",
- "M2"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 179,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "dtype('float64')"
- ]
- },
- "execution_count": 179,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M2.dtype"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 180,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[ True, True],\n",
- " [ True, True]])"
- ]
- },
- "execution_count": 180,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M3 = M.astype(bool)\n",
- "\n",
- "M3"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## 16. 进一步学习"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "* [NumPy 简易教程](https://www.runoob.com/numpy/numpy-tutorial.html)\n",
- "* [NumPy 官方用户指南](https://www.numpy.org.cn/user/)\n",
- "* [NumPy 官方参考手册](https://www.numpy.org.cn/reference/)\n",
- "* [一个针对MATLAB使用者的Numpy教程](https://numpy.org/doc/stable/user/numpy-for-matlab-users.html)"
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.5.4"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 1
- }
|