==============================================================================================
  RAHUL'S ML BLOG -- notes on machine learning, worked out by hand                    est. 2026
==============================================================================================
  home | about | archive | glossary | contact
----------------------------------------------------------------------------------------------

  CHAPTER 3 . SORTING INTO BINS . PART 4 OF 4
  Picking Settings, Skewed Piles, and Averaging Many Classes
  ============================================================================================


  So far the world has been tidy.
  One sheet of breast lumps, one clean yes-or-no question, two groups of roughly equal size.
  Real problems are rarely so polite.
  So this closing post drags the series out into the messy world.
  It arms you for four things that world will throw at you.

  First: how do you tune a machine's settings without cheating by peeking at the exam?
  Tuning means choosing the numbers you set by hand before training, like the leash strength.
  The exam is the pile of rows you hold back to grade the final machine, never used for tuning.
  Second: what do you do when one bin outnumbers the other ninety-nine to one?
  There a proud 99% accuracy turns out to be worthless.
  Accuracy = the fraction of all rows the machine labels correctly.
  Third: which ruler do you trust when an outlier wanders in?
  A ruler here means a formula that rescales a column so columns of different sizes compare fairly.
  Fourth: how do you grade a machine that is sorting into not two bins but ten?
  Answer these and you have left the textbook behind and stepped onto the workshop floor.

  A fraud pile is wildly lopsided: 99,900 honest transactions and 100 thieves. The
  machine blocks 2,000 honest people by mistake. Score that on ROC:

      false-alarm rate = 2,000 / 99,900 = 2%

      honest pile:  #################################   99,900
      blocked:      ##                                   2,000  (a 2% sliver)

  Two percent. The ROC curve bulges into the top corner and the machine looks
  superb -- because it divided the 2,000 mistakes by the enormous honest pile,
  which drowns them.

  But you just enraged 2,000 innocent customers to net at most 100 thieves. Ask the
  question ROC hid -- precision: of everyone you blocked, how many were truly
  thieves?

      precision = 100 / (100 + 2,000) = 100 / 2,100 = 4.7%

  4.7%. On a lopsided pile, score with the precision-recall curve instead: it
  divides by what you flagged, not by the ocean, so the cost cannot hide.

  SETTINGS I PICK BY HAND (HYPERPARAMETERS)

  Some numbers inside a machine are set by rolling downhill on the leftover.
  The leftover means the error the machine measures on each pass and tries to shrink.
  Those self-tuned numbers are the dials, written beta, inside the S-curve machine.
  But other numbers are decided BEFORE training starts and are never touched by the leftover.
  These are the leash strength C, the neighbour-count k, the depth of a decision tree.
  C controls how hard the machine is held back from over-confidence; a small C pulls harder.
  k is how many nearby rows a neighbour-vote machine asks before deciding.
  Such numbers are settings you pick by hand.
  The standard label for a setting you pick by hand is hyperparameter.
  The machine cannot tune them for itself, because the leftover doesn't flow back through them.

    dials (beta):   tuned by the machine as it trains   <- the machine adjusts these
    settings:       chosen by you before training starts <- the machine never sees these

    examples:
      C in LogisticRegression(C=0.1)    <- leash strength
      k in KNeighborsClassifier(k=5)    <- how many neighbours to ask
      n_estimators in RandomForest      <- how many trees to grow

  GRID HUNT

  You have several settings, each with several candidate values.
  A grid lists every combination of those values.
  You try each combination and measure how well it does.
  But you must not use the sealed exam pile to measure.
  The exam pile is the rows held back, opened only once at the very end to grade the machine.
  So the fix is rotating folds, also called k-fold cross-validation.
  This means: split the study pile into, say, 5 equal strips.
  The study pile is everything except the sealed exam pile.
  For each combination, train on 4 strips and score on the 5th.
  Then rotate which strip is left out and repeat, so each strip is the scored one once.
  Then average the 5 scores into one reading for that combination.

    grid for C and k:
    +-------+----+----+----+
    |       |C=.1|C=1 |C=10|
    +-------+----+----+----+
    | k = 3 | .  | .  | .  |   each cell = a combination
    | k = 5 | .  | .  | .  |   each dot = average of 5 fold scores
    | k = 7 | .  | .  | .  |   pick the cell with the best score
    +-------+----+----+----+

  Three things go into making a grid hunt trustworthy:

    1. The range and spacing of each setting must be chosen up front.
       If C should be 0.01 the grid must include 0.01.
       A grid of {1, 10, 100} misses 0.01 entirely, so the best value can never be found.
       Both the candidate values and how finely you space them are decisions you make up front.
    2. Rotating folds (cross-validation) measure each combination reliably.
       A single train/score split might be lucky or unlucky.
       Rotating over 5 strips gives 5 independent readings and averages out that luck.
    3. A scoring rule must match the actual goal.
       Use accuracy if all mistakes cost the same; accuracy = fraction of rows labelled right.
       Use recall if missing sick people is catastrophic; recall = fraction of truly-sick rows caught.
       Use F1 if both false alarms and misses matter; F1 blends precision and recall into one number.

  A concrete 5-fold example for C=0.1 vs C=1.0, by pencil.
  Recall here is the fraction of truly-sick rows the machine catches.
  The study pile has 100 lumps, split into 5 strips of 20 each.

    strip   C=0.1 recall   C=1.0 recall
    ---------------------------------------
     1      0.92           0.95
     2      0.88           0.90
     3      0.94           0.89
     4      0.90           0.93
     5      0.86           0.82

    average:  (0.92+0.88+0.94+0.90+0.86)/5 = 4.50/5 = 0.900  (C=0.1)
              (0.95+0.90+0.89+0.93+0.82)/5 = 4.49/5 = 0.898  (C=1.0)

    C=0.1 wins by 0.002.  Without the 5-fold average, you might
    have picked strip 5 where C=1.0 scores only 0.82 -- a lucky
    stick in that strip's eye.  The fold average smooths out the
    luck and shows the true tendency: C=0.1 is slightly better
    at recall on this sheet.

     A grid pairs 4 candidate C-values with 3 candidate k-values, and scores every
     pair by 5-fold rotation (made-up).  How many full model-fits is that?

     check your slate:  pairs = 4 x 3 = 12;  fits = 12 x 5 folds = 60 complete fits.
     Each fit is a whole downhill solve -- this is why a clerk-room, not a single
     clerk, runs a grid hunt, and why the grid's size is a cost you choose.

  In code the whole hunt is a Pipeline -- scaler plus classifier -- handed to GridSearchCV;
  that code is at the end of the post, and it carries one subtle catch worth stating now:

  BUILD THE RULER INSIDE EACH FOLD, NOT BEFORE THE HUNT
     A subtle leak hides here.
     The ruler means the rescaling formula, built from a column's mean and spread.
     Suppose you scale all of X_train ONCE up front, then pass that pre-scaled pile in.
     Then every validation strip has already helped shape the ruler's mean and spread.
     Which means the strip you score on has leaked into the scaling.
     Therefore the fold scores come out optimistic -- even though the exam pile (X_test) is still sealed.
     The fix is to put the scaler INSIDE a Pipeline and pass raw X_train.
     Now the ruler is rebuilt from each fold's 4 training strips only.
     So the held-out strip is measured by a ruler it never touched.
     This is the same no-peeking rule that governs the whole series: build the ruler from
     study data only, never from the sealed exam pile -- here applied one level deeper,
     inside each fold.

  >> NOTE: THE EXAM PILE IS STILL SEALED
     GridSearchCV only ever touches the study pile (X_train).
     The exam pile (X_test) is opened exactly once at the very end to report the final score.
     But if you tune settings on the exam pile, you are leaking future information.
     Therefore the final score comes out optimistic -- the machine has already peeked.

  TWO KINDS OF SAME-RULER

  The series so far has leaned on the standard ruler.
  The standard ruler shifts each column to mean 0, then divides by its spread.
  In symbols: x~ = (x - mean) / spread, which centres a column at 0 with spread about 1.
  Its standard label is standard scaling, or StandardScaler.
  But there is a second popular ruler, which we will call pinch-to-fit.
  Pinch-to-fit squishes every column's values to sit strictly between 0 and 1.
  Its standard label is min-max scaling, or MinMaxScaler.

    standard ruler:  x~ = (x - mean) / spread        -> centred at 0, spread ~= 1
    pinch-to-fit:    x~ = (x - min)  / (max - min)   -> bounded in [0, 1]

  PINCH-TO-FIT IS FRAGILE AROUND OUTLIERS
     One outlier stretches the range. Say house areas run 500-3000 sq ft but one mansion
     hits 15000. The (max-min) denominator becomes 14500. Every other house gets squished
     into the bottom 17% of [0, 1]. The outlier sits at 1.0; the rest cluster near 0. The
     ruler works mathematically but destroys the relative spacing of normal values. The
     standard ruler shifts and stretches by the spread, so one distant outlier only weakly
     pulls the spread, and the bulk of the data keeps its shape.

    area values:  500, 520, 3000, 15000

    pinch-to-fit (max=15000, min=500):
      500   ->  0.000
      520   ->  0.001      <- normal house, near 0
      3000  ->  0.172      <- large house, still near 0
      15000 ->  1.000      <- outlier, fills the far end

    standard ruler (mean ~= 4755, spread ~= 6150):
      500   -> -0.70
      520   -> -0.69       <- normal houses spread out
      3000  -> -0.29
      15000 ->  1.67       <- outlier: unusual but doesn't crush others

  One rule binds both rulers: build the ruler from the study pile only, then apply it to both piles.
  The study pile is everything except the sealed exam pile.
  So compute min and max (for pinch-to-fit), or mean and spread (for the standard ruler), from the study pile only.
  Therefore the exam pile never helps shape the ruler that grades it.

  WHEN ALARM MATTERS MORE THAN MISSED

  First, two words for the two kinds of mistake.
  A MISSED is a truly-sick row the machine wrongly calls clear (the standard label is false negative).
  An ALARM is a truly-clear row the machine wrongly calls sick (the standard label is false positive).
  In cancer screening, recall is the north star, because a MISSED sick person is catastrophic.
  Recall = caught sick rows / all truly-sick rows, so it falls when MISSED rises.
  But in other settings, the ALARM is the catastrophe instead.

    precision v when ALARM is large   <- false positives pile up
    recall    v when MISSED is large  <- false negatives pile up

    cancer screening:  MISSED = cancer goes untreated    -> prioritise recall
    legal evidence:    ALARM  = innocent person jailed    -> prioritise precision
    email spam:        ALARM  = real email deleted        -> precision matters more
    fraud detection:   MISSED = fraud slips through -> loss -> recall matters

  PRECISION REDUCES ALARMS; RECALL REDUCES MISSES
     Precision = caught sick rows / all rows the machine calls sick, so it falls when ALARM rises.
     Choosing which to prioritise is a business or clinical decision, not a machine decision.
     The machine gives you a curve of deals.
     That curve is a sweep of the cutoff: at each cutoff it plots catch-rate against false-alarm-rate.
     So you pick the deal on that curve that matches what each kind of mistake actually costs.

  In fraud detection, MISSED means a fraudulent transaction slips through and the business absorbs the loss.
  ALARM means a legitimate transaction is blocked and the customer is frustrated.
  For most fraud systems the financial loss of a missed fraud is worse than the friction of a blocked purchase.
  Therefore recall is the primary score.
  But both kinds of mistake matter.
  So the precision-recall curve (next) shows the exact deal between them.

  SKEWED PILES AND THE PRECISION-RECALL CURVE

  The breast lump sheet leaned 63% well to 37% sick.
  That is tilted, but you could still stand on it.
  Now imagine the floor pitched almost vertical.
  A real fraud sheet might run 99.9% honest and 0.1% crooked.
  That is a SKEWED pile, meaning one class vastly outnumbers the other.
  Its standard label is class imbalance.
  And on ground this steep the ordinary scores quietly start lying to you.

    skewed fraud sheet: 100000 rows
      99900  normal transactions   (class 0)
        100  fraud transactions    (class 1)

    fool machine: always call "normal"
      accuracy = 99900 / 100000 = 99.9%   <- looks extraordinary
      recall   = 0 / 100 = 0.0%           <- catches no fraud at all

  The trade curve that sweeps the cutoff also goes by the name ROC curve.
  ROC plots catch-rate (recall) on the Y-axis against false-alarm-rate (FPR) on the X-axis.
  But the ROC curve has a problem with skewed piles.
  FPR means false-alarm-rate = ALARM / all truly-normal rows.
  In the fraud sheet that denominator is 99900, because 99900 rows are truly normal.
  So even if the machine raises 2000 false alarms, FPR = 2000/99900 = 0.02.
  Which looks small and makes the ROC curve bulge optimistically.
  Therefore the 2000 blocked customers are invisible in that tiny fraction.

  Every prediction lands in one of four boxes, named in plain words and by standard label:
    CAUGHT = truly-sick row, called sick   (true positive, TP)
    ALARM  = truly-clear row, called sick   (false positive, FP)
    MISSED = truly-sick row, called clear   (false negative, FN)
    CLEAR  = truly-clear row, called clear   (true negative, TN)

    ROC curve is blind to class imbalance because:
    FPR = ALARM / (ALARM + CLEAR)   <- denominator is huge; ALARM looks tiny

    Precision-recall curve avoids this:
    precision = CAUGHT / (CAUGHT + ALARM)  <- no TN in sight; focuses on the sick pile
    recall    = CAUGHT / (CAUGHT + MISSED) <- also ignores TN

  The precision-recall curve sweeps the same cutoff as the ROC curve.
  But it plots precision on the Y-axis and recall on the X-axis.
  Precision = caught sick rows / all rows called sick.
  Recall = caught sick rows / all truly-sick rows.
  A perfect machine hugs the top-right corner: high precision AND high recall together.
  A flat line near precision = (fraction of sick in the sheet) is the baseline.
  That baseline is the always-shout-sick fool, which calls every row sick.

    precision
     1 | # <- perfect (catch all, zero false alarms)
       | ##
       |   ##
       | - - - - <- baseline (= fraction of sick in the sheet)
     0 +----------- recall
       0              1

    area under precision-recall curve -> average precision (AP)

  USE PRECISION-RECALL CURVES WHEN THE PILE IS SKEWED
     Sometimes one class is rare -- fraud, disease in a healthy population, defects on a line.
     Then the precision-recall curve tells you more than the ROC curve.
     The reason: the precision-recall curve does not use the true-negative count (CLEAR) at all.
     The ROC curve's FPR is diluted by the massive normal pile in its denominator.
     But the precision-recall curve ignores that pile entirely.

  Computing that curve, and its area the average precision (AP), is three lines.
  That code is waiting at the end of the post.

  SCORING WITH THREE OR MORE BINS

  Cancer has subtypes.
  Handwritten digits have ten classes.
  Sentiment has three: positive, neutral, negative.
  So now there are multiple bins and one machine must sort into all of them.
  Earlier each prediction fell into one of four boxes (CAUGHT, ALARM, MISSED, CLEAR).
  With K classes that four-box table expands into a K x K grid, one row and column per class.
  Therefore each class gets its own precision, recall, and F1.
  Precision = caught rows of a class / all rows called that class.
  Recall = caught rows of a class / all rows truly of that class.
  F1 blends those two into one number for that class.
  The question becomes: how do you average those K scores into one number?

  IN HAND: a three-class scorecard.
  Type A scores F1 0.89, type B 0.67, type C 0.34.
  Class C holds only 10 rows against the others' 1000.
  This section asks how to roll three F1 numbers into one.
  And it shows the two answers disagree on purpose.

  TWO AVERAGING RULES

    three-class example: cancer type A, B, C
    +---------+-----------+--------+------+
    | class   | precision | recall |  F1  |  n (study rows)
    +---------+-----------+--------+------+
    | type A  |   0.90    |  0.88  | 0.89 |  1000
    | type B  |   0.70    |  0.65  | 0.67 |  1000
    | type C  |   0.30    |  0.40  | 0.34 |    10
    +---------+-----------+--------+------+

  TREAT-ALL-CLASSES-EQUAL averaging (macro): compute precision, recall, F1 per class, then
  take the plain average across classes with equal weight.

    macro F1 = (0.89 + 0.67 + 0.34) / 3 = 0.63

     Three classes score F1 of 0.80, 0.60, 0.40 (made-up).  Work the macro F1 -- the
     equal-weight average.

     check your slate:  macro F1 = (0.80 + 0.60 + 0.40) / 3 = 1.80 / 3 = 0.60.  Macro
     weights a 10-row class the same as a 1000-row class, so a weak rare class drags
     the score down on purpose -- that is the honest per-class picture.

    class C (only 10 rows) gets the same weight as class A (1000 rows)
    -> a low F1 on class C drags the average down strongly
    -> honest picture of per-class performance regardless of class size

  COUNT-EVERY-LABEL averaging (micro): pool all CAUGHT, ALARM, and MISSED counts across
  every class, then compute one precision, one recall, one F1 from those pooled totals.

    micro pools raw counts:
    total CAUGHT across A+B+C = 880 + 650 + 4   = 1534
    total ALARM  across A+B+C = 97  + 278 + 9   = 384
    total MISSED across A+B+C = 120 + 350 + 6   = 476

    micro precision = 1534 / (1534 + 384)  = 0.80
    micro recall    = 1534 / (1534 + 476)  = 0.76

    class A (1000 rows) dominates; class C (10 rows) barely registers

    Method                 How it weights classes              Use when
    --------------------   --------------------------------    --------------------------
    Macro (equal weight)   every class counts the same         all classes equally
                                                               important; or skewed pile
    Micro (count-weight)   large classes dominate              overall accuracy on all
                                                               labels matters

  MACRO WHEN CLASSES ARE EQUALLY IMPORTANT OR PILE IS SKEWED
     With a skewed pile, micro averaging is swamped by the majority class. If type C cancer
     (10 patients) scores F1=0.34 and the machine is otherwise excellent on the common
     types, micro averaging buries type C's failure. Macro averaging gives type C equal
     weight and forces the failure to show. That is the right signal when you care about
     catching every cancer type regardless of how rare it is.

  One call -- classification_report -- prints every per-class score plus the macro and
  weighted averages (code at the end). It hides one surprise worth flagging right here:

  >> NOTE: WHY classification_report SHOWS "accuracy", NOT "micro avg"
     On ordinary single-label data (each row has exactly one true class), every false
     positive for one class is simultaneously a false negative for another -- the pooled
     counts make micro precision, micro recall, and micro F1 all collapse to the same
     number: plain accuracy. So classification_report prints an "accuracy" row instead of a
     "micro avg" row. If you want the micro metric under its own name, compute it with
     precision_recall_fscore_support(..., average='micro'). (A true "micro avg" row only
     appears for multi-label problems, where the collapse doesn't happen.)

  SUMMARY: WHICH TOOL FOR WHICH PROBLEM

    +------------------------------+------------------------------------------+
    | Situation                    | Reach for                                |
    +------------------------------+------------------------------------------+
    | tuning C, k, depth           | grid hunt + rotating folds (GridSearchCV |
    |                              |  with cv=5) scored on a relevant metric  |
    | columns on wild scales       | standard ruler (mean 0, spread 1)        |
    | columns, but outliers present| standard ruler beats pinch-to-fit        |
    | balanced bins                | ROC / AUC; accuracy OK baseline          |
    | skewed pile (fraud, rare dz) | precision-recall curve + average prec.   |
    | ALARM is the catastrophe     | optimise precision                       |
    | MISSED is the catastrophe    | optimise recall                          |
    | 3+ classes, all equally imp. | macro averaging                          |
    | 3+ classes, size = importance| micro (or weighted) averaging            |
    +------------------------------+------------------------------------------+

  Nothing above needed a computer.  Here the hand examples are spelled out in Python
  so you can run each one and see the same numbers the post printed.

    --- 5-FOLD CV: C=0.1 VS C=1.0, RECALL PER FOLD ---
    c01_fold1, c01_fold2, c01_fold3, c01_fold4, c01_fold5 = 0.92, 0.88, 0.94, 0.90, 0.86
    c10_fold1, c10_fold2, c10_fold3, c10_fold4, c10_fold5 = 0.95, 0.90, 0.89, 0.93, 0.82

    c01_avg = (c01_fold1 + c01_fold2 + c01_fold3 + c01_fold4 + c01_fold5) / 5  # 0.900
    c10_avg = (c10_fold1 + c10_fold2 + c10_fold3 + c10_fold4 + c10_fold5) / 5  # 0.898
    C=0.1 WINS BY 0.002

    --- GRID SIZE: 4 C-VALUES X 3 K-VALUES X 5 FOLDS = 60 FITS ---
    c_choices, k_choices, folds = 4, 3, 5
    total_fits = c_choices * k_choices * folds   # 60

    --- FOOL MACHINE ON 99900-NORMAL / 100-FRAUD SHEET ---
    normal_rows, fraud_rows = 99900, 100
    fool_accuracy = normal_rows / (normal_rows + fraud_rows)  # 0.999
    fool_recall   = 0 / fraud_rows                             # 0.0 -- catches no fraud

    --- OUTLIER SCALING: 4 HOUSES (500, 520, 3000, 15000) ---
    area_A, area_B, area_C, area_D = 500, 520, 3000, 15000
    area_min, area_max = 500, 15000
    pinch_A = (area_A - area_min) / (area_max - area_min)   # 0.000
    pinch_B = (area_B - area_min) / (area_max - area_min)   # 0.001
    pinch_C = (area_C - area_min) / (area_max - area_min)   # 0.172
    pinch_D = (area_D - area_min) / (area_max - area_min)   # 1.000
    NORMAL HOUSES A AND B SQUISHED TO BOTTOM 17%; OUTLIER D FILLS THE FAR END

    --- MACRO VS MICRO: 3-CLASS CANCER SCORECARD ---
    f1_A, f1_B, f1_C = 0.89, 0.67, 0.34
    macro_f1 = (f1_A + f1_B + f1_C) / 3   # 0.633 -- class C (10 rows) drags it down

    caught_A, caught_B, caught_C = 880, 650, 4
    alarm_A,  alarm_B,  alarm_C  = 97,  278, 9
    missed_A, missed_B, missed_C = 120, 350, 6

    total_caught = caught_A + caught_B + caught_C   # 1534
    total_alarm  = alarm_A  + alarm_B  + alarm_C    # 384
    total_missed = missed_A + missed_B + missed_C   # 476

    micro_precision = total_caught / (total_caught + total_alarm)   # 0.800
    micro_recall    = total_caught / (total_caught + total_missed)  # 0.763
    CLASS A (1000 ROWS) DOMINATES THE POOL; CLASS C (10 ROWS) BARELY REGISTERS

  Nothing above needed a computer -- only pencils, clerks, and patience.  This last
  section is for the day you meet one: the same steps, spoken in Python.

  Three pieces, in the order the post met them: the grid hunt (done safely, scaler inside
  the pipeline), the precision-recall curve for skewed piles, and the many-bin scores.

  >> NEW TO PYTHON? Each named once:
       Pipeline([...])     -- chain steps so they are refit together, leak-free
       {'clf__C': [...]}   -- a dict of settings to try; 'clf__C' names a step's knob
       d['key']            -- look a value up in a dict by its name

  The grid hunt -- a Pipeline of scaler + classifier, handed to GridSearchCV. Pass RAW
  X_train, so the scaler is rebuilt inside each fold and nothing leaks:

    from sklearn.model_selection import GridSearchCV
    from sklearn.pipeline import Pipeline
    from sklearn.preprocessing import StandardScaler

    SCALER LIVES INSIDE THE PIPELINE SO IT IS REBUILT ON EACH FOLD'S
    TRAINING STRIP ONLY -- NEVER ON THE STRIP BEING SCORED
    pipe = Pipeline([
        ('scaler', StandardScaler()),
        ('clf',    LogisticRegression()),
    ])
    param_grid = {'clf__C': [0.01, 0.1, 1, 10], 'clf__penalty': ['l2']}
    gs = GridSearchCV(pipe, param_grid, cv=5, scoring='recall')
    gs.fit(X_train, y_train)          # pass RAW X_train, not pre-scaled
    best_C = gs.best_params_['clf__C']

  The precision-recall curve for a skewed pile, and its area (average precision):

    from sklearn.metrics import precision_recall_curve, average_precision_score

    y_proba = model.predict_proba(X_test_scaled)[:, 1]
    precision, recall, thresholds = precision_recall_curve(y_test, y_proba)
    ap = average_precision_score(y_test, y_proba)   # area under the curve

  And the many-bin scores -- one report, plus the micro/macro numbers asked for by name:

    from sklearn.metrics import classification_report, precision_recall_fscore_support

    print(classification_report(y_test, y_pred,
          target_names=['type A', 'type B', 'type C']))
    PER-CLASS PRECISION/RECALL/F1, THEN: ACCURACY, MACRO AVG, WEIGHTED AVG

    NOTE: FOR ORDINARY SINGLE-LABEL MULTICLASS, MICRO PRECISION = MICRO RECALL
    = MICRO F1 = ACCURACY, SO CLASSIFICATION_REPORT DOES NOT PRINT A "MICRO AVG"
    ROW -- IT PRINTS "ACCURACY" INSTEAD. TO SEE THE MICRO NUMBER BY NAME, ASK FOR IT:
    micro = precision_recall_fscore_support(y_test, y_pred, average='micro')
    macro = precision_recall_fscore_support(y_test, y_pred, average='macro')
    MICRO[:3] == (ACCURACY, ACCURACY, ACCURACY);  MACRO[:3] == THE EQUAL-WEIGHT BLEND

  WHERE THAT LEAVES US

  And there the series rests. Look back at the road: we began by turning a sliding number
  into a yes-or-no verdict, learned why a machine that catches nobody can still boast 63%
  accuracy, slid the cutoff to see every bargain between lives and money at once, leashed
  an over-confident machine and met a calmer one that draws its wall in a single stroke,
  and finally walked out into the skewed, many-binned, outlier-ridden world where the
  textbook scores stop being enough.

  None of it required Greek you had not earned. That was the whole point. The labels --
  logistic regression, ROC, regularisation, LDA, cross-validation -- were never the
  understanding; they were handles screwed on at the end, once the thing was already built
  and working in your hands. Keep that order and there is very little in this field you
  cannot teach yourself.

    Plain term used above                 Standard label
    -----------------------------------   ------------------------------------------
    setting I pick by hand                hyperparameter
    grid hunt                             grid search / GridSearchCV
    rotating folds                        k-fold cross-validation
    standard ruler                        standard scaling / StandardScaler
    pinch-to-fit ruler                    min-max scaling / MinMaxScaler
    skewed pile                           class imbalance / imbalanced dataset
    precision-catch curve                 precision-recall curve
    area under precision-recall curve     average precision (AP)
    treat-all-classes-equal averaging     macro averaging
    count-every-label averaging           micro averaging

----------------------------------------------------------------------------------------------
  IN THIS CHAPTER (Chapter 3 -- Sorting Into Bins):
    Part 1 -- The S-Curve, the Four-Box Table .
    Part 2 -- The Trade Curve .
    Part 3 -- Leash and Cloud .
    Part 4 (this post)

  Appendix: Classification Reference -- all terms in one place
  <- Back to all posts
----------------------------------------------------------------------------------------------

  home . source on GitHub
==============================================================================================