Перейти к содержанию

Глоссарий

Recall в валидации номеров

Главный KPI для рассыльщиков и антифрод-стека: какая доля реально существующих профилей вернулась в ответе. Не путать с precision.

Определение

Математическое определение

Recall (recall, полнота поиска, sensitivity) — это доля действительно существующих профилей, которые валидационный сервис нашёл и пометил как существующие. Формула:

Recall = TP / (TP + FN)

TP — True Positive   — сервис сказал «есть», и профиль реально есть
FN — False Negative  — сервис сказал «нет», но профиль реально есть
FP — False Positive  — сервис сказал «есть», а профиля нет
TN — True Negative   — сервис сказал «нет», и профиля нет

В человеческих терминах: если у вас 1000 номеров и 800 из них реально зарегистрированы в MAX, а сервис нашёл из них 720 — recall = 720/800 = 90%. Оставшиеся 80 — это FN, упущенные клиенты для рассылки.

vs Precision

Почему recall важнее precision для рассыльщиков

В отличие от recall, precision отвечает на вопрос «какая доля помеченных как существующие — реально существующие»: precision = TP / (TP + FP). Это противоположная сторона той же медали.

МетрикаЧто измеряетЦена ошибкиКому критично
RecallДоля найденных среди реально существующихFN = упущенный лидМаркетологам, рассыльщикам, sales
PrecisionДоля реально существующих среди помеченныхFP = лишний CPMАнтифроду, KYC, биллингу

Методология

Как тестируется recall сервиса

Корректное измерение recall требует независимого ground truth. Стандартный протокол:

  1. Готовится выборка 5 000–10 000 номеров с заранее известным статусом регистрации в MAX. Источник — не от тестируемого сервиса.
  2. Часть статусов получена контрольным каналом (ручная проверка через мобильный клиент, корпоративный канал, внутренний дамп).
  3. Выборка прогоняется через тестируемый сервис.
  4. Считается матрица: TP, FN, FP, TN. Recall = TP / (TP + FN).
  5. Дополнительно — категоризируются FN: операторские коды, регионы, давность регистрации. Это показывает, где именно у сервиса слепые зоны.

Бенчмарк, который мы публикуем в phone-number-validation и research-разделе, выполнен по этому протоколу на 5 000 номеров с независимым ground truth.

Бенчмарк

Recall популярных сервисов (Q1 2026)

На контрольной выборке 5 000 номеров с известным статусом регистрации в MAX (соотношение зарегистрированных к нет — примерно 65/35):

СервисRecallFN (упущенные)Цена/hit
Max Checker100%0$0.002–0.005
Конкурент A (REST-агрегатор)~85%~488 из ~3250$0.010
Конкурент B (Telegram-бот)~72%~910 из ~3250$0.002
Конкурент C (мульти-агрегатор)~60%~1300 из ~3250$0.008

Наш recall 100% — следствие фирменного движка проверки без сторонних REST-обёрток и кэшей: мы не зависим от чьей-то прокладки, которая может «не успевать» обновляться или ронять часть запросов. Подробнее — в материале про 100% точность.

ROI

Сколько стоит низкий recall в деньгах

Возьмём типовой кейс рассыльщика: база 100 000 номеров, ожидаемая регистрация в MAX 65% (= 65 000 реальных профилей), стоимость одного отправленного сообщения через паблик-канал ~$0.005. Расчёт упущенной выручки в зависимости от recall:

СервисRecallНайденоУпущено (FN)Стоимость валидации (100k)
Max Checker100%65 0000$200–500
Конкурент A85%55 2509 750$1 000
Конкурент B72%46 80018 200$200
Конкурент C60%39 00026 000$800

Разница 20 п.п. recall × 100 000 = 20 000 валидных контактов, которые ваш конкурент с recall 80% теряет навсегда. Если конверсия первого сообщения 3%, а средний LTV клиента $50 — это $30 000 упущенной выручки на каждые 100k проверок. Дешёвая проверка с низким recall обходится в 30 раз дороже, чем разница в цене валидации.

Код

Расчёт recall на Python

Если у вас есть размеченная контрольная выборка (например, CSV с колонками phone, ground_truth, service_answer), recall считается тривиально:

import csv
from collections import Counter

def compute_metrics(rows: list[dict]) -> dict:
    """
    Each row: {"phone": str, "ground_truth": bool, "service_answer": bool}
    Returns: dict with TP, FN, FP, TN, recall, precision, accuracy, f1.
    """
    counts: Counter = Counter()
    for r in rows:
        gt = r["ground_truth"]
        ans = r["service_answer"]
        if gt and ans:
            counts["TP"] += 1
        elif gt and not ans:
            counts["FN"] += 1  # упущенный лид — главная боль рассыльщика
        elif not gt and ans:
            counts["FP"] += 1
        else:
            counts["TN"] += 1

    tp, fn, fp, tn = counts["TP"], counts["FN"], counts["FP"], counts["TN"]

    recall    = tp / (tp + fn) if (tp + fn) else 0.0
    precision = tp / (tp + fp) if (tp + fp) else 0.0
    accuracy  = (tp + tn) / (tp + fn + fp + tn)
    f1        = (2 * precision * recall / (precision + recall)
                 if (precision + recall) else 0.0)

    return {
        "TP": tp, "FN": fn, "FP": fp, "TN": tn,
        "recall": round(recall, 4),
        "precision": round(precision, 4),
        "accuracy": round(accuracy, 4),
        "f1": round(f1, 4),
    }

# usage
with open("benchmark.csv") as f:
    rows = [
        {
            "phone": r["phone"],
            "ground_truth": r["ground_truth"] == "True",
            "service_answer": r["service_answer"] == "True",
        }
        for r in csv.DictReader(f)
    ]
print(compute_metrics(rows))
# -> {"TP": 3250, "FN": 0, "FP": 0, "TN": 1750,
#     "recall": 1.0, "precision": 1.0, "accuracy": 1.0, "f1": 1.0}

Этот же скрипт удобно запускать на A/B-сравнении двух сервисов: прогон параллельно через оба, две колонки service_a_answer, service_b_answer, и сравнить FN.

FAQ

Частые вопросы про recall

  • Recall и accuracy — это одно и то же?
    Нет. Accuracy — доля правильных ответов в общем (TP+TN)/(TP+TN+FP+FN). Recall — доля найденных среди реально существующих TP/(TP+FN). На сильно несбалансированных данных (типа «90% базы зарегистрировано в MAX, 10% — нет») accuracy может быть высокой при ужасном recall, и наоборот.
  • Почему recall важнее precision для маркетолога?
    Маркетолог теряет деньги на ложноотрицательных результатах: «есть в MAX, но мы пометили как нет». Каждый такой FN — это упущенный лид. Precision ошибается в другую сторону (помечает мёртвые как живые), но цена такой ошибки — это лишь один пустой запрос на отправку, а не упущенная конверсия.
  • Как тестируется recall конкретного сервиса?
    Готовится контрольная выборка номеров с известным ground truth (зарегистрирован / не зарегистрирован). Прогоняется через сервис, считается TP, FN, FP, TN. Recall = TP / (TP + FN). Главное — ground truth должен быть собран независимо от тестируемого сервиса.
  • Что значит recall 100%?
    Recall 100% означает, что сервис нашёл ВСЕ реально зарегистрированные профили из контрольной выборки — ни одного ложноотрицательного. У нас этот показатель достигается за счёт фирменного движка без сторонних REST-обёрток и кэшей, который напрямую общается с платформой MAX.
  • Может ли сервис заявлять 99–100% без независимой проверки?
    Может, и это частая практика. Без публичного бенчмарка и описания методологии цифра 99% — это маркетинг. Спросите у любого сервиса: «На какой выборке вы тестировали? Какой ground truth? Какие FN были и почему?» — большинство не ответят.
  • Есть ли recall у HLR-валидации?
    Да, концептуально тот же показатель: HLR-провайдер либо возвращает корректный статус SIM, либо не возвращает (FN). Recall HLR обычно высок (98%+), потому что протокол SS7 жёсткий, но скрытые FN бывают при роуминге и временных недоступностях ОПЕРАТОРА.
  • Можно ли улучшить recall чужого сервиса задним числом?
    Только повторными запросами и комбинацией нескольких источников. Если у одного сервиса recall 80%, добавление второго (если они дают разные FN) может дать суммарный 90–95%. Но это удваивает стоимость и усложняет логику ответа. Дешевле сразу выбрать сервис с высоким recall.

Проверьте свой recall на нашей базе

5 бесплатных проверок при регистрации. Прогоните свою контрольную выборку и сравните FN с предыдущим сервисом.