11  Statistik IV – Häufige Verteilungen [32:14]

Eigentlich jeder und jede kennt die Gauß- oder Normalverteilung mit ihrem symmetrischen Peak, die nach Carl Friedrich Gauß benannt ist, und so häufig beobachtet wird (z.B. bei der Größeverteilung von Menschen, Notenverteilung in Tests oder Messfehlern), dass sie auch Normalverteilung genannt wird. Die Exponential-Verteilung ist ebenfalls recht bekannt, sie ist asymmetrisch, wobei meist die rechte Flanke zu höheren Werten langgezogen ist. Die Exponentialverteilung ist grundlegend in der Natur und z.B. typische für Wachstums- oder Zerstörungsprozesse, also etwa wenn Asteroide wachsen, oder ein Berg als Kies in einem Fluss zerrieben wird. An die gleichmäßige Verteilung denkt man selten, obwohl sie ebenfalls häufig ist, z.B. ist das Rauschen einer Messung meist gleichmäßig um einen Mittelwert verteilt. Von der Poisson-Verteilung ist erstaunlich unbekannt, obwohl sie im Alltag oft beobachtet wird. Z.B. wie viele Menschen zu einem bestimmten Zeitpunkt gleichzeitig ein Geschäft betreten oder wie sich Regentropfen auf einzelnen Fliesen bei einsetzendem Regen summieren, ist meist Poisson verteilt. Es gibt noch weitere Verteilungen, jedoch werden mit diesen 4 schon viele wichtige Prozesse in den Geowissenschaften abgedeckt.

Zunächst stellen wir die verschiednen Verteilungen in einem Diagramm dar und legen Fits an diese an, um sie damit zu unterscheiden. Anschließend sehen wir in Beispielen, wo diese Verteilungen auftreten.

11.1 Grau ist alle Theorie: Gauß/Normal, Exponential, Gleichmäßig, Poisson Verteilungen

.random.normal(), .random.exponential(), .random.uniform(), .random.poisson() +ChatGPT Zunächst lernen wir 4 häufige Verteilungen kennen, und wie man diese unterscheidet, indem man einen einfach Fit an eine Häufigkeitsverteilung anlegt.

11.2 Das Rauschen bei Messungen

Im ersten Beispiel untersuchen wir das Rauschen bei einer typischen analytischen Messung, hier bei einer Mikrosonden-Messung. Wir stellen das Rauschen der Messung in einem Diagramm dar, und schauen dann, was für eine Verteilung dieses Rauschen hat.

11.3 Fallstricke bei der Bestimmung von Modal-Beständen

vibe coding mit ChatGPT

Bei der Bestimmung von Modalbeständen in z.B. einem Gesten muss man darauf achten, einen repräsentativen Ausschnitt auszuwählen. Ist der zu klein, kann man den Modalbestande selten vorkommender z.B. Minerale schnell falsch bestimmen. Warum das so ist, und wie man das visualisieren ohne selbst eine Zeile Code zu schreiben oder irgendetwas anderes zu tippen, lernen wir in diesem Beispiel mit der Technik des vibe codings.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from ipywidgets import interact, IntSlider, Checkbox
from scipy.stats import norm, poisson
import warnings
warnings.filterwarnings("ignore")

def plot_grid_with_stats(grid_size=5, points_count=100, fit_normal=False, fit_poisson=False):
    # --- Data generation ---
    x_points = np.random.uniform(0, grid_size, size=points_count)
    y_points = np.random.uniform(0, grid_size, size=points_count)
    x_bins = np.floor(x_points).astype(int)
    y_bins = np.floor(y_points).astype(int)

    # Count points per square
    counts = np.zeros((grid_size, grid_size), dtype=int)
    for x, y in zip(x_bins, y_bins):
        if 0 <= x < grid_size and 0 <= y < grid_size:
            counts[y, x] += 1
    flat_counts = counts.flatten()

    # Stats
    mean = flat_counts.mean()
    std = flat_counts.std(ddof=1)
    median = np.median(flat_counts)
    min_val, max_val = flat_counts.min(), flat_counts.max()
    total = flat_counts.sum()

    # --- Layout ---
    fig = plt.figure(figsize=(15, 6))
    gs = gridspec.GridSpec(1, 3, width_ratios=[2, 1.2, 1])

    # --- Grid plot ---
    ax0 = fig.add_subplot(gs[0])
    for i in range(grid_size + 1):
        ax0.axhline(i, color='gray', linewidth=0.5)
        ax0.axvline(i, color='gray', linewidth=0.5)
    ax0.scatter(x_points, y_points, color='red', alpha=0.6)
    for row in range(grid_size):
        for col in range(grid_size):
            ax0.text(col + 0.5, row + 0.5, str(counts[row, col]),
                     ha='center', va='center', fontsize=10)
    ax0.set_xlim(0, grid_size)
    ax0.set_ylim(0, grid_size)
    ax0.set_aspect('equal')
    ax0.set_xticks(range(grid_size + 1))
    ax0.set_yticks(range(grid_size + 1))
    ax0.set_title(f"{points_count} Points in {grid_size}×{grid_size} Grid")
    ax0.grid(False)

    # --- Histogram plot ---
    ax1 = fig.add_subplot(gs[1])
    hist_vals, bins, _ = ax1.hist(flat_counts, bins=range(flat_counts.max() + 2),
                                   align='left', color='skyblue', edgecolor='black', label='Histogram')
    x_vals = np.arange(0, flat_counts.max() + 1)

    # Normal fit
    if fit_normal:
        mu, sigma = norm.fit(flat_counts)
        y = norm.pdf(x_vals, mu, sigma) * len(flat_counts)
        ax1.plot(x_vals, y, 'r-', label=f'Normal fit\nμ={mu:.2f}, σ={sigma:.2f}')

    # Poisson fit
    if fit_poisson:
        lambda_ = flat_counts.mean()
        y = poisson.pmf(x_vals, lambda_) * len(flat_counts)
        ax1.plot(x_vals, y, 'g--', label=f'Poisson fit\nλ={lambda_:.2f}')

    ax1.set_xlabel('Points per Square')
    ax1.set_ylabel('Number of Squares')
    ax1.set_title('Distribution of Points')
    ax1.legend()

    # --- Statistics panel ---
    ax2 = fig.add_subplot(gs[2])
    ax2.axis('off')
    text = (
        f"** Descriptive Stats **\n"
        f"Total Squares: {grid_size**2}\n"
        f"Total Points: {total}\n"
        f"Mean: {mean:.2f}\n"
        f"Std Dev: {std:.2f}\n"
        f"Median: {median:.0f}\n"
        f"Min: {min_val}\n"
        f"Max: {max_val}\n"
    )
    ax2.text(0, 1, text, va='top', ha='left', fontsize=11, family='monospace')

    plt.tight_layout()
    plt.show()

# --- UI ---
interact(
    plot_grid_with_stats,
    grid_size=IntSlider(min=2, max=20, step=1, value=5, description='Grid Size'),
    points_count=IntSlider(min=10, max=2000, step=10, value=100, description='Points'),
    fit_normal=Checkbox(value=False, description='Normal Fit'),
    fit_poisson=Checkbox(value=False, description='Poisson Fit')
);