Precision

data analysis

Precision

Definition & Overview

Precision is a classification metric that measures the proportion of true positive predictions among all instances predicted as positive. Formally, precision = TP / (TP + FP), where TP is the count of true positives and FP is the count of false positives. A precision of 0.95 means that 95% of instances the model classified as positive were actually positive, while 5% were false alarms.

Precision is particularly important in contexts where false positives carry high costs. In OSINT intelligence, a false positive PEP match could trigger unnecessary enhanced due diligence, wasting investigator time and potentially damaging client relationships. In security scanning, false positive vulnerability alerts create alert fatigue, causing real threats to be overlooked. In sanctions screening, a false positive could freeze legitimate transactions, causing financial harm and regulatory scrutiny.

The trade-off between precision and recall (the proportion of actual positives correctly identified) is fundamental to classification system design. High precision with low recall means the system is conservative -- it catches fewer threats but rarely raises false alarms. High recall with low precision means the system is aggressive -- it catches most threats but generates many false alarms. The Prismatic Platform calibrates this trade-off based on the operational context, with sanctions screening favoring recall (missing a sanctioned entity is worse than investigating a false match) and PEP screening favoring balanced precision-recall.

Technical Deep Dive

Precision computation in the Prismatic Platform spans multiple subsystems: OSINT tool result quality assessment, PEP/sanctions matching accuracy, vulnerability scanner calibration, and entity resolution quality in the DD pipeline. Each subsystem maintains precision metrics that are tracked over time and used to tune detection thresholds.

defmodule PrismaticAnalytics.ClassificationMetrics do
  @moduledoc """
  Classification metrics computation for ML models and
  rule-based classifiers across the platform.
  """

  @type confusion_matrix :: %{
    true_positives: non_neg_integer(),
    false_positives: non_neg_integer(),
    true_negatives: non_neg_integer(),
    false_negatives: non_neg_integer()
  }

  @type metrics :: %{
    precision: float(),
    recall: float(),
    f1_score: float(),
    accuracy: float(),
    specificity: float()
  }

  @spec from_predictions([{term(), term()}]) :: confusion_matrix()
  def from_predictions(prediction_pairs) do
    Enum.reduce(prediction_pairs, %{
      true_positives: 0,
      false_positives: 0,
      true_negatives: 0,
      false_negatives: 0
    }, fn {predicted, actual}, acc ->
      case {predicted, actual} do
        {true, true} -> %{acc | true_positives: acc.true_positives + 1}
        {true, false} -> %{acc | false_positives: acc.false_positives + 1}
        {false, true} -> %{acc | false_negatives: acc.false_negatives + 1}
        {false, false} -> %{acc | true_negatives: acc.true_negatives + 1}
      end
    end)
  end

  @spec compute_metrics(confusion_matrix()) :: metrics()
  def compute_metrics(cm) do
    precision = safe_divide(cm.true_positives, cm.true_positives + cm.false_positives)
    recall = safe_divide(cm.true_positives, cm.true_positives + cm.false_negatives)
    f1 = safe_divide(2 * precision * recall, precision + recall)
    accuracy = safe_divide(
      cm.true_positives + cm.true_negatives,
      cm.true_positives + cm.false_positives + cm.true_negatives + cm.false_negatives
    )
    specificity = safe_divide(cm.true_negatives, cm.true_negatives + cm.false_positives)

    %{
      precision: precision,
      recall: recall,
      f1_score: f1,
      accuracy: accuracy,
      specificity: specificity
    }
  end

  @spec precision_at_k([{float(), boolean()}], pos_integer()) :: float()
  def precision_at_k(scored_results, k) do
    top_k = scored_results
      |> Enum.sort_by(fn {score, _} -> score end, :desc)
      |> Enum.take(k)

    relevant = Enum.count(top_k, fn {_, is_relevant} -> is_relevant end)
    safe_divide(relevant, k)
  end

  defp safe_divide(_numerator, 0), do: 0.0
  defp safe_divide(numerator, denominator), do: numerator / denominator
end

Precision tracking over time enables trend analysis and automatic threshold adjustment. The platform stores precision measurements with timestamps, enabling detection of model drift where precision degrades as input distributions shift.

defmodule PrismaticAnalytics.PrecisionTracker do
  @moduledoc """
  Tracks precision metrics over time for drift detection
  and automatic threshold adjustment.
  """

  use GenServer

  @ets_table :precision_metrics

  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, name: __MODULE__)
  end

  @impl true
  def init(_opts) do
    :ets.new(@ets_table, [:named_table, :ordered_set, :public, read_concurrency: true])
    {:ok, %{}}
  end

  @spec record(atom(), float(), map()) :: :ok
  def record(classifier, precision, metadata \\ %{}) do
    timestamp = System.system_time(:millisecond)
    entry = {timestamp, classifier, precision, metadata}
    :ets.insert(@ets_table, {timestamp, entry})

    check_drift(classifier, precision)
    :ok
  end

  @spec get_trend(atom(), pos_integer()) :: {:ok, [float()]}
  def get_trend(classifier, window_ms) do
    cutoff = System.system_time(:millisecond) - window_ms

    values =
      :ets.select(@ets_table, [
        {{:"$1", {:"$1", :"$2", :"$3", :_}},
         [{:andalso, {:>=, :"$1", cutoff}, {:==, :"$2", classifier}}],
         [:"$3"]}
      ])

    {:ok, values}
  end

  defp check_drift(classifier, precision) do
    {:ok, recent} = get_trend(classifier, 3_600_000)

    if length(recent) > 10 do
      avg = Enum.sum(recent) / length(recent)

      if precision < avg * 0.9 do
        :telemetry.execute(
          [:prismatic, :precision, :drift_detected],
          %{current: precision, average: avg, degradation: (avg - precision) / avg},
          %{classifier: classifier}
        )
      end
    end
  end
end

Architecture & Implementation

The precision tracking architecture integrates with the platform's telemetry and monitoring subsystems. Each classifier (PEP matcher, sanctions screener, vulnerability scanner) emits precision measurements after evaluation runs. These measurements feed into the PrecisionTracker GenServer, which maintains time-series data in ETS and checks for drift on every new measurement.

The architecture supports both online precision estimation (computed from production classifications with delayed ground truth labels) and offline precision evaluation (computed from labeled test sets during model validation). Online estimates are inherently noisier but provide real-time feedback, while offline evaluations provide authoritative benchmarks during model updates.

Usage in Prismatic Platform

Precision metrics drive operational decisions across the platform. The OSINT toolbox displays precision ratings for each tool, helping analysts assess result reliability. The Perimeter module uses precision-weighted scoring to discount findings from low-precision scanners.

defmodule PrismaticOsint.QualityAssessment do
  @moduledoc """
  Assesses OSINT tool result quality using precision metrics.
  Weights tool outputs by historical precision for aggregated scoring.
  """

  @spec weighted_score([{atom(), float(), float()}]) :: float()
  def weighted_score(tool_results) do
    # Each result: {tool_slug, raw_score, tool_precision}
    weighted_sum =
      Enum.reduce(tool_results, 0.0, fn {_tool, score, precision}, acc ->
        acc + score * precision
      end)

    total_precision = Enum.reduce(tool_results, 0.0, fn {_, _, p}, acc -> acc + p end)

    if total_precision > 0 do
      weighted_sum / total_precision
    else
      0.0
    end
  end
end

Cross-References

  • Percentile - Statistical distribution used to contextualize precision scores
  • Scatter Plot - Visualization technique for precision-recall curves
  • Property Test - Testing approach validating classifier precision bounds
  • Profiling - Performance measurement of classification pipelines
  • PEP - Politically exposed person screening where precision directly impacts operations

Created by Tomas Korcak (korczis) | GitHub