トレンドのトピックやタグを計算する最良の方法は何ですか?


183

多くのサイトは、「過去24時間で最もホットなトピック」などの統計を提供しています。たとえば、Topix.comのセクション「ニューストレンド」ではこれを示しています。そこでは、言及の数が最も急増しているトピックを見ることができます。

トピックについてもこのような「バズ」を計算したいと思います。どうすればこれができますか?アルゴリズムは、常にホットなトピックに重みを付ける必要があります。通常(ほとんど)誰も言及しないトピックは、最もホットなものでなければなりません。

Googleは「ホットトレンド」を提供し、topix.comは「ホットトピック」を示し、fav.or.itは「キーワードトレンド」を示します。これらのサービスにはすべて1つの共通点があります。

「Britney Spears」、「weather」、「Paris Hilton」などの用語は、常に暑くて頻繁であるため、これらのリストには表示されません。この記事では、これを「ブリトニースピアーズ問題」と呼んでいます。

私の質問:どのようにしてアルゴリズムをコーディングするか、または既存のアルゴリズムを使用してこの問題を解決できますか?過去24時間に検索されたキーワードのリストがあれば、アルゴリズムは(たとえば)最もホットな10個を表示するはずです。

上記の記事では、ある種のアルゴリズムについて言及しています。私はそれをPHPでコーディングしようとしましたが、うまくいくとは思いません。過半数を見つけるだけですよね。

あなたが私を助けてくれることを願っています(コーディング例は素晴らしいでしょう)。


4
興味深い質問です。人々の意見を知りたいと思っています。
mmcdole 2009

14
近くする理由は、これは有効な質問ではありません
TStamper

1
これはまったく同じ質問であり、彼もそれを述べています!なぜ人々はそれを支持しているのですか?
ダリルハイン

3
私はあなたが探している結果のタイプについて少し混乱しています。その記事は、「Britney Spears」が「Hot」リストに一貫して見つかるということを示しているようです。非常に多くの人々がその用語を検索するためですが、その質問の検索数は、時間の経過とともにそれほど増加しません(高いままですが、安定しています)。どの結果を達成しようとしていますか?「ブリトニースピアーズ」のランクは高いのか低いのか?
e.James、

1
@eJames、「ブリトニースピアーズ」は常に高い検索用語であり、彼は高速の検索用語を探しているため、上位にランク付けしないでください。
mmcdole 2009

回答:


103

この問題は、Zスコアまたは標準スコアを必要とします。これは、他の人々が言及しているように、履歴平均だけでなく、この履歴データの標準偏差も考慮に入れるため、平均を使用するよりも堅牢になります。

あなたの場合、Zスコアは次の式で計算されます。この場合、傾向はビュー/日などのレートになります。

z-score = ([current trend] - [average historic trends]) / [standard deviation of historic trends]

Zスコアが使用されている場合、Zスコアが高いか低いほど異常な傾向になります。たとえば、Zスコアが非常に正の場合、傾向は異常に上昇し、非常に負の場合、異常に下降します。 。したがって、すべての候補トレンドのZスコアを計算すると、最も高い10個のZスコアが最も異常に増加するZスコアに関連します。

Zスコアの詳細については、Wikipediaを参照してください。

コード

from math import sqrt

def zscore(obs, pop):
    # Size of population.
    number = float(len(pop))
    # Average population value.
    avg = sum(pop) / number
    # Standard deviation of population.
    std = sqrt(sum(((c - avg) ** 2) for c in pop) / number)
    # Zscore Calculation.
    return (obs - avg) / std

出力例

>>> zscore(12, [2, 4, 4, 4, 5, 5, 7, 9])
3.5
>>> zscore(20, [21, 22, 19, 18, 17, 22, 20, 20])
0.0739221270955
>>> zscore(20, [21, 22, 19, 18, 17, 22, 20, 20, 1, 2, 3, 1, 2, 1, 0, 1])
1.00303599234
>>> zscore(2, [21, 22, 19, 18, 17, 22, 20, 20, 1, 2, 3, 1, 2, 1, 0, 1])
-0.922793112954
>>> zscore(9, [1, 2, 0, 3, 1, 3, 1, 2, 9, 8, 7, 10, 9, 5, 2, 4, 1, 1, 0])
1.65291949506

ノート

  • 多くの履歴を考慮しない場合は、スライディングウィンドウ(つまり、過去30日間)でこの方法を使用できます。これにより、短期的な傾向がより顕著になり、処理時間を短縮できます。

  • 1日あたりのビューの変化などの値にZスコアを使用して、1日あたりのビューの増加/減少の異常な値を見つけることもできます。これは、1日あたりのビューの勾配または導関数を使用するようなものです。

  • 母集団の現在のサイズ、母集団の現在の合計、母集団の現在の合計x ^ 2を追跡している場合、これらの値を再計算する必要はなく、更新するだけなので、必要なのは各データ値ではなく、履歴のこれらの値を保持します。次のコードはこれを示しています。

    from math import sqrt
    
    class zscore:
        def __init__(self, pop = []):
            self.number = float(len(pop))
            self.total = sum(pop)
            self.sqrTotal = sum(x ** 2 for x in pop)
        def update(self, value):
            self.number += 1.0
            self.total += value
            self.sqrTotal += value ** 2
        def avg(self):
            return self.total / self.number
        def std(self):
            return sqrt((self.sqrTotal / self.number) - self.avg() ** 2)
        def score(self, obs):
            return (obs - self.avg()) / self.std()
    
  • この方法を使用すると、ワークフローは次のようになります。トピック、タグ、またはページごとに、データベースで二乗された合計日数、ビューの合計、およびビューの合計について、浮動小数点フィールドを作成します。履歴データがある場合は、そのデータを使用してこれらのフィールドを初期化します。それ以外の場合はゼロに初期化します。毎日の終わりに、3つのデータベースフィールドに保存されている履歴データに対するその日のビュー数を使用してZスコアを計算します。XのZスコアが最も高いトピック、タグ、ページは、その日のXの「最も人気のあるトレンド」です。最後に、3つのフィールドのそれぞれを日の値で更新し、明日プロセスを繰り返します。

新しい追加

上記の通常のZスコアはデータの順序を考慮しないため、「1」または「9」の観測値のZスコアは、シーケンス[1、1、1、1]と同じ大きさになります。 、9、9、9、9、9]。明らかに傾向を見つけるために、最新のデータは古いデータよりも重みが大きくなる必要があるため、「1」の観測には「9」の観測よりも大きい等級スコアが必要です。これを達成するために、浮動平均Zスコアを提案します。この方法は統計的に確実であることが保証されているわけではありませんが、傾向の発見などに役立つはずです。標準zスコアと変動平均zスコアの主な違いは、変動平均を使用して平均母集団値と平均母集団値の2乗を計算することです。詳細については、コードを参照してください。

コード

class fazscore:
    def __init__(self, decay, pop = []):
        self.sqrAvg = self.avg = 0
        # The rate at which the historic data's effect will diminish.
        self.decay = decay
        for x in pop: self.update(x)
    def update(self, value):
        # Set initial averages to the first value in the sequence.
        if self.avg == 0 and self.sqrAvg == 0:
            self.avg = float(value)
            self.sqrAvg = float((value ** 2))
        # Calculate the average of the rest of the values using a 
        # floating average.
        else:
            self.avg = self.avg * self.decay + value * (1 - self.decay)
            self.sqrAvg = self.sqrAvg * self.decay + (value ** 2) * (1 - self.decay)
        return self
    def std(self):
        # Somewhat ad-hoc standard deviation calculation.
        return sqrt(self.sqrAvg - self.avg ** 2)
    def score(self, obs):
        if self.std() == 0: return (obs - self.avg) * float("infinity")
        else: return (obs - self.avg) / self.std()

サンプルIO

>>> fazscore(0.8, [1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9]).score(1)
-1.67770595327
>>> fazscore(0.8, [1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9]).score(9)
0.596052006642
>>> fazscore(0.9, [2, 4, 4, 4, 5, 5, 7, 9]).score(12)
3.46442230724
>>> fazscore(0.9, [2, 4, 4, 4, 5, 5, 7, 9]).score(22)
7.7773245459
>>> fazscore(0.9, [21, 22, 19, 18, 17, 22, 20, 20]).score(20)
-0.24633160155
>>> fazscore(0.9, [21, 22, 19, 18, 17, 22, 20, 20, 1, 2, 3, 1, 2, 1, 0, 1]).score(20)
1.1069362749
>>> fazscore(0.9, [21, 22, 19, 18, 17, 22, 20, 20, 1, 2, 3, 1, 2, 1, 0, 1]).score(2)
-0.786764452966
>>> fazscore(0.9, [1, 2, 0, 3, 1, 3, 1, 2, 9, 8, 7, 10, 9, 5, 2, 4, 1, 1, 0]).score(9)
1.82262469243
>>> fazscore(0.8, [40] * 200).score(1)
-inf

更新

David Kempが正しく指摘したように、一連の定数値が与えられ、他の値とは異なる観測値のzscoreが要求された場合、結果はおそらくゼロではないはずです。実際、返される値は無限でなければなりません。この行を変更しました

if self.std() == 0: return 0

に:

if self.std() == 0: return (obs - self.avg) * float("infinity")

この変更は、fazscoreソリューションコードに反映されています。無限の値を処理したくない場合、許容できる解決策は、代わりに行を次のように変更することです。

if self.std() == 0: return obs - self.avg

1
いいえ、次の行にコードの小さな誤りが1つあります。$ z_score = $ hits_today-($ average_hits_per_day / $ standard_deviation); $ z_score =($ hits_today- $ average_hits_per_day)/ $ standard_deviation; 括弧の変更に注意してください。
Nixuz、2009年

1
@nixuz-何か不足していますか:fazscore(0.8、map(lambda x:40、range(0,200)))。score(1)== 0(任意の値)?
ケンプͩ

1
@Nixus-これを墓から掘り出すかもしれないと思った。これのPHP実装を再投稿できますか?pasteリンクが動作していないようだ...感謝を!
Drewness 2013

1
これを希望する人のために、これを行うSQLクエリを用意しました。
thouliha 2016

1
ここでの減衰は直観に反しています。[10、20]のように2つの値を入力し、減衰を0.8にすると、AVGは10 * 0.8 + 20 * 0.2 = 12になります。減衰がある場合、20の重みは10よりも大きいため、15を超える値が予想されます。numpy.averageの加重平均を使用して利用できるはるかに優れた代替方法があります。この場合、加重を使用して並列リストを作成します。次に例を示します。
Jeroen 2018年

93

トピックの速度を測定するアルゴリズムが必要です。つまり、グラフを作成する場合、驚異的な速度で上昇しているものを表示する必要があります。

これは傾向線の一次導関数であり、全体的な計算の加重係数として組み込むことは難しくありません。

ノーマライズ

必要なテクニックの1つは、すべてのデータを正規化することです。フォローしている各トピックについて、そのトピックのベースラインを定義する非常にローパスフィルターを維持します。これで、そのトピックに関するすべてのデータポイントが正規化されます。ベースラインを差し引くと、すべてのトピックが0に近くなり、線の上下にスパイクが生じます。代わりに、信号をベースラインの大きさで除算すると、信号が約1.0になります。これにより、すべての信号が互いに一致する(ベースラインが正規化される)だけでなく、スパイクも正規化されます。ブリトニースパイクは他の誰かのスパイクよりも大きくなるでしょうが、それはあなたがそれに注意を払うべきであることを意味しません-スパイクは彼女のベースラインに比べて非常に小さいかもしれません。

派生する

すべてを正規化したら、各トピックの傾きを把握します。2つの連続した点を取り、その差を測定します。正の差は上昇傾向、負の差は下降傾向です。次に、正規化された違いを比較し、他のトピックと比較して人気が上昇しているトピックを見つけることができます。各トピックは、他のトピックとは異なる次数の大きさである場合がある独自の「通常」に適切にスケーリングされます。

これは問題の最初のパスです。使用する必要があるより高度な手法があります(主に、上記に他のアルゴリズムを組み合わせたもので、ニーズに合わせて重み付けされています)。しかし、それで十分です。

記事について

この記事はトピックのトレンドについてですが、何がホットで何がそうでないかを計算する方法ではなく、そのようなアルゴリズムがLycosやGoogleなどの場所で処理しなければならない大量の情報を処理する方法に関するものです。各トピックにカウンターを設定し、検索の際に各トピックのカウンターを見つけるのに必要なスペースと時間は膨大です。この記事では、そのようなタスクを試みるときに直面する課題について説明します。ブリトニー効果については触れていますが、それを克服する方法については触れていません。

Nixuzが指摘し、これはまた、Zまたはと呼ばれる標準的なスコア


1
編集前にこれに賛成票を投じ、戻ってきてもう一度反対票を投じたかったのです。いい仕事
mmcdole

ありがとう!私は疑似コードをやるつもりですが、今は時間がありません。多分後で、あるいは多分誰かがこれらの概念を取り入れてそれを実装するでしょう...
アダム・デイビス

どうもありがとう、アダム・デイビス!Nixuzが本当に同じことを説明している場合、私はPHPで解決策を持っていると思います:paste.bradleygill.com/index.php ? paste_id=9206このコードは正しいと思いますか?
2009年

速度ではなくトピックの加速ではないでしょうか?最後の回答をチェックしてください
2013年

17

チャドバーチとアダムデイビスは、ベースラインを確立するために後ろ向きに見なければならないという点で正しいです。あなたの質問は、言いましたように、過去24時間のデータのみを表示したいということを示唆しています。

大量の履歴データを照会せずにデータにメモリを与える1つの方法は、指数移動平均を使用することです。 これの利点は、これを期間ごとに1回更新してからすべての古いデータをフラッシュできるため、1つの値を覚えるだけで済むことです。したがって、期間が1日の場合、各トピックの「日次平均」属性を維持する必要があります。これは、次の方法で実行できます。

a_n = a_(n-1)*b + c_n*(1-b)

ここで、a_n一日のように移動平均されn、bが0と1の間にいくつかの定数である(メモリ1に近い、より長い)及びc_n日のヒット数ですn。美しさは、1日の終わりにこの更新を実行すると、nフラッシュc_nおよびフラッシュできることa_(n-1)です。

注意点の1つは、初期値に何を選択しても、最初は影響を受けやすいということですa

編集

それはこのアプローチを視覚化するのに役立ちます場合は、取るn = 5a_0 = 1b = .9

新しい値が5,0,0,1,4であるとしましょう:

a_0 = 1
c_1 = 5 : a_1 = .9*1 + .1*5 = 1.4
c_2 = 0 : a_2 = .9*1.4 + .1*0 = 1.26
c_3 = 0 : a_3 = .9*1.26 + .1*0 = 1.134
c_4 = 1 : a_4 = .9*1.134 + .1*1 = 1.1206
c_5 = 4 : a_5 = .9*1.1206 + .1*5 = 1.40854

平均にそっくりじゃないですか?次の入力が5であっても、値が1に近いままだったことに注意してください。数学を拡張すると、何が得られますか。

a_n = (1-b)*c_n + (1-b)*b*c_(n-1) + (1-b)*b^2*c_(n-2) + ... + (leftover weight)*a_0

残りの重量とはどういう意味ですか?まあ、平均して、すべての重みは1に追加する必要があります。nが無限大で...が永遠に続く場合、すべての重みの合計は1になります。元の入力で。

上記の式を検討すると、この使用法についていくつかのことに気付くはずです。

  1. すべてのデータは何かに貢献します永遠に平均に。実際には、貢献が非常に小さい点があります。
  2. 最近の値は、古い値よりも寄与します。
  3. bが高いほど、新しい値の重要性は低くなり、古い値は長くなります。ただし、bが高いほど、aの初期値を削減するために必要なデータが多くなります。

最初の2つの特性は、まさにあなたが探しているものだと思います。これを実装するのが簡単であるというアイデアを与えるために、これはpython実装です(すべてのデータベースの相互作用を差し引いたものです):

>>> class EMA(object):
...  def __init__(self, base, decay):
...   self.val = base
...   self.decay = decay
...   print self.val
...  def update(self, value):
...   self.val = self.val*self.decay + (1-self.decay)*value
...   print self.val
... 
>>> a = EMA(1, .9)
1
>>> a.update(10)
1.9
>>> a.update(10)
2.71
>>> a.update(10)
3.439
>>> a.update(10)
4.0951
>>> a.update(10)
4.68559
>>> a.update(10)
5.217031
>>> a.update(10)
5.6953279
>>> a.update(10)
6.12579511
>>> a.update(10)
6.513215599
>>> a.update(10)
6.8618940391
>>> a.update(10)
7.17570463519

1
これは、無限インパルス応答フィルター(IIR)とも呼ばれます
アダムデイビス

私の回答のより良いバージョンをちょっとね。
ジョシュア

@アダム本当に?私はそれらに精通していません。IIRの特別なケースですか?私がスキミングしている記事は、単純なケースでは指数移動平均に減少する式を提供していないようです。
David Berger、

どうもありがとう、David Berger!それがうまくいけば、他の答えに素晴らしい追加になるでしょう!でも質問があります。私はあなたがそれらに答えられることを望みます:1)ファクターbは古いデータがどれだけ速く減量するかを定義しますか?2)このアプローチでは、単に古いデータを保存して平均を計算する場合と比較して、ほぼ同等の結果が得られますか?3)これはあなたの言葉の言葉ですか?$ average_value = $ old_average_value * $ smoothing_factor + $ hits_today *(1- $ smoothing_factor)
2009年

ポイント1と3は正しいです。2.の微妙な議論のビットのための私の編集を参照してください
デビッド・バーガー

8

通常、「バズ」は、ある種の指数関数的/ログ減衰メカニズムを使用して計算されます。Hacker News、Reddit、その他がこれを簡単に処理する方法の概要については、この投稿を参照してください。

これは、常に人気のあるものに完全には対処していません。あなたが探しているのは、Googleの「ホットトレンド」機能のようなものです。そのためには、現在の値を履歴値で除算し、ノイズしきい値を下回る値を差し引くことができます。


はい、Googleのホットトレンドはまさに私が探しているものです。歴史的価値はどうあるべきか?たとえば、過去7日間の平均値は?
2009年

1
それはあなたのデータがどれだけ不安定であるかに依存します。あなたは30日の平均から始めることができます。周期的なもの(例:ケンタッキーダービー)の場合は、毎年比較することは理にかなっています。私は実験して何が実際に最もよく機能するかを確認します。
ジェフモーザー、

7

気になるキーワードは「異常」だと思います。何かが「異常」であるかどうかを判別するには、何が正常かを知る必要があります。つまり、特定のクエリの通常の割合を調べるために平均化できる履歴データが必要になります。異常な日を平均計算から除外することもできますが、除外する日がわかるように、十分なデータがすでに必要です。

そこから、しきい値を設定する必要があります(これには実験が必要だと思います)。何かがしきい値の外に出た場合、たとえば通常より50%多く検索が行われた場合、それを「傾向」と見なすことができます。または、あなたが述べたように「トップXトレンディ」を見つけることができるようにしたい場合は、通常のレートからどれだけ離れているか(パーセンテージ)物を注文する必要があります。

たとえば、過去のデータから、ブリトニースピアーズは通常10万回の検索、パリスヒルトンは通常5万回の検索を受けているとしましょう。どちらも通常よりも10,000多い検索を行う日がある場合、パリの検索は通常よりも20%増加したのに対し、ブリトニーは10%しかなかったため、パリは「より暑い」と考える必要があります。

神様、ブリトニー・スピアーズとパリス・ヒルトンの「辛さ」を比較した段落を書いたとは信じられません。あなたが私にしたこと?


ありがとうございますが、年々増加しているだけで注文するのは少し簡単ですよね。
2009年

7

そのような場合に通常の物理加速式を使用することはまったく可能ですか?

v2-v1/t or dv/dt

v1を1時間あたりの初期のいいね/投票/コメント数と見なすことができ、v2を過去24時間の1時間あたりの現在の「速度」と見なすことができますか?

これは答えというよりは質問に似ていますが、うまくいくようです。アクセラレーションが最も高いコンテンツがトレンドトピックになります...

これはブリトニースピアーズの問題を解決しないかもしれません:-)


それは時間あたりの投票数のような増加を計算するだけなので機能し、これが私たちが必要とするものです。この検索用語は常に高くv1v2「トレンド」と見なされるには非常に高い必要があるため、「ブリトニースピアーズ問題」を部分的に解決できます。ただし、これを行うには、より優れた、より洗練された式とアルゴリズムがおそらくあります。それにもかかわらず、それは基本的な実用例です。
CAW

「トレンド」フィードに常に何かが必要な状況では、これは完璧です。「探索」タブのようなもので、現在プラットフォームで最高のものをリストします。別のアルゴを使用すると、結果セットが空になる場合があります。
kilianc

5

おそらくトピックの頻度の単純な勾配が機能します-大きな正の勾配=人気が急速に高まっています。

最も簡単な方法は、毎日の検索数をビニングすることですので、あなたは次のようなものを持っています

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はそうではありません。または、次の日までの傾向を考慮に入れた、より複雑な勾配。


ありがとうございました。しかし、私は勾配が何であるか、そしてどのようにそれを扱うことができるかを正確に知りません。ごめんなさい!
2009

ありがとう。それで、私は毎日の頻度を含むベクトルを構築しなければなりませんね?相対値の方が良いと思います。例:100から110への成長は、1から9への成長ほど良くありません。しかし、最もホットなトピックを見つけるために使用できるベクトル関数はありませんか?相対値を評価するだけでは十分ではないでしょうか?100から200(100%)への成長は、20,000から39,000への成長ほど良くありません!?
2009

これにどのようなWebサイトを追加しますか?@Autoplecticが毎日の検索の変化をカウントするという提案は、毎日新しいトピックが定義されている何千ものトピックがあり、人気のあるフォーラムのようなものではうまく拡張できません。
Quantum7 2009

そうです、大量のデータ、1時間あたり数千のトピックのアルゴリズムが必要です。
2009年

これは貧弱な戦略です。このように、ブリトニースピアーズについての合計50の検索の増加は、ヨーロッパでの新しい国民投票についての+50の検索と同じくらいホットです。
Iman Akbari

4

私はプロジェクトに取り組んでいました。その目的は、ライブTwitterストリームからトレンドトピックを見つけ、トレンドトピックの感傷分析を行うことでした(トレンドトピックが肯定的または否定的に話し合っているかどうかを見つける)。Twitterストリームの処理にStormを使用しました。

レポートをブログとして公開しました:http : //sayrohan.blogspot.com/2013/06/finding-trending-topics-and-trending.html

ランキングにはTotal CountとZ-Scoreを使用しました。

私が使用したアプローチは少し一般的であり、ディスカッションセクションでは、Twitter以外のアプリケーション用にシステムを拡張する方法について説明しました。

情報がお役に立てば幸いです。


3

単にツイートやステータスメッセージを見てトピックを取得すると、多くのノイズに遭遇します。すべてのストップワードを削除しても。トピック候補のより良いサブセットを取得する1つの方法は、URLを共有するツイート/メッセージのみに焦点を当て、それらのWebページのタイトルからキーワードを取得することです。そして、名詞+名詞句も取得するためにPOSタグ付けを適用するようにしてください。

通常、Webページのタイトルはより説明的で、ページの内容を説明する単語が含まれています。さらに、Webページの共有は通常、ニュースの共有と関連しています(つまり、マイケルジャクソンのような有名人が亡くなった場合、多くの人が彼の死についての記事を共有することになります)。

私は、タイトルから人気のあるキーワードのみを取得し、すべてのステータスメッセージでそれらのキーワードの合計数を取得する実験を実行しました。これにより、多くのノイズが確実に除去されます。このようにすれば、複雑なアルゴリズムは必要ありません。キーワードの頻度を単純に並べ替えれば、その中間になります。


2

log-likelihood-ratiosを使用して、現在の日付を先月または過去の年と比較できます。これは統計的に適切です(イベントが通常は分散されない場合、質問から推測されます)。

すべての用語を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は単語の順不同のコレクションです。ドキュメントごとに、用語のバッグを1つ作成します。単語の出現回数を数えるだけです。次に、メソッドoccurrencesは特定の単語の出現回数を返し、メソッドは単語sizeの総数を返します。どういうわけか単語を正規化することが最善であり、通常toLowerCaseは十分です。もちろん、上記の例では、今日のすべてのクエリで1つのドキュメントを作成し、昨年のすべてのクエリで1つのドキュメントを作成します。


コードを理解できません。TermBagsとは何ですか?このコードが何をするのかを簡単に説明できればすばらしいと思います。
2009

1
TermBagは用語のバッグです。つまり、クラスはテキスト内の単語の総数と各単語の出現回数に答えることができる必要があります。
akuhn 09年

0

アイデアは、そのようなことを追跡し、それらが独自のベースラインと比較して大幅にジャンプしたときに通知することです。

したがって、特定のしきい値を超えるクエリの場合は、それぞれを追跡し、履歴値のある値(たとえば、ほぼ2倍)に変化すると、新しいホットトレンドになります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.