Práca s maticami a vektormi II
Spôsob práce s vektormi a maticami v MATLAB je natoľko zásadný tému, že je rozdelené do troch lekcií. Informácie v jednotlivých častiach sa prekrývajú a zakaždým sú podané trochu iným spôsobom. Umožní tak nahliadnuť na problematiku z rôznych uhlov.
V prvej časti sme si vysvetlili indexovanie a prácu s bunkami. Táto časť sa dopodrobna zaoberá tvorbou vektorov, prístupom k jednotlivým prvkom a ich filtrovaním. Podobné témy sú vysvetlené v tretej časti, len s pomocou matíc a na praktické ukážke úpravy fotografie.
Matice
Druhou nevyhnutnou záležitosťou k ovládnutiu MATLABu je práca s
maticami. Jeden príklad za všetky: Máme definované dvojrozmerné pole
(maticu). Úlohou je ku každému prvku poľa pripočítať hodnotu
20.
Ak viete programovať v inom jazyku, možno by vás napadlo použiť cykly. Napr. v C # by sme to urobili takto:
var pole = new int[,]{ {5, 6},{9, 8},{6, 1} }; for(int k=0;k < pole.GetLength(0);k++) for(int l=0;l < pole.GetLength(1);l++) pole[k,l]+=20;
Ekvivalentom v MATLABe ale je:
pole = [5 6; 9 8; 6 1]; pole = pole + 20;
Žiadny dvojitý cyklus, iba jednoduché pripočítanie. MATLAB tu pochopil,
že ku každému prvku z matice chceme pripísať 20. Ak by sme to
urobili takto: pole = pole + [10 20], teda snažili sa priradiť k
matici vektor, zahlási nám prostredie chybu, pretože už nevie, ako si s tým
poradiť (čo by sa tiež dalo čakať).
Typovanie
MATLAB je slabo typizovanom jazyk (rovnako ako napr. JavaScript alebo Python), nemusíme
mu definovať, že číslo je int alebo double. Táto
vlastnosť je skvelá pre rýchle písanie skriptov. Pri tvorbe komplexnejšieho
programu trochu prekáža, respektíve nepohlídá za nás niektoré hlúpe
chyby. Môžeme totiž napísať niečo ako:
promenna = 21; promenna = "teď je tu string a nikdo si nestěžuje"
Nikto si síce nesťažuje, ale až sa o pár desiatok riadkov kódu ďalej budeme snažiť pripočítať k premennej nejakej číslo, bude to už problém. A pre zistenie jeho príčiny sa budeme musieť prehrýzť o tie desiatky riadkov späť (a nevieme ako moc späť).
Tvorba vektorov
Po teoretickej odbočke späť k maticiam. Z definície premennej
pole = [5 6; 9 8; 6 1]; je zreteľné, ako sa definuje matice. Je
to teda v hranatých zátvorkách. Oddeľovačom čísel je medzera (alebo
čiarka), oddeľovačom riadkov je bodkočiarka. Finálny bodkočiarka je tu
preto, aby sa zamedzilo vypísanie do konzoly.
Ak chceme vytvoriť vektor obsahujúci čísla napríklad o 1 do
100, možno to pomocou dvojbodky:
vektor = 1:100;
Skúsme si zahrnúť každé druhé číslo od 1 do
100:
vektor = 1:2:100;
Vložením ďalšieho čísla medzi dvojbodky sa teda definuje krok. Funguje to aj s desatinnými číslami:
vektor = 1:0.1:100;
alebo bez tej nuly:
vektor = 1:.1:100;
Funguje to tiež pospiatky, len je nutné krokovať zápornou hodnotou:
vektor = 100:-.5:1;
Prístup k prvkom vektora
Ak chceme zistiť, čo sa vo vektore skrýva, teda pristúpiť k prvkom
poľa, využijeme index a okrúhle zátvorky. Tu priraďujeme do premennej
v dvadsiatej číslo vektora:
v = vektor(20)
Ekvivalentom v C# by bolo:
int v = vektor[19];
Áno, MATLAB, na rozdiel od väčšiny používaných jazykov,
indexuje od 1. Ak chceme vytiahnuť viac prvkov z vektora, stačí
ho naindexovat vektorom. 20., 21., A 22. prvok vektora získame:
prvky20_22 = vektor([20 21 22]);
Tu je čiastočné vysvetlenie toho, prečo sa k prístupom prvkov nevyužívajú hranaté zátvorky - tie sa používajú k definícii vektorov a matíc.
Ak by prvkov bolo viac, nebudeme ich v indexácie vektora vypisovať všetky, ale zas využijeme dvojbodky:
prvky20_50 = vektor(20:50)
Tu už nepotrebujeme hranatú zátvorku, vektor sa prezradil práve onou dvojbodkou. Ďalším spôsobom, ako vytiahnuť prvky vektora, je pomocou binárneho vektora:
vektor = [1 5 6 9 8 3]; pouze_neco_z_vektoru = vektor([0 0 1 1 0 0])
Týmto zápisom hovoríme: Prvý prvok neber, druhý tiež nie, tretí áno,
štvrtý áno, piaty nie, šiesty tiež nie ... Výsledkom je
[6 9]. Binárne vektor musia mať rovnakú dĺžku ako vektor
pôvodný (inak by to nedávalo zmysel). K čomu je to dobré?
Podmienky pri výbere prvkov vektora
Z vektora chceme iba čísla väčšie ako 6:
vetsi_nez_6 = vektor(vektor > 6)
Výsledok je [9 8].
Tento na prvý pohľad trochu krkolomný zápis obsahuje dva kroky. Ten
vnútorný je tvorba binárneho vektora. Pýtame Ak sa, či je vektor väčšia
ako skalár (vektor > 6), MATLAB to pochopí a proiteruje
podmienkou celý vektor. Tam, kde je splnená, zaznamená jedničku, tam, kde
nie, nulu. No a tento binárny vektor je následne využitý na indexovanie
samotného vektora.
C# ekvivalentom bolo toto:
var vetsi_nez_6 = new List<int>(); for(int k = 0; k < pole.GetLength(0); k++) if(pole[k] > 6) vetsi_nez_6.Add(pole[k]);
Alebo zjednodušene prevodom na List a za použitia LINQ:
var pole = new int[] { 1, 5, 6, 9, 8, 3 }; var vetsi_nez_6 = (new List<int>(pole)).Where(x => x > 6);
Niekoľkých podmienok pri výbere prvkov
Podmienky na získavanie prvkov z vektora sa pochopiteľne dajú kombinovať.
Ak chceme teda z vektora získať iba prvky väčšie ako 6, ktoré
sú navyše párne, použijeme nasledujúce zápis:
vetsi_nez_6_sude = vektor((vektor > 6) & (~mod(vektor, 2)))
Prvá časť výrazu už poznáme, za ňou nasleduje logické AND (teda
jednotka vznikne iba v prípade, že na oboch stranách budú jednotky). Druhá
časť je zodpovedná za určenie, či je číslo vo vektora párne. Deje sa tak
s pomocou funkcie mod() (MATLAB nemá operátor modulo, ako
napríklad C# má %. Percento je v MATLABe používané pre
komentára). Modulo nejakého čísla je zvyšok po delení a môže nadobúdať
akékoľvek hodnoty od 0 do čísla - 1. V prípade, že "moduluje"
s pomocou dvojky, sú možnosti buď 0 alebo 1. Tu sa
prejavuje výhoda slabé typovosti. Výstupom funkcie mod() je v
tomto prípade iba binárne vektor. Vlnovka ~ je operátorom
negácie (v C# výkričník !). Využívame ju preto, aby sa z
jedničiek, ktoré vzniknú po "modulovania" dvojkou u nepárnych čísel, stali
nuly, a tým pádom výsledné číslo nebolo vybrané.
Rovnaké pravidlá ako pre indexovanie vektorov platí aj pre indexovanie
matíc. Ak chceme získať z matice M iba prvky, ktoré sú
deliteľné 3, urobíme to nasledovne:
M = [1 3 6 8; 5 6 9 3; 2 1 2 9]; delitelne_3 = M(mod(M, 3)==0) % 1. řešení delitelne_3_alt = M(~mod(M, 3)) % 2. řešení
Tu sme vytvorili 2 riešenie, prvý porovnáva výsledok modula s nulou,
ktorá vznikne v prípade deliteľnosti tromi. Alternatívne zápis využíva
opäť operátora negácie. Ten zo všetkých čísel, ktoré nie sú
0, urobí práve 0. Výsledky sú rovnaké.
Zápis je úplne totožný tomu, ako by sme operáciu vykonávali s vektormi. Výstupom je tiež vektor, tiež z toho dôvodu, že vopred nevieme, aký výsledok bude a či by sa vôbec do matice poskladal (ako vytvoríte dvojrozmernú maticu o troch prvkoch ...).
MATLAB iteruje maticou podobne ako vektorom. Nemusíme k tomu používať
cykly a tento funkcionálne a maticový prístup je odporúčaný spôsob
práce. Tiež je to spôsob, ktorý mnohým ľuďom robí problém riadne
uchopiť, zvlášť keď za všetkým vidia cyklus (a on tam v skutočnosti je).
Avšak komu sa to podarí, má nad Matlab napoly vyhraté. A nielen to.
Funkcionálne prístup sa premieta v mnohých iných jazykoch: R, Haskell,
Scala, F #, a mnohé ďalšie. Konieckoncov aj C #, predovšetkým od svojej 7.
verzie, pridáva spôsoby, ako riešiť problémy funkcionálne (napríklad
vyššie spomínaný kód pre filtrovanie čísiel väčších než
6).
Nahradenie prvkov spĺňajúcich podmienku
Už vieme, ako z vektora (alebo matica) získame prvky spĺňajúce podmienku. Teraz tieto prvky nahradíme iným číslom:
vektor = [1 5 6 9 8 3]; vektor(vektor > 6) = 0;
Týmto kusom kódu sme čísla presahujúcej 6 nahradili nulou.
Výber prvkov sa nám presunul na ľavú stranu rovná sa.
Editácia prvkov spĺňajúcich podmienku
Predchádzajúci príklad čísla úplne nahradil, teraz prvky len trochu upravíme:
vektor(vektor > 6) = vektor(vektor > 6) + 3;
Je to zas kombinácia už známych postupov. Podmienka je na oboch stranách. Tento zápis by som osobne najradšej zjednodušil nasledovne:
%Tento kód není validní vektor(vektor > 6) +=3;
tak, ako to poznáme z mnohých iných jazykov. Avšak v MATLABe to nedá. Musíme sa teda uspokojiť s podmienkou na oboch stranách. Odporuje to princípu DRY (do not repeat yourself). Môžeme s tým vykonať len toto:
podminka = vektor > 6; vektor(podminka) = vektor(podminka) + 3;
Kód nevyzerá moc elegantnejšie, avšak ak je podmienka náročnejšie
(dlhšia), oplatí sa ju takto odstrčiť do premennej. podminka
bude obsahovať len 0 a 1.
Cvičenie
Na záver nasleduje pár príkladov, ktorých riešenie nájdete na konci priloženého súboru. Súbor obsahuje aj všetok kód z tohto článku.
Vytvorte vektor f s celými číslami od 101 do
202 az neho získajte:
- prvý a posledný prvok.
- prvých 12 prvkov.
- všetky prvky deliteľné
9. - každý 4. prvok.
- vektor, ktorého hodnoty majú polovičnú hodnotu.
- vektor, ktorého hodnoty sú o 7 väčšie.
- posledných 13 prvkov.
- posledných 10 prvkov deliteľných 2.
- siedmy až devätnásty prvok.
- prvky deliteľné piatimi, ktorých posledný číslovka nie je
0.
Nabudúce, v lekcii , sa podrobnejšie pozrieme na matice a konečne
si povieme, k čomu je to všetko dobré 
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 14x (1.3 kB)
Aplikácia je vrátane zdrojových kódov

