|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887 |
- {
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Numpy - multidimensional data arrays"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "J.R. Johansson (jrjohansson at gmail.com)\n",
- "\n",
- "The latest version of this [IPython notebook](http://ipython.org/notebook.html) lecture is available at [http://github.com/jrjohansson/scientific-python-lectures](http://github.com/jrjohansson/scientific-python-lectures).\n",
- "\n",
- "The other notebooks in this lecture series are indexed at [http://jrjohansson.github.io](http://jrjohansson.github.io)."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "# what is this line all about?!? Answer in lecture 4\n",
- "%matplotlib inline\n",
- "import matplotlib.pyplot as plt"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Introduction"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The `numpy` package (module) is used in almost all numerical computation using Python. It is a package that provide high-performance vector, matrix and higher-dimensional data structures for Python. It is implemented in C and Fortran so when calculations are vectorized (formulated with vectors and matrices), performance is very good. \n",
- "\n",
- "To use `numpy` you need to import the module, using for example:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [],
- "source": [
- "from numpy import *\n",
- "import numpy as np"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "In the `numpy` package the terminology used for vectors, matrices and higher-dimensional data sets is *array*. \n",
- "\n"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Creating `numpy` arrays"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "There are a number of ways to initialize new numpy arrays, for example from\n",
- "\n",
- "* a Python list or tuples\n",
- "* using functions that are dedicated to generating numpy arrays, such as `arange`, `linspace`, etc.\n",
- "* reading data from files"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### From lists"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "For example, to create new vector and matrix arrays from Python lists we can use the `numpy.array` function."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([1, 2, 3, 4])"
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "import numpy as np\n",
- "\n",
- "# a vector: the argument to the array function is a Python list\n",
- "v = np.array([1,2,3,4])\n",
- "\n",
- "v"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[1 2]\n",
- " [3 4]\n",
- " [5 6]]\n",
- "(3, 2)\n"
- ]
- }
- ],
- "source": [
- "# a matrix: the argument to the array function is a nested Python list\n",
- "M = array([[1, 2], [3, 4], [5, 6]])\n",
- "\n",
- "print(M)\n",
- "print(M.shape)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The `v` and `M` objects are both of the type `ndarray` that the `numpy` module provides."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(numpy.ndarray, numpy.ndarray)"
- ]
- },
- "execution_count": 8,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "type(v), type(M)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The difference between the `v` and `M` arrays is only their shapes. We can get information about the shape of an array by using the `ndarray.shape` property."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(4,)"
- ]
- },
- "execution_count": 9,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v.shape"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(3, 2)"
- ]
- },
- "execution_count": 10,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M.shape"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The number of elements in the array is available through the `ndarray.size` property:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 14,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "6"
- ]
- },
- "execution_count": 14,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M.size"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Equivalently, we could use the function `numpy.shape` and `numpy.size`"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(3, 2)"
- ]
- },
- "execution_count": 12,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.shape(M)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 13,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "6"
- ]
- },
- "execution_count": 13,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.size(M)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "So far the `numpy.ndarray` looks awefully much like a Python list (or nested list). Why not simply use Python lists for computations instead of creating a new array type? \n",
- "\n",
- "There are several reasons:\n",
- "\n",
- "* Python lists are very general. They can contain any kind of object. They are dynamically typed. They do not support mathematical functions such as matrix and dot multiplications, etc. Implementing such functions for Python lists would not be very efficient because of the dynamic typing.\n",
- "* Numpy arrays are **statically typed** and **homogeneous**. The type of the elements is determined when the array is created.\n",
- "* Numpy arrays are memory efficient.\n",
- "* Because of the static typing, fast implementation of mathematical functions such as multiplication and addition of `numpy` arrays can be implemented in a compiled language (C and Fortran is used).\n",
- "\n",
- "Using the `dtype` (data type) property of an `ndarray`, we can see what type the data of an array has:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 17,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "dtype('int64')"
- ]
- },
- "execution_count": 17,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M.dtype"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We get an error if we try to assign a value of the wrong type to an element in a numpy array:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 17,
- "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-17-e1f336250f69>\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;34m=\u001b[0m \u001b[0;34m\"hello\"\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] = \"hello\""
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "If we want, we can explicitly define the type of the array data when we create it, using the `dtype` keyword argument: "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 19,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1.+0.j, 2.+0.j],\n",
- " [3.+0.j, 4.+0.j]])"
- ]
- },
- "execution_count": 19,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M = np.array([[1, 2], [3, 4]], dtype=complex)\n",
- "\n",
- "M"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Common data types that can be used with `dtype` are: `int`, `float`, `complex`, `bool`, `object`, etc.\n",
- "\n",
- "We can also explicitly define the bit size of the data types, for example: `int64`, `int16`, `float128`, `complex128`."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Using array-generating functions"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "For larger arrays it is inpractical to initialize the data manually, using explicit python lists. Instead we can use one of the many functions in `numpy` that generate arrays of different forms. Some of the more common are:"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### arange"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 20,
- "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": [
- "# create a range\n",
- "\n",
- "x = np.arange(0, 10, 1) # arguments: start, stop, step\n",
- "y = range(0, 10, 1)\n",
- "print(x)\n",
- "print(list(y))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 21,
- "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": 21,
- "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": 24,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 0. , 0.41666667, 0.83333333, 1.25 , 1.66666667,\n",
- " 2.08333333, 2.5 , 2.91666667, 3.33333333, 3.75 ,\n",
- " 4.16666667, 4.58333333, 5. , 5.41666667, 5.83333333,\n",
- " 6.25 , 6.66666667, 7.08333333, 7.5 , 7.91666667,\n",
- " 8.33333333, 8.75 , 9.16666667, 9.58333333, 10. ])"
- ]
- },
- "execution_count": 24,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# using linspace, both end points ARE included\n",
- "np.linspace(0, 10, 25)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 25,
- "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": 25,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.logspace(0, 10, 10, base=e)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### mgrid"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 26,
- "metadata": {},
- "outputs": [],
- "source": [
- "x, y = np.mgrid[0:5, 0:5] # similar to meshgrid in MATLAB"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 27,
- "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": 27,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "x"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 28,
- "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": 28,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "y"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### random data"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 29,
- "metadata": {},
- "outputs": [],
- "source": [
- "from numpy import random"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 30,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.82594014, 0.31160547, 0.77827738, 0.59082014, 0.69654657],\n",
- " [0.64715318, 0.05551977, 0.38057657, 0.45135262, 0.37209654],\n",
- " [0.01234335, 0.12906551, 0.75598568, 0.20905719, 0.86103339],\n",
- " [0.62784645, 0.87732666, 0.96543239, 0.41053462, 0.87116428],\n",
- " [0.44218283, 0.70837525, 0.15065753, 0.93552422, 0.79261749]])"
- ]
- },
- "execution_count": 30,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# uniform random numbers in [0,1)\n",
- "random.rand(5,5)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 31,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[ 0.69829709, 0.04679976, 0.95770162, 1.91007838, -0.41865049],\n",
- " [ 0.51678337, -0.34692074, 2.19264774, -0.59725524, -1.15314406],\n",
- " [ 0.03361378, -0.0054733 , -0.77389592, -0.12696594, 1.69339468],\n",
- " [-0.13267375, 0.95688595, 0.28043241, 0.83043672, 0.62677072],\n",
- " [-0.09168095, -0.25064829, 0.49440189, -1.18704973, -1.28781414]])"
- ]
- },
- "execution_count": 31,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# standard normal distributed random numbers\n",
- "random.randn(5,5)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### diag"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 32,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 0, 0],\n",
- " [0, 2, 0],\n",
- " [0, 0, 3]])"
- ]
- },
- "execution_count": 32,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# a diagonal matrix\n",
- "np.diag([1,2,3])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 36,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0, 1, 0, 0],\n",
- " [0, 0, 2, 0],\n",
- " [0, 0, 0, 3],\n",
- " [0, 0, 0, 0]])"
- ]
- },
- "execution_count": 36,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# diagonal with offset from the main diagonal\n",
- "diag([1,2,3], k=1) "
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### zeros and ones"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 37,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0., 0., 0.],\n",
- " [0., 0., 0.],\n",
- " [0., 0., 0.]])"
- ]
- },
- "execution_count": 37,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.zeros((3,3))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 38,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1., 1., 1.],\n",
- " [1., 1., 1.],\n",
- " [1., 1., 1.]])"
- ]
- },
- "execution_count": 38,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.ones((3,3))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## File I/O"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Comma-separated values (CSV)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "A very common file format for data files is comma-separated values (CSV), or related formats such as TSV (tab-separated values). To read data from such files into Numpy arrays we can use the `numpy.genfromtxt` function. For example, "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 39,
- "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": 41,
- "metadata": {},
- "outputs": [],
- "source": [
- "import numpy as np\n",
- "data = np.genfromtxt('stockholm_td_adj.dat')"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 42,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(77431, 7)"
- ]
- },
- "execution_count": 42,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "data.shape"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 44,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/png": "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\n",
- "text/plain": [
- "<Figure size 1008x288 with 1 Axes>"
- ]
- },
- "metadata": {
- "needs_background": "light"
- },
- "output_type": "display_data"
- }
- ],
- "source": [
- "%matplotlib inline\n",
- "import matplotlib.pyplot as plt\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('tempeatures in Stockholm')\n",
- "ax.set_xlabel('year')\n",
- "ax.set_ylabel('temperature (C)');"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Using `numpy.savetxt` we can store a Numpy array to a file in CSV format:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 45,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.85030715, 0.33330859, 0.64002838],\n",
- " [0.52521743, 0.21572812, 0.33287991],\n",
- " [0.74605429, 0.35134767, 0.45873422]])"
- ]
- },
- "execution_count": 45,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M = np.random.rand(3,3)\n",
- "\n",
- "M"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 47,
- "metadata": {},
- "outputs": [],
- "source": [
- "np.savetxt(\"random-matrix.csv\", M)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 48,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "8.503071542574233144e-01 3.333085915891427220e-01 6.400283846962552259e-01\r\n",
- "5.252174340396357222e-01 2.157281249144539226e-01 3.328799104985459278e-01\r\n",
- "7.460542870039649221e-01 3.513476662217395186e-01 4.587342216214667090e-01\r\n"
- ]
- }
- ],
- "source": [
- "!cat random-matrix.csv"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 49,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "0.85031 0.33331 0.64003\r\n",
- "0.52522 0.21573 0.33288\r\n",
- "0.74605 0.35135 0.45873\r\n"
- ]
- }
- ],
- "source": [
- "np.savetxt(\"random-matrix.csv\", M, fmt='%.5f') # fmt specifies the format\n",
- "\n",
- "!cat random-matrix.csv"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Numpy's native file format"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Useful when storing and reading back numpy array data. Use the functions `numpy.save` and `numpy.load`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 50,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "random-matrix.npy: data\r\n"
- ]
- }
- ],
- "source": [
- "np.save(\"random-matrix.npy\", M)\n",
- "\n",
- "!file random-matrix.npy"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 51,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.85030715, 0.33330859, 0.64002838],\n",
- " [0.52521743, 0.21572812, 0.33287991],\n",
- " [0.74605429, 0.35134767, 0.45873422]])"
- ]
- },
- "execution_count": 51,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.load(\"random-matrix.npy\")"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## More properties of the numpy arrays"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 52,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "float64\n",
- "8\n"
- ]
- }
- ],
- "source": [
- "print(M.dtype)\n",
- "print(M.itemsize) # bytes per element\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 53,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "72"
- ]
- },
- "execution_count": 53,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M.nbytes # number of bytes"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 54,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "2"
- ]
- },
- "execution_count": 54,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M.ndim # number of dimensions"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Manipulating arrays"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Indexing"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can index elements in an array using square brackets and indices:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 55,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "1"
- ]
- },
- "execution_count": 55,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v = np.array([1, 2, 3, 4, 5])\n",
- "# v is a vector, and has only one dimension, taking one index\n",
- "v[0]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 56,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "0.21572812491445392\n",
- "0.21572812491445392\n",
- "[0.52521743 0.21572812 0.33287991]\n"
- ]
- }
- ],
- "source": [
- "\n",
- "# M is a matrix, or a 2 dimensional array, taking two indices \n",
- "print(M[1,1])\n",
- "print(M[1][1])\n",
- "print(M[1])"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "If we omit an index of a multidimensional array it returns the whole row (or, in general, a N-1 dimensional array) "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 57,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.85030715, 0.33330859, 0.64002838],\n",
- " [0.52521743, 0.21572812, 0.33287991],\n",
- " [0.74605429, 0.35134767, 0.45873422]])"
- ]
- },
- "execution_count": 57,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 58,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0.52521743, 0.21572812, 0.33287991])"
- ]
- },
- "execution_count": 58,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M[1]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The same thing can be achieved with using `:` instead of an index: "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 59,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0.52521743, 0.21572812, 0.33287991])"
- ]
- },
- "execution_count": 59,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M[1,:] # row 1"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 60,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0.33330859, 0.21572812, 0.35134767])"
- ]
- },
- "execution_count": 60,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M[:,1] # column 1"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can assign new values to elements in an array using indexing:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 61,
- "metadata": {},
- "outputs": [],
- "source": [
- "M[0,0] = 1"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 62,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1. , 0.33330859, 0.64002838],\n",
- " [0.52521743, 0.21572812, 0.33287991],\n",
- " [0.74605429, 0.35134767, 0.45873422]])"
- ]
- },
- "execution_count": 62,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 64,
- "metadata": {},
- "outputs": [],
- "source": [
- "# also works for rows and columns\n",
- "M[1,:] = 0\n",
- "M[:,2] = -1"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 24,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[ 1. , 0.85499268, -1. ],\n",
- " [ 0. , 0. , -1. ],\n",
- " [ 0.55448257, 0.53279085, -1. ]])"
- ]
- },
- "execution_count": 24,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Index slicing"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Index slicing is the technical name for the syntax `M[lower:upper:step]` to extract part of an array:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 65,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([1, 2, 3, 4, 5])"
- ]
- },
- "execution_count": 65,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A = np.array([1,2,3,4,5])\n",
- "A"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 66,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([2, 3])"
- ]
- },
- "execution_count": 66,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[1:3]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Array slices are *mutable*: if they are assigned a new value the original array from which the slice was extracted is modified:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 67,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1, -2, -3, 4, 5])"
- ]
- },
- "execution_count": 67,
- "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": [
- "We can omit any of the three parameters in `M[lower:upper:step]`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 68,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1, -2, -3, 4, 5])"
- ]
- },
- "execution_count": 68,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[::] # lower, upper, step all take the default values"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 69,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1, -2, -3, 4, 5])"
- ]
- },
- "execution_count": 69,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[:]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 70,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1, -3, 5])"
- ]
- },
- "execution_count": 70,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[::2] # step is 2, lower and upper defaults to the beginning and end of the array"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 71,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1, -2, -3])"
- ]
- },
- "execution_count": 71,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[:3] # first three elements"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 72,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([4, 5])"
- ]
- },
- "execution_count": 72,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[3:] # elements from index 3"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Negative indices counts from the end of the array (positive index from the begining):"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 73,
- "metadata": {},
- "outputs": [],
- "source": [
- "A = np.array([1,2,3,4,5])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 74,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "5"
- ]
- },
- "execution_count": 74,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[-1] # the last element in the array"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 75,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([3, 4, 5])"
- ]
- },
- "execution_count": 75,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A[-3:] # the last three elements"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Index slicing works exactly the same way for multidimensional arrays:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 76,
- "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": 76,
- "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": 77,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[11, 12, 13],\n",
- " [21, 22, 23],\n",
- " [31, 32, 33]])"
- ]
- },
- "execution_count": 77,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# a block from the original array\n",
- "A[1:4, 1:4]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 63,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[ 0, 2, 4],\n",
- " [20, 22, 24],\n",
- " [40, 42, 44]])"
- ]
- },
- "execution_count": 63,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# strides\n",
- "A[::2, ::2]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Fancy indexing"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Fancy indexing is the name for when an array or list is used in-place of an index: "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 78,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[10 11 12 13 14]\n",
- " [20 21 22 23 24]\n",
- " [30 31 32 33 34]]\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": [
- "row_indices = [1, 2, 3]\n",
- "print(A[row_indices])\n",
- "print(A)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 79,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([11, 22, 34])"
- ]
- },
- "execution_count": 79,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "col_indices = [1, 2, -1] # remember, index -1 means the last element\n",
- "A[row_indices, col_indices]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can also use index masks: If the index mask is an Numpy array of data type `bool`, then an element is selected (True) or not (False) depending on the value of the index mask at the position of each element: "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 80,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 1, 2, 3, 4])"
- ]
- },
- "execution_count": 80,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "B = array([n for n in range(5)])\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 81,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 2])"
- ]
- },
- "execution_count": 81,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "row_mask = array([True, False, True, False, False])\n",
- "B[row_mask]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 82,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 2])"
- ]
- },
- "execution_count": 82,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# same thing\n",
- "row_mask = array([1,0,1,0,0], dtype=bool)\n",
- "B[row_mask]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "This feature is very useful to conditionally select elements from an array, using for example comparison operators:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 84,
- "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": 84,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "x = np.arange(0, 10, 0.5)\n",
- "x"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 86,
- "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": 86,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "mask = (5 < x) * (x < 7.5)\n",
- "\n",
- "mask"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 87,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([5.5, 6. , 6.5, 7. ])"
- ]
- },
- "execution_count": 87,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "x[mask]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 92,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([3.5, 4. , 4.5, 5. , 5.5])"
- ]
- },
- "execution_count": 92,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "x[(3<x) * (x<6)]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Functions for extracting data from arrays and creating arrays"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### where"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The index mask can be converted to position index using the `where` function"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 47,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(array([11, 12, 13, 14]),)"
- ]
- },
- "execution_count": 47,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "indices = np.where(mask)\n",
- "\n",
- "indices"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 48,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([5.5, 6. , 6.5, 7. ])"
- ]
- },
- "execution_count": 48,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "x[indices] # this indexing is equivalent to the fancy indexing x[mask]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### diag"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "With the diag function we can also extract the diagonal and subdiagonals of an array:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 74,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 0, 11, 22, 33, 44])"
- ]
- },
- "execution_count": 74,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "diag(A)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 75,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([10, 21, 32, 43])"
- ]
- },
- "execution_count": 75,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "diag(A, -1)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### take"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The `take` function is similar to fancy indexing described above:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 76,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([-3, -2, -1, 0, 1, 2])"
- ]
- },
- "execution_count": 76,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v2 = arange(-3,3)\n",
- "v2"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 77,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([-2, 0, 2])"
- ]
- },
- "execution_count": 77,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "row_indices = [1, 3, 5]\n",
- "v2[row_indices] # fancy indexing"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 78,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([-2, 0, 2])"
- ]
- },
- "execution_count": 78,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v2.take(row_indices)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "But `take` also works on lists and other objects:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 79,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([-2, 0, 2])"
- ]
- },
- "execution_count": 79,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "take([-3, -2, -1, 0, 1, 2], row_indices)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### choose"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Constructs an array by picking elements from several arrays:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 49,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 5, -2, 5, -2])"
- ]
- },
- "execution_count": 49,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "which = [1, 0, 1, 0]\n",
- "choices = [[-2,-2,-2,-2], [5,5,5,5]]\n",
- "\n",
- "np.choose(which, choices)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Linear algebra"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Vectorizing code is the key to writing efficient numerical calculation with Python/Numpy. That means that as much as possible of a program should be formulated in terms of matrix and vector operations, like matrix-matrix multiplication."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Scalar-array operations"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can use the usual arithmetic operators to multiply, add, subtract, and divide arrays with scalar numbers."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 93,
- "metadata": {},
- "outputs": [],
- "source": [
- "v1 = np.arange(0, 5)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 94,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 2, 4, 6, 8])"
- ]
- },
- "execution_count": 94,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v1 * 2"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 95,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([2, 3, 4, 5, 6])"
- ]
- },
- "execution_count": 95,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v1 + 2"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 96,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(array([[ 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]]), array([[ 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]]))"
- ]
- },
- "execution_count": 96,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A * 2, A + 2"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Element-wise array-array operations"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "When we add, subtract, multiply and divide arrays with each other, the default behaviour is **element-wise** operations:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 97,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.41002411, 0.52156709, 0.77687362],\n",
- " [0.86406459, 0.00587552, 0.04683701]])"
- ]
- },
- "execution_count": 97,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A = np.random.rand(2, 3)\n",
- "\n",
- "A * A # element-wise multiplication"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 98,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 0, 1, 4, 9, 16])"
- ]
- },
- "execution_count": 98,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v1 * v1"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "If we multiply arrays with compatible shapes, we get an element-wise multiplication of each row:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 99,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "((2, 3), (5,))"
- ]
- },
- "execution_count": 99,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A.shape, v1.shape"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 100,
- "metadata": {},
- "outputs": [
- {
- "ename": "ValueError",
- "evalue": "operands could not be broadcast together with shapes (2,3) (5,) ",
- "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-1af134c5c5d0>\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[0m\n\u001b[0m",
- "\u001b[0;31mValueError\u001b[0m: operands could not be broadcast together with shapes (2,3) (5,) "
- ]
- }
- ],
- "source": [
- "A * v1"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Matrix algebra"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "What about matrix mutiplication? There are two ways. We can either use the `dot` function, which applies a matrix-matrix, matrix-vector, or inner vector multiplication to its two arguments: "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 102,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.3767892 , 1.47079714, 0.31117826, 1.29726746, 0.51486767],\n",
- " [0.25604237, 0.97247777, 0.34479677, 0.93969314, 0.3976715 ],\n",
- " [0.81557228, 1.22841789, 0.86636095, 0.93499185, 0.28560187],\n",
- " [0.52515694, 1.56792282, 1.1443364 , 1.84965072, 0.74141231],\n",
- " [0.78004097, 1.51298694, 1.22023006, 1.42991218, 0.71648303]])"
- ]
- },
- "execution_count": 102,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A = np.random.rand(5, 5)\n",
- "v = np.random.rand(5, 1)\n",
- "\n",
- "np.dot(A, A)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 107,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([3.03824466, 2.65209134, 2.94637897, 6.50153897, 5.54270391])"
- ]
- },
- "execution_count": 107,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.dot(A, v1)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 108,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "30"
- ]
- },
- "execution_count": 108,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.dot(v1, v1)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Alternatively, we can cast the array objects to the type `matrix`. This changes the behavior of the standard arithmetic operators `+, -, *` to use matrix algebra."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 111,
- "metadata": {},
- "outputs": [],
- "source": [
- "M = np.matrix(A)\n",
- "v = np.matrix(v1).T # make it a column vector"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 112,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[0],\n",
- " [1],\n",
- " [2],\n",
- " [3],\n",
- " [4]])"
- ]
- },
- "execution_count": 112,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "v"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 113,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[0.3767892 , 1.47079714, 0.31117826, 1.29726746, 0.51486767],\n",
- " [0.25604237, 0.97247777, 0.34479677, 0.93969314, 0.3976715 ],\n",
- " [0.81557228, 1.22841789, 0.86636095, 0.93499185, 0.28560187],\n",
- " [0.52515694, 1.56792282, 1.1443364 , 1.84965072, 0.74141231],\n",
- " [0.78004097, 1.51298694, 1.22023006, 1.42991218, 0.71648303]])"
- ]
- },
- "execution_count": 113,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M * M"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 114,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[3.03824466],\n",
- " [2.65209134],\n",
- " [2.94637897],\n",
- " [6.50153897],\n",
- " [5.54270391]])"
- ]
- },
- "execution_count": 114,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M * v"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 117,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[30]])"
- ]
- },
- "execution_count": 117,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# inner product\n",
- "v.T * v"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 118,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[3.03824466],\n",
- " [3.65209134],\n",
- " [4.94637897],\n",
- " [9.50153897],\n",
- " [9.54270391]])"
- ]
- },
- "execution_count": 118,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# with matrix objects, standard matrix algebra applies\n",
- "v + M*v"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "If we try to add, subtract or multiply objects with incomplatible shapes we get an error:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 125,
- "metadata": {},
- "outputs": [],
- "source": [
- "v = np.matrix([1,2,3,4,5,6]).T"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 123,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "((5, 5), (5, 1))"
- ]
- },
- "execution_count": 123,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.shape(M), np.shape(v)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 124,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[5.06458489],\n",
- " [4.08471675],\n",
- " [4.990684 ],\n",
- " [9.17423165],\n",
- " [8.08502244]])"
- ]
- },
- "execution_count": 124,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M * v"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "See also the related functions: `inner`, `outer`, `cross`, `kron`, `tensordot`. Try for example `help(kron)`."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Array/Matrix transformations"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Above we have used the `.T` to transpose the matrix object `v`. We could also have used the `transpose` function to accomplish the same thing. \n",
- "\n",
- "Other mathematical functions that transform matrix objects are:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 126,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[0.04208911 0.65828119 0.21987187 0.10069326]\n",
- " [0.61960112 0.52726045 0.35884175 0.51931613]\n",
- " [0.66708619 0.76886997 0.06792093 0.6548313 ]]\n",
- "[[0.04208911 0.61960112 0.66708619]\n",
- " [0.65828119 0.52726045 0.76886997]\n",
- " [0.21987187 0.35884175 0.06792093]\n",
- " [0.10069326 0.51931613 0.6548313 ]]\n"
- ]
- }
- ],
- "source": [
- "A = np.random.rand(3,4)\n",
- "print(A)\n",
- "print(A.T)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 127,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[0.+1.j, 0.+2.j],\n",
- " [0.+3.j, 0.+4.j]])"
- ]
- },
- "execution_count": 127,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "C = np.matrix([[1j, 2j], [3j, 4j]])\n",
- "C"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 128,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[0.-1.j, 0.-2.j],\n",
- " [0.-3.j, 0.-4.j]])"
- ]
- },
- "execution_count": 128,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "conjugate(C)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Hermitian conjugate: transpose + conjugate"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 129,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[0.-1.j, 0.-3.j],\n",
- " [0.-2.j, 0.-4.j]])"
- ]
- },
- "execution_count": 129,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "C.H"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can extract the real and imaginary parts of complex-valued arrays using `real` and `imag`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 130,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[0., 0.],\n",
- " [0., 0.]])"
- ]
- },
- "execution_count": 130,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "real(C) # same as: C.real"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 131,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[1., 2.],\n",
- " [3., 4.]])"
- ]
- },
- "execution_count": 131,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "imag(C) # same as: C.imag"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Or the complex argument and absolute value"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 106,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[ 0.78539816, 1.10714872],\n",
- " [ 1.24904577, 1.32581766]])"
- ]
- },
- "execution_count": 106,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "angle(C+1) # heads up MATLAB Users, angle is used instead of arg"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 107,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[ 1., 2.],\n",
- " [ 3., 4.]])"
- ]
- },
- "execution_count": 107,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "abs(C)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Matrix computations"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### Inverse"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 132,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[0.+2.j , 0.-1.j ],\n",
- " [0.-1.5j, 0.+0.5j]])"
- ]
- },
- "execution_count": 132,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.linalg.inv(C) # equivalent to C.I "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 133,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "matrix([[1.00000000e+00+0.j, 0.00000000e+00+0.j],\n",
- " [2.22044605e-16+0.j, 1.00000000e+00+0.j]])"
- ]
- },
- "execution_count": 133,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "C.I * C"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### Determinant"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 134,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(2.0000000000000004+0j)"
- ]
- },
- "execution_count": 134,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.linalg.det(C)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 135,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(0.49999999999999967+0j)"
- ]
- },
- "execution_count": 135,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "linalg.det(C.I)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Data processing"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Often it is useful to store datasets in Numpy arrays. Numpy provides a number of functions to calculate statistics of datasets in arrays. \n",
- "\n",
- "For example, let's calculate some properties from the Stockholm temperature dataset used above."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 136,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(77431, 7)"
- ]
- },
- "execution_count": 136,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# reminder, the tempeature dataset is stored in the data variable:\n",
- "np.shape(data)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### mean"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 88,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "(77431, 7)\n"
- ]
- },
- {
- "data": {
- "text/plain": [
- "6.197109684751585"
- ]
- },
- "execution_count": 88,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# the temperature data is in column 3\n",
- "print(data.shape)\n",
- "np.mean(data[:,3])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 137,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "0.4764047026464162"
- ]
- },
- "execution_count": 137,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A = np.random.rand(4, 3)\n",
- "np.mean(A)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The daily mean temperature in Stockholm over the last 200 years has been about 6.2 C."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### standard deviations and variance"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 138,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(8.282271621340573, 68.59602320966341)"
- ]
- },
- "execution_count": 138,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.std(data[:,3]), np.var(data[:,3])"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### min and max"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 139,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "-25.8"
- ]
- },
- "execution_count": 139,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# lowest daily average temperature\n",
- "data[:,3].min()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 140,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "28.3"
- ]
- },
- "execution_count": 140,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# highest daily average temperature\n",
- "data[:,3].max()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### sum, prod, and trace"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 141,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])"
- ]
- },
- "execution_count": 141,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "d = np.arange(0, 10)\n",
- "d"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 142,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "45"
- ]
- },
- "execution_count": 142,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# sum up all elements\n",
- "np.sum(d)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 143,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "3628800"
- ]
- },
- "execution_count": 143,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# product of all elements\n",
- "np.prod(d+1)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 144,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 0, 1, 3, 6, 10, 15, 21, 28, 36, 45])"
- ]
- },
- "execution_count": 144,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# cummulative sum\n",
- "np.cumsum(d)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 147,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1, 2, 6, 24, 120, 720, 5040,\n",
- " 40320, 362880, 3628800])"
- ]
- },
- "execution_count": 147,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# cummulative product\n",
- "np.cumprod(d+1)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 148,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "1.04879166276667"
- ]
- },
- "execution_count": 148,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# same as: diag(A).sum()\n",
- "np.trace(A)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Computations on subsets of arrays"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can compute with subsets of the data in an array using indexing, fancy indexing, and the other methods of extracting data from an array (described above).\n",
- "\n",
- "For example, let's go back to the temperature dataset:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 149,
- "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": [
- "The dataformat is: year, month, day, daily average temperature, low, high, location.\n",
- "\n",
- "If we are interested in the average temperature only in a particular month, say February, then we can create a index mask and use it to select only the data for that month using:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 99,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.])"
- ]
- },
- "execution_count": 99,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.unique(data[:,1]) # the month column takes values from 1 to 12"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 150,
- "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": 151,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "-3.212109570736596\n",
- "5.090390768766271\n"
- ]
- }
- ],
- "source": [
- "# the temperature data is in column 3\n",
- "print(np.mean(data[mask_feb,3]))\n",
- "print(np.std(data[mask_feb,3]))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "With these tools we have very powerful data processing capabilities at our disposal. For example, to extract the average monthly average temperatures for each month of the year only takes a few lines of code: "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 153,
- "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": [
- "months = np.arange(1,13)\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": [
- "### Calculations with higher-dimensional data"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "When functions such as `min`, `max`, etc. are applied to a multidimensional arrays, it is sometimes useful to apply the calculation to the entire array, and sometimes only on a row or column basis. Using the `axis` argument we can specify how these functions should behave: "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 157,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.99782852, 0.15992805, 0.31262638],\n",
- " [0.51702607, 0.45658172, 0.66789036],\n",
- " [0.77771351, 0.42574723, 0.14011317]])"
- ]
- },
- "execution_count": 157,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "import numpy as np\n",
- "\n",
- "m = np.random.rand(3,3)\n",
- "m"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 158,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "0.997828517861979"
- ]
- },
- "execution_count": 158,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# global max\n",
- "m.max()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 159,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0.99782852, 0.45658172, 0.66789036])"
- ]
- },
- "execution_count": 159,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# max in each column\n",
- "m.max(axis=0)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 160,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0.99782852, 0.66789036, 0.77771351])"
- ]
- },
- "execution_count": 160,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# max in each row\n",
- "m.max(axis=1)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Many other functions and methods in the `array` and `matrix` classes accept the same (optional) `axis` keyword argument."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Reshaping, resizing and stacking arrays"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The shape of an Numpy array can be modified without copying the underlaying data, which makes it a fast operation even for large arrays."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 162,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[0.97579482 0.78668761 0.61373444]\n",
- " [0.58850244 0.9784108 0.08465447]\n",
- " [0.57262123 0.44795615 0.75564229]\n",
- " [0.36770219 0.34095592 0.16259103]]\n"
- ]
- }
- ],
- "source": [
- "import numpy as np\n",
- "\n",
- "A = np.random.rand(4, 3)\n",
- "print(A)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 163,
- "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": 166,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[0.97579482, 0.78668761, 0.61373444, 0.58850244, 0.9784108 ,\n",
- " 0.08465447, 0.57262123, 0.44795615, 0.75564229, 0.36770219,\n",
- " 0.34095592, 0.16259103]])"
- ]
- },
- "execution_count": 166,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "B = A.reshape((1,n*m))\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 167,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[0.97579482]\n",
- " [0.78668761]\n",
- " [0.61373444]\n",
- " [0.58850244]\n",
- " [0.9784108 ]\n",
- " [0.08465447]\n",
- " [0.57262123]\n",
- " [0.44795615]\n",
- " [0.75564229]\n",
- " [0.36770219]\n",
- " [0.34095592]\n",
- " [0.16259103]]\n"
- ]
- }
- ],
- "source": [
- "B2 = A.reshape((n*m, 1))\n",
- "print(B2)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 168,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[5. , 5. , 5. , 5. , 5. ,\n",
- " 0.08465447, 0.57262123, 0.44795615, 0.75564229, 0.36770219,\n",
- " 0.34095592, 0.16259103]])"
- ]
- },
- "execution_count": 168,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "B[0,0:5] = 5 # modify the array\n",
- "\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 169,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[5. , 5. , 5. ],\n",
- " [5. , 5. , 0.08465447],\n",
- " [0.57262123, 0.44795615, 0.75564229],\n",
- " [0.36770219, 0.34095592, 0.16259103]])"
- ]
- },
- "execution_count": 169,
- "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": 170,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([5. , 5. , 5. , 5. , 5. ,\n",
- " 0.08465447, 0.57262123, 0.44795615, 0.75564229, 0.36770219,\n",
- " 0.34095592, 0.16259103])"
- ]
- },
- "execution_count": 170,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "B = A.flatten()\n",
- "\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 171,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "(12,)\n"
- ]
- }
- ],
- "source": [
- "print(B.shape)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 172,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[0.0643267 0.02070895 0.01127191 0.36318507 0.26309744 0.8332378\n",
- " 0.79477743 0.52745619 0.35675021 0.55907373 0.18993756 0.15919449\n",
- " 0.54789401 0.23186893 0.02898541 0.43545343 0.80684175 0.44014057\n",
- " 0.05129167 0.95111801 0.40743132 0.57197596 0.6692788 0.80824496\n",
- " 0.40301441 0.84369196 0.95294593 0.14876807 0.58005171 0.30849079\n",
- " 0.27846197 0.01062528 0.62870079 0.6416306 0.76945123 0.39443503\n",
- " 0.76619764 0.42833327 0.60720341 0.16246792 0.76067082 0.27134944\n",
- " 0.36268568 0.78501742 0.36935191 0.43410334 0.10594888 0.12941728\n",
- " 0.51760718 0.57260509 0.09756568 0.13216908 0.32918105 0.9338644\n",
- " 0.71681907 0.58218819 0.58798528 0.81665138 0.73604797 0.91730101]\n"
- ]
- }
- ],
- "source": [
- "T = np.random.rand(3, 4, 5)\n",
- "T2 = T.flatten()\n",
- "print(T2)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 176,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([10. , 10. , 10. , 10. , 10. ,\n",
- " 0.08465447, 0.57262123, 0.44795615, 0.75564229, 0.36770219,\n",
- " 0.34095592, 0.16259103])"
- ]
- },
- "execution_count": 176,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "B[0:5] = 10\n",
- "\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 177,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[5. , 5. , 5. ],\n",
- " [5. , 5. , 0.08465447],\n",
- " [0.57262123, 0.44795615, 0.75564229],\n",
- " [0.36770219, 0.34095592, 0.16259103]])"
- ]
- },
- "execution_count": 177,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A # now A has not changed, because B's data is a copy of A's, not refering to the same data"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Adding a new dimension: newaxis"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "With `newaxis`, we can insert new dimensions in an array, for example converting a vector to a column or row matrix:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 178,
- "metadata": {},
- "outputs": [],
- "source": [
- "v = np.array([1,2,3])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 179,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(3,)"
- ]
- },
- "execution_count": 179,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.shape(v)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 180,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[1 2 3]\n"
- ]
- }
- ],
- "source": [
- "print(v)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 182,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "(3, 1)\n"
- ]
- }
- ],
- "source": [
- "v2 = v.reshape(3, 1)\n",
- "print(v2.shape)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 190,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "(3,)\n",
- "(3, 1)\n"
- ]
- }
- ],
- "source": [
- "# make a column matrix of the vector v\n",
- "v2 = v[:, np.newaxis]\n",
- "print(v.shape)\n",
- "print(v2.shape)\n"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 191,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(3, 1)"
- ]
- },
- "execution_count": 191,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# column matrix\n",
- "v[:,newaxis].shape"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 144,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(1, 3)"
- ]
- },
- "execution_count": 144,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# row matrix\n",
- "v[newaxis,:].shape"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Stacking and repeating arrays"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Using function `repeat`, `tile`, `vstack`, `hstack`, and `concatenate` we can create larger vectors and matrices from smaller ones:"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### tile and repeat"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 192,
- "metadata": {},
- "outputs": [],
- "source": [
- "a = np.array([[1, 2], [3, 4]])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 194,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[[1 2]\n",
- " [3 4]]\n"
- ]
- },
- {
- "data": {
- "text/plain": [
- "array([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4])"
- ]
- },
- "execution_count": 194,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "print(a)\n",
- "\n",
- "# repeat each element 3 times\n",
- "np.repeat(a, 3)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 195,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2, 1, 2, 1, 2],\n",
- " [3, 4, 3, 4, 3, 4]])"
- ]
- },
- "execution_count": 195,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# tile the matrix 3 times \n",
- "np.tile(a, 3)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 196,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2, 1, 2, 1, 2],\n",
- " [3, 4, 3, 4, 3, 4]])"
- ]
- },
- "execution_count": 196,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# better method\n",
- "np.tile(a, (1, 3))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 34,
- "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": 34,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.tile(a, (3, 1))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### concatenate"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 197,
- "metadata": {},
- "outputs": [],
- "source": [
- "b = np.array([[5, 6]])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 198,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2],\n",
- " [3, 4],\n",
- " [5, 6]])"
- ]
- },
- "execution_count": 198,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.concatenate((a, b), axis=0)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 200,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2, 5],\n",
- " [3, 4, 6]])"
- ]
- },
- "execution_count": 200,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.concatenate((a, b.T), axis=1)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### hstack and vstack"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 201,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2],\n",
- " [3, 4],\n",
- " [5, 6]])"
- ]
- },
- "execution_count": 201,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.vstack((a,b))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 202,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2, 5],\n",
- " [3, 4, 6]])"
- ]
- },
- "execution_count": 202,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "np.hstack((a,b.T))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Copy and \"deep copy\""
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "To achieve high performance, assignments in Python usually do not copy the underlaying objects. This is important for example when objects are passed between functions, to avoid an excessive amount of memory copying when it is not necessary (technical term: pass by reference). "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 203,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2],\n",
- " [3, 4]])"
- ]
- },
- "execution_count": 203,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A = np.array([[1, 2], [3, 4]])\n",
- "\n",
- "A"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 204,
- "metadata": {},
- "outputs": [],
- "source": [
- "# now B is referring to the same array data as A \n",
- "B = A "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 205,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[10, 2],\n",
- " [ 3, 4]])"
- ]
- },
- "execution_count": 205,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# changing B affects A\n",
- "B[0,0] = 10\n",
- "\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 206,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[10, 2],\n",
- " [ 3, 4]])"
- ]
- },
- "execution_count": 206,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "If we want to avoid this behavior, so that when we get a new completely independent object `B` copied from `A`, then we need to do a so-called \"deep copy\" using the function `copy`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 207,
- "metadata": {},
- "outputs": [],
- "source": [
- "B = np.copy(A)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 208,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[-5, 2],\n",
- " [ 3, 4]])"
- ]
- },
- "execution_count": 208,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# now, if we modify B, A is not affected\n",
- "B[0,0] = -5\n",
- "\n",
- "B"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 209,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[10, 2],\n",
- " [ 3, 4]])"
- ]
- },
- "execution_count": 209,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "A"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Iterating over array elements"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Generally, we want to avoid iterating over the elements of arrays whenever we can (at all costs). The reason is that in a interpreted language like Python (or MATLAB), iterations are really slow compared to vectorized operations. \n",
- "\n",
- "However, sometimes iterations are unavoidable. For such cases, the Python `for` loop is the most convenient way to iterate over an array:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 210,
- "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": 211,
- "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": [
- "When we need to iterate over each element of an array and modify its elements, it is convenient to use the `enumerate` function to obtain both the element and its index in the `for` loop: "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 162,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "('row_idx', 0, 'row', array([1, 2]))\n",
- "('col_idx', 0, 'element', 1)\n",
- "('col_idx', 1, 'element', 2)\n",
- "('row_idx', 1, 'row', array([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",
- " # update the matrix M: square each element\n",
- " M[row_idx, col_idx] = element ** 2"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 163,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[ 1, 4],\n",
- " [ 9, 16]])"
- ]
- },
- "execution_count": 163,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# each element in M is now squared\n",
- "M"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Vectorizing functions"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "As mentioned several times by now, to get good performance we should try to avoid looping over elements in our vectors and matrices, and instead use vectorized algorithms. The first step in converting a scalar algorithm to a vectorized algorithm is to make sure that the functions we write work with vector inputs."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 213,
- "metadata": {},
- "outputs": [],
- "source": [
- "def Theta(x):\n",
- " \"\"\"\n",
- " Scalar implemenation of the Heaviside step function.\n",
- " \"\"\"\n",
- " if x >= 0:\n",
- " return 1\n",
- " else:\n",
- " return 0"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 214,
- "metadata": {},
- "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-214-2cb2062a7e18>\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[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[0m\n\u001b[0m",
- "\u001b[0;32m<ipython-input-213-f72d7f42be84>\u001b[0m in \u001b[0;36mTheta\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mScalar\u001b[0m \u001b[0mimplemenation\u001b[0m \u001b[0mof\u001b[0m \u001b[0mthe\u001b[0m \u001b[0mHeaviside\u001b[0m \u001b[0mstep\u001b[0m \u001b[0mfunction\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[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[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;32melse\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(array([-3,-2,-1,0,1,2,3]))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "OK, that didn't work because we didn't write the `Theta` function so that it can handle a vector input... \n",
- "\n",
- "To get a vectorized version of Theta we can use the Numpy function `vectorize`. In many cases it can automatically vectorize a function:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 215,
- "metadata": {},
- "outputs": [],
- "source": [
- "Theta_vec = np.vectorize(Theta)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 216,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 0, 0, 1, 1, 1, 1])"
- ]
- },
- "execution_count": 216,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "Theta_vec(np.array([-3,-2,-1,0,1,2,3]))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We can also implement the function to accept a vector input from the beginning (requires more effort but might give better performance):"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 217,
- "metadata": {},
- "outputs": [],
- "source": [
- "def Theta(x):\n",
- " \"\"\"\n",
- " Vector-aware implemenation of the Heaviside step function.\n",
- " \"\"\"\n",
- " return 1 * (x >= 0)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 219,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([0, 0, 0, 1, 1, 1, 1])"
- ]
- },
- "execution_count": 219,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "Theta(np.array([-3,-2,-1,0,1,2,3]))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 221,
- "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": 221,
- "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": 222,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "(0, 1)"
- ]
- },
- "execution_count": 222,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# still works for scalars as well\n",
- "Theta(-1.2), Theta(2.6)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Using arrays in conditions"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "When using arrays in conditions,for example `if` statements and other boolean expressions, one needs to use `any` or `all`, which requires that any or all elements in the array evalutes to `True`:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 223,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1, 2],\n",
- " [3, 4]])"
- ]
- },
- "execution_count": 223,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M = np.array([[1, 2], [3, 4]])\n",
- "M"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 224,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 224,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "(M > 2).any()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 225,
- "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": 226,
- "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": [
- "## Type casting"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Since Numpy arrays are *statically typed*, the type of an array does not change once created. But we can explicitly cast an array of some type to another using the `astype` functions (see also the similar `asarray` function). This always create a new array of new type:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 227,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "dtype('int64')"
- ]
- },
- "execution_count": 227,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M.dtype"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 228,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[1., 2.],\n",
- " [3., 4.]])"
- ]
- },
- "execution_count": 228,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M2 = M.astype(float)\n",
- "\n",
- "M2"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 229,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "dtype('float64')"
- ]
- },
- "execution_count": 229,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M2.dtype"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 230,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array([[ True, True],\n",
- " [ True, True]])"
- ]
- },
- "execution_count": 230,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "M3 = M.astype(bool)\n",
- "\n",
- "M3"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Further reading"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "* http://numpy.scipy.org\n",
- "* http://scipy.org/Tentative_NumPy_Tutorial\n",
- "* http://scipy.org/NumPy_for_Matlab_Users - A Numpy guide for MATLAB users."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Versions"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 178,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "application/json": {
- "Software versions": [
- {
- "module": "Python",
- "version": "2.7.10 64bit [GCC 4.2.1 (Apple Inc. build 5577)]"
- },
- {
- "module": "IPython",
- "version": "3.2.1"
- },
- {
- "module": "OS",
- "version": "Darwin 14.1.0 x86_64 i386 64bit"
- },
- {
- "module": "numpy",
- "version": "1.9.2"
- }
- ]
- },
- "text/html": [
- "<table><tr><th>Software</th><th>Version</th></tr><tr><td>Python</td><td>2.7.10 64bit [GCC 4.2.1 (Apple Inc. build 5577)]</td></tr><tr><td>IPython</td><td>3.2.1</td></tr><tr><td>OS</td><td>Darwin 14.1.0 x86_64 i386 64bit</td></tr><tr><td>numpy</td><td>1.9.2</td></tr><tr><td colspan='2'>Sat Aug 15 11:02:09 2015 JST</td></tr></table>"
- ],
- "text/latex": [
- "\\begin{tabular}{|l|l|}\\hline\n",
- "{\\bf Software} & {\\bf Version} \\\\ \\hline\\hline\n",
- "Python & 2.7.10 64bit [GCC 4.2.1 (Apple Inc. build 5577)] \\\\ \\hline\n",
- "IPython & 3.2.1 \\\\ \\hline\n",
- "OS & Darwin 14.1.0 x86\\_64 i386 64bit \\\\ \\hline\n",
- "numpy & 1.9.2 \\\\ \\hline\n",
- "\\hline \\multicolumn{2}{|l|}{Sat Aug 15 11:02:09 2015 JST} \\\\ \\hline\n",
- "\\end{tabular}\n"
- ],
- "text/plain": [
- "Software versions\n",
- "Python 2.7.10 64bit [GCC 4.2.1 (Apple Inc. build 5577)]\n",
- "IPython 3.2.1\n",
- "OS Darwin 14.1.0 x86_64 i386 64bit\n",
- "numpy 1.9.2\n",
- "Sat Aug 15 11:02:09 2015 JST"
- ]
- },
- "execution_count": 178,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "%reload_ext version_information\n",
- "\n",
- "%version_information numpy"
- ]
- }
- ],
- "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.2"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 1
- }
|