许多网站提供一些统计数据,例如“过去 24 小时最热门的主题”。 例如,Topix.com 在其“新闻趋势”部分中显示了这一点。 在那里,您可以看到提及次数增长最快的主题。
我也想计算一个主题的这样的“嗡嗡声”。 我怎么能这样做呢? 该算法应该对始终热门的主题赋予较少的权重。 通常(几乎)没有人提及的话题应该是最热门的话题。
Google 提供“热门趋势”,topix.com 显示“热门主题”,fav.or.it 显示“关键字趋势”——所有这些服务都有一个共同点:它们只向您显示当前异常热门的即将出现的趋势。
“布兰妮·斯皮尔斯”、“天气”或“帕丽斯·希尔顿”等术语不会出现在这些列表中,因为它们总是热门且频繁出现。 本文将此称为“布兰妮·斯皮尔斯问题”。
我的问题:如何解决你能编写一种算法或使用现有的算法来解决这个问题吗? 有了过去 24 小时内搜索的关键字列表,算法应该向您显示 10 个(例如)最热门的关键字。
我知道,在上面的文章中,提到了某种算法。 我尝试用 PHP 编写它,但我不认为它会工作的。 它只是找到了大多数,不是吗?
我希望你能帮助我(编码示例会很棒)。
Many sites offer some statistics like "The hottest topics in the last 24h". For example, Topix.com shows this in its section "News Trends". There, you can see the topics which have the fastest growing number of mentions.
I want to compute such a "buzz" for a topic, too. How could I do this? The algorithm should weight the topics which are always hot less. The topics which normally (almost) no one mentions should be the hottest ones.
Google offers "Hot Trends", topix.com shows "Hot Topics", fav.or.it shows "Keyword Trends" - all these services have one thing in common: They only show you upcoming trends which are abnormally hot at the moment.
Terms like "Britney Spears", "weather" or "Paris Hilton" won't appear in these lists because they're always hot and frequent. This article calls this "The Britney Spears Problem".
My question: How can you code an algorithm or use an existing one to solve this problem? Having a list with the keywords searched in the last 24h, the algorithm should show you the 10 (for example) hottest ones.
I know, in the article above, there is some kind of algorithm mentioned. I've tried to code it in PHP but I don't think that it'll work. It just finds the majority, doesn't it?
I hope you can help me (coding examples would be great).
发布评论
评论(11)
这个问题需要 z 分数或标准分数,正如其他人提到的那样,它会考虑历史平均值,而且还会考虑该历史数据的标准差,使其比仅使用平均值更加稳健。
在您的情况下,z 分数是通过以下公式计算的,其中趋势是一个比率,例如观看次数/天。
使用 z 分数时,z 分数越高或越低,趋势越异常,因此,例如,如果 z 分数高度正,则趋势异常上升,而如果高度负,则趋势异常下降。 因此,一旦计算了所有候选趋势的 z 分数,最高的 10 个 z 分数将与最异常增加的 z 分数相关。
有关 z 分数的更多信息,请参阅维基百科。
代码
示例输出
注释
如果您不想采取这种方法,可以使用带有滑动窗口(即最近 30 天)的方法考虑大量历史记录,这将使短期趋势更加明显,并可以减少处理时间。
您还可以使用 z 分数作为值,例如从一天到第二天的观看次数变化,以找到每天观看次数增加/减少的异常值。 这就像使用每日观看次数图表的斜率或导数。
如果您跟踪当前的人口规模、当前的人口总数以及当前的人口总数 x^2,则无需重新计算这些值,只需更新它们即可只需要保留这些值作为历史记录,而不是每个数据值。 以下代码演示了这一点。
使用此方法,您的工作流程如下。 为每个主题、标签或页面创建一个浮点字段,用于表示数据库中的总天数、观看次数总和以及观看次数平方和。 如果您有历史数据,请使用该数据初始化这些字段,否则初始化为零。 每天结束时,根据三个数据库字段中存储的历史数据,使用当天的观看次数来计算 z 分数。 具有最高 X z 分数的主题、标签或页面是当天的 X 个“最热门趋势”。 最后用当天的值更新 3 个字段中的每一个,并在第二天重复该过程。
新添加
如上所述,正常 z 分数不考虑数据的顺序,因此“1”或“9”观测值的 z 分数与序列 [1, 1, 1, 1, 9, 9, 9, 9]。 显然,对于趋势发现,最新数据应该比旧数据具有更大的权重,因此我们希望“1”观测值比“9”观测值具有更大的幅度分数。 为了实现这一目标,我提出了浮动平均 z 分数。 应该清楚的是,这种方法不能保证在统计上是合理的,但对于趋势发现或类似方法应该有用。 标准 z 分数和浮动平均 z 分数之间的主要区别在于使用浮动平均值来计算平均总体值和平均总体值的平方。 有关详细信息,请参阅代码:
代码
示例 IO
更新
正如 David Kemp 正确指出的那样,如果给定一系列常量值,然后给定一个 zscore要求观察值与其他值不同,结果可能应为非零。 事实上返回的值应该是无穷大。 所以我将这一行更改
为:
此更改反映在 fazscore 解决方案代码中。 如果不想处理无限值,可接受的解决方案可能是将行更改为:
This problem calls for a z-score or standard score, which will take into account the historical average, as other people have mentioned, but also the standard deviation of this historical data, making it more robust than just using the average.
In your case a z-score is calculated by the following formula, where the trend would be a rate such as views / day.
When a z-score is used, the higher or lower the z-score the more abnormal the trend, so for example if the z-score is highly positive then the trend is abnormally rising, while if it is highly negative it is abnormally falling. So once you calculate the z-score for all the candidate trends the highest 10 z-scores will relate to the most abnormally increasing z-scores.
Please see Wikipedia for more information, about z-scores.
Code
Sample Output
Notes
You can use this method with a sliding window (i.e. last 30 days) if you wish not to take to much history into account, which will make short term trends more pronounced and can cut down on the processing time.
You could also use a z-score for values such as change in views from one day to next day to locate the abnormal values for increasing/decreasing views per day. This is like using the slope or derivative of the views per day graph.
If you keep track of the current size of the population, the current total of the population, and the current total of x^2 of the population, you don't need to recalculate these values, only update them and hence you only need to keep these values for the history, not each data value. The following code demonstrates this.
Using this method your work flow would be as follows. For each topic, tag, or page create a floating point field, for the total number of days, sum of views, and sum of views squared in your database. If you have historic data, initialize these fields using that data, otherwise initialize to zero. At the end of each day, calculate the z-score using the day's number of views against the historic data stored in the three database fields. The topics, tags, or pages, with the highest X z-scores are your X "hotest trends" of the day. Finally update each of the 3 fields with the day's value and repeat the process next day.
New Addition
Normal z-scores as discussed above do not take into account the order of the data and hence the z-score for an observation of '1' or '9' would have the same magnitude against the sequence [1, 1, 1, 1, 9, 9, 9, 9]. Obviously for trend finding, the most current data should have more weight than older data and hence we want the '1' observation to have a larger magnitude score than the '9' observation. In order to achieve this I propose a floating average z-score. It should be clear that this method is NOT guaranteed to be statistically sound but should be useful for trend finding or similar. The main difference between the standard z-score and the floating average z-score is the use of a floating average to calculate the average population value and the average population value squared. See code for details:
Code
Sample IO
Update
As David Kemp correctly pointed out, if given a series of constant values and then a zscore for an observed value which differs from the other values is requested the result should probably be non-zero. In fact the value returned should be infinity. So I changed this line,
to:
This change is reflected in the fazscore solution code. If one does not want to deal with infinite values an acceptable solution could be to instead change the line to:
您需要一种算法来测量某个主题的速度 - 或者换句话说,如果您将其绘制成图表,您希望显示那些以令人难以置信的速度增长的主题。
这是趋势线的一阶导数,将其作为整体计算的加权因子并不困难。
标准化
您需要执行的一项技术是标准化所有数据。 对于您关注的每个主题,保留一个定义该主题基线的低通滤波器。 现在,关于该主题的每个数据点都应该标准化 - 减去它的基线,您将得到所有接近 0 的主题,在线上方和下方有峰值。 相反,您可能想要将信号除以其基线幅度,这将使信号达到 1.0 左右 - 这不仅使所有信号彼此一致(标准化基线),而且还标准化尖峰。 布兰妮的峰值将比其他人的峰值大很多,但这并不意味着您应该注意它 - 相对于她的基线,峰值可能非常小。
推导
一旦你标准化了所有内容,就可以计算出每个主题的斜率。 取两个连续的点,并测量差异。 正差值呈上升趋势,负差值呈下降趋势。 然后,您可以比较归一化的差异,并找出与其他主题相比哪些主题的受欢迎程度正在上升 - 每个主题都根据其自身的“正常”进行缩放,这可能与其他主题的数量级不同。
这确实是解决问题的第一步。 您需要使用更高级的技术(主要是上述技术与其他算法的组合,加权以满足您的需求),但它应该足以让您入门。
关于这篇文章
这篇文章是关于主题趋势的,但它不是关于如何计算什么热门、什么不热门,而是关于如何处理这样的算法在 Lycos 这样的地方必须处理的大量信息和谷歌。 为每个主题提供一个计数器并在搜索时找到每个主题的计数器所需的空间和时间是巨大的。 本文介绍的是人们在尝试执行此类任务时所面临的挑战。 它确实提到了布兰妮效应,但没有谈论如何克服它。
正如 Nixuz 指出的,这也称为 Z或标准分数。
You need an algorithm that measures the velocity of a topic - or in other words, if you graph it you want to show those that are going up at an incredible rate.
This is the first derivative of the trend line, and it is not difficult to incorporate as a weighted factor of your overall calculation.
Normalize
One technique you'll need to do is to normalize all your data. For each topic you are following, keep a very low pass filter that defines that topic's baseline. Now every data point that comes in about that topic should be normalized - subtract its baseline and you'll get ALL of your topics near 0, with spikes above and below the line. You may instead want to divide the signal by its baseline magnitude, which will bring the signal to around 1.0 - this not only brings all signals in line with each other (normalizes the baseline), but also normalizes the spikes. A britney spike is going to be magnitudes larger than someone else's spike, but that doesn't mean you should pay attention to it - the spike may be very small relative to her baseline.
Derive
Once you've normalized everything, figure out the slope of each topic. Take two consecutive points, and measure the difference. A positive difference is trending up, a negative difference is trending down. Then you can compare the normalized differences, and find out what topics are shooting upward in popularity compared to other topics - with each topic scaled appropriate to it's own 'normal' which may be magnitudes of order different from other topics.
This is really a first-pass at the problem. There are more advanced techniques which you'll need to use (mostly a combination of the above with other algorithms, weighted to suit your needs) but it should be enough to get you started.
Regarding the article
The article is about topic trending, but it's not about how to calculate what's hot and what's not, it's about how to process the huge amount of information that such an algorithm must process at places like Lycos and Google. The space and time required to give each topic a counter, and find each topic's counter when a search on it goes through is huge. This article is about the challenges one faces when attempting such a task. It does mention the Brittney effect, but it doesn't talk about how to overcome it.
As Nixuz points out this is also referred to as a Z or Standard Score.
查德·伯奇和亚当·戴维斯的观点是正确的,你必须回顾过去才能建立基线。 正如您所提出的问题,您只想查看过去 24 小时的数据,但这不太可行。
为数据提供一些内存而无需查询大量历史数据的一种方法是使用 指数移动平均线。这样做的优点是您可以每个周期更新一次,然后刷新所有旧数据,因此您只需要记住一个值。 因此,如果您的经期是一天,则必须为每个主题维护一个“每日平均值”属性,您可以通过以下方式执行此操作:
其中
a_n
是截至n
n 天的移动平均值code>,b 是 0 到 1 之间的某个常数(越接近 1,记忆时间越长),c_n
是n
天的点击次数。 美妙之处在于,如果您在n
天结束时执行此更新,则可以刷新c_n
和a_(n-1)
。需要注意的是,它最初会对您选择的
a
初始值敏感。编辑
如果有助于可视化此方法,请采用
n = 5
、a_0 = 1
和b = .9
。假设新值为 5,0,0,1,4:
看起来不太像平均值,不是吗? 请注意,即使我们的下一个输入是 5,该值仍然接近 1。这是怎么回事? 如果你展开数学计算,你会得到:
剩余重量是什么意思? 好吧,在任何平均值中,所有权重都必须加到 1。如果 n 是无穷大并且……可以永远持续下去,那么所有权重之和将等于 1。但是如果 n 相对较小,则剩下大量的权重在原始输入上。
如果您研究了上面的公式,您应该意识到有关此用法的一些事情:
我认为前两个特征正是您所寻找的。 为了让您对实现有一个简单的想法,这里是一个 python 实现(减去所有数据库交互):
Chad Birch and Adam Davis are correct in that you will have to look backward to establish a baseline. Your question, as phrased, suggests that you only want to view data from the past 24 hours, and that won't quite fly.
One way to give your data some memory without having to query for a large body of historical data is to use an exponential moving average. The advantage of this is that you can update this once per period and then flush all old data, so you only need to remember a single value. So if your period is a day, you have to maintain a "daily average" attribute for each topic, which you can do by:
Where
a_n
is the moving average as of dayn
, b is some constant between 0 and 1 (the closer to 1, the longer the memory) andc_n
is the number of hits on dayn
. The beauty is if you perform this update at the end of dayn
, you can flushc_n
anda_(n-1)
.The one caveat is that it will be initially sensitive to whatever you pick for your initial value of
a
.EDIT
If it helps to visualize this approach, take
n = 5
,a_0 = 1
, andb = .9
.Let's say the new values are 5,0,0,1,4:
Doesn't look very much like an average does it? Note how the value stayed close to 1, even though our next input was 5. What's going on? If you expand out the math, what you get that:
What do I mean by leftover weight? Well, in any average, all weights must add to 1. If n were infinity and the ... could go on forever, then all weights would sum to 1. But if n is relatively small, you get a good amount of weight left on the original input.
If you study the above formula, you should realize a few things about this usage:
I think the first two characteristics are exactly what you are looking for. To give you an idea of simple this can be to implement, here is a python implementation (minus all the database interaction):
通常,“嗡嗡声”是使用某种形式的指数/对数衰减机制计算出来的。 有关 Hacker News、Reddit 和其他网站如何以简单方式处理此问题的概述,请参阅 这篇文章。
这并不能完全解决那些总是流行的事情。 您正在寻找的内容似乎类似于 Google 的“热门趋势”功能。 为此,您可以将当前值除以历史值,然后减去低于某个噪声阈值的值。
Typically "buzz" is figured out using some form of exponential/log decay mechanism. For an overview of how Hacker News, Reddit, and others handle this in a simple way, see this post.
This doesn't fully address the things that are always popular. What you're looking for seems to be something like Google's "Hot Trends" feature. For that, you could divide the current value by a historical value and then subtract out ones that are below some noise threshold.
我认为你需要注意的关键词是“异常”。 为了确定何时出现“异常”,您必须知道什么是正常的。 也就是说,您将需要历史数据,您可以对其进行平均以找出特定查询的正常速率。 您可能希望从平均计算中排除异常日期,但这同样需要拥有足够的数据,以便您知道要排除哪些日期。
从那里,您必须设置一个阈值(我确信这需要实验),如果某些内容超出阈值,例如搜索量比正常情况多 50%,您可以将其视为“趋势”。 或者,如果您希望能够像您提到的那样找到“Top X Trendiest”,您只需根据商品与正常价格的差距(百分比)进行排序即可。
例如,假设您的历史数据告诉您,布兰妮·斯皮尔斯通常会获得 100,000 次搜索,而帕丽斯·希尔顿通常会获得 50,000 次搜索。 如果有一天他们的搜索量都比平时多 10,000 次,那么您应该认为巴黎比布兰妮“更热门”,因为她的搜索量比正常情况增加了 20%,而布兰妮的搜索量只增加了 10%。
天哪,我不敢相信我刚刚写了一段比较布兰妮·斯皮尔斯和帕丽斯·希尔顿的“性感”的段落。 你对我做了什么?
I think they key word you need to notice is "abnormally". In order to determine when something is "abnormal", you have to know what is normal. That is, you're going to need historical data, which you can average to find out the normal rate of a particular query. You may want to exclude abnormal days from the averaging calculation, but again that'll require having enough data already, so that you know which days to exclude.
From there, you'll have to set a threshold (which would require experimentation, I'm sure), and if something goes outside the threshold, say 50% more searches than normal, you can consider it a "trend". Or, if you want to be able to find the "Top X Trendiest" like you mentioned, you just need to order things by how far (percentage-wise) they are away from their normal rate.
For example, let's say that your historical data has told you that Britney Spears usually gets 100,000 searches, and Paris Hilton usually gets 50,000. If you have a day where they both get 10,000 more searches than normal, you should be considering Paris "hotter" than Britney, because her searches increased 20% more than normal, while Britney's were only 10%.
God, I can't believe I just wrote a paragraph comparing "hotness" of Britney Spears and Paris Hilton. What have you done to me?
我想知道在这种情况下是否可以使用常规的物理加速公式?
我们可以将 v1 视为每小时的初始点赞数/投票数/评论数,将 v2 视为过去 24 小时内每小时的当前“速度”?
这更像是一个问题而不是答案,但似乎它可能会起作用。 任何具有最高加速度的内容都将成为热门话题...
我确信这可能无法解决布兰妮·斯皮尔斯的问题:-)
I was wondering if it is at all possible to use regular physics acceleration formula in such a case?
We can consider v1 to be initial likes/votes/count-of-comments per hour and v2 to be current "velocity" per hour in last 24 hours?
This is more like a question than an answer, but seems it may just work. Any content with highest acceleration will be the trending topic...
I am sure this may not solve Britney Spears problem :-)
也许一个简单的主题频率梯度会起作用——大的正梯度=流行度快速增长。
最简单的方法是对每天的搜索次数进行分类,这样你就可以得到类似的结果
,然后找出每天的变化量:
然后应用某种阈值,以便增加>的日子。 50 被认为是“热门”。 如果你愿意的话,你也可以让这个变得更加复杂。 您可以采用相对差异,而不是绝对差异,这样从 100 到 150 就被认为是热的,但 1000 到 1050 则不是。 或者更复杂的梯度,不仅仅考虑一天到下一天的趋势。
probably a simple gradient of topic frequency would work -- large positive gradient = growing quickly in popularity.
the easiest way would be to bin the number of searched each day, so you have something like
and then find out how much it changed from day to day:
and just apply some sort of threshold so that days where the increase was > 50 are considered 'hot'. you could make this far more complicated if you'd like, too. rather than absolute difference you can take the relative difference so that going from 100 to 150 is considered hot, but 1000 to 1050 isn't. or a more complicated gradient that takes into account trends over more than just one day to the next.
我曾参与过一个项目,我的目标是从 Twitter 直播流中查找热门话题,并对热门话题进行情感分析(查找热门话题是否受到积极/消极的谈论)。 我使用 Storm 来处理 Twitter 流。
我已将我的报告发布为博客: http:// /sayrohan.blogspot.com/2013/06/finding-trending-topics-and-trending.html
我使用总计数和 Z 分数进行排名。
我使用的方法有点通用,在讨论部分,我提到了如何为非 Twitter 应用程序扩展系统。
希望信息有所帮助。
I had worked on a project, where my aim was finding Trending Topics from Live Twitter Stream and also doing sentimental analysis on the trending topics (finding if Trending Topic positively/negatively talked about). I've used Storm for handling twitter stream.
I've published my report as a blog: http://sayrohan.blogspot.com/2013/06/finding-trending-topics-and-trending.html
I've used Total Count and Z-Score for the ranking.
The approach that I've used is bit generic, and in the discussion section, I've mentioned that how we can extend the system for non-Twitter Application.
Hope the information helps.
如果您只是查看推文或状态消息来获取主题,您将会遇到很多噪音。 即使您删除所有停用词。 获得更好的候选主题子集的一种方法是仅关注共享 URL 的推文/消息,并从这些网页的标题中获取关键字。 并确保应用词性标记来获取名词+名词短语。
网页的标题通常更具描述性,并且包含描述页面内容的单词。 此外,共享网页通常与共享重大新闻相关(即,如果像迈克尔·杰克逊这样的名人去世了,就会有很多人分享有关他去世的文章)。
我进行了实验,只从标题中提取流行的关键字,然后获取所有状态消息中这些关键字的总数,它们肯定消除了很多噪音。 如果你这样做,你不需要复杂的算法,只需对关键词频率进行简单的排序,你就成功了一半。
If you simply look at tweets, or status messages to get your topics, you're going to encounter a lot of noise. Even if you remove all stop words. One way to get a better subset of topic candidates is to focus only on tweets/messages that share a URL, and get the keywords from the title of those web pages. And make sure you apply POS tagging to get nouns + noun phrases as well.
Titles of web pages usually are more descriptive and contain words that describe what the page is about. In addition, sharing a web page usually is correlated with sharing news that is breaking (ie if a celebrity like Michael Jackson died, you're going to get a lot of people sharing an article about his death).
I've ran experiments where I only take popular keywords from titles, AND then get the total counts of those keywords across all status messages, and they definitely remove a lot of noise. If you do it this way, you don't need a complex algorith, just do a simple ordering of the keyword frequencies, and you're halfway there.
您可以使用对数似然比将当前日期与上个月或上一年进行比较。 这是统计上合理的(假设您的事件不是正态分布的,这是从您的问题中假设的)。
只需按 logLR 对所有术语进行排序,然后选择前十个即可。
PS,TermBag 是无序的单词集合。 对于每个文档,您创建一袋术语。 只需计算单词出现的次数即可。 然后,
occurrences
方法返回给定单词出现的次数,size
方法返回单词的总数。 最好以某种方式规范化单词,通常toLowerCase
就足够了。 当然,在上面的示例中,您将创建一个包含今天所有查询的文档,以及一个包含去年所有查询的文档。You could use log-likelihood-ratios to compare the current date with the last month or year. This is statistically sound (given that your events are not normally distributed, which is to be assumed from your question).
Just sort all your terms by logLR and pick the top ten.
PS, a TermBag is an unordered collection of words. For each document you create one bag of terms. Just count the occurrences of words. Then the method
occurrences
returns the number of occurrences of a given word, and the methodsize
returns the total number of words. It is best to normalize the words somehow, typicallytoLowerCase
is good enough. Of course, in the above examples you would create one document with all queries of today, and one with all queries of the last year.这个想法是跟踪这些事情,并注意它们与自己的基线相比何时显着跳跃。
因此,对于超过某个阈值的查询,跟踪每个查询,当它更改为其历史值的某个值(例如几乎两倍)时,它就是一个新的热门趋势。
The idea is to keep track of such things and notice when they jump significantly as compared to their own baseline.
So, for queries that have more than a certain threshhold, track each one and when it changes to some value (say almost double) of its historical value, then it is a new hot trend.