从先验概率中得出其他概率,估算一个概率

5

我有一堆数据(自动呼叫中心的通话记录),关于一个人是否购买特定产品,1代表购买,0代表未购买。

我想利用这些数据创建一个估计概率,即一个人购买特定产品的概率,但问题是我可能需要用相对较少的历史数据来完成这个任务,了解有多少人购买/未购买该产品。

一位朋友建议使用贝叶斯概率,通过制定“先验概率分布”来“帮助”您的概率估计,本质上这是关于您在考虑实际数据之前所期望看到的信息。

因此,我想创建一个具有以下签名(Java)的方法:

double estimateProbability(double[] priorProbabilities, int buyCount, int noBuyCount);

priorProbabilities是一个概率数组,用于此方法创建此概率的先验分布。buyCount和noBuyCount是特定产品的实际数据,我希望从中估计出用户购买的概率,考虑到数据和先验概率。该方法将返回一个双精度数值。

我不需要完美的数学解决方案,只需要比均匀或平坦的先验分布更好的解决方案(即probability = buyCount / (buyCount+noBuyCount))。由于我对源代码比数学符号更熟悉,所以我希望人们在解释时使用代码。


1
这是一个非常酷的问题,我认为我知道确切的贝叶斯解决方案,但编码仍需要一些时间(你介意可执行的伪代码,也就是Python源代码吗?我对Java有点生疏...;-)。 - Alex Martelli
2
我认为这不是一个纯粹的编程问题;它是一个包装在Java方法桩中的理论数学问题。 - Steven A. Lowe
1
@Steven,为什么在这里对任何与数学相关的东西都充满了厌恶之情?数学和编程息息相关。许多编程问题都有数学组成部分。如果在SO上任何与数学相关的东西都不被允许,那么很抱歉,SO将会是一个更不实用、更不有趣的网站。 - sanity
@sanity:我已经阅读了您的个人资料并尊重您的工作,如果我表现出无礼/自大/居高临下的态度,我很抱歉——现在时间有点晚了,我并不是有意冒犯。 (1)和(2)只是观察,并非指责;重新措辞可能会更清楚明白。至于您的具体问题(3),您已经和我一样成为了该网站的会员,并且可能已经阅读了FAQ。我建议PlanetMath比SO更适合数学问题,如http://stackoverflow.com/questions/321618/where-can-i-ask-questions-that-arent-programming-questions所述。 - Steven A. Lowe
@sanity:作为一种和解的措施,我已经取消了您的“踩”操作;-) - Steven A. Lowe
显示剩余16条评论
4个回答

3
这里是贝叶斯计算和一个例子/测试:
def estimateProbability(priorProbs, buyCount, noBuyCount):
  # first, estimate the prob that the actual buy/nobuy counts would be observed
  # given each of the priors (times a constant that's the same in each case and
  # not worth the effort of computing;-)`
  condProbs = [p**buyCount * (1.0-p)**noBuyCount for p in priorProbs]
  # the normalization factor for the above-mentioned neglected constant
  # can most easily be computed just once
  normalize = 1.0 / sum(condProbs)
  # so here's the probability for each of the prior (starting from a uniform
  # metaprior)
  priorMeta = [normalize * cp for cp in condProbs]
  # so the result is the sum of prior probs weighed by prior metaprobs
  return sum(pm * pp for pm, pp in zip(priorMeta, priorProbs))

def example(numProspects=4):
  # the a priori prob of buying was either 0.3 or 0.7, how does it change
  # depending on how 4 prospects bought or didn't?
  for bought in range(0, numProspects+1):
    result = estimateProbability([0.3, 0.7], bought, numProspects-bought)
    print 'b=%d, p=%.2f' % (bought, result)

example()

输出结果为:
b=0, p=0.31
b=1, p=0.36
b=2, p=0.50
b=3, p=0.64
b=4, p=0.69

这与我手动计算的简单案例相符。请注意,购买的概率根据定义,始终会在先验概率集合中的最低值和最高值之间;如果这不是您想要的,您可能需要引入两个“伪产品”,一个永远不会被购买(p = 0.0),一个任何人都会购买(p = 1.0)-- 这更加重视实际观察结果,尽管它们可能很少,而较少关注过去产品的统计数据。如果我们在这里这样做,我们得到:

b=0, p=0.06
b=1, p=0.36
b=2, p=0.50
b=3, p=0.64
b=4, p=0.94

中间级别的数据调整(为了考虑这种新产品比以前销售的任何产品都更糟糕或更好的可能性,虽然不太可能但也不是不可能)可以很容易地想象出来(通过将先前权重向量添加到estimateProbability参数中,降低人工0.0和1.0概率的权重)。我现在从事商业智能应用程序开发,这种工作占据我一天中相当大的时间,但我还是远远不够满足...!-)

谢谢Alex,我很高兴有人欣赏这个问题 :-) 这看起来肯定是对的,但我要到明天才能详细检查你的答案。话虽如此,我现在很乐意接受你的答案 :-) - sanity
无论如何,检查一下(根据需要转码为Java,但考虑使用Jython进行快速测试),然后回答我,无论是在这个问题上还是一个新的问题上。我和你一样渴望让它正常工作!:) 贝叶斯万岁...!-) - Alex Martelli

2
一个非常简单的方法,不需要进行任何复杂的数学计算,就是通过添加虚拟客户来人为地增加购买次数和未购买次数。这些虚拟客户可以是已经购买或未购买该产品的客户。您可以根据您认为值得多少虚拟客户来调整您对每种先验概率的信任程度。
伪代码如下:
def estimateProbability(priorProbs, buyCount, noBuyCount, faithInPrior=None):
    if faithInPrior is None: faithInPrior = [10 for x in buyCount]
    adjustedBuyCount = [b + p*f for b,p,f in 
                                zip(buyCount, priorProbs, faithInPrior]
    adjustedNoBuyCount = [n + (1-p)*f for n,p,f in 
                                zip(noBuyCount, priorProbs, faithInPrior]
    return [b/(b+n) for b,n in zip(adjustedBuyCount, adjustedNoBuyCount]

0
听起来你想做的是关联规则学习。我现在没有时间为你提供任何代码,但我会指向WEKA这个Java开源数据挖掘工具包,它非常棒。你应该能在那里找到很多有趣的东西,可以帮助你解决问题。

这很有趣,但我不明白它如何解决我所描述的具体问题 :-/ - sanity
+1 给无知和懒惰加分;这是一个非常好的建议。 - Steven A. Lowe
史蒂文,我已经完整地阅读了关于ARL的链接文章。也许您可以解释一下这个建议如何解决我概述的具体问题? - sanity
@sanity:如果你有其他相关的东西需要关联,ARL会提供帮助。 - Steven A. Lowe
@Steven,我并不打算与任何附加的元数据相关联。我认为你(和n3rd)试图解决的是一个与问题中提出的问题不同的问题。 - sanity

0
在我看来,最好的方法就是使用均匀分布,除非你有一些关于分布的线索。或者你是在谈论将这些产品与以前由同一人在亚马逊时尚购买的产品建立联系,比如“购买此产品的人还购买了...”?


分配方面的线索是在priorProbabilities参数中提供给该方法的。这是我们为其他产品找到的购买概率列表,可以(希望)用来得出该产品购买概率的先验分布。 - sanity
在我看来,你需要将购买或不购买与其他参数(例如年龄、性别、国家、年份、时间、其他已购买的产品等)相关联。否则,你所拥有的最佳信息就是使用累积购买率的均匀分布。 - tekBlues
现在我只想要这些。通常我会尝试和年龄、性别等元数据进行关联,但问题在于数据量不足。我的挑战在于基于极少的数据(也许只有几百个调用,典型的购买率约为5-10%)得出最精确的购买概率。基于年龄或性别划分数据根本不可行,因为数据量太小了。 - sanity
@sanity:那么你必须使用均匀分布,其他任何方法都属于魔法领域。如果100人中有20人购买了,新人购买的概率是1/5,没有别的。 - tekBlues
@tekBlues:我不这么认为。其他产品的实际发现概率形成了我们期望该概率所在位置的先验分布。例如,如果所有其他概率都在5%和15%之间,则均匀分布显然不合适。 - sanity

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接