Anomaly Detection Fundamentals
Evaluation Challenges
Read aloud is unavailable in this browser.
The Evaluation Paradox in Anomaly Detection
Evaluating anomaly detection systems is fundamentally harder than evaluating standard classifiers. The same properties that make anomalies worth detecting—rarity, diversity, evolving nature—create formidable obstacles for meaningful performance measurement.
Practitioners frequently encounter what we call the Evaluation Paradox:
We need labeled anomalies to evaluate our detector, but if we had reliable labels for all anomalies, we might not need a detector in the first place.
This paradox manifests across multiple dimensions:
- Class Imbalance: Anomalies represent < 1% of data, rendering accuracy meaningless
- Label Scarcity: Obtaining ground-truth labels is expensive and often incomplete
- Concept Drift: Anomaly patterns evolve, making historical evaluation less predictive
- Novel Anomalies: By definition, some anomalies have never been seen before
Mastering these challenges is essential for building anomaly detection systems that actually work in production.
Improper evaluation leads to dangerous outcomes: systems that appear effective in testing but fail catastrophically in production, wasted resources on tuning methods that don't generalize, and false confidence in detection capabilities. The evaluation methodology is as important as the detection algorithm itself.
Challenge 1: Extreme Class Imbalance
Anomaly detection operates in regimes of extreme class imbalance that break standard evaluation metrics. Understanding why requires careful analysis of what these metrics actually measure.
The Scale of Imbalance:
Typical anomaly ratios across domains:
- Credit card fraud: ~0.1-0.5% of transactions
- Network intrusion: ~0.01-1% of packets
- Manufacturing defects: ~0.1-5% of products
- Medical anomalies: ~0.01-10% depending on condition
In the most extreme cases (rare diseases, novel cyberattacks), anomaly rates may be below 0.001%.
Why Accuracy Fails:
Consider a dataset with 1% anomaly rate (99% normal, 1% anomaly):
A trivial classifier that predicts "normal" for everything achieves: $$Accuracy = \frac{TN + TP}{N} = \frac{99 + 0}{100} = 99%$$
This "99% accurate" classifier is completely useless—it detects zero anomalies. Accuracy is dominated by the majority class and provides no signal about detection capability.
The Base Rate Fallacy:
Even with non-trivial classifiers, high true positive rates can coexist with overwhelming false positive counts:
Example: 1 million transactions, 1% fraud rate (10,000 frauds)
- Detector with 90% recall, 99% precision sounds excellent
- Reality: TP = 9,000, FP = 90 (from the 99% precision)
- But wait: 99% precision means FP ≈ TP × (1 - precision)/precision ≈ 90-100
Let's recalculate properly:
- Total positives predicted = TP + FP
- If precision = 99%, then TP/(TP+FP) = 0.99
- With TP = 9,000: 9,000/(9,000+FP) = 0.99 → FP ≈ 90
Actually, this is reasonable. But consider:
- Same 90% recall, but 90% precision (still "good")
- TP = 9,000, FP = 1,000
- Analysts must review 10,000 alerts for 9,000 frauds
Now consider a more realistic scenario:
- 0.1% fraud rate (1,000 frauds in 1M transactions)
- 90% recall (900 TP), 90% precision (900/(900+FP) = 0.9)
- FP = 100... but how?
Actually with 999,000 normal transactions and even 0.01% FP rate:
- FP = 99,900 × 0.01 = 99.9...
The Real Issue: When the negative class is huge, even a tiny false positive rate creates enormous false positive counts.
A useful heuristic: if anomalies are 0.1% of data (1 in 1000), then to achieve a reasonable precision (say 50%), your classifier must have a false positive rate below 0.1%. At 1 million instances, even a 0.1% FP rate yields 1,000 false alarms matching the 1,000 true anomalies. This illustrates why anomaly detection requires exceptionally specific classifiers.
Metrics That Handle Imbalance:
Precision-Recall Framework:
$$Precision = \frac{TP}{TP + FP}$$
How many predicted anomalies are actually anomalies? (Measures false alarm burden)
$$Recall = \frac{TP}{TP + FN}$$
How many actual anomalies are detected? (Measures detection coverage)
Key insight: In imbalanced settings, precision is the harder metric because FP can be large relative to TP even with low FP rates.
Precision-Recall Curve (PR Curve):
Plot precision vs recall at different thresholds. The PR-AUC summarizes performance across thresholds.
Why PR curve over ROC curve?
- ROC uses FPR = FP/(FP+TN), which is dominated by the huge TN count
- A method that produces many FPs can still have low FPR due to massive TN
- PR curve exposes this: FPs directly hurt precision
- In anomaly detection, PR-AUC is the gold standard
F1-Score and F-beta:
$$F_1 = 2 \cdot \frac{Precision \cdot Recall}{Precision + Recall}$$
$$F_\beta = (1 + \beta^2) \cdot \frac{Precision \cdot Recall}{\beta^2 \cdot Precision + Recall}$$
- β > 1: Weights recall more (prioritize not missing anomalies)
- β < 1: Weights precision more (prioritize not burdening analysts)
Matthews Correlation Coefficient (MCC):
$$MCC = \frac{TP \cdot TN - FP \cdot FN}{\sqrt{(TP+FP)(TP+FN)(TN+FP)(TN+FN)}}$$
Ranges from -1 to +1; robust to imbalance but less intuitive than PR metrics.
| Metric | Formula | Imbalance Handling | When to Use |
|---|---|---|---|
| Accuracy | (TP+TN)/(TP+TN+FP+FN) | Poor | Never for anomaly detection |
| Precision | TP/(TP+FP) | Good | When FP cost is high |
| Recall | TP/(TP+FN) | Good | When missing anomalies is costly |
| F1-Score | Harmonic mean of P and R | Good | Balanced trade-off |
| PR-AUC | Area under PR curve | Excellent | Overall ranking quality |
| ROC-AUC | Area under ROC curve | Moderate | Less informative for anomaly detection |
| MCC | Correlation coefficient | Excellent | Single holistic measure |
Challenge 2: Label Scarcity and Incompleteness
Even when evaluation data exists, obtaining complete and accurate labels is typically infeasible. This creates systematic biases and constraints on evaluation methodology.
Sources of Label Scarcity:
1. Annotation Cost
Labeling anomalies often requires domain expertise:
- Medical anomalies: Physician review, potentially with diagnostic testing
- Financial fraud: Investigator analysis, customer confirmation
- Security incidents: Forensic analysis, impact assessment
At $10-100 per labeled instance, comprehensive labeling of millions of instances is prohibitive.
2. Delayed Feedback
Many anomalies are only confirmed long after occurrence:
- Fraud confirmed when customer complains (days to months)
- Security breach discovered during incident response (weeks to years)
- Equipment failure attribution after root cause analysis (days to weeks)
Evaluation on recent data may use incomplete labels.
3. Cannot Prove Absence
How do you label something as "definitely normal"?
- We observe an instance, nothing bad happens... but maybe it was an undetected anomaly?
- "Normal" label often means "not known to be anomalous" rather than "confirmed normal"
This creates systematic labeling bias: FN are systematically under-counted.
4. Label Noise
Even when labels exist, they may be incorrect:
- Human annotator errors (fatigue, ambiguity)
- Systematic biases (only flagging obvious anomalies)
- Evolving definitions (what counts as anomalous changes over time)
A particularly pernicious issue is verification bias: labels exist only for instances that analysts investigated, which are typically those flagged by an existing detector. This creates a dataset that is not representative of the full distribution—it's enriched in anomalies that the old detector caught and depleted in anomalies it missed. Evaluating a new detector on such data systematically overestimates performance on familiar anomaly types and underestimates on novel types.
Strategies for Imperfect Labels:
1. Treat Labels as Noisy
Model the label generation process:
- Let $\tilde{y}$ be the observed (noisy) label and $y$ be the true label
- Estimate noise parameters: $P(\tilde{y}=1|y=0)$ (false positive rate), $P(\tilde{y}=0|y=1)$ (miss rate)
- Correct evaluation metrics for estimated noise
Implementation: $$Recall_{corrected} = \frac{Recall_{observed} - P(\tilde{y}=1|y=0)}{1 - P(\tilde{y}=1|y=0) - P(\tilde{y}=0|y=1)}$$
2. Partial Label Evaluation
Evaluate only on the subset with reliable labels:
- Use high-confidence labels (e.g., analyst-confirmed with investigation)
- Acknowledge evaluation covers only a subset of true performance
- Report coverage: "Performance on 80% of confirmed anomaly types"
3. Semi-Supervised Evaluation
Use the structure of predictions to evaluate:
- Compare detector rankings: Does detector A consistently rank known anomalies higher than detector B?
- Relative evaluation possible without complete labels
4. Synthetic Anomaly Injection
Create artificial anomalies with known ground truth:
- Point-injection: Modify random instances to create obvious anomalies
- Pattern-injection: Insert known anomalous sequences
- Realistic generation: Use domain knowledge to synthesize plausible anomalies
Caveat: Synthetic anomalies may not match real anomaly distribution; results may not generalize.
5. Time-Delayed Evaluation
Wait for labels to mature before final evaluation:
- Deploy detector, collect predictions
- Wait for label feedback (fraud confirmations, incident reports)
- Evaluate on now-labeled data
Caveat: Cannot evaluate in real-time; evaluation lags deployment.
- •Coverage: What fraction of true anomalies are labeled? What about normal instances?
- •Delay: How much time passes between occurrence and labeling?
- •Verification Bias: Were labels generated based on existing detector output?
- •Annotator Agreement: For ambiguous cases, do experts agree?
- •Temporal Validity: Are old labels still valid for current patterns?
- •Type Coverage: Are all important anomaly subtypes represented in labels?
Challenge 3: Threshold Selection
Anomaly detectors output scores, not binary decisions. Converting scores to actionable alerts requires selecting a threshold, which is a non-trivial task with significant downstream impact.
The Threshold-Performance Tradeoff:
$$\text{Predicted Anomaly} = \mathbb{1}[s(x) > \tau]$$
where $s(x)$ is the anomaly score and $\tau$ is the threshold.
As threshold increases:
- Precision increases (fewer false alarms)
- Recall decreases (more missed anomalies)
As threshold decreases:
- Recall increases (catch more anomalies)
- Precision decreases (more false alarms)
The optimal threshold depends on business context, not just model properties.
Threshold Selection Methods:
1. Equal Error Rate (EER)
Find threshold where false positive rate equals false negative rate: $$\tau_{EER} = \arg\min_\tau |FPR(\tau) - FNR(\tau)|$$
Balanced but may not match business reality.
2. F1-Optimal Threshold
Find threshold maximizing F1-score: $$\tau_{F1} = \arg\max_\tau F_1(\tau)$$
Good default when precision and recall are equally important.
3. Cost-Based Threshold
Optimize based on explicit costs: $$\tau_{cost} = \arg\min_\tau [C_{FP} \cdot FP(\tau) + C_{FN} \cdot FN(\tau)]$$
Requires specifying:
- $C_{FP}$: Cost of investigating a false alarm
- $C_{FN}$: Cost of missing an anomaly
Example: If missing a fraud costs $10,000 and investigating a false alarm costs $50, then $C_{FN}/C_{FP} = 200$, and threshold should be set to tolerate 200 false alarms per missed fraud.
4. Operational Capacity Constraint
Set threshold based on available resources: $$\tau_{capacity} = \min{\tau : \text{Predicted positives}(\tau) \leq \text{Analyst capacity}}$$
If you can investigate 100 alerts per day, set threshold so at most 100 alerts fire.
5. Percentile-Based Threshold
Flag the top k% most anomalous instances: $$\tau_{%} = \text{Percentile}_{100-k}({s(x_i)})$$
Simple and automatic, but doesn't adapt to varying anomaly rates.
A critical mistake is optimizing threshold on the test set. This invalidates the evaluation by leaking test information into the decision process. Always select threshold on a validation set separate from the test set, or use cross-validated threshold selection.
Dynamic Thresholding:
In production, static thresholds often degrade as data distributions shift. Dynamic approaches maintain performance:
1. Statistical Process Control (SPC)
Recalculate threshold periodically based on recent score distribution: $$\tau_t = \mu_{scores,t} + k \cdot \sigma_{scores,t}$$
where $k$ controls sensitivity (typically 2-3 for 95-99.7% coverage).
2. Extreme Value Theory (EVT)
Model the tail of the score distribution using EVT: $$P(s > \tau) = 1 - F_{GEV}(\tau; \mu, \sigma, \xi)$$
Set threshold at desired false alarm rate under EVT model.
3. Adaptive Percentile
Maintain rolling percentile that adapts to recent data: $$\tau_t = \text{Percentile}{99}({s(x_i)}{i=t-W}^{t})$$
where $W$ is the window size.
Multi-Threshold Systems:
Instead of a single threshold, use multiple thresholds for tiered response:
- $\tau_{high}$: Critical alert, immediate investigation
- $\tau_{medium}$: Normal priority, queue for review
- $\tau_{low}$: Log for audit, no active investigation
This acknowledges uncertainty in borderline cases and allocates resources efficiently.
| Method | Optimizes For | Requires | Best When |
|---|---|---|---|
| EER | Balance FPR/FNR | Labeled validation set | No cost preference |
| F1-Optimal | Balanced precision/recall | Labeled validation set | Equal P/R importance |
| Cost-Based | Business outcome | Cost estimates + labels | Costs are known |
| Capacity Constraint | Operational limits | Capacity specification | Fixed investigation budget |
| Percentile | Top-k detection | Score distribution only | Unsupervised, no labels |
Challenge 4: Temporal Evaluation Issues
Time-series and streaming data introduce unique evaluation challenges that standard cross-validation ignores. Temporal integrity is essential for realistic performance estimates.
The Temporal Leakage Problem:
Standard k-fold cross-validation randomly splits data, potentially using future observations to predict past events:
Timeline: ─────t1────t2────t3────t4────t5────t6────>
│ │
│ └─ Test instance
│
└─ Training instance (from the FUTURE!)
This leakage inflates performance estimates because:
- Future patterns inform predictions of past events
- Model learns temporal patterns that won't be available in production
- Concept drift is hidden within folds
Temporal Split Strategies:
1. Simple Train/Test Split
Split data at a single time point:
[──────── Training ────────][──── Test ────]
t0 t_split T
Limitation: Single test period may not be representative; doesn't capture drift.
2. Walk-Forward Validation
Expanding window that maintains temporal order:
Fold 1: [Train ][Test]
Fold 2: [Train ][Test]
Fold 3: [Train ][Test]
Fold 4: [Train ][Test]
Each fold trains on all data up to test period, tests on subsequent period. Mimics production deployment: always use past to predict future.
3. Sliding Window Validation
Fixed window moves forward:
Fold 1: [Train][Test]
Fold 2: [Train][Test]
Fold 3: [Train][Test]
Fold 4: [Train][Test]
Captures performance variation over time; handles concept drift better than expanding window.
4. Time-Series Cross-Validation with Gap
Insert gap between train and test to prevent leakage:
[Train][Gap][Test]
Gap prevents leakage from autocorrelation or slow-moving features.
A good rule of thumb: the gap should be at least as long as the longest autocorrelation lag in your features. For daily data with weekly patterns, use at least 7-day gap. For hourly data with daily patterns, use at least 24-hour gap. When in doubt, longer gaps are safer (at cost of slightly less training data).
Concept Drift and Temporal Degradation:
Model performance typically degrades over time as data distributions shift:
$$\text{Performance}(t) = \text{Performance}(t_0) \cdot e^{-\lambda(t - t_0)}$$
where $\lambda$ is the drift rate.
Measuring Temporal Degradation:
Evaluate at multiple time horizons after training:
- Week 1 after training: PR-AUC = 0.85
- Week 4 after training: PR-AUC = 0.78
- Week 12 after training: PR-AUC = 0.65
This performance decay curve informs retraining frequency.
Reporting Requirements:
For temporal data, evaluation reports should include:
- Training period and test period explicitly stated
- Gap between training and test
- Performance at multiple time horizons (not just aggregate)
- Comparison to performance on more recent training (drift indicator)
Alert-Level vs. Event-Level Metrics:
For time series anomaly detection, distinguish:
- Point-level: Was each timestamp correctly classified?
- Event-level: Was each anomaly event detected? (even if boundary is imprecise)
Point-level metrics penalize boundary imprecision; event-level metrics focus on whether the anomaly was surfaced at all.
| Strategy | Description | Strengths | Weaknesses |
|---|---|---|---|
| Simple Split | Train before t, test after t | Simple, fast | Single test period |
| Walk-Forward | Expanding training window | More test points, mimics production | Computationally expensive |
| Sliding Window | Fixed-size moving window | Handles drift, equal weight | Loses early training data |
| With Gap | Any strategy + gap period | Prevents leakage | Requires gap calibration |
Challenge 5: Evaluating Detection of Novel Anomaly Types
A fundamental goal of anomaly detection is identifying novel anomalies—types never before seen. Evaluating this capability poses unique challenges because, by definition, we cannot label what we haven't conceived.
The Novelty Evaluation Paradox:
- To evaluate detection of type X, we need labeled instances of type X
- If type X is truly novel, we have no labeled instances
- Therefore, we cannot directly evaluate detection of truly novel types
Resolution Strategies:
1. Leave-One-Type-Out (LOTO) Evaluation
If you have labeled anomalies of multiple types, hold out one type during training:
Anomaly Types: A, B, C, D, E
LOTO-A: Train on B, C, D, E → Evaluate on A (novel)
LOTO-B: Train on A, C, D, E → Evaluate on B (novel)
... and so on
Report average performance across held-out types. This estimates generalization to unseen types.
2. Temporal Type Emergence
In historical data, identify when new anomaly types first appeared:
Timeline:
t0────────t1────────t2────────t3────────>
│ │
│ └─ Type B first appears
└─ Type A first appears
Train on data before t1, evaluate on Type A at t1. Train on data before t2, evaluate on Type B at t2.
This mirrors real-world experience: new attack types emerge over time.
3. Synthetic Novel Types
Generate anomalies that differ systematically from training anomalies:
- Modify existing anomaly prototypes in directions not seen in training
- Use domain knowledge to create plausible new variants
- Vary magnitude, duration, or pattern of known anomalies
Caveat: Synthetic novel anomalies may not match true novelty.
4. Asymmetric Evaluation
Report separate metrics for:
- Known types (seen in training): Measures recall on familiar patterns
- Unknown types (held out): Measures novelty detection capability
A good detector should excel at known types AND have reasonable coverage of novel types.
- •Unsupervised methods (learn normal, detect deviations)
- •Low-dimensional representations that generalize
- •Simple, robust features less prone to overfitting
- •Ensemble diversity (different methods, different blind spots)
- •Supervised methods (only detect trained patterns)
- •Complex, high-capacity models (overfit to known types)
- •Highly specific features (miss novel manifestations)
- •Single method (single blind spot affects all predictions)
Reporting Guidelines for Novel Type Evaluation:
When reporting anomaly detection performance, clearly state:
- Known vs Novel Split: How many anomaly types were in training vs held out?
- Type Coverage: What fraction of all anomaly types does training cover?
- Performance Breakdown: Separate metrics for known types vs novel types
- Generalization Gap: Difference in performance between known and novel types
- Type Diversity: How different are held-out types from training types?
Example Report:
Evaluation Summary:
- Training anomaly types: 5 (representing 78% of historical incidents)
- Held-out anomaly types: 2 (representing 22% of historical incidents)
Performance:
Known Types Novel Types Overall
Precision 0.92 0.71 0.85
Recall 0.88 0.62 0.79
PR-AUC 0.94 0.68 0.84
Generalization Gap: 26% relative recall reduction on novel types
Recommendation: Investigate feature engineering for novel type generalization
This transparent reporting prevents overconfidence in novelty detection capability.
Challenge 6: Benchmark Dataset Limitations
Standard benchmark datasets, while convenient for algorithm comparison, suffer from systematic issues that limit their predictive value for real-world performance.
Common Benchmark Issues:
1. Artificial Anomalies
Many benchmarks create anomalies artificially:
- Random point injection (not realistic)
- Simple transformations of normal data (too easy to detect)
- Downsampled minority classes from classification datasets
Real anomalies have complex, domain-specific characteristics that synthetic versions don't capture.
2. Label Quality Issues
Benchmark labels are often:
- Created by non-experts
- Based on outdated definitions
- Inconsistent across different versions of the dataset
Label noise in benchmarks can flip algorithm rankings.
3. Unrealistic Class Balance
To enable evaluation, benchmark anomaly rates are often artificially elevated:
- 5-10% anomaly rates common in benchmarks
- Real-world rates often 0.01-1%
Algorithms that perform well at 5% may struggle at 0.1%.
4. Limited Diversity
A few datasets dominate the literature:
- KDD Cup 99/NSL-KDD (network intrusion, but with known issues)
- Credit Card Fraud (limited features, specific domain)
- Various UCI datasets repurposed for anomaly detection
Overfitting to benchmark quirks is common.
A method achieving state-of-the-art on benchmarks may fail spectacularly in production, while a 'worse' method on benchmarks may excel in the real world. Always validate on domain-specific data before deployment decisions. Benchmarks are for algorithm development and relative comparison, not deployment confidence.
Best Practices for Benchmark Usage:
1. Use Multiple Benchmarks
Evaluate on diverse benchmark datasets; consistent improvement across benchmarks is more meaningful than state-of-the-art on one.
2. Report with Uncertainty
Report confidence intervals or multiple runs: $$\text{PR-AUC} = 0.82 \pm 0.03 \text{ (5 runs, different seeds)}$$
Benchmark rankings often change with random seed.
3. Compare Against Strong Baselines
Always include proven baselines:
- Isolation Forest (efficient, general-purpose)
- LOF (density-based, handles varying density)
- Autoencoder (deep learning baseline)
Claims of improvement should be relative to properly tuned baselines.
4. Sensitivity Analysis
Report performance across hyperparameter ranges, not just optimal settings:
- Methods requiring extensive tuning may not transfer to new domains
- Methods robust across hyperparameters are more trustworthy
5. Domain-Specific Evaluation
Before deployment, evaluate on:
- Data from your actual domain
- Realistic anomaly rates
- Labels from domain experts
- Temporal dynamics matching production
Benchmark performance is necessary but not sufficient for deployment confidence.
| Dataset | Domain | Instances | Anomaly Rate | Known Issues |
|---|---|---|---|---|
| NSL-KDD | Network intrusion | 148K | 48% | Unrealistic rate, dated attacks |
| Credit Card Fraud | Finance | 284K | 0.17% | Limited features, single source |
| SMTP/HTTP | Network | 95K | 0.03-2.5% | Simple anomalies, old data |
| Thyroid | Medical | 7.2K | 2.5% | Classification repurposed |
| Shuttle | Spacecraft | 58K | 7% | Synthetic, UCI classification |
A Practical Evaluation Framework
Given the challenges discussed, here is a comprehensive framework for rigorous anomaly detection evaluation.
Phase 1: Dataset Preparation
-
Document Label Provenance
- Who created labels? What process?
- What coverage? What delay?
- Any known biases?
-
Validate Data Quality
- Check for leakage (future information in features)
- Verify temporal ordering
- Identify missing or corrupted data
-
Characterize Distribution
- Anomaly rate and type distribution
- Feature distributions and correlations
- Temporal patterns and seasonality
Phase 2: Evaluation Design
-
Split Strategy
- For temporal data: walk-forward or sliding window with gap
- For i.i.d. data: stratified k-fold with matched imbalance
- Never use random split for temporal data
-
Metric Selection
- Primary: PR-AUC (standard), F1 at operational threshold (if threshold known)
- Secondary: Recall at fixed precision, latency metrics for time series
- Never: Accuracy alone
-
Threshold Protocol
- Select threshold on validation set only
- Document threshold selection criterion (cost-based, capacity, etc.)
- Report sensitivity to threshold choice
Phase 3: Experimental Protocol
-
Baseline Inclusion
- At least 2-3 strong baselines (IF, LOF, domain standard)
- Properly tuned, not strawman implementations
-
Hyperparameter Handling
- Tune on validation set (separate from test)
- Report sensitivity to key hyperparameters
- Document tuning process
-
Statistical Significance
- Multiple runs with different seeds
- Confidence intervals or significance tests
- Don't over-claim small differences
Phase 4: Reporting Standards
Report the following transparently:
- Dataset characteristics (size, anomaly rate, types)
- Split protocol (temporal strategy, holdout proportions)
- Metrics with uncertainty (mean ± std or CI)
- Threshold selection method
- Computational cost (training time, inference time)
- Known limitations
- •☐ Labels documented (source, coverage, potential bias)
- •☐ Temporal integrity maintained (no future leakage)
- •☐ PR-AUC reported (not just accuracy)
- •☐ Threshold selected on validation, not test set
- •☐ Multiple runs with confidence intervals
- •☐ Strong baselines included and properly tuned
- •☐ Novel anomaly performance separately reported
- •☐ Limitations and failure modes documented
KEEP LEARNING
There’s more to understand.
You’re reading the introduction. Create a free account to read the complete lesson, save notes and keep track of your progress.