# Momentové statistiky
Dosud jsem po proměné požadovali aby měla uspořádání, tedy byla alespoň ordinální. To nám umožnilo definovat medián, kvantily a viualizaci rozloření dat pomocí box-plot. Abychom mohli přejít k aritmetickému průměru a statistikám z něj odvozeným, musíme přejít do vyšší úrovně měření, tedy k proměnným **kardinálním poměrovým**.
## Momentová míra polohy
Jak již bylo zmíněno, nejznámější statistikou je **(aritmetický) průměr** označovaný jako **$\bar{x}$** nebo **m (mean)**. Jedná se o statistiku momentovou, ale co to vlastně znamená?
Slovo **moment** pochází původně z fyziky, kde popisuje situaci na páce - **moment síly je součin hmotnosti $x_i$ a vzdálenosti $d_i$ od bodu otáčení**. Artimetický průměr v této situaci ukazuje na **těžiště**, tedy když páku podepřeme právě v tomto místě, bude v rovnováze. Hmotnost je ve statistice nahrazena relativní četností $p_i$, vzdálenost je nahrazena pojmem **odchylka od průměru** $d_i$.
```{ojs}
//| echo: false
//| label: fig-teziste-vizualizace
data_base = [1, 2, 2, 2, 3, 3, 4, 5, 8, 11]
mean_vypocet = d3.sum(data_base) / data_base.length
Plot.plot({
width: 600,
height: 180,
grid: true,
x: { domain: [0, 12], label: "Hodnota (poloha na páce) →" },
y: { axis: null, domain: [0, 4] },
marks: [
// Tyč páky
Plot.ruleY([0.5], { strokeWidth: 2, stroke: "#333" }),
// Závaží (datové body) naskládané na sebe
Plot.dot(data_base.map(d => ({x: d})), Plot.stackY({
x: "x",
y: 0.3,
dy: -10,
fill: "steelblue",
stroke: "white",
r: 6
})),
// Těžiště (Průměr) jako podpěra páky
Plot.dot([{x: mean_vypocet, y: 0.5}], {
x: "x",
y: "y",
symbol: "triangle",
r: 10,
rotate: 0, // otočení trojúhelníku, aby vypadal jako podstavec
fill: "darkred",
dy: 15
}),
// Popisek těžiště
Plot.text([{x: mean_vypocet, y: 0}], {
x: "x",
y: "y",
text: [`Těžiště (průměr) = ${mean_vypocet.toFixed(1)}`],
dy: 25,
fill: "red",
fontWeight: "bold"
})
]
})
```
## Momentové míry variability
Pojďme se podívat na to, jak na lze charakterizovat variabilitu dat vzhledem k průměru. Můžeme zjistit, jak daleko od průměru jsou jednotlivé body a získáme **odchylky jednotlivých hodnot od průměru**, $e_i=x_i-\bar{x}$. Naším zájmem je získat **průměrnou odchylku**, což vypadá snadno: sečteme všechny odchylky a vydělíme počtem. Jenže (!) problém je ten, že když je sečteme, dostaneme vždy nulu.
::: {.callout-note collapse="true"}
# Odvození, že $\sum e_i=0$
\begin{align}
\sum(e_i) &= \sum(x_i-\bar{x}) \\
&= (x_1-\bar{x}) + (x_2-\bar{x})+\dots \\
&= x_1+x_2+\dots -(\bar{x}+\bar{x}+\dots) \\
&= \sum x_i-\sum \bar{x} \\
&= \sum x_i-n\cdot \bar{x} \\
&=\sum x_i-n\cdot \frac{\sum x_i}{n} \\
&=0
\end{align}
:::
:::{.callout-note}
To že součet odchylek je nulový ukazuje na to, že se opravdu jedná o těžiště: součet odchylek záporných = součet odchylek kladných, žádná strana není zvýhodněna.
:::
Abychom získali průměrnou odchylku můžeme buď použít absolutní hodnoty a získat tak hodnotu zvanou ***mean absolute deviance, MAD*** : $MAD=\frac{\sum |x_i-\bar{x}|}{n}$, Nebo spočítat nejprve kvadratické odchylky $(x_i-\bar{x})^2$, určit průměrnou kvadratickou odchylku $\frac{\sum (x_i-\bar{x})^2}{n}$ a poté ji odmocnit. Získáme tím hodnotu které se říká **směrodatná odchylka** a značí se symbolem *sd (standard deviation)*
$$ sd=\sqrt{\frac{\sum (x_i-\bar{x})^2}{n}} $$
Koncept směrodatné odchylky lze získat také jinou, geometrickou cestou. Pro zájemce ji zde uvedeme.
::: {.callout-note collapse="true"}
# Směrodatná odchylka lineárně algebraicky
Abychom mohli vizualizovat potřebujeme jednodušší příklad: mějme dvě domácnosti, kteří omají počet vozidel v rozsahu 0-10. Na ose x budeme mít počet u první domácnosti, na ose y druhé. V defaultím nastavení má první 7 vozidel, druhá 3 vozidla, což reprezentuje modrý bod, který má souřadice [7,3]. Pro lepší vyjádření použijeme vektorovou formu zápisu, která je bližší i sloupcům v tabulce dat $\mathbf{x}=\begin{pmatrix} x_1\\ x_2\end{pmatrix}=\begin{pmatrix} 7\\ 3\end{pmatrix}$
Naším zájmem je nalézt jedno číslo, které charakterizuje naše data. Fakticky tedy řešíme soustavy rovnic
\begin{align} x_1&=c\\ x_2&=c\end{align}
Tato soustava však v praktických situacích nemá řešení. Zkusme se však na situaci podívat pohledem geometrie:
\begin{align} x_1&=c \\ x_2&=c \end{align}
$$
\Longrightarrow \begin{pmatrix} x_1\\x_2 \end{pmatrix} =c \cdot \begin{pmatrix} 1 \\ 1 \end{pmatrix} \Longrightarrow \mathbf{ x}=c \cdot\mathbf{1}
$$
Na levé straně máme vektor dat, na pravé straně neznámý násobek vektoru jedničkového.
**Na přímce dané jedničkovým vektorem tedy hledáme takové c, aby výsledný vektor byl co nejblíže vektoru našich dat.**
```{ojs}
//| echo: false
// Statické hodnoty
x1_static = 7
x2_static = 3
pru_static = (x1_static + x2_static) / 2
// Vizualizace
Plot.plot({
grid: true,
width: 500,
height: 500,
x: {domain: [0, 10], label: "Osa x₁"},
y: {domain: [0, 10], label: "Osa x₂"},
marks: [
// Přímka y = x
Plot.line([[0,0], [10,10]], {stroke: "darkgrey", strokeDasharray: "4,4", strokeWidth: 2}),
// VEKTOR jedniček
Plot.link([{x: pru_static, y: pru_static}], {
x1: 0, y1: 0, x2: 1, y2: 1,
stroke: "#666", strokeWidth: 2,markerEnd: "arrow"
}),
Plot.text([{x: pru_static/2, y: pru_static/2}], {
x: "x", y: "y", text: ["prostor generovaný 1"],
rotate: -45, dy: 15, fill: "#666"
}),
// BOD DAT
Plot.dot([{x: x1_static, y: x2_static}], {
x: "x", y: "y",
fill: "steelblue",
r: 5 // poloměr bodu
}),
Plot.text([{x: x1_static, y: x2_static}], {
x: "x",
y: "y",
text: [`Data X = [${x1_static.toFixed(1)}, ${x2_static.toFixed(1)}]`],
dy: 20, dx: -5,
fontWeight: "bold",
fill: "steelblue"
})
]
})
```
Provedeme lineárně algebraické úpravy rovnice
\begin{align}
c \cdot\mathbf{1} &=\mathbf{x} \\
c \cdot\mathbf{1}^T \mathbf{1} &=\mathbf{1}^T\mathbf{x} \\
c &= (\mathbf{1}^T \mathbf{1})^{-1}\mathbf{1}^T\mathbf{x}
\end{align}
V našem případě však
\begin{align}
\mathbf{1}^T \mathbf{1} &= (1,1) \cdot \begin{pmatrix} 1 \\ 1 \end{pmatrix} = 2 \\
\mathbf{1}^T\mathbf{x} &= (1,1) \cdot \begin{pmatrix} x_1\\x_2 \end{pmatrix} =\sum x_i\\
c &= (\mathbf{1}^T \mathbf{1})^{-1} \cdot \mathbf{1}^T\mathbf{x}\\
&= 2^{-1} \cdot \sum x_i\\
&= \frac{\sum x_i}{2} \\
&= \bar{x}
\end{align}
Aritmetický **průměr** tedy popisuje nejbliší bod na přímce **1** od bodu našich dat **x**.
Můžeme tedy sestrojit vektor odchylek našich dat od vektoru průměru
$$
\mathbf{e}=\mathbf{x}-\bar{x}\mathbf{1}=\begin{pmatrix} 7\\3\end{pmatrix}-5\begin{pmatrix}1\\ 1\end{pmatrix}=\begin{pmatrix} 2\\ -2\end{pmatrix}
$$
Vektor $\mathbf{x}$ je tedy rozložen do vektoru do směru vektoru $\mathbf{1}$ a směru kolmého, takže platí vektorově
$$\mathbf{x}=\bar{x}\mathbf{1}+\mathbf{e}$$
Vektor dat jsme rozložili na dvě složky, složku průměru a složku odchylek.
```{ojs}
//| echo: false
// 1. Ovládací prvky (stále stejné)
viewof x1 = Inputs.range([0, 10], {step: 1, value: 7, label: " Respondent 1"})
viewof x2 = Inputs.range([0, 10], {step: 1, value: 3, label: " Respondent 2"})
// 2. Výpočty
pru = (x1 + x2) / 2
norma_e = Math.sqrt(Math.pow(x1 - pru, 2) + Math.pow(x2 - pru, 2))
norma_x = Math.sqrt(Math.pow(x1, 2) + Math.pow(x2, 2))
sigma_val = norma_e / Math.sqrt(2)
// 3. Vizualizace
Plot.plot({
grid: true,
width: 500,
height: 500,
x: {domain: [0, 10], label: "Osa x₁"},
y: {domain: [0, 10], label: "Osa x₂"},
marks: [
// Přímka y = x
Plot.line([[0,0], [10,10]], {stroke: "#ccc", strokeDasharray: "4,4"}),
// VEKTOR jedniček
Plot.link([{x: pru_static, y: pru_static}], {
x1: 0, y1: 0, x2: 1, y2: 1,
stroke: "#666", strokeWidth: 3,markerEnd: "arrow"
}),
// VEKTOR PRŮMĚRU (Projekce)
Plot.link([{x: pru, y: pru}], {x1: 0, y1: 0, x2: "x", y2: "y", stroke: "#666", strokeWidth: 2}),
Plot.text([{x: pru/2, y: pru/2}], {
x: "x", y: "y", text: ["vektor průměru (x̄.1)"],
rotate: -45, dy: 15, fill: "#666"
}),
// VEKTOR ODCHYLEK (Kolmice)
Plot.link([{x1: x1, y1: x2, x2: pru, y2: pru}], {
x1: "x1", y1: "y1", x2: "x2", y2: "y2",
stroke: "darkred", strokeWidth: 3,
}),
Plot.text([{x: (x1+pru)/2, y: (x2+pru)/2}], {
x: "x", y: "y", text: ["vektor odchylek (e)"],
rotate: 45, dx: 25, fill: "darkred"
}),
// Pravý úhel (symbol čtverce)
Plot.dot([{x: pru, y: pru}], {
symbol: "square", r: 6, rotate: 45, fill: "none", stroke: "black",
dx: (x1 > x2 ? -4 : 4), dy: (x1 > x2 ? 4 : -4)
}),
// VEKTOR DAT (Přepona)
Plot.link([{x: x1, y: x2}], {x1: 0, y1: 0, x2: "x", y2: "y", stroke: "steelblue", strokeWidth: 1, markerEnd: "dot"}),
Plot.text([{x: x1/2, y: x2/2}], {
x: "x", y: "y", text: ["vektor dat (x)"],
//rotate: Math.atan2(x2, x1) * (180/Math.PI),
dy: -12, fill: "steelblue"
}),
// BOD DAT
Plot.dot([{x: x1, y: x2}], {
x: "x", y: "y",
fill: "steelblue",
r: 5 // poloměr bodu
}),
Plot.text([{x: x1, y: x2}], {
x: "x",
y: "y",
text: [`X = [${x1.toFixed(1)}, ${x2.toFixed(1)}]`],
dy: 20, // Posun nad bod
dx: -5,
fontWeight: "bold",
fill: "steelblue"
}),
// Legenda s výsledky// Legenda s výpočty
Plot.text([{x: 0.5, y: 10.0}],{x: "x", y: "y", text: [`||x||² = ${Math.pow(norma_x,2).toFixed(2)}`], textAnchor: "start", fill: "black" }),
Plot.text([{x: 0.5, y: 9.5}], {x: "x", y: "y", text: [`x̄= ${Math.pow(pru,1).toFixed(1)}`], textAnchor: "start", fill: "black" }),
Plot.text([{x: 0.5, y: 9.0}], {x: "x", y: "y", text: [`||x̄||²= ${Math.pow(pru,2).toFixed(2)}`], textAnchor: "start", fill: "black" }),
Plot.text([{x: 0.5, y: 8.5}], {x: "x", y: "y", text: [`||e||² = ${Math.pow(norma_e,2).toFixed(2)}`], textAnchor: "start", fill: "black" }),
Plot.text([{x: 0.5, y: 8.0}], {x: "x", y: "y", text: [`σ² = ||e||² / 2 = ${(Math.pow(norma_e, 2) / 2).toFixed(2)}`], textAnchor: "start", fill: "black" }),
Plot.text([{x: 0.5, y: 7.5}], {x: "x", y: "y", text: [`σ = √σ² = ${sigma_val.toFixed(2)}`], textAnchor: "start", fill: "black"})
]
})
```
Zaměřme se na velikosti těchto vektorů:Pomocí Pythogorovy věty dostáváme rovnici
$$\|\mathbf{x}\|^2 = \|\mathbf{\bar{x}}\|^2 + \|\mathbf{e}\|^2$$
Víme, že $\|\mathbf{x}\|=\sqrt{x_1^2+x_2^2}$, proto pro nás bude výhodnější zůstat u druhých mocnin. Můžeme vyjádřit $\|\mathbf{e}\|^2$ ve tvaru
\begin{align}
\|\mathbf{e}\|^2
&=e_1^2+e_2^2\\
&=(x_1-\bar{x})^2+(x_2-\bar{x})^2\\
&=\sum (x_i-\bar{x})^2,
\end{align}
nebo ve tvaru
\begin{align}
\|\mathbf{e}\|^2
&=\|\mathbf{x}\|^2 - \|\mathbf{\bar{x}}\|^2
&=(x_1^2+x_2^2)-(\bar{x}^2+\bar{x}^2)
&=\sum x_i^2-n\cdot\bar{x}^2
\end{align}
$\|\mathbf{e}\|^2$ vyjadřuje celkovou odchylku dat od vekotru průměrů, přepočítáno na jedno pozorování dostaneme veličiny zvanou **rozptyl** a označovanou jako $var$ nebo $\sigma^2$ a která se tedy rovná $= \frac{\|\mathbf{e}\|^2}{n}$
$$
var=\sigma^2 = \frac{\sum (x_i - \bar{x})^2}{n}
$$
Protože tohle je velikost na druhou, "průměrnou odchylku" získáme jako odmocninu z rozptylu
$$
sd=\sqrt{\frac{\sum (x_i - \bar{x})^2}{n}}
$$
:::
## Momentové míry tvaru rozdělení
Připomeňme, že základním nástrojem vizualizace kardinálních dat je histogram. Tvarem rozdělení tedy rozumíme tvar histogramu - jestli je symetrický, zešikmený , vodorovný, $\dots$ .
```{ojs}
// 1. Generování dat na základě výběru
data02 = {
let v;
const n = 500;
if (distType02 === "Normální") {
v = Array.from({length: n}, d3.randomNormal(0, 1));
} else if (distType02 === "Zešikmené") {
// Log-normální rozdělení je přirozeně zešikmené
v = Array.from({length: n}, d3.randomLogNormal(0, 0.5));
} else if (distType02 === "Uniformní") {
v = Array.from({length: n}, d3.randomUniform(-2, 2));
}
return v.map(d => ({val: d}));
}
// 2. Ovládací prvky
viewof distType02 = Inputs.select(
["Normální", "Zešikmené", "Uniformní"],
{label: "Typ rozdělení"}
)
viewof binCount = Inputs.range([2, 200], {value: 20, step: 1, label: "Počet bins"})
// 3. Graf
Plot.plot({
height: 400,
grid: true,
marks: [
// Histogram (Density)
Plot.rectY(data02, Plot.binX({y: "count"}, {x: "val", thresholds: binCount, fill: "steelblue", fillOpacity: 0.7})),
// dodgeY vytvoří "mrak" bodů, anchor: "bottom" je drží u spodní hrany
Plot.dot(data02, Plot.dodgeY({
x: "val",
anchor: "bottom",
padding: 0.5, // Tímto zvětšuješ/zmenšuješ rozestupy mezi body
r: 2,
fill: "black",
fillOpacity: 0.4
})),
Plot.ruleY([0])
],
y: {
label: "Četnost / Hustota",
tickFormat: "d"
},
x: {
label: "Hodnota x"
}
})
```
### šikmost
Jak číselně odlišit data, tkerá jsou symetrická od dat, která symetrická nejsou? Pokud využijeme odchylky, pak musíme **zdůraznit větší odchylky** a **potlačit malé odchylky**, a zároveň **zachovat znaménko** odchylky. Abychom získali míru která je nezávislá na poloze a variabilitě konkrétních dat, musíme data nejprve **standardizovat**, tedy převést na
$$z_i=\frac{(x_i-\bar{x})}{sd}$$
Proměnná $z$ má průměr nula a směrodatnou odchylku jedna nezávisle na tom, z jakých dat pochází (viz kapitola o aritmetice dat). hodnota $z_i$ naám tak přímo ukazuje standardizovanou odchylku dat od průměru. Pro zjištění zešikmení využijeme třetí mocninu - ta potlačuje hodnoty menší než $|x_i|<1$ ,zvýrazňuje hodnoty $|x_i|>1$ a přitom zachovává stejné znaménko, takže budeme umět rozlišit, zda jsou data zešikmená napravo nebo nalevo. **Šikmost** (*skewness, skew*) tedy počítáme pomocí vzorce
$$
skew(X)=\frac{\sum z_i^3}{n}
$$
Když je skew záporné znamená to, že větší odchylky jsou vlevo a datsa jsou nahuštěná vpravo, když je šikmost kladná, znamená to že větší odchylky jsou doprava a data jsou nahuštěná vlevo. skew kolem hodnoty 0 znamená symetrické rozdělení
::: {#fig-skewness}
```{ojs}
//| echo: false
// 1. Ovládací prvek
viewof distType03 = Inputs.select(
["Normální", "Doprava (kladně) zešikmené", "Doleva (záporně) zešikmené", "Uniformní"],
{label: "Typ rozdělení"}
)
// 2. Generování dat
data03 = {
const n = 512;
let v;
if (distType03 === "Normální") {
v = Array.from({length: n}, d3.randomNormal(0,1));
} else if (distType03 === "Doprava (kladně) zešikmené") {
v = Array.from({length: n}, () => d3.randomLogNormal(0, 0.8)());
} else if (distType03 === "Doleva (záporně) zešikmené") {
const gen = d3.randomLogNormal(0, 0.8);
v = Array.from({length: n}, () => 4 - gen());
} else if (distType03 === "Uniformní") {
v = Array.from({length: n}, d3.randomUniform(-2, 2));
}
return v.map(d => ({val: d}));
}
// 3. Výpočet statistik (včetně Sturgese a momentů)
stats03 = {
const values = data03.map(d => d.val);
const n = values.length;
const mean = d3.mean(values);
const sd = d3.deviation(values);
const median = d3.median(values);
const skew = d3.sum(values, v => Math.pow((v - mean) / sd, 3)) / n;
const kurt = (d3.sum(values, v => Math.pow((v - mean) / sd, 4)) / n) - 3;
const sturges = Math.ceil(Math.log2(n) + 1);
// Dynamický text porovnání
let relation = "";
if (distType03 === "Normální" || distType03 === "Uniformní") relation = "průměr ≈ medián";
else if (distType03 === "Doprava (kladně) zešikmené") relation = "průměr > medián";
else if (distType03 === "Doleva (záporně) zešikmené") relation = "průměr < medián";
return { mean, median, skew, kurt, sturges, relation };
}
// 4. Graf s integrovanou legendou v Plot.text
Plot.plot({
height: 450,
grid: true,
marks: [
// Histogram
Plot.rectY(data03, Plot.binX({y: "count"}, {
x: "val",
thresholds: stats03.sturges,
fill: "#f0f0f0",
stroke: "#ccc"
})),
// Svislé čáry
Plot.ruleX([stats03.mean], {stroke: "steelblue", strokeWidth: 2}),
Plot.ruleX([stats03.median], {stroke: "darkred", strokeWidth: 2}),
// Dynamická legenda pomocí Plot.text
// Souřadnice x a y je nutné ladit podle rozsahu tvých dat (zde x: vlevo, y: nahoře)
Plot.text([`Průměr: ${stats03.mean.toFixed(3)}`], {frameAnchor: "top-left", dx: 10, dy: 20, fill: "steelblue", fontWeight: "bold", fontSize: 14}),
Plot.text([`Medián: ${stats03.median.toFixed(3)}`], {frameAnchor: "top-left", dx: 10, dy: 40, fill: "darkred", fontWeight: "bold", fontSize: 14}),
Plot.text([`Šikmost (z³): ${stats03.skew.toFixed(3)}`], {frameAnchor: "top-left", dx: 10, dy: 60, fontWeight: "bold", fontSize: 14}),
Plot.text([stats03.relation], {frameAnchor: "top-left", dx: 10, dy: 80, fontSize: 14, fontWeight: "bold"}),
// Mrak bodů
Plot.dot(data03, Plot.dodgeY({
x: "val",
anchor: "bottom",
padding: 0.5,
r: 2,
fill: "black",
fillOpacity: 0.2
})),
Plot.ruleY([0])
],
y: { label: "Četnost" },
x: { label: "Hodnota (x)" }
})
```
Vztah mezi šikmostí průměrem, mediánem a tvarem distribuce.
:::
### Špičatost
Jak číselně odlišit data, která mají většinu hodnot blízko průměru od hodnot, která mají rozprostření dat volnější a vzdálenější hodnoty nejsou vyjímkou (*heavy tails, těžké ocasy*)? Protože zešikmení máme popsané pomocí skew, nezáleží nám nyní na směru ochylky, musíme však velmi zvýraznit odlehlé hodnoty. K tomu nám poslouží čtvrtá mocnina $z$, pomocí které určujeme **špičatost** (*kurtoisis, kurt*), kterou určíme pomocí vzorce
$$
kurt(X) = \frac{\sum z_i^4}{n}
$$
Protože se jako základní distribuce bere **normální, gaussova, zvonová** která má $kurt=3$, uvádí se často vzorec pro *excess kurtosis* $kurt_{excess}=\frac{\sum z_i^4}{n}-3$ který pak lze intepretovat jako odchýlení špičatosti od normálního rozdělení. Podrobněji o normálním rozdělení viz samostatná kapitola.
Následující graf ukazuje vliv velikosti odchylek na jejich "příspěvek" do průměru, rozptylu, šikmosti a špičatosti. Na ose x je hodnota $z$, na jednotlivých křivkách velikosti $|z|,z^2,z^3,z^4$, které tvoří příspěvek do příslušných momentových metrik.
Pro $k={2,3,4}$ platí: $|z_i|<1\Longrightarrow |z_i|^k<|z_i|$, takže jejich vliv je potlačen. Pro hodnoty $|z_i|>1\Longrightarrow |z_i|^k > |z_i|$, takže jejich vliv je výrazně posílen.
::: {#fig-skewness}
```{ojs}
//| echo: false
viewof z = Inputs.range([-2, 2], {label: "Odchylka (z-skóre)", step: 0.05, value: 1.5})
Plot.plot({
height: 800,
y: {domain: [-8, 8], grid: true, label: "Váha v momentu (f(z))"},
x: {domain: [-2, 2], grid: true, label: "Vzdálenost od průměru (z)"},
style: {fontSize: "14px"},
marks: [
// Vodorovná osa (nula) - opraveno na ruleY
Plot.ruleY([0], {strokeWidth: 1.5}),
// Svislé pomocné čáry na jednotkových odchylkách
Plot.ruleX([-1, 1], {strokeOpacity: 0.2, strokeDasharray: "4,4"}),
// MAD |z| - Lineární
Plot.line(d3.range(-2, 2.05, 0.05), {x: d => d, y: d => Math.abs(d), stroke: "steelblue", dash: "none", strokeWidth: 2, label: "Průměr (|z|¹)"}),
// Rozptyl z^2
Plot.line(d3.range(-2, 2.05, 0.05), {x: d => d, y: d => d**2, stroke: "#7A5B8C", dash: "8,4", strokeWidth: 2, label: "Rozptyl (z²)"}),
// Šikmost z^3
Plot.line(d3.range(-2, 2.05, 0.05), {x: d => d, y: d => d**3, stroke: "#AF3363", dash: "4,3", strokeWidth: 2, label: "Šikmost (z³)"}),
// Špičatost z^4
Plot.line(d3.range(-2, 2.05, 0.05), {x: d => d, y: d => d**4, stroke: "darkred", dash: "1,2", strokeWidth: 2, label: "Špičatost (z⁴)"}),
// Interaktivní tečky (body na křivkách podle posuvníku)
Plot.dot([z], {x: d => d, y: d => Math.abs(d), fill: "steelblue", r: 4}),
Plot.dot([z], {x: d => d, y: d => d**2, fill: "#7A5B8C", r: 4}),
Plot.dot([z], {x: d => d, y: d => d**3, fill: "#AF3363", r: 4}),
Plot.dot([z], {x: d => d, y: d => d**4, fill: "darkred", r: 6}),
// Dynamická legenda v rohu
Plot.text([`pro průměr: |z|= ${Math.abs(z).toFixed(2)}`], {x: -1.9, y: 7.5, fill: "steelblue", textAnchor: "start"}),
Plot.text([`pro rozptyl: z²= ${(z**2).toFixed(2)}`], {x: -1.9, y: 6.5, fill: "#7A5B8C", textAnchor: "start"}),
Plot.text([`pro šikmost: z³= ${(z**3).toFixed(2)}`], {x: -1.9, y: 5.5, fill: "#AF3363", textAnchor: "start"}),
Plot.text([`pro špičatost: z⁴= ${(z**4).toFixed(2)}`], {x: -1.9, y: 4.5, fill: "darkred", textAnchor: "start"})
]
})
```
Vliv vzdálenosti od průměru na velikost započítávané hodnoty do momentových charakteristik mad, sd, skew a kurt. Osa $x$ obsahuje standardizovaná data $z_i$, osa y transformovaná data $z_i^k$ pro všechny čtyři momentové charakteristiky.
:::
A jak to konkrétně vypadá pro různě rozprostřená data ukazuje následující graf. Pro $k={2,3,4}$ platí: $|z_i|<1\Longrightarrow |z_i|^k<|z_i|$, takže jejich vliv je potlačen. V následujícím grafu jsou to data v modře podsvícené oblasti. Pro hodnoty $|z_i|>1\Longrightarrow |z_i|^k > |z_i|$, takže jejich vliv je výrazně posílen.
::: {#fig-moments}
```{ojs}
//| echo: false
// 1. Vstupy
viewof moment = Inputs.select(
new Map([
["MAD (Průměrná odchylka) |z|", "abs"],
["Rozptyl (Kvadratická) z²", "var"],
["Šikmost (Kubická) z³", "skew"],
["Špičatost (Kvadraticá) z⁴", "kurt"]
]),
{label: "Zvolte statistický moment:"}
)
viewof distType = Inputs.radio(
["Normální", "Těžké ocasy", "Šikmé vpravo", "Šikmé vlevo"],
{value: "Normální", label: "Rozdělení dat:"}
)
// Slovník pro popisky výsledku
momentLabels = ({
abs: "Průměrná odchylka (MAD)",
var: "Rozptyl (Var)",
skew: "Šikmost (Skewness)",
kurt: "Špičatost (Kurtosis)"
})
// 2. Dynamický rozsah osy Y podle zvoleného momentu
yLimit = {
if (moment === "abs") return 2.5;
if (moment === "var") return 4.5;
if (moment === "skew") return 8.5;
return 16.5; // pro z^3 a z^4
}
// 3. Definice dat (beze změny)
dataMap = new Map([
["Normální", [-1.5, -0.6, -0.3, -0.2, -0.1, 0.1, 0.2, 0.3, 0.6, 1.5]],
["Těžké ocasy", [-2.0, -0.5, -0.3, -0.1, 0, 0, 0.1, 0.3, 0.5, 2.0]],
["Šikmé vpravo", [-0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, 0.5, 1.2, 1.8]],
["Šikmé vlevo", [-1.8, -1.2, -0.5, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]]
])
currentData = dataMap.get(distType)
functionTransform = (z) => {
if (moment === "abs") return Math.abs(z);
if (moment === "var") return z**2;
if (moment === "skew") return z**3;
if (moment === "kurt") return z**4;
}
results = currentData.map(functionTransform)
finalValue = d3.mean(results)
// 4. Graf s responzivním y domain
Plot.plot({
height: 600,
width: width,
y: {
domain: moment === "skew" ? [-yLimit, yLimit] : [moment === "abs" ? -1.5 : -1, yLimit],
grid: true,
label: "Transformovaná hodnota (y)"
},
x: {domain: [-3, 3], grid: true, label: "Původní z-skóre (x)"},
marks: [
// KRABICE TLUMIVOSTI: x i y v rozsahu [-1, 1]
Plot.rect([-1], {
x1:-1, x2: 1, y1: -1, y2: 1,
fill: "steelblue", fillOpacity: 0.15,
stroke: "steelblue",
strokeDasharray: "2,2",
strokeOpacity: 0.3
}),
Plot.frame({stroke: "#ccc", strokeDasharray: "4,4"}),
// hlavní osy
Plot.ruleY([0], {strokeOpacity: 0.8}),
Plot.ruleX([0], {strokeOpacity: 0.5}),
// Svislé referenční čáry na bodech zlomu
Plot.ruleX([-1, 1], {stroke: "#666", strokeDasharray: "4,4", strokeWidth: 1}),
// Vodorovná referenční čára y=1 (bod, kde se všechny křivky potkají)
Plot.ruleY([1], {stroke: "#666", strokeDasharray: "4,4", strokeWidth: 1, strokeOpacity: 1}),
Plot.ruleY([-1], {stroke: "#666", strokeDasharray: "4,4", strokeWidth: 1, strokeOpacity: 1}),
// Křivka funkce
Plot.line(d3.range(-3, 3.1, 0.1), {
x: d => d,
y: d => functionTransform(d),
stroke: "#ccc", strokeWidth: 4
}),
// Projekce X -> Křivka -> Y
Plot.ruleX(currentData, {x: d => d, y1: 0, y2: d => functionTransform(d), stroke: "steelblue", strokeOpacity: 0.5}),
Plot.ruleY(results, {y: d => d, x1: (d, i) => currentData[i], x2: 0, stroke: "steelblue", strokeDasharray: "2,2", strokeOpacity: 0.5}),
// Body
Plot.dot(currentData, {x: d => d, y: 0, fill: "steelblue", r: 6}), // Data na X
Plot.dot(currentData, {x: d => d, y: d => functionTransform(d), fill: "steelblue", r: 3}), // Na křivce
Plot.dot(results, {x: 0, y: d => d, fill: "steelblue", r: 4}), // Na ose Y
// Modrý diamant - Průměr (Výsledný moment)
Plot.dot([finalValue], {x: 0, y: d => d, fill: "darkred", symbol: "circle", r: 10, stroke: "white", strokeWidth: 2}),
// Dynamický popisek výsledku
Plot.text([finalValue], {
x: 0.2, y: d => d,
text: d => ` ${momentLabels[moment]} = ${d.toFixed(3)}`,
textAnchor: "start", fill: "darkred", fontWeight: "bold", fontSize: 16
})
]
})
```
Momentové charakteristiky různých rozdělení. Osa $x$ obsahuje standardizovaná data $z_i$, osa y transformovaná data $z_i^k$ a jejich průměr. Modrá oblast je oblast útlumu, data z této oblasti mají potlačený vliv a data mimo naopak posílený.
:::
## Klíčové poznatky {.unnumbered}
| | |
|:---|:---|
|průměr |$\bar{x}=\frac{\sum x_i}{n}$|
|směrodatná odchylka|$sd=\sqrt{\frac{1}{n}\sum (x_i - \bar{x})^2}=\sqrt{var}$|
|rozptyl|$var=\frac{1}{n}\sum (x_i - \bar{x})^2=sd^2$|
|standardizace|$z_i=\frac{x_i - \bar{x}}{sd}$|
|šikmost|$skew=\frac{1}{n}\sum z_i^3$|
|špičatost|$kurt=\frac{1}{n}\sum z_i^4$, nebo $kurt_{excess}=\frac{1}{n}\sum z_i^4-3$|