Mục lục
- Mục tiêu bài học
- Phân phối xác suất là gì
- Phân phối chuẩn — Gaussian
- Công thức PDF
- Quy tắc 68-95-99.7
- Standard normal và z-score
- Central Limit Theorem
- Khi nào dữ liệu thực sự normal
- Test một dataset có normal không
- Use case trong AI / ML / DL
- Code Python với statistics.NormalDist
- Bài tập
- Tổng kết và bài tiếp theo
Mục tiêu bài học
Sau bài học, bạn sẽ:
- Hiểu phân phối xác suất là cách mô tả dữ liệu phân bố thế nào quanh các giá trị.
- Đọc được ký hiệu \( X \sim \mathcal{N}(\mu, \sigma^2) \) và công thức PDF của Gaussian.
- Áp dụng quy tắc 68-95-99.7 để ước lượng nhanh tỉ lệ dữ liệu nằm trong khoảng \( \mu \pm k\sigma \).
- Tính được z-score và chuyển từ phân phối chuẩn bất kỳ về standard normal \( \mathcal{N}(0, 1) \).
- Hiểu intuition của Central Limit Theorem (CLT) và vì sao Gaussian xuất hiện khắp nơi.
- Biết khi nào dữ liệu thực sự normal, khi nào không, và cách kiểm tra sơ bộ.
- Nhận diện các use case Gaussian trong AI: noise, weight init, VAE, linear regression, Naive Bayes.
Bài này nối tiếp bài 22 về variance và standard deviation — hai tham số \( \mu \) và \( \sigma \) chính là input để định nghĩa một phân phối chuẩn.
Phân phối xác suất là gì
Khi quan sát một biến ngẫu nhiên (chiều cao, điểm thi, sai số đo, thời gian phản hồi của API...), ta thấy các giá trị không xuất hiện đều nhau: một số khoảng giá trị "nhiều" hơn, một số khoảng "ít" hơn. Phân phối xác suất là mô tả toán học cho hiện tượng đó — nó nói: với mỗi giá trị (hoặc khoảng giá trị), xác suất biến nhận giá trị ấy là bao nhiêu.
Phân phối có hai họ chính:
- Discrete (rời rạc) — biến chỉ nhận một số giá trị tách biệt. Ví dụ: số mặt khi tung xúc xắc (1..6), số email mới mỗi giờ. Mô tả bằng
PMF(probability mass function). - Continuous (liên tục) — biến nhận giá trị trong một khoảng số thực. Ví dụ: chiều cao, nhiệt độ. Mô tả bằng
PDF(probability density function).
Một số phân phối liên tục thường gặp:
- Uniform — mọi giá trị trong khoảng \( [a, b] \) có mật độ bằng nhau.
- Normal / Gaussian — hình chuông quanh mean. Trọng tâm bài này.
- Exponential — mô tả thời gian chờ giữa các sự kiện độc lập (ví dụ: thời gian giữa 2 request).
- Log-normal — log của biến mới là normal. Hay gặp ở income, kích thước file.
Bài này tập trung Gaussian; các phân phối còn lại sẽ chỉ được nhắc khi cần đối chiếu.
Phân phối chuẩn — Gaussian
Phân phối chuẩn (còn gọi là Gaussian, theo Carl Friedrich Gauss) có hình dạng chuông đối xứng quanh giá trị trung bình:
- Đỉnh chuông ở \( x = \mu \) — đây cũng là mean, median và mode (cả ba trùng nhau).
- Đối xứng qua đường thẳng đứng \( x = \mu \).
- Càng xa \( \mu \), mật độ càng giảm — nhưng không bao giờ chạm 0. Đuôi (tail) kéo dài ra cả hai phía vô cực.
- Độ "béo" của chuông được kiểm soát bởi \( \sigma \): \( \sigma \) lớn thì chuông thấp và rộng; \( \sigma \) nhỏ thì chuông cao và hẹp.
Ký hiệu chuẩn:
\[ X \sim \mathcal{N}(\mu, \sigma^2) \]
đọc là "biến \( X \) tuân theo phân phối chuẩn với mean \( \mu \) và phương sai \( \sigma^2 \)". Lưu ý: trong ngoặc là variance \( \sigma^2 \), không phải standard deviation \( \sigma \). Một số sách / paper viết \( \mathcal{N}(\mu, \sigma) \) — luôn nên kiểm tra convention khi đọc.
Hai tham số duy nhất để xác định trọn vẹn một phân phối chuẩn:
| Tham số | Ý nghĩa | Ảnh hưởng đến đồ thị |
|---|---|---|
| \( \mu \) (mean) | Vị trí trung tâm | Dịch chuyển chuông sang trái / phải |
| \( \sigma \) (std) | Độ phân tán | Béo / thon. Nhỏ = nhọn, Lớn = bẹt |
Công thức PDF
Hàm mật độ xác suất (PDF) của \( \mathcal{N}(\mu, \sigma^2) \):
\[ f(x) = \frac{1}{\sigma\sqrt{2\pi}} \exp\left(-\frac{(x-\mu)^2}{2\sigma^2}\right) \]
Tách thành 3 phần để dễ đọc:
- \( \frac{1}{\sigma\sqrt{2\pi}} \) — hằng số chuẩn hoá, đảm bảo tổng diện tích dưới đường cong bằng 1 (vì \( f \) là mật độ, không phải xác suất trực tiếp).
- \( (x - \mu)^2 \) — khoảng cách bình phương từ \( x \) tới mean. Càng xa mean, phần này càng lớn.
- \( \exp(-\cdot / 2\sigma^2) \) — đưa khoảng cách bình phương vào hàm \( e^{-\,\cdot} \), tạo hình chuông và làm tail giảm cực nhanh khi ra xa \( \mu \).
Một số lưu ý quan trọng:
- \( f(x) \) không phải xác suất tại điểm \( x \). Với biến liên tục, xác suất tại một điểm cụ thể bằng 0. \( f(x) \) chỉ là mật độ.
- Xác suất nằm trong khoảng \( [a, b] \) là tích phân: \( P(a \le X \le b) = \int_a^b f(x) \, dx \).
- Tổng diện tích dưới đường cong (\( \int_{-\infty}^{\infty} f(x) \, dx \)) luôn bằng 1 — đó là lý do có hệ số \( \frac{1}{\sigma\sqrt{2\pi}} \).
- \( f(x) \) có thể lớn hơn 1 khi \( \sigma \) đủ nhỏ — mật độ không bị chặn bởi 1, chỉ xác suất mới bị chặn.
Quy tắc 68-95-99.7
Còn gọi là empirical rule — quy tắc nhanh để ước lượng tỉ lệ dữ liệu nằm trong khoảng cách \( k\sigma \) so với mean. Áp dụng cho mọi phân phối chuẩn, bất kể \( \mu \) hay \( \sigma \) bằng bao nhiêu.
| Khoảng | Tỉ lệ dữ liệu | Ý nghĩa |
|---|---|---|
| \( \mu \pm 1\sigma \) | ~68.27% | "Vùng phổ biến" — khoảng 2/3 mẫu |
| \( \mu \pm 2\sigma \) | ~95.45% | Hầu hết mẫu |
| \( \mu \pm 3\sigma \) | ~99.73% | Gần như toàn bộ; ngoài khoảng này gọi là outlier |
Ví dụ: điểm IQ thường được chuẩn hoá thành \( \mathcal{N}(100, 15^2) \). Áp dụng quy tắc:
- ~68% dân số có IQ trong \( [85, 115] \) — tức \( 100 \pm 15 \).
- ~95% có IQ trong \( [70, 130] \) — tức \( 100 \pm 30 \).
- ~99.7% có IQ trong \( [55, 145] \) — tức \( 100 \pm 45 \).
Trong ML, khi ai đó nói "outlier là điểm xa hơn 3 sigma", họ đang dùng ngầm quy tắc này: chỉ ~0.27% điểm thật sự nằm ngoài \( 3\sigma \), nên những điểm đó có khả năng là anomaly. Tuy nhiên cách này chỉ hợp lệ khi dữ liệu thực sự gần Gaussian (xem bước 8).
Standard normal và z-score
Standard normal là phân phối chuẩn với \( \mu = 0 \) và \( \sigma = 1 \):
\[ Z \sim \mathcal{N}(0, 1) \]
Mọi phân phối chuẩn đều có thể chuyển về standard normal bằng phép biến đổi gọi là z-score:
\[ z = \frac{x - \mu}{\sigma} \]
\( z \) là số lần \( \sigma \) mà \( x \) lệch khỏi \( \mu \). Một số trường hợp:
- \( z = 0 \) — đúng bằng mean.
- \( z = 1 \) — cao hơn mean 1 std.
- \( z = -2 \) — thấp hơn mean 2 std.
- \( |z| > 3 \) — ứng viên outlier (theo quy tắc 3-sigma).
Ví dụ: điểm thi của một bạn là 85, lớp có \( \mu = 70 \) và \( \sigma = 10 \). Z-score:
\[ z = \frac{85 - 70}{10} = 1.5 \]
Bạn này cao hơn trung bình lớp 1.5 std. Tra bảng standard normal (hoặc NormalDist.cdf trong Python), \( P(Z < 1.5) \approx 0.9332 \) — tức bạn này xếp khoảng top 7% (vượt 93% lớp).
Trong ML, z-score chính là phép standardization — một bước tiền xử lý phổ biến trước khi feed dữ liệu vào model. Mục tiêu là đưa mỗi feature về mean 0, std 1, để các thuật toán dựa trên khoảng cách (KNN, K-means, gradient descent với learning rate cố định...) không bị feature có scale lớn lấn át. sklearn.preprocessing.StandardScaler làm chính xác phép này.
Central Limit Theorem
Đây là kết quả giải thích vì sao Gaussian xuất hiện trong rất nhiều bài toán thực — kể cả khi không có lý do "vật lý" rõ ràng.
Phát biểu (intuition): Lấy nhiều mẫu độc lập từ một phân phối bất kỳ có mean \( \mu \) và phương sai \( \sigma^2 \) hữu hạn. Tính trung bình của \( n \) mẫu. Khi \( n \) đủ lớn (thường \( n \ge 30 \) là tạm đủ trong thực hành), phân phối của trung bình mẫu xấp xỉ:
\[ \bar{X}_n \sim \mathcal{N}\!\left(\mu, \frac{\sigma^2}{n}\right) \]
Điểm quan trọng:
- Phân phối gốc không cần normal. Có thể là uniform, exponential, lệch trái, lệch phải — miễn variance hữu hạn.
- Càng cộng / lấy trung bình nhiều biến độc lập, kết quả càng tiến gần Gaussian.
- Variance của trung bình giảm theo \( 1/n \) — nên std giảm theo \( 1/\sqrt{n} \). Đây là nguồn gốc công thức "sai số chuẩn = \( \sigma / \sqrt{n} \)".
Nhiều đại lượng đo trong tự nhiên thực ra là tổng / trung bình của vô số yếu tố nhỏ độc lập (gen, dinh dưỡng, ngẫu nhiên đo đạc...). Theo CLT, tổng đó tiến gần Gaussian — và đó là lý do chiều cao, sai số đo, nhiễu cảm biến thường có phân phối chuẩn.
Cảnh báo: CLT cần các giả định độc lập và phương sai hữu hạn. Một số phân phối "đuôi nặng" (heavy-tail như Cauchy, Pareto khi shape parameter nhỏ) có phương sai vô hạn — CLT chuẩn không áp dụng. Trong ML, giả định CLT là cơ sở cho rất nhiều phép kiểm định và confidence interval, nên cần kiểm tra giả định trước khi dùng.
Khi nào dữ liệu thực sự normal
Một số dataset thường gần Gaussian:
- Chiều cao người lớn cùng giới và cùng nhóm tuổi — tổng hiệu ứng của hàng nghìn gen và yếu tố môi trường.
- Điểm IQ được test thiết kế để chuẩn hoá thành \( \mathcal{N}(100, 15^2) \).
- Sai số đo lường trong dụng cụ vật lý — đặc biệt khi nhiễu là tổ hợp nhiều nguồn nhỏ.
- Trung bình mẫu của bất kỳ dataset nào, khi cỡ mẫu đủ lớn (CLT).
Một số dataset thường không Gaussian:
- Income (thu nhập) — lệch phải, có đuôi dài về phía cao (vài người siêu giàu). Hay được model bằng log-normal hoặc Pareto.
- Waiting time / inter-arrival time — thời gian chờ giữa các sự kiện ngẫu nhiên thường theo exponential, không phải normal. Đuôi phải dài, không đối xứng.
- Số lượng đếm (count data: số click, số request mỗi phút) — thường Poisson hoặc negative binomial, đặc biệt khi giá trị trung bình nhỏ.
- Giá cổ phiếu — log của tỉ lệ thay đổi gần normal, nhưng giá tuyệt đối thì không. Đuôi nặng hơn Gaussian, hay có "đột biến".
- Kích thước file / tệp tin — log-normal hoặc Pareto.
Quy tắc thực hành: không giả định Gaussian khi chưa kiểm tra. Nhiều thuật toán ML (linear regression, LDA, Gaussian Naive Bayes) có giả định ngầm về phân phối; bỏ qua bước kiểm tra dễ dẫn đến mô hình sai số hệ thống.
Test một dataset có normal không
Có hai hướng kiểm tra: trực quan (visual) và thống kê (statistical test).
Visual — nhanh, không cần thư viện
- Histogram — vẽ histogram của dữ liệu và quan sát: có hình chuông đối xứng không? Có đuôi lệch trái / phải không? Có 2 đỉnh (bimodal) không? Đây là bước đầu tiên luôn nên làm.
- QQ-plot (Quantile-Quantile plot) — sắp xếp dữ liệu mẫu theo thứ tự, vẽ chúng so với quantile của \( \mathcal{N}(0, 1) \). Nếu dữ liệu gần Gaussian, các điểm sẽ nằm gần đường thẳng \( y = x \). Đuôi cong lên phía trên = đuôi phải nặng hơn normal; cong xuống = đuôi nhẹ hơn. QQ-plot thường nhạy hơn histogram trong việc phát hiện lệch đuôi.
Statistical test
- Shapiro-Wilk — test phổ biến nhất cho cỡ mẫu nhỏ tới trung bình (n < 5000). \( H_0 \): dữ liệu lấy từ Gaussian. P-value nhỏ (thường < 0.05) thì bác bỏ \( H_0 \). Hàm:
scipy.stats.shapiro. - Kolmogorov-Smirnov — so sánh CDF mẫu với CDF lý thuyết của Gaussian. Hàm:
scipy.stats.kstest. - Anderson-Darling — nhạy hơn KS ở phần đuôi. Hàm:
scipy.stats.anderson.
Lưu ý: với cỡ mẫu rất lớn (n > 5000), các test thống kê dễ bác bỏ \( H_0 \) ngay cả khi dữ liệu chỉ lệch nhẹ. Trong thực hành ML, thường tin vào QQ-plot và histogram hơn là p-value của test khi n lớn. Hai loại bằng chứng kết hợp với nhau là cách an toàn nhất.
Use case trong AI / ML / DL
Gaussian noise trong dữ liệu
Khi augment dữ liệu (training image, audio, sensor), một kỹ thuật phổ biến là cộng nhiễu Gaussian: \( x' = x + \epsilon \) với \( \epsilon \sim \mathcal{N}(0, \sigma^2) \). Model học cách bền vững với nhiễu nhỏ — đây là một dạng regularization. Trong diffusion model (Stable Diffusion, DALL·E), nhiễu Gaussian là trung tâm: ảnh được "phá huỷ" dần bằng cách cộng noise Gaussian qua nhiều bước, sau đó model học cách đảo ngược.
Weight initialization — Xavier / He
Khi tạo neural network, weight ban đầu thường được sample từ phân phối chuẩn (hoặc uniform) với mean 0 và một std được chọn cẩn thận:
- Xavier / Glorot init (Glorot & Bengio, 2010) — phù hợp với activation đối xứng (tanh, sigmoid). Weight sample từ \( \mathcal{N}(0, \frac{2}{n_{in} + n_{out}}) \).
- He init (He et al., 2015) — phù hợp với ReLU. Weight sample từ \( \mathcal{N}(0, \frac{2}{n_{in}}) \). Hiện là default cho PyTorch
nn.Linear/nn.Conv2dkhi dùng ReLU.
Mục tiêu: giữ variance của activation và gradient ổn định qua các lớp, tránh vanishing / exploding gradient ở thời điểm khởi tạo.
Variational Autoencoder (VAE)
VAE (Kingma & Welling, 2013, arXiv:1312.6114) giả định latent variable \( z \sim \mathcal{N}(0, I) \) — phân phối chuẩn đa chiều với mean 0 và covariance đơn vị. Encoder dự đoán \( \mu \) và \( \sigma \) cho mỗi sample, decoder tạo lại dữ liệu từ \( z \) sampled. Loss có 2 phần: reconstruction + KL divergence so với \( \mathcal{N}(0, I) \).
Linear regression — giả định residual normal
Linear regression giả định \( y = X\beta + \epsilon \) với \( \epsilon \sim \mathcal{N}(0, \sigma^2) \) — sai số phần dư là Gaussian. Giả định này không cần thiết để fit (OLS chỉ cần residual có mean 0 và variance bằng nhau), nhưng cần thiết để các test thống kê về hệ số (t-test, confidence interval) hợp lệ. Thực hành: vẽ QQ-plot của residual sau khi fit để kiểm tra.
Gaussian Naive Bayes
Naive Bayes giả định feature độc lập có điều kiện theo label. Gaussian Naive Bayes giả định thêm: mỗi feature liên tục, theo phân phối chuẩn riêng cho từng class. Model học \( \mu \) và \( \sigma \) cho mỗi (feature, class) rồi dùng PDF để tính likelihood. Nhanh, ít tham số, baseline tốt cho text / sensor data. Hàm: sklearn.naive_bayes.GaussianNB.
Batch Normalization và Layer Normalization
Hai lớp này chuẩn hoá activation về mean 0, std 1 (trong batch hoặc trong layer) trước khi cho qua layer tiếp theo — chính là phép z-score được tích hợp vào kiến trúc model.
Code Python với statistics.NormalDist
Bài này chưa dùng NumPy. Python standard library có sẵn module statistics với class NormalDist (Python 3.8+) và module random với hàm random.gauss. Đủ dùng cho các phép cơ bản.
Sample 5 số từ \( \mathcal{N}(0, 1) \):
import random
random.seed(42)
samples = [random.gauss(0, 1) for _ in range(5)]
print(samples)
# [0.27..., -1.01..., -0.41..., -0.34..., 1.32...]
# Giá trị cụ thể phụ thuộc bản Python; seed giúp tái lập.
Dùng NormalDist để tính PDF và CDF:
from statistics import NormalDist
# Phân phối chuẩn N(70, 10) — như ví dụ điểm thi
dist = NormalDist(mu=70, sigma=10)
print(dist.pdf(85)) # mật độ tại x=85
print(dist.cdf(85)) # P(X <= 85), khoảng 0.9332
print(1 - dist.cdf(85)) # P(X > 85), khoảng 0.0668
print(dist.cdf(80) - dist.cdf(60)) # P(60 <= X <= 80), khoảng 0.6827
Tính z-score bằng tay và kiểm chứng với CDF của standard normal:
from statistics import NormalDist
x, mu, sigma = 85, 70, 10
z = (x - mu) / sigma
print(z) # 1.5
std_normal = NormalDist(0, 1)
print(std_normal.cdf(z)) # 0.9331927987... — top ~6.7%
Verify quy tắc 68-95-99.7 bằng tích phân (CDF) thay vì sampling:
from statistics import NormalDist
n = NormalDist(0, 1)
for k in (1, 2, 3):
p = n.cdf(k) - n.cdf(-k)
print(f"mu +/- {k} sigma: {p:.4f}")
# mu +/- 1 sigma: 0.6827
# mu +/- 2 sigma: 0.9545
# mu +/- 3 sigma: 0.9973
Trong các bài Module 4 (NumPy) và sau, chúng ta sẽ thay random.gauss bằng numpy.random.normal hoặc numpy.random.default_rng().normal() để sample vector / ma trận lớn nhanh hơn nhiều.
Bài tập
- Sample 1000 số từ \( \mathcal{N}(0, 1) \) bằng
random.gauss, sau đó tính tỉ lệ số rơi vào khoảng \( [-1, 1] \). So sánh với giá trị lý thuyết (~0.6827). Lặp lại với khoảng \( [-2, 2] \) và \( [-3, 3] \). - Với phân phối điểm thi \( \mathcal{N}(70, 10) \), tính z-score của điểm 85 và dùng
NormalDistđể cho biết điểm 85 vượt khoảng bao nhiêu phần trăm học sinh. - Một thiết bị đo cho kết quả phân phối \( \mathcal{N}(100, 2^2) \). Theo quy tắc 3 sigma, khoảng giá trị nào được coi là "bình thường"? Một lần đo cho ra 105 — có phải outlier không?
- Giải thích vì sao income không nên model bằng \( \mathcal{N} \). Đề xuất một phân phối thay thế và lý do.
Đáp án
-
Sai số so với lý thuyết là do n=1000 chưa thật lớn; chạy với n=100000 sẽ rất sát 0.6827, 0.9545, 0.9973.import random random.seed(0) samples = [random.gauss(0, 1) for _ in range(1000)] for k in (1, 2, 3): count = sum(1 for x in samples if -k <= x <= k) print(f"+/- {k} sigma: {count/1000:.3f}") # +/- 1 sigma: ~0.68 # +/- 2 sigma: ~0.95 # +/- 3 sigma: ~0.99 hoặc 1.00 -
from statistics import NormalDist dist = NormalDist(70, 10) x = 85 z = (x - dist.mean) / dist.stdev print(z) # 1.5 print(dist.cdf(x)) # 0.9332 # Vượt khoảng 93.3% học sinh, tức nằm trong top ~6.7%. - \( \mu = 100 \), \( \sigma = 2 \). Khoảng "bình thường" theo 3 sigma là \( [94, 106] \). Giá trị 105 có \( z = (105 - 100)/2 = 2.5 \) — vẫn nằm trong \( [94, 106] \), không phải outlier theo quy tắc 3 sigma. Tuy nhiên \( |z| = 2.5 \) đã thuộc ~1.2% dữ liệu xa nhất, đáng để chú ý nếu xuất hiện nhiều lần.
- Income không Gaussian vì phân phối thực tế lệch phải (right-skewed): phần lớn người có thu nhập tầm trung, một thiểu số rất nhỏ có thu nhập cực cao kéo đuôi phải dài. Mean lớn hơn median, và Gaussian sẽ buộc đối xứng — sai cấu trúc. Thay thế phổ biến: log-normal (log của income gần normal) hoặc Pareto cho phần đuôi giàu.
Tổng kết và bài tiếp theo
- Phân phối xác suất mô tả cách giá trị của một biến ngẫu nhiên phân bố. Liên tục dùng PDF, rời rạc dùng PMF.
- Phân phối chuẩn \( \mathcal{N}(\mu, \sigma^2) \) là hình chuông đối xứng quanh \( \mu \), độ rộng do \( \sigma \) kiểm soát. PDF: \( f(x) = \frac{1}{\sigma\sqrt{2\pi}} \exp(-\frac{(x-\mu)^2}{2\sigma^2}) \).
- Quy tắc 68-95-99.7 ước lượng nhanh tỉ lệ dữ liệu trong \( \mu \pm k\sigma \) với \( k = 1, 2, 3 \).
- Standard normal \( \mathcal{N}(0, 1) \) là dạng chuẩn hoá. Z-score \( z = (x - \mu)/\sigma \) là phép biến đổi đưa biến về standard normal — cũng chính là standardization trong tiền xử lý ML.
- Central Limit Theorem giải thích vì sao Gaussian xuất hiện khắp nơi: trung bình của nhiều mẫu độc lập (từ phân phối bất kỳ có variance hữu hạn) xấp xỉ Gaussian khi \( n \) lớn.
- Không phải dataset nào cũng Gaussian. Income, waiting time, count data thường không. Luôn kiểm tra bằng histogram + QQ-plot trước khi giả định.
- Use case AI: Gaussian noise (augmentation, diffusion), weight init (Xavier / He), latent variable VAE \( \mathcal{N}(0, I) \), residual của linear regression, Gaussian Naive Bayes, batch / layer normalization.
Bài tiếp theo: Bài 24 — Xác suất cơ bản và xác suất có điều kiện — nền tảng cho Naive Bayes, Bayesian inference và rất nhiều mô hình xác suất sau này.
- Python docs — statistics.NormalDist
- Python docs — random.gauss
- Wikipedia — Normal distribution
- Wikipedia — 68–95–99.7 rule
- Wikipedia — Central Limit Theorem
- Glorot & Bengio (2010) — Understanding the difficulty of training deep feedforward neural networks (Xavier init)
- He et al. (2015) — Delving Deep into Rectifiers (He init)
- Kingma & Welling (2013) — Auto-Encoding Variational Bayes (VAE)
- scikit-learn — GaussianNB
- scikit-learn — StandardScaler
- SciPy — scipy.stats.shapiro (Shapiro-Wilk test)
