Popüler konuları veya etiketleri hesaplamanın en iyi yolu nedir?


183

Birçok site "Son 24 saatteki en sıcak konular" gibi bazı istatistikler sunar. Örneğin, Topix.com bunu "Haber Eğilimleri" bölümünde gösterir. Burada, en hızlı büyüyen bahseden konulara bakabilirsiniz.

Ben de bir konu için böyle bir "vızıltı" hesaplamak istiyorum. Bunu nasıl yapabilirim? Algoritma her zaman sıcak olan konuları ağırlıklandırmalıdır. Normalde (neredeyse) hiç kimsenin bahsetmediği konular en ateşli konular olmalıdır.

Google "Sıcak Eğilimler" sunar, topix.com "Sıcak Konular" gösterir, fav.or.it "Anahtar Kelime Eğilimler" gösterir - tüm bu hizmetlerin ortak bir noktası vardır: Size şu anda anormal derecede sıcak olan yaklaşan eğilimleri gösterirler.

"Britney Spears", "hava durumu" veya "Paris Hilton" gibi terimler bu listelerde görünmez, çünkü bunlar her zaman sıcak ve sıktır. Bu makalede buna "Britney Spears Sorunu" deniyor.

Sorum: Bu sorunu çözmek için bir algoritmayı nasıl kodlayabilir veya mevcut bir algoritmayı kullanabilirsiniz? Son 24 saatte aranan anahtar kelimeleri içeren bir listeye sahip olan algoritma, size en sıcak 10 anahtar kelimeyi göstermelidir.

Biliyorum, yukarıdaki makalede, bahsedilen bir tür algoritma var. Ben PHP kodlamak denedim ama işe yarayacağını sanmıyorum. Sadece çoğunluğu bulur, değil mi?

Umarım bana yardım edebilirsin (kodlama örnekleri harika olurdu).


4
İlginç bir soru, insanların ne söylemesi gerektiğini merak ediyor.
mmcdole

14
Kapatmak için bir neden yok, bu geçerli bir soru
TStamper

1
Bu tam olarak aynı soru ve hatta bunu söylüyor! İnsanlar neden onu destekliyor!
Darryl Hein

3
Ne tür bir sonuç aradığınız konusunda biraz kafam karıştı. Makale, "Britney Spears" ın sürekli olarak "Sıcak" listesinde bulunacağını gösteriyor gibi görünüyor, çünkü birçok kişi bu terimi arıyor, ancak sorunuz o terim için yapılan aramaların sayısı nedeniyle listede görünmeyeceğini belirtiyor zamanla fazla artmaz (yüksek kalır, ancak sabittir). Hangi sonucu elde etmeye çalışıyorsunuz? "Britney Spears" yüksek mi alçak mı olmalı?
James James

1
@eJames, "Britney Spears" sıralamasında yüksek bir arama terimi olduğu ve yüksek bir hıza sahip arama terimleri aradığı için üst sıralarda yer almamalıdır.
mmcdole

Yanıtlar:


103

Bu sorun, diğer insanların belirttiği gibi, tarihsel ortalamayı dikkate alacak bir z skoru veya standart puan gerektirir, ancak bu geçmiş verilerin standart sapmasını da sadece ortalamayı kullanmaktan daha sağlam hale getirir.

Sizin durumunuzda, z-puanı, aşağıdaki formülle hesaplanır; buradaki eğilim, görüntüleme / gün gibi bir oran olacaktır.

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

Bir z-skoru kullanıldığında, z-skoru ne kadar yüksek veya düşükse eğilim o kadar anormal olur, bu nedenle örneğin z-skoru oldukça pozitifse, eğilim anormal bir şekilde yükselir, çok negatifse anormal olarak düşer . Bu nedenle, tüm aday trendler için z skorunu hesapladığınızda, en yüksek 10 z skoru, en anormal şekilde artan z skorlarıyla ilişkilendirilir.

Z skorları hakkında daha fazla bilgi için lütfen Wikipedia'ya bakınız .

kod

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

Örnek Çıktı

>>> 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

notlar

  • Kısa vadeli eğilimleri daha belirgin hale getirecek ve işlem süresini kısaltabilecek olan çok fazla geçmişi dikkate almak istemiyorsanız, bu yöntemi kayan bir pencereyle (yani son 30 gün) kullanabilirsiniz.

  • Ayrıca, günlük görüntüleme sayısını artırmak / azaltmak için anormal değerleri bulmak için bir günden sonraki güne görünüm değişikliği gibi değerler için bir z puanı kullanabilirsiniz. Bu, günlük görünümlerin eğiminin veya türevinin kullanılması gibidir.

  • Nüfusun mevcut boyutunu, nüfusun mevcut toplamını ve nüfusun mevcut toplam x ^ 2'sini takip ederseniz, bu değerleri yeniden hesaplamanıza, yalnızca güncellemenize ve bu nedenle yalnızca bu değerleri her veri değeri için değil, geçmiş için saklayın. Aşağıdaki kod bunu göstermektedir.

    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()
    
  • Bu yöntemi kullanarak iş akışınız aşağıdaki gibi olacaktır. Her konu, etiket veya sayfa için, toplam gün sayısı, görünümlerin toplamı ve veritabanınızdaki karelerin toplamları için bir kayan nokta alanı oluşturun. Geçmiş verileriniz varsa bu alanları bu verileri kullanarak başlatın, aksi halde sıfıra başlatın. Her günün sonunda, üç veritabanı alanında depolanan geçmiş verilere karşı günün görüntüleme sayısını kullanarak z skorunu hesaplayın. En yüksek X z puanına sahip konular, etiketler veya sayfalar, günün X "en sıcak trendleri" dir. Son olarak 3 alanın her birini günün değeri ile güncelleyin ve işlemi yarın tekrarlayın.

Yeni eklenti

Yukarıda tartışıldığı gibi normal z-skorları verilerin sırasını dikkate almaz ve bu nedenle '1' veya '9' gözlemi için z-skoru sekansa karşı aynı büyüklüğe sahip olacaktır [1, 1, 1, 1 , 9, 9, 9, 9]. Açıkçası, eğilim bulmak için, en güncel veriler daha eski verilerden daha fazla ağırlığa sahip olmalıdır ve bu nedenle '1' gözleminin '9' gözleminden daha büyük bir büyüklük skoruna sahip olmasını istiyoruz. Bunu başarmak için değişken bir ortalama z puanı öneriyorum. Bu yöntemin istatistiksel olarak sağlam olduğu garanti EDİLMEDİĞİ açık olmalıdır, ancak eğilim bulma veya benzeri için yararlı olmalıdır. Standart z-skoru ve değişken ortalama z-skoru arasındaki temel fark, ortalama nüfus değerini ve ortalama nüfus değerinin karesini hesaplamak için değişken bir ortalamanın kullanılmasıdır. Ayrıntılar için koda bakın:

kod

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()

Örnek ES

>>> 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

Güncelleme

David Kemp'in doğru bir şekilde işaret ettiği gibi, bir dizi sabit değer ve daha sonra gözlemlenen bir değer için diğer değerlerden farklı bir zscore istenirse, sonuç muhtemelen sıfır olmamalıdır. Aslında döndürülen değer sonsuz olmalıdır. Bu yüzden bu çizgiyi değiştirdim,

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

için:

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

Bu değişiklik fazscore çözüm koduna yansır. Eğer biri sonsuz değerlerle uğraşmak istemiyorsa, kabul edilebilir bir çözüm satırı aşağıdaki gibi değiştirmek olabilir:

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

1
Hayır, kodunuzun aşağıdaki satırda küçük bir hatası var. $ z_score = $ hits_today - ($ average_hits_per_day / $ standard_deviation); Şu şekilde olmalıdır: $ z_score = ($ hits_today- $ ortalama_hits_per_day) / $ standard_deviation; Parantez içindeki değişikliğe dikkat edin.
Nixuz

1
@nixuz - bir şey eksik mi: fazscore (0.8, harita (lambda x: 40, aralık (0,200))). skor (1) == 0 (herhangi bir değer için)?
kͩeͣmͮpͥ ͩ

1
@Nixus - Bunu mezardan kazabileceğimi düşündüm. Bunun PHP uygulamasını yeniden gönderebilir misiniz? pasteLinkler ... çalışmaktan sayesinde görünmüyor!
Drewness

1
İsteyen herkes için, şimdi bunu yapmak için SQL sorguları var.
thouliha

1
Buradaki çürüme karşı sezgiseldir; 2 değer girerseniz, diyelim ki [10, 20] 0.8'lik bir azalma ile AVG 10 * 0.8 + 20 * 0.2 = 12'dir. Çürüme varsa 20'nin 10'dan fazla ağırlığa sahip olması gerektiğinden, 15'in üzerinde bir değer beklersiniz. Ağırlıklar ile paralel bir liste oluşturduğunuz, numpy.average içinde ağırlıklı bir ortalama kullanarak çok daha iyi bir alternatif var. Örneğin: veri = aralık (10,30,10) bozulma = 0,8 decay_weights = [aralık (a) (len (veri), 0, -1)] için bozulma ** a
Jeroen

93

Bir konunun hızını ölçen bir algoritmaya ihtiyacınız var - ya da başka bir deyişle, eğer grafiğini çizerseniz, inanılmaz bir hızda olanları göstermek istiyorsunuz.

Bu, trend çizgisinin ilk türevidir ve genel hesaplamanızın ağırlıklı bir faktörü olarak dahil edilmesi zor değildir.

Normale

Yapmanız gereken bir teknik, tüm verilerinizi normalleştirmek. İzlediğiniz her konu için, o konunun taban çizgisini tanımlayan çok düşük geçişli bir filtre bulundurun. Şimdi, bu konuyla ilgili gelen her veri noktası normalleştirilmelidir - taban çizgisini çıkartın ve TÜM konularınızı 0'ın yakınında, satırın üstünde ve altında ani artışlarla elde edersiniz. Bunun yerine, sinyali 1.0'a getirecek olan temel büyüklüğüne bölmek isteyebilirsiniz - bu sadece tüm sinyalleri birbiriyle aynı hizaya getirmekle kalmaz (taban çizgisini normalleştirir), aynı zamanda ani yükselmeleri de normalleştirir. Bir britney başak, bir başkasının başaktan daha büyük olacak, ancak bu ona dikkat etmeniz gerektiği anlamına gelmez - başak, taban çizgisine göre çok küçük olabilir.

Derive

Her şeyi normalleştirdikten sonra, her konunun eğimini bulun. Art arda iki nokta alın ve farkı ölçün. Olumlu bir fark artıyor, olumsuz bir fark azalıyor. Daha sonra normalleştirilmiş farklılıkları karşılaştırabilir ve diğer konularla karşılaştırıldığında popülerlik içinde hangi konuların yukarı doğru çekildiğini öğrenebilirsiniz - her konu, diğer konulardan farklı düzen büyüklükleri olabilecek kendi 'normal'e uygun olarak ölçeklendirilir.

Bu gerçekten problemin ilk geçişidir. Kullanmanız gereken daha gelişmiş teknikler vardır (çoğunlukla yukarıdakilerin diğer algoritmalarla birleşimi, ihtiyaçlarınıza uyacak şekilde ağırlıklandırılmış), ancak başlamanız için yeterli olmalıdır.

Makaleye ilişkin

Makale konu eğilimi hakkında, ancak neyin sıcak ve neyin olmadığını hesaplamakla ilgili değil, bu tür bir algoritmanın Lycos ve Google gibi yerlerde işlemesi gereken büyük miktarda bilginin nasıl işleneceği ile ilgili. Her konuya bir sayaç vermek ve üzerinde bir arama yapıldığında her konunun sayacını bulmak için gereken alan ve zaman çok büyüktür. Bu makale böyle bir görevi denerken karşılaşılan zorluklarla ilgilidir. Brittney etkisinden bahsediyor, ancak bunun üstesinden nasıl geleceği hakkında konuşmuyor.

Şöyle Nixuz işaret bu da Z ya da adlandırılır standart Puanı .


1
Düzenlemeden önce bunu iptal ettim ve geri geldim ve tekrar yükseltmek istedim! Güzel iş
mmcdole

Teşekkürler! Sahte kod yaparım, ama şu anda vaktim yok. Belki daha sonra, ya da belki başka biri bu kavramları alıp uygular ...
Adam Davis

Çok teşekkür ederim, Adam Davis! Nixuz gerçekten de aynı şeyi açıkladıysa, PHP'de bir çözüm bulduğumu düşünüyorum : paste.bradleygill.com/index.php?paste_id=9206 Bu kodun doğru olduğunu düşünüyor musunuz?
caw

Hızdan ziyade konunun hızlanması değil mi? Son cevaba göz atın
Sap

17

Chad Birch ve Adam Davis, bir taban çizgisi oluşturmak için geriye doğru bakmanız gerekeceğinden haklılar. Sorunuz, ifade edildiği gibi, yalnızca son 24 saatteki verileri görüntülemek istediğinizi ve bu durumun tam olarak uçmayacağını gösteriyor.

Tarihsel verilerin büyük bir kısmını sorgulamak zorunda kalmadan verilerinize biraz bellek vermenin bir yolu, üstel hareketli bir ortalama kullanmaktır. Bunun avantajı, bunu dönem başına bir kez güncelleyip tüm eski verileri temizleyebilmenizdir, böylece yalnızca tek bir değeri hatırlamanız gerekir. Dolayısıyla, döneminiz bir günse, her bir konu için "günlük ortalama" özelliğini korumanız gerekir;

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

a_nGün itibariyle hareketli ortalama nerede n, b 0 ile 1 arasında bir sabittir (1'e ne kadar yakınsa, bellek o kadar uzun olur) ve c_ngün içindeki isabet sayısıdır n. Güzelliği, bu güncellemeyi gün sonunda nyaparsanız, yıkayabilir c_nve a_(n-1).

Bir uyarı, başlangıç ​​değeriniz için seçtiğiniz her şeye duyarlı olacağıdır a.

DÜZENLE

Bu yaklaşım görselleştirmek için yardımcı olursa, almak n = 5, a_0 = 1ve b = .9.

Yeni değerlerin 5,0,0,1,4 olduğunu varsayalım:

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

Ortalama gibi görünmüyor mu? Bir sonraki girdimiz 5 olmasına rağmen, değerin nasıl 1'e yakın kaldığına dikkat edin. Neler oluyor? Eğer matematiği genişletirseniz, bunu elde edersiniz:

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

Artık ağırlıkla ne demek istiyorum? Eh, herhangi bir ortalamada, tüm ağırlıklar 1'e eklenmelidir. Eğer n sonsuz olsaydı ve ... sonsuza kadar devam edebilseydi, o zaman tüm ağırlıklar 1 olurdu. Ama n nispeten küçükse, iyi miktarda ağırlık kalırsın orijinal giriş.

Yukarıdaki formülü incelerseniz, bu kullanım hakkında birkaç şey fark etmelisiniz:

  1. Tüm veriler ortalamaya sonsuza dek bir şeyler katmaktadır. Pratik olarak, katkının gerçekten çok küçük olduğu bir nokta var.
  2. Son değerler eski değerlerden daha fazla katkıda bulunur.
  3. B ne kadar yüksek olursa, yeni değerler o kadar az önem taşır ve eski değerler de o kadar uzun olur. Bununla birlikte, b ne kadar yüksek olursa, a'nın başlangıç ​​değerini sulamak için o kadar fazla veri gerekir.

İlk iki özelliğin tam olarak aradığınız şey olduğunu düşünüyorum. Size uygulamak için basit bir fikir vermek için, burada bir python uygulaması (eksi tüm veritabanı etkileşimi):

>>> 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
Bu aynı zamanda sonsuz bir dürtü yanıt filtresi (IIR) olarak da bilinir
Adam Davis

Hey cevabımın daha iyi bir versiyonu.
Joshua

@ Gerçekten mi? Onlara aşina değilim. Bu özel bir IIR vakası mıdır? Gözden geçirdiğim makaleler, basit durumda üstel bir hareketli ortalamaya inen formüller sağlamıyor gibi görünüyor.
David Berger

Çok teşekkür ederim, David Berger! Çalışırsa, diğer cevaplara harika bir ektir! Yine de bazı sorularım var. Umarım onlara cevap verebilirsiniz: 1) b faktörü, eski verilerin ne kadar hızlı kilo verdiğini tanımlar mı? 2) Bu yaklaşım, eski verileri depolamak ve ortalamayı hesaplamakla karşılaştırıldığında yaklaşık olarak eşdeğer sonuçlar verecek mi? 3) Bu formülün formülü mü? $ average_value = $ old_average_value * $ smoothing_factor + $ hits_today * (1- $ smoothing_factor)
pençe

Nokta 1 ve 3 doğrudur. 2 nüanslı biraz tartışması için düzenlememi görün.
David Berger

8

Tipik olarak "vızıltı", bir tür üstel / log bozunma mekanizması kullanılarak anlaşılır. Hacker News, Reddit ve diğerlerinin bunu basit bir şekilde nasıl ele aldığına genel bir bakış için bu gönderiye bakın .

Bu her zaman popüler olan şeyleri tam olarak ele almaz. Aradığınız şey Google'ın " Hot Trends " özelliği gibi görünüyor . Bunun için, geçerli değeri tarihsel bir değere bölebilir ve sonra bir miktar gürültü eşiğinin altındaki değerleri çıkarabilirsiniz.


Evet, Google'ın Sıcak Trendleri tam da aradığım şey. Tarihsel değer ne olmalı? Örneğin, son 7 günün ortalama değeri?
caw

1
Verilerinizin ne kadar değişken olduğuna bağlıdır. 30 günlük ortalama ile başlayabilirsiniz. Eğer döngüsel bir şeyse (örneğin Kentucky Derby) yıllık karşılaştırmalar yapmak mantıklı olabilir. Pratikte neyin en iyi olduğunu deneyip görürüm.
Jeff Moser

7

Sanırım dikkat etmeniz gereken anahtar kelimeler "anormal". Bir şeyin ne zaman "anormal" olduğunu belirlemek için neyin normal olduğunu bilmeniz gerekir. Yani, belirli bir sorgunun normal oranını bulmak için ortalayabileceğiniz geçmiş verilere ihtiyacınız olacak. Anormal günleri ortalama hesaplamadan hariç tutmak isteyebilirsiniz, ancak yine de yeterli veriye sahip olmayı gerektirecek, böylece hangi günleri hariç tutacağınızı bileceksiniz.

Oradan, bir eşik belirlemeniz gerekecek (deneyi gerektirecek, eminim) ve eşiğin dışına çıkan bir şey varsa, normalden% 50 daha fazla arama söyleyin, bunu bir "trend" olarak düşünebilirsiniz. Ya da, bahsettiğiniz gibi "Top X Trendiest" i bulmak istiyorsanız, işleri normal oranlarından ne kadar uzakta olduklarını (yüzde olarak) sipariş etmeniz yeterlidir.

Örneğin, geçmiş verilerinizin size Britney Spears'ın genellikle 100.000 arama aldığını ve Paris Hilton'un genellikle 50.000 aldığını söylediğini varsayalım. Her ikisinin de normalden 10.000 daha fazla arama aldığı bir gününüz varsa, Paris'i Britney'den "daha sıcak" olarak düşünmelisiniz, çünkü aramaları normalden% 20 daha fazla artarken, Britney's sadece% 10'du.

Tanrım, Britney Spears ve Paris Hilton'un "sıcaklığını" karşılaştıran bir paragraf yazdığımı düşünemiyorum. Bana ne yaptın?


Teşekkürler, ancak sadece procentual artışlarıyla sipariş vermek biraz kolay olurdu, değil mi?
caw

7

Böyle bir durumda düzenli fizik ivme formülü kullanmanın mümkün olup olmadığını merak ediyordum.

v2-v1/t or dv/dt

V1'in saatte ilk beğeni / oy / yorum sayısı ve v2'nin son 24 saatte saatte geçerli "hız" olduğunu düşünebilir miyiz?

Bu bir cevaptan çok bir soru gibidir, ancak işe yarayabilir gibi görünüyor. En yüksek hıza sahip herhangi bir içerik, trend olan konu olacaktır ...

Eminim bu Britney Spears sorununu çözmeyebilir :-)


Zaman başına oy / beğen artışını hesapladığı için işe yarayacaktır ve ihtiyacımız olan şey budur. "Britney spears problemini" parçalar halinde çözebilir, çünkü bu arama terimi her zaman yüksektir v1ve v2"trend" olarak kabul edilmesi için çok yüksek bir değere ihtiyaç duyacaktır . Ancak, bunu yapmak için muhtemelen daha iyi ve daha karmaşık formüller ve algoritmalar vardır. Bununla birlikte, bu temel bir çalışma örneğidir.
13'te çene

Her zaman "trend olan" feed'de bir şeye sahip olmanız gereken bir bağlamda, bu mükemmeldir. Platformda şu anda en iyi olanı listelediğiniz bir Keşfet sekmesi gibi bir şey. Farklı bir algo kullanarak sonuçta boş bir sonuç elde edebilirsiniz.
kilianc

5

muhtemelen konu sıklığının basit bir gradyanı işe yarayacaktır - büyük pozitif gradyan = popülerlikte hızla büyüyor.

en kolay yol, her gün aranan sayıyı bölmektir.

searches = [ 10, 7, 14, 8, 9, 12, 55, 104, 100 ]

ve günden güne ne kadar değiştiğini öğrenin:

hot_factor = [ b-a for a, b in zip(searches[:-1], searches[1:]) ]
# hot_factor is [ -3, 7, -6, 1, 3, 43, 49, -4 ]

ve sadece bir tür eşik uygulayın, böylece artışın> 50 olduğu günler 'sıcak' sayılır. isterseniz bunu çok daha karmaşık hale getirebilirsiniz. mutlak farktan ziyade, göreli farkı alabilir, böylece 100'den 150'ye kadar sıcak kabul edilir, ancak 1000'den 1050'ye kadar. veya bir günden bir güne kadar olan eğilimleri dikkate alan daha karmaşık bir gradyan.


Teşekkür ederim. Ama bir eğimin ne olduğunu ve onunla nasıl çalışabileceğimi tam olarak bilmiyorum. Afedersiniz!
caw

Teşekkürler. Yani günlük frekansı içeren bir vektör yapmalıyım, değil mi? Göreli değerler daha iyi olurdu, eminim. Örnek: 100'den 110'a kadar bir büyüme, 1'den 9'a kadar bir büyüme kadar iyi değildir. Ama en sıcak konuları bulmak için kullanabileceğim bir vektör fonksiyonu yok mu? Sadece göreli değerleri değerlendirmek yeterli olmaz, değil mi? 100'den 200'e (% 100) bir büyüme, 20.000'den 39.000'e kadar bir büyüme kadar iyi değil !?
gak

Bunu ne tür bir web sitesine ekliyorsunuz? @ Autoplectic'in günlük aramalardaki değişimi sayma önerisi, her gün yeni konuların tanımlandığı binlerce konunun olduğu popüler bir forum gibi bir şey için iyi ölçeklenmeyecektir.
Quantum7

Haklısın, devasa miktarda veri için bir algoritmaya ihtiyacım var, saatte binlerce konu.
caw

bu zayıf bir stratejidir. Bu şekilde, Britney Spears ile ilgili toplam 50 arama, Avrupa'da yeni bir referandumla ilgili +50 arama kadar sıcak.
Iman Akbari

4

Amacımın Canlı Twitter Akışı'ndan Trend Olan Konular'ı bulmak ve trend olan konular hakkında duygusal analiz yapmak (Trending Topic'in olumlu / olumsuz olarak konuşulup konuşulmadığını bulmak) olan bir proje üzerinde çalıştım. Twitter akışını işlemek için Storm'u kullandım.

Raporumu bir blog olarak yayınladım: http://sayrohan.blogspot.com/2013/06/finding-trending-topics-and-trending.html

Sıralama için Total Count ve Z-Score kullandım.

Kullandığım yaklaşım biraz genel ve tartışma bölümünde, Twitter olmayan Uygulama için sistemi nasıl genişletebileceğimize değindim.

Umarım bilgi yardımcı olur.


3

Konularınızı almak için tweet'lere veya durum mesajlarına bakarsanız, çok fazla gürültü ile karşılaşırsınız. Tüm durdurma kelimelerini kaldırsanız bile. Konu adaylarının daha iyi bir alt kümesini almanın bir yolu, yalnızca bir URL paylaşan tweet'lere / iletilere odaklanmak ve anahtar kelimeleri bu web sayfalarının başlığından almaktır. Ayrıca isimler + isim cümleleri almak için POS etiketleme uyguladığınızdan emin olun.

Web sayfalarının başlıkları genellikle daha açıklayıcıdır ve sayfanın ne hakkında olduğunu açıklayan kelimeler içerir. Buna ek olarak, bir web sayfasını paylaşmak genellikle son dakika haberlerini paylaşmakla ilişkilidir (yani Michael Jackson gibi bir ünlü öldüğünde, ölümü hakkında bir makale paylaşan birçok insan alacaksınız).

Ben sadece başlıklardan popüler anahtar kelimeler almak deneyler koştu, ve sonra tüm durum mesajları genelinde bu anahtar kelimelerin toplam sayısını almak, ve kesinlikle çok gürültü kaldırmak. Bu şekilde yaparsanız, karmaşık bir algoritmaya ihtiyacınız yoktur, sadece anahtar kelime frekanslarını basit bir şekilde sıralayın ve orada yarı yoldasınız.


2

Geçerli tarihi son ay veya yıl ile karşılaştırmak için günlük olabilirlik oranlarını kullanabilirsiniz. Bu istatistiksel olarak sağlamdır (olaylarınızın normal olarak dağıtılmadığı göz önüne alındığında, sorunuzdan olduğu varsayılır).

Tüm terimlerinizi logLR'ye göre sıralayın ve ilk 10'u seçin.

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, bir TermBag sıralanmamış bir kelime koleksiyonudur. Her belge için bir adet terim oluşturursunuz. Sadece kelimelerin oluşumlarını sayın. Ardından yöntem occurrences, belirli bir sözcüğün yineleme sayısını döndürür ve yöntem size, toplam sözcük sayısını döndürür. Kelimeleri bir şekilde normalleştirmek en iyisidir, genellikle toLowerCaseyeterince iyidir. Tabii ki, yukarıdaki örneklerde bugünün tüm sorgularını içeren bir belge ve geçen yılın tüm sorgularını içeren bir belge oluşturacaksınız.


Üzgünüm, kodu anlamıyorum. TermBag'ler nedir? Bu kodun ne yaptığını kısaca açıklarsanız harika olur.
caw

1
Bir TermBag bir terim torbasıdır, yani sınıf metindeki toplam kelime sayısını ve her bir kelime için gerçekleşme sayısını cevaplayabilmelidir.
akuhn

0

Fikir, bu tür şeyleri takip etmek ve kendi temellerine kıyasla önemli ölçüde atladıklarında fark etmektir.

Dolayısıyla, belirli bir harmandan daha fazlasına sahip sorgular için, her birini izleyin ve tarihsel değerinin bir değerine (neredeyse iki katına) değiştiğinde, yeni bir sıcak trenddir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.