IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

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

 

Predchádzajúci článok
Zobrazenie grafov v MATLAB
Všetky články v sekcii
Matlab
Článok pre vás napísal tesař.tech
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje dýchání přibližně celý život
Aktivity