Logika pracuje s tvrzeními, která jsou buď pravdivá (1) nebo nepravdivá (0). Spojuje je pomocí operátorů:
| Operátor | Význam | Je pravda, když… |
|---|---|---|
| AND (∧, „a zároveň“) | konjunkce | obě části jsou pravda |
| OR (∨, „nebo“) | disjunkce | aspoň jedna část je pravda |
| NOT (¬, „není“) | negace | obrátí pravdu na nepravdu a naopak |
| → (implikace, „když…, tak…“) | implikace | nepravda jen když je vlevo pravda a vpravo nepravda |
AND je „přísné“ (musí platit všechno), OR je „benevolentní“ (stačí jedno). Implikace A → B je nepravdivá jen v jednom případě: A platí, ale B ne.
Správný algoritmus má tyto vlastnosti:
if … else … (rozhodnutí).for, while (opakování).Zapsat se dá slovně, vývojovým diagramem, pseudokódem nebo přímo v programovacím jazyce.
Některé problémy nelze vyřešit žádným algoritmem. Nejznámější je problém zastavení (halting problem): neexistuje program, který by pro libovolný jiný program dopředu spolehlivě řekl, zda se zastaví, nebo poběží navždy.
Časová složitost říká, jak rychle roste počet kroků algoritmu, když roste velikost vstupu n. Zapisuje se jako O(...) – „nejtěsnější horní odhad v nejhorším případě“.
| Složitost | Název | Typický příklad |
|---|---|---|
| O(1) | konstantní | přístup do pole podle indexu |
| O(log n) | logaritmická | binární vyhledávání, hledání v BST |
| O(n) | lineární | projít celé pole jedním cyklem |
| O(n log n) | kvazilineární | rychlé řadicí algoritmy (merge sort) |
| O(n²) | kvadratická | dva vnořené cykly přes pole |
Spočítej vnořené cykly přes data: jeden cyklus přes n = O(n), dva do sebe vnořené = O(n²). Pozor ale na return uvnitř – ten může cyklus předčasně ukončit a složitost srazit dolů (viz řešený příklad níže).
Binární strom = každý uzel má max. dva potomky (levý, pravý). U vyhledávacího (BST) navíc platí pravidlo:
Díky tomu při hledání/vkládání jdeme od kořene a v každém uzlu se rozhodneme vlevo/vpravo – nikdy nemusíme procházet celý strom.
Výchozí strom:
9
/ \
4 16
/ \ \
1 8 18
Provedeme insert(root, 17) a insert(root, 20).
Vkládáme 17: 17 > 9 → doprava k 16. 17 > 16 → doprava k 18. 17 < 18 → doleva. → 17 je levý potomek 18.
Vkládáme 20: 20 > 9 → 16. 20 > 16 → 18. 20 > 18 → doprava. → 20 je pravý potomek 18.
9
/ \
4 16
/ \ \
1 8 18
/ \
17 20
Nejdelší cesta: 9 → 16 → 18 → 17 = 3 hrany.
def func(arr, target):
s = 0
for i in range(len(arr)): # cyklus přes n prvků
if arr[i] == target:
for j in range(i + 1): # vnitřní cyklus...
s = s + arr[j]
return s # ...ale hned poté RETURN!
return s
Na první pohled to vypadá na O(n²) (dva cykly). Ale: vnitřní cyklus se spustí jen jednou, protože hned po něm je return – funkce skončí. V nejhorším případě (target je poslední prvek) projdeme vnější cyklus n-krát a vnitřní jednou n-krát. To je n + n = O(n).
Dva operátory navíc, které se v testech občas objeví:
| Operátor | Zápis | Pravda, když… |
|---|---|---|
| Bikonditional (↔) | A ↔ B | A i B mají stejnou pravdivostní hodnotu (obě 1 nebo obě 0) |
| XOR (⊕) | A ⊕ B | právě jedna z nich je pravda (ne obě) |
A ∨ ¬A (buď prší nebo neprší – vždy pravda).A ∧ ¬A (prší a zároveň neprší).A → B je nepravdivá jen když A je pravda a B je lež. Ve všech ostatních kombinacích je pravdivá. Takže „Pokud je prase létavé, pak je Měsíc ze sýra" = pravda (A je lež).
| Symbol | Tvar | Použití |
|---|---|---|
| Terminátor | oválný / zaoblený obdélník | Start / Konec algoritmu |
| Proces | obdélník | výpočet, přiřazení hodnoty |
| Rozhodnutí | kosočtverec (diamant) | podmínka Ano/Ne (větvení) |
| Vstup / Výstup | rovnoběžník | načtení vstupu nebo výpis výsledku |
n! = n × (n−1)!, kde 0! = 1.
Rekurzivní průchod celým stromem / všemi prvky → O(n). Dělení problému na půlky (binární vyhledávání) → O(log n). Merge sort (dělení na půlky + slévání) → O(n log n).
Sám o sobě je srozumitelný – vidíš, podle čeho rozhoduje.
Funguje dobře, ale nevidíš dovnitř – proč rozhodl, je těžké říct.
XAI (Explainable AI) = nástroje a metody, které dělají i black-box modely srozumitelnými.
LIME i SHAP řeší stejný cíl – „proč model řekl zrovna tohle?” – ale u black-box modelů. White-box modely (strom, pravidla) jsou vysvětlitelné rovnou.
Popisuje chování modelu jako celku. „Co model obecně považuje za důležité?”
Vysvětlí jedno konkrétní rozhodnutí. „Proč takhle zařadil tento bod?”
SHAP vychází z teorie kooperativních her. Každé proměnné přidělí „spravedlivý podíl” na výsledku – jako když hráčům v týmu přidělíme podíl na výhře.
Součet všech SHAP hodnot + průměrná předpověď = celková předpověď pro daný vzorek.
LIME: rychlejší, lokální lineární model kolem bodu, aproximativní. SHAP: přesnější, konzistentní, ale pomalejší. Oba jsou model-agnostické – fungují s jakýmkoli black-box modelem.
„Pytel slov“ – text převedeme na vektor, který říká, kolikrát se každé slovo vyskytlo. Pořadí slov se ignoruje.
Příklad slovník: [clovek, kouse, pes]
(1, 1, 1)(1, 1, 1)Protože BoW počítá jen výskyty a ne pořadí, věty „pes kouše člověka“ a „člověk kouše psa“ mají stejný vektor, i když mají jiný význam. To je hlavní omezení BoW.
Vylepšení BoW. Slovu dá váhu podle dvou věcí:
Výsledek: zvýrazní slova typická pro daný dokument a potlačí běžná slova.
Moderní přístup. Slova/věty převede na vektory tak, aby podobná slova měla podobné vektory (např. „pes“ a „kočka“ blízko sebe). Na rozdíl od BoW zachycuje význam, ne jen výskyt.
Měří, jak podobné jsou dva vektory – podle úhlu mezi nimi (ne podle délky). Hodnoty od −1 do 1; 1 = stejný směr, 0 = kolmé (nesouvisí).
Vzorec: cos(θ) = (d1 · d2) / (|d1| · |d2|)
d1 = (1, 1, 0), d2 = (1, 0, 1)
Skalární součin: 1·1 + 1·0 + 0·1 = 1
Délky: |d1| = √(1+1+0) = √2, |d2| = √(1+0+1) = √2
Dosadíme: cos(θ) = 1 / (√2 · √2) = 1 / 2 = 0,5
Před převodem textu na vektor se text obvykle „vyčistí". Typický postup:
| Krok | Co dělá | Příklad |
|---|---|---|
| Tokenizace | Rozdělí text na tokeny (slova/znaky) | "Pes běží" → ["Pes", "běží"] |
| Lowercasing | Převede na malá písmena | "Pes" → "pes" |
| Stop slova | Odstraní nejčastější bezvýznamná slova | "a", "je", "the", "in" |
| Stemming | Ořízne slovo na kmen (mechanicky, hrubě) | "running" → "run", "dogs" → "dog" |
| Lemmatizace | Převede na základní slovníkový tvar | "lepší" → "dobrý" (gramaticky správně) |
Stemming: rychlejší, může dát neexistující kmen. Lemmatizace: pomalejší, vrátí skutečné slovníkové slovo. Pro přesné NLP použij lemmatizaci.
TF(t,d) = počet výskytů t v dokumentu d / celkový počet slov v d
IDF(t) = log(N / df(t)) kde N = počet dokumentů, df(t) = počet dokumentů s t.
TF-IDF = TF × IDF → vzácná, ale v dokumentu častá slova dostanou vysokou váhu.
Program skládáme z objektů, které mají data (vlastnosti) i chování (metody). Čtyři pilíře:
| Pojem | Co to je | Příklad |
|---|---|---|
| Třída | šablona / vzor | class User |
| Objekt | konkrétní instance třídy | uživatel Jan |
| Dědičnost | třída přebírá vlastnosti jiné třídy | Reader dědí z User |
| Polymorfismus | stejná metoda se chová různě v různých třídách | tisk() jinak u faktury, jinak u dopisu |
| Zapouzdření | skrytí vnitřních dat (private), přístup jen přes metody | nesaháš přímo na zůstatek účtu |
Když je User → Reader a User → Librarian, znamená to, že Reader a Librarian dědí z User (potomci přebírají vlastnosti rodiče). Ne naopak! Vztah „je druhem“: Reader je druhem User.
Program = posloupnost procedur/funkcí, které pracují s daty. Data a funkce jsou oddělené.
Příklady: C, klasický Pascal.
Data a chování jsou pohromadě v objektech. Lépe se škáluje a udržuje u velkých aplikací.
Příklady: Java, Python, C#.
if/else) – rozhodování.for, while) – opakování. Když potřebuješ projít všechny prvky seznamu, použiješ cyklus.try/except), aby program nespadl.interface Printable { void print(); }. Umožňuje polymorfismus bez přímé dědičnosti.
Může mít i implementované metody. Třída dědí z max. jedné abstraktní třídy.
Jen deklarace metod (bez implementace). Třída může implementovat více rozhraní najednou.
| Struktura | Princip | Složitost | Příklad použití |
|---|---|---|---|
| Zásobník (Stack) | LIFO – poslední dovnitř, první ven. push / pop | O(1) | volání funkcí, undo/redo |
| Fronta (Queue) | FIFO – první dovnitř, první ven. enqueue / dequeue | O(1) | tiskový front, BFS průchod grafem |
| Spojový seznam | Uzly propojené ukazateli. Přidání O(1), hledání O(n) | O(n) search | dynamicky rostoucí kolekce |
| Hash mapa (dict) | Klíč → hash → index. Průměrně O(1) přístup | O(1) avg. | slovníky, cache, indexy |
Pole: O(1) přístup podle indexu, ale pomalé vkládání uprostřed O(n). Spojový seznam: O(1) vkládání na začátek, ale O(n) přístup k prvku.
Fáze jdou za sebou: analýza → návrh → implementace → testování → nasazení. Tuhé, těžko se vrací zpět.
Vývoj po krátkých iteracích (sprintech), průběžné dodávky, rychlá reakce na změny.
Git ukládá historii změn v kódu a umožňuje práci ve více lidech. Klíčové pojmy:
| Pojem | Co dělá |
|---|---|
| commit | uloží snímek změn s popisem |
| branch (větev) | samostatná linie vývoje (např. feature-export) |
| merge | sloučí změny z jedné větve do druhé |
| checkout | přepne se na jinou větev |
| pull / push | stáhne / nahraje změny ze/na server |
Když chceš dostat hotovou funkci z větve feature-export do hlavní větve main, použiješ merge. Ne mazání větve, ne ruční přepisování souborů.
Automatizovaná sekvence kroků: build → test → dockerize → deploy. Nástroje: GitHub Actions, GitLab CI, Jenkins.
| HTTP metoda | Operace (CRUD) | Příklad |
|---|---|---|
| GET | Read – čtení dat | GET /users/1 → vrátí uživatele |
| POST | Create – vytvoření | POST /users → přidá uživatele |
| PUT / PATCH | Update – aktualizace | PUT /users/1 → upraví |
| DELETE | Delete – smazání | DELETE /users/1 → smaže |
HTTP stavové kódy: 200 OK · 201 Created · 400 Bad Request · 401 Unauthorized · 404 Not Found · 500 Internal Server Error.
Zkratka SOLID – pět principů dobrého OOP návrhu:
Data v tabulkách (řádky a sloupce), pevné schéma, propojení přes klíče. Dotazy v jazyce SQL.
Např. MySQL, MariaDB, Oracle, PostgreSQL.
Flexibilní struktura – dokumenty, klíč–hodnota, grafy. Dobré pro velká a nestrukturovaná data.
Např. MongoDB, Redis.
Strukturovaná data = tabulky (jasné sloupce). Nestrukturovaná = text, obrázky, videa.
Při návrhu kreslíme entity (tabulky) a vztahy mezi nimi. Kardinalita říká, kolik kusů se k sobě váže:
Vztah M:N nejde uložit přímo přidáním sloupce. Řeší se vazební (spojovací) tabulkou, která obsahuje cizí klíče na obě tabulky. (Např. tabulka loans_books propojuje výpůjčky a knihy.)
SELECT sloupce -- co chci vrátit
FROM tabulka -- odkud
JOIN tabulka2 ON ... -- propojení tabulek
WHERE podmínka -- filtr řádků
GROUP BY sloupec -- seskupení
ORDER BY sloupec; -- řazení
Chceme jména a id čtenářů + počet jejich výpůjček (i ty s nulou).
SELECT readers.id, readers.name, COUNT(loans.id)
FROM readers
LEFT JOIN loans ON readers.id = loans.reader
GROUP BY readers.name, readers.id;
Proč právě tento:
loans.reader = readers.id.COUNT počítal výpůjčky pro každého zvlášť.Normalizace = návrh tabulek tak, aby se minimalizovaly redundance a anomálie při vkládání/mazání dat.
| Normální forma | Požadavek |
|---|---|
| 1NF | Každá buňka obsahuje jen jednu atomickou hodnotu (žádné seznamy v buňce). |
| 2NF | 1NF + neklíčový atribut závisí na celém primárním klíči (ne jen části složeného klíče). |
| 3NF | 2NF + žádný neklíčový atribut nezávisí tranzitivně na klíči (A→B→C → B musí do vlastní tabulky). |
PK (Primary Key) = jednoznačně identifikuje řádek; unikátní, NOT NULL. FK (Foreign Key) = odkazuje na PK jiné tabulky → vytváří vztah a zajišťuje referenční integritu.
Transakce = skupina operací, která se buď celá provede, nebo vůbec. ACID zaručuje spolehlivost:
-- HAVING = filtr PO GROUP BY (pro agregáty)
SELECT reader_id, COUNT(*) AS pocet
FROM loans
GROUP BY reader_id
HAVING COUNT(*) > 3; -- jen čtenáři s více než 3 výpůjčkami
-- Poddotaz (subquery)
SELECT name FROM readers
WHERE id IN (SELECT reader_id FROM loans WHERE fine > 0);
-- Agregační funkce
SELECT AVG(price), SUM(price), MAX(price), MIN(price) FROM books;
WHERE filtruje řádky před GROUP BY. HAVING filtruje skupiny po GROUP BY. Na agregáty (COUNT, AVG…) musíš vždy HAVING.
Lehký, čitelný, standard pro REST API.
{"name": "Jan",
"age": 25,
"books": [1, 3]}
Starší, rozsáhlejší, enterprise systémy, konfigurace.
<user>
<name>Jan</name>
<age>25</age>
</user>
CSV = tabulkový formát oddělený čárkami (import/export dat). Parquet = sloupcový binární formát pro big data (efektivní komprese).
NoSQL typy podrobněji: Dokumentové (MongoDB – JSON dokumenty) · Klíč–hodnota (Redis – cache) · Sloupcové (Cassandra) · Grafové (Neo4j – vztahy mezi entitami).
Perceptron je nejjednodušší model – hledá přímku (nadrovinu), která oddělí dvě třídy. Funguje jen tehdy, když lze třídy oddělit jednou přímkou (jsou lineárně separabilní).
Když body jedné třídy leží „do kříže“ (na protilehlých úhlopříčkách), žádná přímka je neoddělí. To je situace XOR – perceptron si s ní neporadí.
třída +1: (0,0) a (2,2) | třída −1: (0,2) a (2,0)
Body +1 leží na jedné úhlopříčce, body −1 na druhé – přesně vzor XOR. Žádná přímka je neoddělí.
„Řekni mi, kdo jsou tvoji sousedé, a já ti řeknu, kdo jsi.“ Nový bod zařadíme podle k nejbližších trénovacích bodů – hlasováním většiny.
Trénink: třída A na bodě 0; třída B na bodech 2, 3, 4. Klasifikujeme bod 0,5 (L1 vzdálenost).
Vzdálenosti: k A(0) = 0,5; k B(2) = 1,5; k B(3) = 2,5; k B(4) = 3,5.
k = 1: nejbližší je A (0,5) → A.
k = 3: tři nejbližší jsou A(0,5), B(1,5), B(2,5) → třídy A, B, B → většina B.
Rozhodovací strom rozhoduje sérií otázek ano/ne („docházka ≤ 71 %?“). V každém uzlu si vybere otázku, která data nejlépe rozdělí na třídy.
Strom má v kořeni otázku docházka ≤ 71 (entropie 1.0, value [6,6] = půl na půl). To znamená, že docházka je nejdůležitější dělicí znak – proto je v kořeni.
Pozor na nesprávné možnosti: docházku nelze vždy vykompenzovat studiem (větev s nízkou docházkou končí „neuspěl“), a vysoká docházka negarantuje úspěch (záleží i na hodinách studia).
Navzdory názvu je to klasifikační metoda. Vrací pravděpodobnost (0–1) pomocí sigmoid (logistické) funkce:
P(y=1|X) = 1 / (1 + e^(-z)) kde z = b0 + b1·X1 + b2·X2 + ...
Model příliš jednoduchý – neumí ani trénovací data. Nízká přesnost na tréninku i testu.
Příklad: lineární model na nelineárních datech.
Model si data „zapamatoval". Vysoká přesnost na tréninku, nízká na nových datech.
Příklad: příliš hluboký rozhodovací strom.
Trénuje více modelů paralelně na náhodných podmnožinách dat. Výsledek = průměr / hlasování. Snižuje variance (overfitting).
Příklad: Random Forest
Modely se trénují sekvenčně – každý opravuje chyby předchozího. Snižuje bias (underfitting).
Příklady: AdaBoost, Gradient Boosting, XGBoost
Bagging = paralelní, nezávislé modely → stabilita. Boosting = sekvenční, každý se učí z chyb → přesnější, ale náchylnější na overfitting.
Předem zvolíme k shluků. Algoritmus opakovaně: přiřadí body k nejbližšímu středu → přepočítá středy. Dokud se to neustálí.
Začne s každým bodem jako vlastním shlukem a postupně spojuje nejbližší shluky dohromady. Vytvoří strom (dendrogram).
Hledají, co se kupuje společně: „kdo koupí chleba, koupí i máslo“. Pravidlo {chleba} → {máslo} se hodnotí dvěma mírami:
Support dělíme všemi košíky. Confidence dělíme jen těmi, co mají levou stranu pravidla. (Bonus: lift > 1 znamená, že spolu věci souvisí víc, než kdyby byly náhodné.)
10 košíků. Chleba v 6 košících. Chleba i máslo zároveň ve 3 košících. Pravidlo {chleba} → {máslo}:
Support = 3 / 10 = 30 % (chleba i máslo ze všech košíků).
Confidence = 3 / 6 = 50 % (z košíků s chlebem mělo i máslo).
Jak zvolit správný počet shluků k?
Jak měřit vzdálenost mezi shluky (linkage metody)?
| Linkage | Vzdálenost = … | Vlastnost |
|---|---|---|
| Single (min) | min vzdálenost nejbližších bodů | může vznikat „řetěz" (chaining) |
| Complete (max) | max vzdálenost nejvzdálenějších bodů | kompaktnější, kulovité shluky |
| Average | průměr všech párových vzdáleností | kompromis |
| Ward | minimalizuje nárůst WCSS | nejčastěji nejlepší pro praxi |
Příklad: confidence = 50 %, P(máslo) = 40 % → lift = 0,5 / 0,4 = 1,25 → mírná pozitivní asociace.
Tabulka, která porovnává předpověď modelu se skutečností u binární klasifikace:
| Předpověď: pozitivní | Předpověď: negativní | |
|---|---|---|
| Skutečně pozitivní | TP (správně pozitivní) | FN (falešně negativní) |
| Skutečně negativní | FP (falešně pozitivní) | TN (správně negativní) |
Druhé slovo = co řekl model, první slovo = jestli se spletl. False Negative = model řekl „negativní“, ale ve skutečnosti to bylo pozitivní (přehlédl to). False Positive = falešný poplach.
| Metrika | Vzorec | Co měří |
|---|---|---|
| Accuracy | (TP+TN) / vše | kolik z celku správně |
| Precision | TP / (TP+FP) | z označených jako pozitivní, kolik jich opravdu je |
| Recall | TP / (TP+FN) | ze skutečně pozitivních, kolik jich model zachytil |
| F1 | harm. průměr P a R | vyváženost precision a recall |
ROC křivka ukazuje poměr zachycených vs. falešných poplachů při různých prazích. AUC (plocha pod křivkou) shrne kvalitu jedním číslem: 1 = perfektní, 0,5 = náhoda.
Data rozdělíme na K dílů. Vždy 1 díl je test, zbytek trénink – a takhle K-krát, výsledky zprůměrujeme.
Extrém K-fold, kde K = počet pozorování. Pokaždé testujeme na jediném bodu, zbytek je trénink.
LOOCV je speciální případ K-fold validace, kde K = počet všech pozorování.
Problém: 990 negativních a 10 pozitivních případů. Model, který vždy odpoví „negativní", má accuracy 99 %, ale je k ničemu.
U nerovnováhy sleduj raději precision, recall a F1. AUC-ROC je také robustní vůči nevyvážení.
Techniky:
class_weight='balanced').…falešný poplach (FP) je nákladný. Nechceš označit nevinného.
…přehlédnutí (FN) je nebezpečné. Nesmíš přehlédnout žádný pozitivní případ.
Pokud se testovací data „přimíchají" do tréninku (např. normalizace přes celá data před splitem), výsledky jsou uměle lepší. V praxi model selže.
Hledáme vztah, kde výsledek (závislá proměnná Y) závisí lineárně na vstupech (X):
Y = b0 + b1·X1 + b2·X2 + ...
Odhadne koeficienty tak, aby součet druhých mocnin odchylek (rozdílů mezi skutečností a předpovědí) byl co nejmenší – přímka „nejlépe sedne“ na body.
Dummy (binární) proměnná nabývá jen 0 nebo 1 a kóduje kategorii. Např. dům = 1 pro dům, 0 pro byt → byt je referenční kategorie. Koeficient u dummy říká rozdíl oproti referenční kategorii.
Vždy si ohlídej jednotky. Když je cena „v tisících Kč“ a koeficient je 2000, znamená to 2000 tisíc = 2 miliony Kč.
Model (cena v tisících Kč): cena = 10 + 100·plocha + 2000·dům
Koeficient u dům je 2000 tisíc Kč = 2 miliony Kč. To je rozdíl oproti bytu (referenční kategorie) při stejné ploše.
→ Při stejné ploše je dům o 2 miliony Kč dražší než byt.
Proč ne ostatní: intercept 10 není průměrná cena bytu (to by musela být plocha 0); +100 m² zvýší cenu o 100·100 = 10 000 tisíc = 10 milionů, ne o tisíc.
U každého koeficientu testujeme, zda je významně různý od nuly (t-test). p-hodnota < 0,05 obvykle znamená, že proměnná má statisticky významný vliv. Velká p-hodnota → vliv neprokázán.
R² = 1 - (SS_res / SS_tot)
SS_res = Σ(yi − ŷi)² (reziduály – nevysvětlená variabilita)
SS_tot = Σ(yi − ȳ)² (celková variabilita kolem průměru)
Reziduál = skutečná hodnota − předpověď. Analýza reziduálů ověřuje předpoklady:
Když jsou dvě vstupní proměnné silně korelované (výška v cm a výška v palcích), koeficienty se stávají nestabilní. Detekce: VIF (Variance Inflation Factor) – VIF > 10 signalizuje problém. Řešení: odstranit jeden z korelovaných prediktorů.
Na přijetí potřebuješ 60 % – tady by to bylo 9 z 15. 💪
return v cyklu – sráží složitost.Když si nebudeš jistý, vyluč zjevně špatné možnosti a vyber tu, co dává logicky a jednotkově smysl. Hodně štěstí zítra – zvládneš to. 🍀