Який найкращий спосіб обчислити тенденційні теми чи теги?


183

Багато сайтів пропонують статистику на кшталт "Найгарячіші теми за останні 24 години". Наприклад, Topix.com показує це у своєму розділі «Новини тенденцій». Там ви можете побачити теми, які найчастіше згадуються.

Я також хочу обчислити такий "кайф" для теми. Як я міг це зробити? Алгоритм повинен набирати ваги тем, які завжди менш гарячі. Теми, які зазвичай (майже) ніхто не згадує, мають бути найгарячішими.

Google пропонує "Гарячі тенденції", topix.com показує "Гарячі теми", fav.or.it показує "Тенденції ключових слів" - усі ці сервіси мають одне спільне: вони лише показують вам майбутні тенденції, які є надзвичайно актуальними на даний момент.

Такі терміни, як "Брітні Спірс", "Погода" або "Періс Хілтон", не відображатимуться в цих списках, оскільки вони завжди гарячі та часті. Ця стаття називає це "Проблема Брітні Спірс".

Моє запитання: Як можна кодувати алгоритм або використовувати існуючий для вирішення цієї проблеми? Маючи список із ключовими словами, які шукали протягом останніх 24 годин, алгоритм повинен показати вам 10 (наприклад) найгарячіших.

Я знаю, у статті вище згадується якийсь алгоритм. Я спробував зашифрувати це в PHP, але не думаю, що він спрацює. Це просто знаходить більшість, чи не так?

Сподіваюся, ви можете мені допомогти (приклади кодування були б чудовими).


4
Цікаве запитання, цікаво побачити, що люди мають сказати.
mmcdole

14
Немає підстав для закриття, це справедливе питання
TStamper

1
Це саме те саме питання, і він це навіть констатує! Чому люди підкреслюють це!
Дарріл Хайн

3
Я трохи розгублений, який тип результату ви шукаєте. Стаття, схоже, вказує на те, що "Брітні Спірс" постійно знайдеться у списку "Гарячих", оскільки так багато людей шукають цей термін, але у вашому запитанні зазначено, що він НЕ відображатиметься у списку, оскільки кількість пошуків за цим терміном роблять не сильно збільшуються з часом (вони залишаються високими, але стійкими). Який результат ви намагаєтеся досягти? Чи повинен "Брітні Спірс" рейтингувати високим чи низьким?
e.James

1
@eJames, "Брітні Спірс" не повинна займати високі позиції, оскільки вона є високо пошуковим терміном, і він шукає пошукові терміни з великою швидкістю.
mmcdole

Відповіді:


103

Ця проблема вимагає отримання z-балу або стандартного бала, який враховуватиме середню історію, як згадують інші люди, а також стандартне відхилення цих історичних даних, що робить його більш надійним, ніж просто використання середнього.

У вашому випадку z-оцінка обчислюється за наступною формулою, де тенденція буде такою швидкістю, як перегляди / день.

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

Якщо використовується z-оцінка, то вищий чи нижчий z-оцінка тим більше аномальний тренд, тому, наприклад, якщо z-оцінка є дуже позитивним, то тенденція аномально зростає, тоді як якщо вона є дуже негативною, вона ненормально падає . Отже, як тільки ви обчислите z-бал для всіх кандидатських тенденцій, найвищі 10 z-балів будуть стосуватися найбільш аномально зростаючих z-балів.

Будь ласка, перегляньте Вікіпедію для отримання додаткової інформації про z-результати.

Код

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 днів), якщо ви не хочете брати до уваги велику історію, що зробить короткострокові тенденції більш вираженими та може скоротити час обробки.

  • Ви також можете використовувати z-бал для таких значень, як зміна поглядів від одного дня до наступного дня, щоб знайти аномальні значення для збільшення / зменшення переглядів на день. Це подібно до використання нахилу або похідної графіки переглядів на день.

  • Якщо ви відстежуєте поточний чисельність населення, поточну загальну чисельність населення та поточну загальну кількість 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()
    
  • Використовуючи цей метод, ваш робочий процес буде таким. Для кожної теми, тегу чи сторінки створіть поле з плаваючою точкою за загальну кількість днів, суму переглядів та суму переглядів у квадраті вашої бази даних. Якщо у вас є історичні дані, ініціалізуйте ці поля за допомогою цих даних, інакше ініціалізуйте до нуля. В кінці кожного дня обчислюйте z-бал, використовуючи кількість переглядів дня за попередні дані, що зберігаються у трьох полях бази даних. Теми, теги чи сторінки з найвищими показниками z z X - це ваші X "найбільш популярні тенденції" дня. Нарешті оновіть кожне з 3-х полів зі значенням дня та повторіть процес завтра.

Нове доповнення

Звичайні z-бали, про які йшлося вище, не враховують порядок даних, а отже, z-оцінка для спостереження '1' або '9' матиме однакову величину щодо послідовності [1, 1, 1, 1 , 9, 9, 9, 9]. Очевидно, що для пошуку тенденцій найсучасніші дані повинні мати більшу вагу, ніж старі дані, і тому ми хочемо, щоб спостереження "1" мали більшу оцінку, ніж спостереження "9". Для цього я пропоную плаваючий середній z-бал. Повинно бути зрозуміло, що цей метод НЕ гарантовано є статистично обгрунтованим, але повинен бути корисним для пошуку тенденцій чи подібних. Основна відмінність стандартного z-балу від плаваючого середнього z-бала полягає у використанні плаваючого середнього для обчислення середнього значення населення та середнього значення кількості населення у квадраті. Докладні відомості див. У коді:

Код

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

Оновлення

Як правильно зазначав Девід Кемп, якщо задається серія постійних значень, а потім запитується zscore для спостережуваного значення, яке відрізняється від інших значень, результат, ймовірно, повинен бути не нульовим. Насправді повернене значення повинно бути нескінченним. Тому я змінив цю лінію,

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

до:

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

Ця зміна відображена в коді рішення фасскоре. Якщо людина не хоче мати справу з нескінченними значеннями, прийнятним рішенням може бути замість цього змінити рядок на:

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

1
Ні, у вашому коді є одна невелика помилка в наступному рядку. $ z_score = $ hits_today - ($ середнє_хіц_пер_ден / $ стандартне_направлення); Це повинно бути: $ z_score = ($ hits_today- $ prosjeний_hits_per_day) / $ standard_deviation; Зверніть увагу на зміну в дужках.
Ніксуз

1
@nixuz - чи щось мені не вистачає: fazscore (0,8, карта (лямбда x: 40, діапазон (0,200))), оцінка (1) == 0 (для будь-яких значень)?
kͩeͣmͮpͥ ͩ

1
@Nixus - Я думав, що я можу викопати це з могили. Чи можете ви повторно опублікувати реалізацію цього PHP? У pasteздається , посилання не працюють ... спасибі!
Drewness

1
Для всіх, хто хотів би цього, у мене зараз є SQL запити для цього.
Теліха

1
Розпад тут протилежний інтуїтивному; якщо ви введете 2 значення, скажімо [10, 20] із занепадом 0,8, AVG дорівнює 10 * 0,8 + 20 * 0,2 = 12. Ви очікували б значення вище 15, оскільки 20 має мати більшу вагу, ніж 10, якщо відбувається занепад. Існує набагато краща альтернатива з використанням середньозваженого середнього значення в numpy.average, де ви створюєте паралельний список з вагами. Наприклад: data = range (10,30,10) decay = 0.8 decay_weights = [decay ** a для діапазону (len (дані), 0, -1)] print np.average (дані, ваги = decay_weights)
Jeroen

93

Вам потрібен алгоритм, який вимірює швидкість теми - або іншими словами, якщо ви графікуєте її, ви хочете показати ті, що збираються з неймовірною швидкістю.

Це перша похідна від лінії тренду, і її не важко включити як зважений коефіцієнт вашого загального розрахунку.

Нормалізувати

Один з методів, який вам потрібно буде зробити, - це нормалізувати всі ваші дані. Для кожної теми, яку ви переглядаєте, зберігайте фільтр дуже низьких частот, який визначає базову лінію цієї теми. Тепер кожну точку даних, що надходить у цій темі, слід нормалізувати - відніміть її базову лінію, і ви отримаєте ВСІ ваші теми біля 0, з шипами над і під рядком. Ви можете замість цього розділити сигнал на його базову величину, що приведе сигнал приблизно до 1,0 - це не тільки приведе всі сигнали у відповідність один одному (нормалізує базову лінію), але й нормалізує шипи. Колос Брітні буде на величину більший, ніж чужий, але це не означає, що вам слід звернути на це увагу - шип може бути дуже малим відносно її базової лінії.

Вивести

Після того, як ви все нормалізуєте, з’ясуйте нахил кожної теми. Візьміть два очки поспіль і виміряйте різницю. Позитивна різниця тенденція вгору, негативна різниця - тенденція вниз. Тоді ви можете порівняти нормовані відмінності та дізнатись, які теми набирають популярність у порівнянні з іншими темами - з кожною темою масштабується відповідно до її "нормальної", яка може бути на порядок відмінною від інших тем.

Це справді перше проходження проблеми. Є більш досконалі методи, які вам потрібно буде використовувати (в основному це комбінація перерахованого вище з іншими алгоритмами, зваженими відповідно до ваших потреб), але їх має бути достатньо для початку роботи.

Щодо статті

У статті йдеться про тенденцію теми, але справа не в тому, як обчислити те, що гаряче, а що ні, а про те, як обробити величезну кількість інформації, яку такий алгоритм повинен обробляти в таких місцях, як Lycos та Google. Простір та час, необхідний для того, щоб дати кожній темі лічильник, і знайти лічильник кожної теми, коли відбувається пошук по ній, величезний. У цій статті йдеться про проблеми, з якими стикається при спробі такого завдання. У ньому згадується ефект Брітні, але він не говорить про те, як його подолати.

Як зазначає Ніксуз, це також називається Z або стандартним показником .


1
Я схвалив це перед редагуванням, і повернуся, і я хотів його знову повторити! Приємна робота
mmcdole

Дякую! Я б робив псевдокод, але зараз не маю часу. Можливо, пізніше, чи, можливо, хтось інший візьме ці концепції та втілить їх у життя ...
Адам Девіс

Дуже дякую, Адам Девіс! Якщо Nixuz насправді описав те саме, я думаю, що у мене є рішення в PHP: paste.bradleygill.com/index.php?paste_id=9206 Чи вважаєте ви цей код правильним?
каре

Чи не повинно це бути прискоренням теми, а не швидкістю? Ознайомтеся з останньою відповіддю
Сап

17

Чад Береза ​​та Адам Девіс мають правильне рішення, що вам доведеться дивитися назад, щоб встановити базову лінію. Ваше запитання, висловлене фразою, говорить про те, що ви хочете переглядати лише дані за останні 24 години, і вони не будуть повністю летіти.

Один із способів дати вашим даним деяку пам’ять, не вимагаючи великого масиву історичних даних, - це використовувати експоненціальну ковзну середню. Перевагою цього є те, що ви можете оновлювати це раз на період, а потім очищати всі старі дані, тому вам потрібно запам’ятати лише одне значення. Отже, якщо ваш період становить день, вам потрібно підтримувати атрибут "середнє середнє щоденне" для кожної теми, що ви можете:

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

Де a_nсередня ковзная дня n, b - деяка константа між 0 і 1 (чим ближче до 1, тим довше пам’ять) і c_nце кількість звернень за день n. Краса полягає в тому, що якщо ви виконаєте це оновлення наприкінці дня n, ви можете змити c_nі a_(n-1).

Одне застереження полягає в тому, що він буде спочатку чутливим до того, що ви вибрали для початкової цінності a.

EDIT

Якщо це допомагає візуалізувати цей підхід, прийняти n = 5, a_0 = 1і b = .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

Це не дуже схоже на середній показник? Зверніть увагу, як значення залишилося близьким до 1, хоча наступний наш вхід становив 5. Що відбувається? Якщо ви розгорнете математику, що ви отримаєте:

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. Але якщо n порівняно невелике, ви отримаєте гарну кількість ваги на вихідному вході.

Якщо ви вивчаєте вищевказану формулу, вам слід усвідомити кілька речей щодо цього використання:

  1. Усі дані назавжди вносять щось у середнє значення. Практично кажучи, є момент, коли внесок дійсно, дуже малий.
  2. Останні значення вносять більше, ніж старі значення.
  3. Чим вище b, тим менш важливими є нові значення та значення довших старих значень. Однак чим вище b, тим більше даних потрібно зменшити, щоб зменшити початкове значення a.

Я думаю, що перші дві характеристики - це саме те, що ви шукаєте. Щоб дати вам уявлення про просто, це можна реалізувати, ось реалізація 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)
Адам Девіс

Привіт, краща версія моєї відповіді.
Джошуа

@Adam Дійсно? Я з ними не знайомий. Це особливий випадок IIR? Статті, які я скублю, не здаються формулами, що зводяться до експоненціальної ковзної середньої величини в простому випадку.
Девід Бергер

Дуже дякую, Девід Бергер! Якщо це працює, це було б чудовим доповненням до інших відповідей! Однак у мене є деякі запитання. Я сподіваюся, що ви зможете на них відповісти: 1) Чи визначає коефіцієнт b, наскільки швидко старі дані втрачають вагу? 2) Чи дасть такий підхід приблизно еквівалентні результати порівняно з просто зберіганням старих даних та обчисленням середнього? 3) Це ваша формула на словах? $ povpre_value = $ old_average_value * $ smoothing_factor + $ hits_today * (1- $ smoothing_factor)
caw

Точки 1 і 3 є правильними. Дивіться у моїй редакції трохи нюансовану дискусію від 2.
Девід Бергер

8

Зазвичай "кайф" розбирається за допомогою певної форми механізму розпаду експоненціальної / журнальної роботи. Огляд того, як Hacker News, Reddit та інші справляються з цим простим способом, дивіться у цій публікації .

Це не повністю стосується речей, які завжди популярні. Те, що ви шукаєте, схоже, на зразок функції Google " Гарячі тренди ". Для цього ви можете розділити поточне значення на історичне значення, а потім відняти ті, які знаходяться нижче деякого порогу шуму.


Так, гарячі тенденції Google - саме те, що я шукаю. Якою має бути історична цінність? Наприклад, середнє значення за останні 7 днів?
кая

1
Це залежить від того, наскільки нестабільні ваші дані. Ви можете почати із середнього за 30 днів. Якщо це циклічна річ (наприклад, Кентуккі Дербі), то, можливо, має сенс робити щорічні порівняння. Я б експериментував і бачив, що найкраще працює на практиці.
Джефф Мозер

7

Я думаю, що ключове слово, яке потрібно помітити, - це "ненормально". Для того, щоб визначити, коли щось є "ненормальним", ви повинні знати, що є нормальним. Тобто вам знадобляться історичні дані, за допомогою яких ви зможете визначити нормальну швидкість конкретного запиту. Ви можете виключити ненормальні дні з розрахунку усереднення, але знову ж таки знадобиться мати достатньо даних, щоб ви знали, які дні виключати.

Звідти вам доведеться встановити поріг (який би потребував експериментів, я впевнений), і якщо щось виходить за межі порогу, скажіть, на 50% більше пошукових запитів, ніж зазвичай, ви можете вважати це "трендом". Або, якщо ви хочете знайти "Top X Trendiest", як ви згадали, вам просто потрібно замовити речі, наскільки далеко (у відсотках) вони віддалені від їх нормальної швидкості.

Наприклад, скажімо, що ваші історичні дані говорили вам, що Брітні Спірс зазвичай отримує 100 000 пошукових запитів, а Періс Хілтон зазвичай отримує 50 000. Якщо у вас є день, коли вони обидва отримують на 10 000 більше пошукових запитів, ніж зазвичай, ви повинні вважати Париж "гарячішим", ніж Брітні, оскільки її пошуки зросли на 20% більше, ніж зазвичай, тоді як Брітні - лише на 10%.

Боже, я не можу повірити, що я лише написав абзац, порівнюючи "гарячість" Брітні Спірс та Періс Хілтон. Що ти зробив зі мною?


Дякую, але було б занадто просто замовити їх лише шляхом їхнього збільшення, чи не так?
каре

7

Мені було цікаво, чи взагалі можна застосовувати регулярну формулу прискорення фізики в такому випадку?

v2-v1/t or dv/dt

Ми можемо вважати, що v1 є початковими лайками / голосами / підрахунками коментарів за годину, а v2 - поточною "швидкістю" за годину за останні 24 години?

Це більше схоже на питання, ніж на відповідь, але, здається, може просто спрацювати. Будь-яка тема з найвищим прискоренням стане актуальною темою ...

Я впевнений, що це може не вирішити проблему Брітні Спірс :-)


Він буде працювати, оскільки він просто розраховує збільшення кількості голосів / як за раз, і це те, що нам потрібно. Це могло б вирішити "проблему Брітні Спірс" частинами, оскільки цей пошуковий термін завжди високий v1і потребує дуже високого рівня, v2щоб вважати його "тенденцією". Однак для цього, мабуть, є кращі і більш складні формули та алгоритми. Тим не менш, це основний робочий приклад.
каре

У контексті, коли вам завжди потрібно мати щось у "трендовій" стрічці, це ідеально. Щось на зразок вкладки «Дослідити», де ви перераховуєте, що зараз найкраще на платформі. Використовуючи інший альго, у вас може бути порожній набір результатів.
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 - це не так. або більш складний градієнт, який враховує тенденції протягом більше ніж одного дня на наступний.


Дякую. Але я точно не знаю, що таке градієнт і як я можу з ним працювати. Вибачте!
каре

Дякую. Тож я маю побудувати вектор, що містить добову частоту, правда? Відносні значення були б кращими, я впевнений. Приклад: Зростання від 100 до 110 не так добре, як зростання від 1 до 9, я б сказав. Але чи не існує векторної функції, яку я можу використовувати для пошуку найгарячіших тем? Тільки оцінювати відносні значення не можна було б вважати, чи не так? Зростання від 100 до 200 (100%) не так добре, як зростання від 20 000 до 39 000!
каре

До якого веб-сайту ви додаєте це? @ Пропозиція Autoplectic порахувати зміни в пошуках щодня не буде масштабувати щось на зразок популярного форуму, де кожен день визначаються тисячі тем із новими.
Quantum7

Ви маєте рацію, мені потрібен алгоритм для величезної кількості даних, тисяч тем на годину.
каре

це погана стратегія. Таким чином, загальний приріст 50 пошукових запитів про Брітні Спірс настільки ж гарячий, як і 50 запитів про новий референдум у Європі.
Іман Акбарі

4

Я працював над проектом, де моєю метою було знайти тренд-теми з потоку в прямому ефірі Twitter, а також робив сентиментальний аналіз тренд-тем (з'ясовуючи, чи позитивно / негативно говорив про тренд-тему). Я використовував Storm для обробки щебетати.

Я опублікував свій звіт як блог: http://sayrohan.blogspot.com/2013/06/finding-trending-topics-and-trending.html

Я використовував Total Count та Z-Score для рейтингу.

Підхід, який я використав, трохи загальний, і в розділі обговорень я згадував, що як ми можемо розширити систему для не Twitter програми.

Сподіваюся, що інформація допомагає.


3

Якщо ви просто переглянете твіти або повідомлення про статус, щоб отримати свої теми, ви зіткнетеся з великим шумом. Навіть якщо ви видалите всі стоп-слова. Один із способів отримати кращу підмножину кандидатів на теми - зосередитись лише на твітах / повідомленнях, які мають спільну URL-адресу, та отримати ключові слова з назви цих веб-сторінок. І не забудьте застосувати позначення POS, щоб отримати іменники + іменникові фрази.

Заголовки веб-сторінок зазвичай більш описові та містять слова, що описують, про що йдеться. Крім того, обмін веб-сторінкою зазвичай співвідноситься з поділом новин, які порушуються (тобто, якщо померла така знаменитість, як Майкл Джексон, ви збираєтеся отримати багато людей, які діляться статтею про його смерть).

Я проводив експерименти, де я беру лише популярні ключові слова з заголовків, а потім отримую загальний підрахунок цих ключових слів у всіх повідомленнях про стан, і вони, безумовно, видаляють багато шуму. Якщо ви робите це таким чином, вам не потрібен складний алгоритм, просто виконайте просте впорядкування частоти ключових слів, і ви вже на півдорозі.


2

Ви можете використовувати коефіцієнти ймовірності ймовірності, щоб порівняти поточну дату з останнім місяцем чи роком. Це статистично обгрунтовано (враховуючи, що ваші події зазвичай не поширюються, що слід припустити з вашого запитання).

Просто відсортуйте всі умови за допомогою logLR та виберіть десятку найкращих.

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це досить добре. Звичайно, у наведених вище прикладах ви створили б один документ із усіма запитами сьогодні та один із усіма запитами минулого року.


Вибачте, я не розумію код. Що таке TermBags? Було б чудово, якби ви могли коротко пояснити, що робить цей код.
каре

1
TermBag - це мішок термінів, тобто клас повинен мати можливість відповідати на загальну кількість слів у тексті та кількість зустрічей для кожного слова.
akuhn

0

Ідея полягає у тому, щоб слідкувати за такими речами та помічати, коли вони значно підстрибують у порівнянні з власною базовою лінією.

Отже, для запитів, які мають більше визначеної межі, відстежуйте кожен, і коли він змінюється на деяке значення (скажімо, майже вдвічі) його історичного значення, то це нова гаряча тенденція.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.