Einführung
Ärger der Kunden durch Wartezeiten. Anrufe kommen zufällig an, daher folgt die Wartezeit X einer Exponentialverteilung – die meisten Wartezeiten sind kurz, einige sind schmerzhaft lang.
Nun würde ich argumentieren, dass Ärger nicht linear ist: Eine 10-minütige Wartezeit fühlt sich mehr als doppelt so schlimm an wie eine 5-minütige Wartezeit. Sie beschließen additionally, „Belästigungseinheiten“ als (Y = X²) zu modellieren.
Ganz einfach, oder? Nehmen Sie einfach das PDF von X, ersetzen Sie x durch (sqrt{y}) und fertig.
Sie planen es. Es sieht vernünftig aus – Spitzenwert nahe Null, langer Schwanz.
Aber was wäre, wenn Sie den CDF tatsächlich berechnen würden? Sie würden 1 erwarten, oder?
Das Ergebnis? 2.
Kurzer Numpy-Snippet zur Bestätigung
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import expon
# CDF of Exponential(1): F(x) = 1 - exp(-x) for x >= 0
def cdf_exp(x):
return 1 - np.exp(-x)
# Flawed (naive) pdf for Y = X²: simply substitute x = sqrt(y)
def wrong_pdf(y):
return np.exp(-np.sqrt(y)) # This integrates to 2!
# Fast numerical test of integral
from scipy.combine import quad
integral, err = quad(wrong_pdf, 0, np.inf)
print(f"Numerical integral ≈ {integral:.3f} (needs to be 1, nevertheless it's 2)")
# prints 2
Ihre neue Verteilung behauptet, dass jedes mögliche Ergebnis doppelt so wahrscheinlich ist, wie es sein sollte.
Das ist unmöglich … aber es ist passiert, weil Sie eine kleine Anpassung verpasst haben.
Diese „Anpassung“ ist der Jacobi-Wert – ein Skalierungsfaktor, der kompensiert, wie die Transformation die Achse an verschiedenen Punkten streckt oder staucht. Überspringen Sie es und Ihre Wahrscheinlichkeiten liegen. Fügen Sie es hinzu, und alles fügt sich wieder perfekt zusammen.
In diesem Beitrag bauen wir die Instinct auf, leiten die Mathematik Schritt für Schritt ab, sehen, wie sie bei der Histogrammentzerrung natürlich erscheint, visualisieren die Dehnung/Schrumpfung empirisch und beweisen sie mit Simulationen.
Die Instinct
Um zu verstehen, warum die Jacobi-Anpassung notwendig ist, verwenden wir eine greifbare Analogie: Stellen Sie sich eine Wahrscheinlichkeitsverteilung als eine feste Menge Sand – genau 1 Pfund – vor, die entlang einer Zahlenlinie verteilt ist, wobei die Höhe des Sandhaufens an jedem Punkt die Wahrscheinlichkeitsdichte darstellt. Der Gesamtsand ergibt immer 1, was einer Wahrscheinlichkeit von 100 % entspricht.
Wenn Sie nun die Zufallsvariable transformieren (z. B. von Sie fügen keinen Sand hinzu oder entfernen ihn. Sie dehnen oder komprimieren lediglich verschiedene Teile des Blattes.
In Bereichen, in denen die Transformation das Blatt komprimiert (ein langer Abschnitt der ursprünglichen Linie wird auf der neuen Y-Achse in ein kürzeres Section gequetscht), nimmt dieselbe Sandmenge jetzt weniger horizontalen Raum ein. Um die Gesamtsandmenge zu erhalten, muss der Haufen höher werden – die Dichte nimmt zu. Beispielsweise werden in der Nähe von Y=0 in der Quadrierungstransformation viele kleine X-Werte (von 0 bis 1) in einem winzigen Y-Intervall (0 bis 1) zusammengepfercht, sodass die Dichte dramatisch ansteigt.
Umgekehrt breitet sich der Sand in Bereichen, in denen die Transformation das Blatt ausdehnt (ein kurzes Section der ursprünglichen Linie wird in ein längeres auf der Y-Achse gezogen), über einen größeren Raum aus, wodurch der Stapel kürzer und flacher wird – die Dichte nimmt ab. Bei großem X (z. B. 10 bis 11) erstreckt sich Y von 100 bis 121 – einem viel größeren Intervall –, sodass die Dichte dort dünner wird.
Der entscheidende Punkt: Die gesamte Sandmenge bleibt genau 1 Pfund, egal wie man die Platte verformt. Ohne Berücksichtigung dieser lokalen Dehnung und Schrumpfung wäre Ihre neue Dichte inkonsistent, als ob Sie behaupten würden, Sie hätten nach der Verzerrung 2 Pfund Sand. Der Jacobi ist der mathematische Faktor, der die Höhe überall automatisch anpasst, um den Gesamtbetrag beizubehalten.
Die Mathematik
Lassen Sie uns die Instinct am Beispiel von ( Y = g(X) = X^2 ) formalisieren, wobei (
Betrachten Sie ein kleines Intervall um ( x ) mit der Breite ( Delta x ).
Die Wahrscheinlichkeit in diesem Intervall beträgt ungefähr ( f_X(x) Delta x ).
Nach der Transformation wird dies einem Intervall um ( y = x^2 ) mit der Breite zugeordnet
( Delta y approx left| g'(x) proper| Delta x = |2x| Delta x ).
Um die Wahrscheinlichkeit zu erhalten:
$$ f_Y(y) Delta y approx f_X(x) Delta x, $$
Additionally
$$ f_Y(y) approx frac{f_X(x)} g'(x) proper $$
Im Limes als ( Delta x to 0 ) wird dies genau:
$$ f_Y(y) = f_X(x) left| frac{dx}{dy} proper|, $$
wobei ( x = sqrt{y} ) (die Umkehrung) und
( frac{dx}{dy} = frac{1}{2sqrt{y}} ).
Einstecken:
$$ f_Y(y) = e^{-sqrt{y}} cdot frac{1}{2sqrt{y}} quad textual content{für } y > 0. $$
Ohne den Jacobi-Time period ( frac{1}{2sqrt{y}} ), das Naive
( f_Y(y) = e^{-sqrt{y}} )
integriert sich zu 2:
Sei ( u = sqrt{y} ), ( y = u^2 ), ( dy = 2u , du ):
$$ int_0^infty e^{-sqrt{y}} , dy $$
$$ = int_0^infty e^{-u}cdot 2u , du $$
$$= 2 int_0^infty ue^{-u} , du $$
$$ = 2 Gamma(2) = 2 cdot 1 = 2. $$
Die Jacobi-Anpassung gewährleistet $$ int_0^infty f_Y(y) , dy = 1. $$
Eine Anmerkung zu (Gamma)
(Gamma) ist die Darstellung der Fakultät für reelle Zahlen. $$Gamma(n) = (n-1)! quad textual content{für constructive ganze Zahlen } n$$
Dieser Skalierungsfaktor ( left| frac{dx}{dy} proper| ) gleicht genau die lokale Streckung und Schrumpfung der Achse aus.
Die allgemeine Type
Sei Y = g(X), wobei g eine streng monotone (steigende oder fallende) differenzierbare Funktion ist und X pdf ( f_X(x) ) hat.
Wir wollen das pdf ( f_Y(y) ) von Y.
Betrachten Sie ein kleines Intervall um x mit der Breite ( Delta x ).
Die Wahrscheinlichkeit in diesem Intervall beträgt ungefähr ( f_X(x) Delta x ).
Nach der Transformation y = g(x) wird dieses Intervall einem Intervall um y mit der Breite zugeordnet
( Delta y approx left| g'(x) proper| Delta x ).
Zurück zu der Gleichung, die wir zuvor entwickelt haben:
$$ f_Y(y) = f_X(x) left| frac{dx}{dy} proper|, $$
wobei wir die Umkehrbeziehung (x = h(y) = g^{-1}(y) ) verwenden, und
( frac{dx}{dy} = h'(y) = frac{1}{g'(x)} ).
Somit lautet die allgemeine Formel
$$ f_Y(y) = f_X(h(y)) left| h'(y) proper|. $$
Emperischer Beweis
Simulieren Sie das Dehnen und Schrumpfen
Der beste Weg, die Dehnung und Schrumpfung zu „spüren“, besteht darin, zwei Bereiche separat zu vergrößern: nahe Null (wo die Komprimierung stattfindet) und weiter außen (wo die Dehnung dominiert).
Wir erstellen vier Diagramme:
1. Ursprüngliches X-Histogramm, gezoomt auf kleine Werte (X < 1), mit gleichen kleinen Intervallen der Breite 0,1 – um die Quelle der Komprimierung anzuzeigen.
2. Entsprechendes Y = X²-Histogramm, nahe Null gezoomt – zeigt, wie diese winzigen X-Intervalle auf Y noch kleiner werden (schrumpfen).
3. Ursprüngliches X-Histogramm für größere Werte (X > 1) mit gleichen Intervallen der Breite 1 – um die Ursache der Streckung anzuzeigen.
4. Entsprechendes Y-Histogramm für große Werte – zeigt, wie diese X-Intervalle in riesige Y-Intervalle explodieren (Streckung).
Code
import numpy as np
import matplotlib.pyplot as plt
# Generate massive pattern for clear visuals
n = 50000
x = np.random.exponential(scale=1, dimension=n)
y = x**2
fig = plt.determine(figsize=(16, 10))
def plot_histogram(ax, knowledge, bins, density, coloration, alpha, title, xlabel, ylabel):
ax.hist(knowledge, bins=bins, density=density, coloration=coloration, alpha=alpha)
ax.set_title(title)
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
# Plot 1: X small values (compression supply)
ax1 = fig.add_subplot(2, 2, 1)
plot_histogram(ax1, x(x < 1), bins=50, density=True, coloration='skyblue', alpha=0.7,
title='Authentic X (zoomed X < 1)', xlabel='X', ylabel='Density')
# Equal-width intervals of 0.1 on small X
small_x_lines = np.arange(0, 1.01, 0.1)
for line in small_x_lines:
ax1.axvline(line, coloration='crimson', linestyle='--', alpha=0.8)
# Plot 2: Y close to zero (displaying shrink/compression)
ax2 = fig.add_subplot(2, 2, 2)
plot_histogram(ax2, y(y < 1), bins=100, density=True, coloration='lightcoral', alpha=0.7,
title='Y = X² close to zero (compression seen)', xlabel='Y', ylabel='Density')
# Mapped small intervals on Y (very slim!)
small_y_lines = small_x_lines**2
for line in small_y_lines:
ax2.axvline(line, coloration='crimson', linestyle='--', alpha=0.8)
# Plot 3: X bigger values (stretching supply)
ax3 = fig.add_subplot(2, 2, 3)
plot_histogram(ax3, x((x > 1) & (x < 12)), bins=50, density=True, coloration='skyblue', alpha=0.7,
title='Authentic X (X > 1)', xlabel='X', ylabel='Density')
# Equal-width intervals of 1 on bigger X
large_x_starts = (1, 3, 5, 7, 9, 11)
large_x_lines = large_x_starts + (s + 1 for s in large_x_starts)
for line in large_x_lines:
if line < 12:
ax3.axvline(line, coloration='crimson', linestyle='--', alpha=0.8)
# Plot 4: Y massive values (displaying stretch)
ax4 = fig.add_subplot(2, 2, 4)
plot_histogram(ax4, y((y > 1) & (y < 150)), bins=80, density=True, coloration='lightgreen', alpha=0.7,
title='Y = X² massive values (stretching seen)', xlabel='Y', ylabel='Density')
# Mapped massive intervals on Y (enormous gaps!)
large_y_lines = np.array(large_x_lines)**2
for line in large_y_lines:
if line < 150:
ax4.axvline(line, coloration='crimson', linestyle='--', alpha=0.8)
# Replace annotation types with modified font type
fig.textual content(0.5, 0.75, "X-axis shrinking → Density increasesnY-axis greater close to zero",
ha='middle', va='middle', fontsize=12, coloration='black',
fontstyle='italic', bbox=dict(facecolor='#f7f7f7', edgecolor='none', alpha=0.9))
fig.textual content(0.5, 0.25, "X-axis stretching → Density decreasesnY-axis decrease for giant values",
ha='middle', va='middle', fontsize=12, coloration='black',
fontstyle='italic', bbox=dict(facecolor='#f7f7f7', edgecolor='none', alpha=0.9))
fig.set_dpi(250)
plt.tight_layout()
plt.present()

Simulation der Jacobi-Anpassung
Um die Jacobi-Anpassung in Aktion zu sehen, simulieren wir Daten aus der Exponential(1)-Verteilung für X, berechnen Y = X² und zeichnen das empirische Histogramm von Y gegen das theoretische PDF für zunehmende Stichprobengrößen n auf. Wenn n wächst, sollte das Histogramm zum korrekt angepassten PDF konvergieren, nicht zum naiven.
Code
import numpy as np
import matplotlib.pyplot as plt
def correct_pdf(y):
return np.exp(-np.sqrt(y)) / (2 * np.sqrt(y))
def naive_pdf(y):
return np.exp(-np.sqrt(y))
# Pattern sizes to check
sample_sizes = (100, 1_000, 10_000)
fig, axs = plt.subplots(1, len(sample_sizes), figsize=(15, 5))
y_vals = np.linspace(0.01, 50, 1000) # Vary for plotting theoretical pdfs
for i, n in enumerate(sample_sizes):
# Pattern X ~ Exp(1)
x = np.random.exponential(scale=1, dimension=n)
y = x**2
# Plot histogram (normalized to density)
axs(i).hist(y, bins=50, vary=(0, 50), density=True, alpha=0.6, coloration='skyblue', label='Empirical Histogram')
# Plot theoretical pdfs
axs(i).plot(y_vals, correct_pdf(y_vals), 'g-', label='Appropriate PDF (with Jacobian)')
axs(i).plot(y_vals, naive_pdf(y_vals), 'r--', label='Naive PDF (no Jacobian)')
axs(i).set_title(f'n = {n}')
axs(i).set_xlabel('Y = X²')
axs(i).set_ylabel('Density')
axs(i).legend()
axs(i).set_ylim(0, 0.5) # For constant viewing
axs(i).grid(True) # Add grid to every subplot
# Set the determine DPI to 250 for greater decision
fig.set_dpi(250)
plt.grid()
plt.tight_layout()
plt.present()
Und das Ergebnis ist das, was wir erwarten.

Histogrammausgleich: eine reale Anwendung

Ein klassisches Beispiel, bei dem die Jacobi-Anpassung natürlich auftritt, ist die Histogrammentzerrung in der Bildverarbeitung.
Wir behandeln Pixelintensitäten X (typischerweise in ((0, 255))) als Stichproben aus einer Verteilung mit empirischem PDF basierend auf dem Bildhistogramm.
Das Ziel besteht darin, sie in neue Intensitäten Y umzuwandeln, sodass Y auf ((0, 255)) ungefähr gleichmäßig ist – dies verteilt die Werte und verbessert den Kontrast.
Die verwendete Transformation ist genau die skalierte kumulative Verteilungsfunktion (CDF) von X:
$$ Y = 255 cdot F_X(X) $$
wobei ( F_X(x) = int_{-infty}^x f_X
Warum funktioniert das? Es handelt sich um eine direkte Anwendung der Chance Integral Remodel (PIT):
Wenn ( Y = F_X(X) ) und X stetig ist, dann ist Y ~ Uniform((0,1)).
Eine Skalierung um 255 ergibt Uniform((0,255)).
Sehen Sie sich nun den Jacobianer bei der Arbeit an:
Sei ( g(x) = L cdot F_X(x) ) (( L = 255 )).
Die Ableitung ( g'(x) = L cdot f_X(x) ) (da die Ableitung der CDF das pdf ist).
Wenden Sie die Formel zur Änderung der Variablen an:
$$ f_Y(y) = f_X(x) / |g'(x)| = f_X(x) / (L f_X(x)) = 1/L $$
Das ( f_X(x) ) hebt sich perfekt auf und hinterlässt eine konstante (gleichmäßige) Dichte.
Der Jacobi-Faktor ( 1 / |g'(x)| ) flacht die Verteilung automatisch ab, indem er Bereiche kompensiert, in denen die ursprüngliche Dichte hoch oder niedrig battle.
Bei diskreten Bildern wird durch Rundung eine Annäherung erzielt, das Prinzip ist jedoch das gleiche.
Weitere Informationen zum Histogrammausgleich anhand von Beispielen finden Sie in meinem früheren Beitrag: Hier.
Abschließend
Die Jacobi-Anpassung ist einer dieser stillen Teile der Mathematik, die unnötig erscheinen – bis Sie sie überspringen und plötzlich Ihre Wahrscheinlichkeiten nicht mehr 1 ergeben. Ganz gleich, ob Sie Wartezeiten quadrieren, Energie anhand der Geschwindigkeit modellieren oder Bildhistogramme abflachen, die Transformation ändert nicht nur die Werte, sondern auch die Wahrscheinlichkeitsverteilung auf ihnen. Der Faktor ( left| frac{dx}{dy} proper| ) (oder sein multivariater Cousin, die Determinante) ist die genaue Kompensation, die die Gesamtwahrscheinlichkeit beibehält und gleichzeitig lokale Streckung und Stauchung berücksichtigt.
Wenn Sie das nächste Mal eine Zufallsvariable transformieren, denken Sie an den Sand auf der Gummiplatte: Verzerren Sie die Achse so weit Sie möchten, aber der gesamte Sand muss gleich bleiben. Die Jacobi-Anpassung ist die Regel, die dies ermöglicht.
Code
Referenzen und weiterführende Literatur
Ein paar Dinge, die ich nützlich fand.
