KL(Kullback-Leibler)散度及其python实现

目的:描述两个概率分布P和Q之间的差异

计算方法:用P拟合Q:P对Q的散度 = 交叉熵 - P熵
D K L ( p ∥ q ) = H ( p , q ) − H ( p ) = − ∑ x p ( x ) log ⁡ q ( x ) − ∑ x − p ( x ) log ⁡ p ( x ) = − ∑ x p ( x ) ( log ⁡ q ( x ) − log ⁡ p ( x ) ) = − ∑ x p ( x ) log ⁡ q ( x ) p ( x ) \begin{aligned} D_{K L}(p \| q) &=H(p, q)-H(p) \\ &=-\sum_{x} p(x) \log q(x)-\sum_{x}-p(x) \log p(x) \\ &=-\sum_{x} p(x)(\log q(x)-\log p(x)) \\ &=-\sum_{x} p(x) \log \frac{q(x)}{p(x)} \end{aligned} DKL(pq)=H(p,q)H(p)=xp(x)logq(x)xp(x)logp(x)=xp(x)(logq(x)logp(x))=xp(x)logp(x)q(x)(离散型概率分布)
D ( P ∥ Q ) = ∫ x P ( x ) ∗ [ log ⁡ ( P ( x ) Q ( x ) ) ] d x \mathrm{D}(\mathrm{P} \| \mathrm{Q})=\int_{x} P(x) *\left[\log \left(\frac{P(x)}{Q(x)}\right)\right] d x D(PQ)=xP(x)[log(Q(x)P(x))]dx(连续型概率分布)

意义:两个分布越接近(P越拟合Q),KL散度越小,两个分布越远(拟合越差),KL散度越大

性质
正定性: D K L ( p ∥ q ) ≥ 0 D_{K L}(p \| q) \geq 0 DKL(pq)0

不对称性:KL散度并不是一个真正的度量或者距离,因为它不具有对称性
D ( p ∥ q ) ≠ D ( q ∥ p ) D(p \| q) \neq D(q \| p) D(pq)=D(qp)各种散度中,Jensen-Shannon divergence(JS散度)是对称的。

代码实现

scipy.stats.entropy(pk, qk=None, base=None, axis=0)为给定的概率值计算分布的熵。

  • 如果仅给出概率p(x=k)=pk,则将熵计算为S = -sum(pk * log(pk), axis=axis)。
  • 如果qk不为None,则计算Kullback-Leibler散度S = sum(pk * log(pk / qk), axis=axis)。
  • 如果pk和qk的总和不为1,则此例程将对其进行标准化。
import numpy as np
import scipy.stats

import matplotlib.pyplot as plt

L =10  # 假设有十个类别
# x,y是从randint中采样的样本集合, 为方便将值作为对应样本类别出现的频次
x = [np.random.randint(1,11) for i in range(L)]
y = [np.random.randint(1,11) for i in range(L)]
print('x:',x)
print('y:',y)
# x: [1, 4, 8, 10, 4, 8, 2, 8, 7, 3]
# y: [5, 2, 4, 6, 9, 6, 4, 6, 2, 3]
# scipy计算函数可以处理非归一化情况,因此这里使用scipy.stats.entropy(x, y),无需手动归一化
KL = scipy.stats.entropy(x, y) 
print('KL散度值',KL) # KL散度值 0.2166112020167879
print(scipy.stats.entropy(y, x)) # 0.2622196813519766
print(scipy.stats.entropy(y, y)) #  0.0

# 按照公式手动实现
px = x / np.sum(x)
py = y / np.sum(y)# 归一化
kl= 0.0
for i in range(L):
    kl += px[i] * np.log(px[i]/py[i])
print('按照公式KL:',kl) # 按照公式KL: 0.2166112020167879

你可能感兴趣的:(python,机器学习)