Correlation

data analysis

Correlation

Definition & Overview

Correlation is a statistical measure that quantifies the strength and direction of the relationship between two variables. The most common measure, Pearson's correlation coefficient (r), ranges from -1.0 (perfect negative correlation) through 0.0 (no linear correlation) to +1.0 (perfect positive correlation). A correlation of 0.85 between two OSINT signals means they tend to move together strongly, while -0.85 means they move in opposite directions. Critically, correlation does not imply causation -- two variables may be correlated due to a shared underlying cause rather than a direct causal relationship.

Beyond Pearson's linear correlation, other measures capture different relationship types: Spearman's rank correlation (monotonic relationships), Kendall's tau (concordance of ordinal data), mutual information (general dependency), and distance correlation (non-linear relationships). The choice of correlation measure depends on the data type, distribution assumptions, and the nature of the relationship being investigated.

In the Prismatic Platform, correlation analysis is fundamental to OSINT signal synthesis, security threat correlation, and data quality assessment. The Blue Team's blue-signal-aggregator agent performs cross-domain signal correlation to identify relationships between seemingly unrelated events. The NABLA Infinity framework's Signal Plurality axiom uses correlation to determine source independence -- highly correlated sources may share a common upstream, reducing their collective evidential value.

Technical Deep Dive

Correlation Measures

MeasureRangeAssumptionsBest For
Pearson (r)[-1, 1]Linear, continuous, normalContinuous data
Spearman (rho)[-1, 1]MonotonicOrdinal/ranked data
Kendall (tau)[-1, 1]OrdinalSmall samples, ties
Point-Biserial[-1, 1]One binary, one continuousBinary + continuous
Cramers V[0, 1]CategoricalCategorical x categorical
Mutual Information[0, inf)NoneAny dependency

Signal Correlation Engine

defmodule PrismaticOsintCore.CorrelationEngine do
  @moduledoc """
  Computes statistical correlations between OSINT signals.
  Used by the Blue Team's signal-aggregator for cross-domain
  correlation and by NABLA for source independence assessment.
  """

  @type correlation_result :: %{
    signal_a: String.t(),
    signal_b: String.t(),
    pearson_r: float(),
    significance: float(),
    sample_size: non_neg_integer(),
    interpretation: atom()
  }

  @spec pearson([number()], [number()]) :: {:ok, float()} | {:error, atom()}
  def pearson(xs, ys) when length(xs) == length(ys) and length(xs) >= 3 do
    n = length(xs)
    mean_x = Enum.sum(xs) / n
    mean_y = Enum.sum(ys) / n

    covariance = Enum.zip(xs, ys)
    |> Enum.map(fn {x, y} -> (x - mean_x) * (y - mean_y) end)
    |> Enum.sum()

    std_x = :math.sqrt(Enum.map(xs, fn x -> (x - mean_x) ** 2 end) |> Enum.sum())
    std_y = :math.sqrt(Enum.map(ys, fn y -> (y - mean_y) ** 2 end) |> Enum.sum())

    if std_x > 0 and std_y > 0 do
      {:ok, covariance / (std_x * std_y)}
    else
      {:error, :zero_variance}
    end
  end

  def pearson(xs, ys) when length(xs) != length(ys), do: {:error, :length_mismatch}
  def pearson(_, _), do: {:error, :insufficient_data}

  @spec spearman([number()], [number()]) :: {:ok, float()} | {:error, atom()}
  def spearman(xs, ys) do
    ranked_x = rank(xs)
    ranked_y = rank(ys)
    pearson(ranked_x, ranked_y)
  end

  @spec correlate_signals(String.t(), String.t(), [map()]) :: {:ok, correlation_result()}
  def correlate_signals(signal_a_id, signal_b_id, time_series) do
    values_a = Enum.map(time_series, &Map.get(&1, signal_a_id, 0))
    values_b = Enum.map(time_series, &Map.get(&1, signal_b_id, 0))

    case pearson(values_a, values_b) do
      {:ok, r} ->
        {:ok, %{
          signal_a: signal_a_id,
          signal_b: signal_b_id,
          pearson_r: r,
          significance: approximate_p_value(r, length(values_a)),
          sample_size: length(values_a),
          interpretation: interpret_correlation(r)
        }}

      {:error, reason} ->
        {:error, reason}
    end
  end

  defp rank(values) do
    values
    |> Enum.with_index()
    |> Enum.sort_by(fn {v, _} -> v end)
    |> Enum.with_index(1)
    |> Enum.sort_by(fn {{_, orig_idx}, _} -> orig_idx end)
    |> Enum.map(fn {_, rank} -> rank * 1.0 end)
  end

  defp interpret_correlation(r) when abs(r) >= 0.8, do: :strong
  defp interpret_correlation(r) when abs(r) >= 0.5, do: :moderate
  defp interpret_correlation(r) when abs(r) >= 0.3, do: :weak
  defp interpret_correlation(_r), do: :negligible

  defp approximate_p_value(r, n) when n > 4 do
    t = r * :math.sqrt((n - 2) / (1 - r * r))
    2.0 * (1.0 - students_t_cdf(abs(t), n - 2))
  end
  defp approximate_p_value(_, _), do: 1.0

  defp students_t_cdf(t, _df) when t > 3.5, do: 0.999
  defp students_t_cdf(t, _df) when t > 2.5, do: 0.99
  defp students_t_cdf(t, _df) when t > 1.96, do: 0.975
  defp students_t_cdf(_t, _df), do: 0.5
end

Correlation in Source Independence Assessment

CorrelationIndependenceNABLA Signal Plurality
r < 0.3IndependentFull signal plurality credit
0.3 <= r < 0.7Partially dependentReduced plurality credit
r >= 0.7DependentTreated as single signal source

Architecture & Implementation

The correlation engine is designed for two primary use cases within the platform. First, OSINT signal correlation identifies relationships between intelligence signals from different tools. When multiple tools report findings about the same entity, the correlation engine determines whether those findings are genuinely independent (supporting Signal Plurality) or derived from a shared upstream source (reducing their combined evidential value).

Second, the Blue Team's cross-domain signal aggregation uses correlation to detect attack patterns that span multiple observable dimensions. A correlation between unusual DNS queries and unusual authentication failures might indicate a coordinated attack, even if each signal individually falls below alert thresholds. The blue-signal-aggregator agent computes correlation matrices across all monitored signal channels in real time.

The engine supports both batch correlation (computing a full correlation matrix for historical analysis) and streaming correlation (updating correlation estimates as new signals arrive). Streaming correlation uses an exponentially weighted moving average approach, giving more weight to recent observations while maintaining a running estimate.

Usage in Prismatic Platform

The OSINT toolbox uses correlation analysis when presenting multi-source investigation results. If two tools return highly correlated data about a target entity, the dashboard highlights this correlation and adjusts the composite confidence score accordingly -- highly correlated sources provide less incremental confidence than independent sources.

The Perimeter security rating computes correlation between security dimensions to identify organizations with systemic security weaknesses. An organization might have correlated failures across TLS configuration, DNS security, and email authentication, suggesting a common root cause (e.g., lack of security staff) rather than three independent issues.

The DD pipeline tracks entity attribute correlations over time. If an entity's financial data and public registry data become unexpectedly uncorrelated (after being historically correlated), this divergence is flagged as a potential data quality issue or a signal of changed circumstances worth investigating.

Cross-References

  • Covariance - unstandardized measure of joint variability
  • Confidence Score - reliability metric informed by correlation
  • Cross-Tabulation - categorical data analysis
  • Anomaly Detection - detecting unexpected correlation changes
  • Chart - scatter charts for visualizing correlations
  • Livebooks: livebooks/domains/data_analysis/ - statistical analysis lab
  • Academy: Statistical reasoning and OSINT signal analysis

Created by Tomas Korcak (korczis) | GitHub