在很多场合,经常会遇到KL散度这个概念,那么它到底是什么含义呢?如何定义的?又有哪些应用场景?最后如何用Python进行计算呢?
KL散度(Kullback-Leibler divergence,简称KLD):
KL散度是用于衡量分布P相对于分布Q的差异性。典型情况下,P表示数据的真实分布,Q表示数据的理论分布、估计的模型分布、或P的近似分布
注:这个指标不能用作距离衡量,因为该指标不具有对称性,DKL(P|Q) ≠ DKL(Q|P)
离散分布:
D K L ( P ∣ Q ) = ∑ i P ( i ) log P ( i ) Q ( i ) D_{KL}(P|Q)=\sum\limits_i P(i)\log \frac{P(i)}{Q(i)} DKL(P∣Q)=i∑P(i)logQ(i)P(i)
连续分布:
D K L ( P ∣ Q ) = ∫ − ∞ ∞ p ( x ) log p ( x ) q ( x ) d x D_{KL}(P|Q)=\int_{-\infty}^{\infty}p(x)\log\frac{p(x)}{q(x)}dx DKL(P∣Q)=∫−∞∞p(x)logq(x)p(x)dx
机器学习领域中的生成模型往往涉及到生成尽可能反映真实情况的分布模型。
比如,生成对抗网络(GAN)在图片上的应用往往执行的是类似基于黑白图片生成看起来尽量真实的彩色图片这样的任务。在这类似的应用中,输入往往是图像或像素。网络会学习这些像素之间的依赖关系(比如临近像素通常有相似的颜色),然后使用它来创建看起来尽量真实的图像。因此,生成器的目标就是最小化所学到的像素分布于真实图像像素分布之间的散度。
比如电商场景,可以使用KL散度去计算同一类型商品不同用户群体之间的金额(或其余指标)KL散度,如果都很接近,说明这个类型商品不是不同用户群体之间的差异点,可以进行剔除,只保留有差异性的商品类型(KL散度较大),这样就可以基于结果去对用户进行更好的画像~
import numpy as np
import scipy.stats
# 随机生成两个离散型分布
x = [np.random.randint(1, 11) for i in range(10)]
print(x)
print(np.sum(x))
px = x / np.sum(x)
print(px)
y = [np.random.randint(1, 11) for i in range(10)]
print(y)
print(np.sum(y))
py = y / np.sum(y)
print(py)
[9, 3, 10, 5, 10, 4, 7, 6, 8, 1]
63
[0.14285714 0.04761905 0.15873016 0.07936508 0.15873016 0.06349206
0.11111111 0.0952381 0.12698413 0.01587302]
[6, 5, 10, 1, 7, 9, 9, 6, 2, 8]
63
[0.0952381 0.07936508 0.15873016 0.01587302 0.11111111 0.14285714
0.14285714 0.0952381 0.03174603 0.12698413]
# 利用scipy API进行计算
# scipy计算函数可以处理非归一化情况,因此这里使用
# scipy.stats.entropy(x, y)或scipy.stats.entropy(px, py)均可
'''
用函数entropy用x和y 或者 px, py 都可以
'''
KL = scipy.stats.entropy(px, py)
print(KL)
KL = scipy.stats.entropy(x, y)
print(KL)
0.2815657077409675
0.2815657077409676
# 编程实现
'''
用公式编程就用px和py
'''
KL = 0.0
for i in range(10):
KL += px[i] * np.log(px[i] / py[i])
# print(str(px[i]) + ' ' + str(py[i]) + ' ' + str(px[i] * np.log(px[i] / py[i])))
print(KL)
0.2815657077409677
验证对称性不成立:
KL = scipy.stats.entropy(y, x)
print(KL)
0.3085447676484088
确实和上述0.28不一致~