You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:构建依赖Laplace变量的无NaN截断Laplace/正态分布

How to Generate a Truncated Laplace-Dependent Variable Without NaNs

Problem Breakdown

Your current workflow generates full-range Laplace noise, adds it to your linear prediction, then discards out-of-bounds values by setting them to NaNs. This leads to data loss and defeats the goal of having every x map to a valid, bounded y. The fix is to generate noise that strictly stays within your constraints from the start.

Solution: Direct Truncated Laplace Sampling

Instead of post-processing with NaNs, we can generate truncated Laplace noise tailored to each x's bounds. This uses the inverse CDF method to efficiently produce samples that exactly follow the truncated Laplace distribution, ensuring no invalid values are created in the first place.

Full Modified Code

import numpy as np
from matplotlib import pyplot as plt
from scipy.stats import gaussian_kde, truncnorm

slope = 0.2237
intercept = 1.066
spread = 4.8719

def truncated_laplace(loc, scale, lower, upper, size):
    """Generate samples from a truncated Laplace distribution."""
    def laplace_cdf(z, loc, scale):
        """CDF for the Laplace distribution (loc = center, scale = spread)."""
        return 0.5 * (1 + np.sign(z - loc) * (1 - np.exp(-np.abs(z - loc)/scale)))
    
    # Calculate CDF values at our truncation bounds
    cdf_lower = laplace_cdf(lower, loc, scale)
    cdf_upper = laplace_cdf(upper, loc, scale)
    
    # Generate uniform samples between the two CDF values
    u = np.random.uniform(cdf_lower, cdf_upper, size=size)
    
    # Invert the CDF to get truncated Laplace samples
    z = np.empty(size)
    # Handle right half of the Laplace distribution (samples >= loc)
    mask_right = u >= 0.5
    z[mask_right] = loc - scale * np.log(2 * (1 - u[mask_right]))
    # Handle left half of the Laplace distribution (samples < loc)
    mask_left = ~mask_right
    z[mask_left] = loc + scale * np.log(2 * u[mask_left])
    
    return z

def dependency(x):
    y_lin = slope * x + intercept
    # Compute noise bounds relative to the linear prediction y_lin
    noise_lower = (slope / spread * 3 * x) - y_lin
    noise_upper = (slope * spread / 3 * x + 2 * intercept) - y_lin
    
    # Generate truncated noise tailored to each x's bounds
    noise = truncated_laplace(loc=0, scale=spread, lower=noise_lower, upper=noise_upper, size=len(x))
    
    # Calculate final y values
    y = y_lin + noise
    
    # Optional validation to ensure no values are out of bounds
    assert np.all(y >= slope / spread * 3 * x), "y values below lower constraint!"
    assert np.all(y <= slope * spread / 3 * x + 2 * intercept), "y values above upper constraint!"
    return y

# Generate x from truncated normal distribution
max_x = 100
min_x = 1
mean_x = 40
sigma_x = 25
x = truncnorm((min_x - mean_x)/sigma_x, (max_x - mean_x)/sigma_x, loc=mean_x, scale=sigma_x).rvs(5000)

# Generate y with no NaNs
y = dependency(x)

# Plotting (no need to filter NaNs anymore!)
xx = np.linspace(min_x, max_x, 100)
yy = slope * xx + intercept
lower = slope/spread*3*xx
upper = slope*spread/3*xx + 2*intercept

xy = np.vstack([x, y])
z = gaussian_kde(xy)(xy)
idz = z.argsort()
x_sorted, y_sorted, z_sorted = x[idz], y[idz], z[idz]

fig, ax = plt.subplots(figsize=(5, 5))
plt.plot(xx, upper, 'r-.', label='upper constraint')
plt.plot(xx, lower, 'r--', label='lower constraint')
ax.scatter(x_sorted, y_sorted, c=z_sorted, s=3)
plt.xlabel(r'$\bf X_{truncated\ normal}$')
plt.ylabel(r'$\bf Y_{truncated\ Laplace}$')
plt.plot(xx, yy, 'r', label='regression model')
plt.legend()
plt.tight_layout()
plt.show()

Key Improvements

  • No NaNs: Every x gets a valid y within your specified bounds—no data filtering required.
  • True Truncated Laplace: The sampling method ensures noise follows the exact truncated Laplace distribution, not just a filtered version of the full distribution.
  • Validation Checks: The assert statements confirm your constraints are respected (you can remove them in production for speed).

Quick Note on Bounds

We verified your constraints are valid for all x in [1, 100]: given your spread value (~4.87), lower(x) < y_lin < upper(x) always holds, so the truncation range is meaningful for every input.

内容的提问来源于stack exchange,提问作者M. Weeker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:53:19