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

PyMC3拟合双峰分布报TypeError: Unsupported dtype for TensorType: object及收敛问题

问题根因分析

初始报错原因

初始代码中使用scipy.stats.norm.pdf计算似然,该函数是基于numpy的数值计算接口,无法识别PyMC3内部的Theano张量类型参数,因此触发类型错误。编写自定义对数似然时必须全量使用pm.math下的张量运算函数,不能混合numpy/scipy的数值运算接口。

修改后参数不收敛的核心原因

自定义的正态分布概率密度公式存在严重错误:
正确的正态分布PDF公式为:
$$p(y|\mu,\sigma) = \frac{1}{\sigma\sqrt{2\pi}} \exp\left( -\frac{(y-\mu)2}{2\sigma2} \right)$$
你的代码存在3个问题:

  • 指数部分缺少负号,导致似然计算逻辑完全颠倒
  • 指数分母缺少系数2
  • 归一化项缺少$\sqrt{2\pi}$系数(该问题不影响极值位置,但前两个错误直接导致似然计算完全失效)

修复方案

方案1:修复自定义对数似然

import pymc3 as pm
import numpy as np
import theano.tensor as tt

# 生成模拟数据
mu1_true = 1
sigma1_true = 0.1
mu2_true = 2
sigma2_true = 0.2
w1_true = 2/3
n = 7500
n1 = int(n*w1_true)
n2 = n - n1
y = np.concatenate((np.random.normal(mu1_true, sigma1_true, n1), 
                    np.random.normal(mu2_true, sigma2_true, n2)))

# 修正后的正态分布PDF张量运算
def normpdf(y, mu, sigma):
    return (1 / (sigma * tt.sqrt(2 * np.pi))) * tt.exp(-tt.pow(y - mu, 2) / (2 * tt.pow(sigma, 2)))

def logp(mu, sigma, w, y):
    comp1 = w[0] * normpdf(y, mu[0], sigma[0])
    comp2 = w[1] * normpdf(y, mu[1], sigma[1])
    return tt.sum(tt.log(comp1 + comp2))

with pm.Model() as model:
    # 给mu加有序约束,避免标签交换问题
    mu = pm.Normal("mu", mu=np.array([0.5, 1.5]), sigma=1, shape=2, 
                  transform=pm.distributions.transforms.ordered)
    sigma = pm.HalfNormal("sigma", sigma=1, shape=2)
    w = pm.Dirichlet("w", a=np.array([1, 1]), shape=2)
    
    likelihood = pm.DensityDist('Likelihood', logp, observed=dict(mu=mu, sigma=sigma, w=w, y=y))
    # 优先用MCMC采样,比MAP点估计更稳定,避免陷入局部最优
    trace = pm.sample(2000, tune=1000, cores=2, return_inferencedata=True)

# 查看参数均值
print(trace.posterior.mean())

方案2:使用PyMC3内置Mixture分布(更稳定,无需自定义logp)

PyMC3已经内置了混合分布实现,无需手动编写似然,避免公式写错的问题:

with pm.Model() as model:
    mu = pm.Normal("mu", mu=np.array([0.5, 1.5]), sigma=1, shape=2,
                  transform=pm.distributions.transforms.ordered)
    sigma = pm.HalfNormal("sigma", sigma=1, shape=2)
    w = pm.Dirichlet("w", a=np.array([1, 1]), shape=2)
    
    # 定义混合分量
    comps = [pm.Normal.dist(mu=mu[i], sigma=sigma[i]) for i in range(2)]
    # 定义混合分布作为似然
    likelihood = pm.Mixture('Likelihood', w=w, comp_dists=comps, observed=y)
    
    trace = pm.sample(2000, tune=1000, cores=2, return_inferencedata=True)

print(trace.posterior.mean())

运行后得到的参数均值会非常接近真实值:mu接近[1,2],sigma接近[0.1,0.2],w接近[0.666, 0.333]。


内容的提问来源于stack exchange,提问作者Tarik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 23:21:02