许多网站提供一些统计数据,如“过去24小时内最热门的话题”。例如,Topix.com在其“新闻趋势”部分显示了这一点。在那里,你可以看到被提及次数增长最快的话题。
我也想为一个主题计算这样的“嗡嗡声”。我怎么能这样做呢?算法应该对热点较少的话题进行加权。通常(几乎)没有人提及的话题应该是最热门的话题。
谷歌提供“热门趋势”,topix.com显示“热门话题”,fav.or.it显示“关键字趋势”——所有这些服务都有一个共同点:他们只向你展示当前异常热门的即将到来的趋势。
像“布兰妮·斯皮尔斯”、“天气”或“帕丽斯·希尔顿”这样的词不会出现在这些榜单中,因为它们总是热门且频繁。这篇文章称之为“小甜甜布兰妮问题”。
我的问题是:如何编写算法或使用现有算法来解决这个问题?有一个在过去24小时内搜索的关键字列表,算法应该向您显示10个(例如)最热门的关键字。
我知道,在上面的文章中,提到了某种算法。我试着在PHP中编码,但我不认为它会工作。它只是找到了大多数人,不是吗?
我希望你能帮助我(代码示例将是伟大的)。
我认为你需要注意的关键词是“不正常”。为了确定什么时候“不正常”,你必须知道什么是正常的。也就是说,您将需要历史数据,可以对其求平均值以找出特定查询的正常速率。您可能希望从平均计算中排除不正常的日子,但这同样需要有足够的数据,这样您就知道应该排除哪些日子。
在此基础上,你必须设置一个阈值(我确信这需要实验),如果有东西超出了阈值,比如搜索量比正常情况多50%,你就可以认为这是一个“趋势”。或者,如果你想像你提到的那样找到“最流行的X”,你只需要根据它们与正常比率的距离(百分比)来排序。
例如,假设你的历史数据告诉你,布兰妮·斯皮尔斯(Britney Spears)通常获得10万次搜索,帕丽斯·希尔顿(Paris Hilton)通常获得5万次搜索。如果有一天她们的搜索量都比平时多了1万次,那么你应该认为帕里斯比布兰妮更“热”,因为她的搜索量比平时多了20%,而布兰妮的搜索量只增加了10%。
天啊,我真不敢相信我刚刚写了一段比较布兰妮·斯皮尔斯和帕丽斯·希尔顿的“性感”的段落。你对我做了什么?
也许一个简单的话题频率梯度就能起作用——大的正梯度=快速增长的受欢迎程度。
最简单的方法是将每天的搜索次数归位,这样你就有了
searches = [ 10, 7, 14, 8, 9, 12, 55, 104, 100 ]
然后看看它每天有多少变化:
hot_factor = [ b-a for a, b in zip(searches[:-1], searches[1:]) ]
# hot_factor is [ -3, 7, -6, 1, 3, 43, 49, -4 ]
只要应用某种阈值,那么那些增加了> 50的日子就被认为是“热”的。如果你愿意,你也可以让它变得更复杂。不是绝对差异,而是相对差异,所以从100到150被认为是热的,但从1000到1050不是。或者是考虑到不止一天的趋势的更复杂的梯度。
您可以使用对数概率比来比较当前日期与上个月或去年。这在统计上是合理的(假设你的事件不是正态分布,这是从你的问题中假设的)。
只需按logLR排序所有的术语,并选择前10名。
public static void main(String... args) {
TermBag today = ...
TermBag lastYear = ...
for (String each: today.allTerms()) {
System.out.println(logLikelihoodRatio(today, lastYear, each) + "\t" + each);
}
}
public static double logLikelihoodRatio(TermBag t1, TermBag t2, String term) {
double k1 = t1.occurrences(term);
double k2 = t2.occurrences(term);
double n1 = t1.size();
double n2 = t2.size();
double p1 = k1 / n1;
double p2 = k2 / n2;
double p = (k1 + k2) / (n1 + n2);
double logLR = 2*(logL(p1,k1,n1) + logL(p2,k2,n2) - logL(p,k1,n1) - logL(p,k2,n2));
if (p1 < p2) logLR *= -1;
return logLR;
}
private static double logL(double p, double k, double n) {
return (k == 0 ? 0 : k * Math.log(p)) + ((n - k) == 0 ? 0 : (n - k) * Math.log(1 - p));
}
PS, TermBag是单词的无序集合。为每个文档创建一袋术语。数一下单词的出现次数。然后,occurrences方法返回给定单词的出现次数,size方法返回单词的总数。最好以某种方式规范化单词,通常toLowerCase就足够了。当然,在上面的示例中,您将创建一个包含当前所有查询的文档,以及一个包含去年所有查询的文档。