Наивный байесовский расчет в sql

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

Скажем, находим в статье текст «Дженерал Моторс». У нас есть набор данных, который содержит статьи и правильные объекты, упомянутые в них. Таким образом, если мы нашли «Дженерал Моторс», упомянутую в новой статье, должна ли она попасть в тот класс статей в предыдущих данных, которые содержали известные подлинные упоминать «Дженерал Моторс» по сравнению с классом статей, в которых эта организация не упоминается?

(Я не создаю класс для каждой сущности и не пытаюсь классифицировать каждую новую статью по каждому возможному классу. У меня уже есть эвристический метод для поиска правдоподобных упоминаний имен сущностей, и я просто хочу проверить правдоподобие ограниченного числа имя объекта упоминается в статье, которую метод уже обнаруживает.)

Учитывая, что количество потенциальных классов и статей было довольно большим, а наивный байес относительно простым, я хотел сделать все это в sql, но у меня возникли проблемы с запросом оценки...

Вот что у меня есть до сих пор:

CREATE TABLE `each_entity_word` (
  `word` varchar(20) NOT NULL,
  `entity_id` int(10) unsigned NOT NULL,
  `word_count` mediumint(8) unsigned NOT NULL,
  PRIMARY KEY (`word`, `entity_id`)
);

CREATE TABLE `each_entity_sum` (
  `entity_id` int(10) unsigned NOT NULL DEFAULT '0',
  `word_count_sum` int(10) unsigned DEFAULT NULL,
  `doc_count` mediumint(8) unsigned NOT NULL,
  PRIMARY KEY (`entity_id`)
);

CREATE TABLE `total_entity_word` (
  `word` varchar(20) NOT NULL,
  `word_count` int(10) unsigned NOT NULL,
  PRIMARY KEY (`word`)
);

CREATE TABLE `total_entity_sum` (
  `word_count_sum` bigint(20) unsigned NOT NULL,
  `doc_count` int(10) unsigned NOT NULL,
  `pkey` enum('singleton') NOT NULL DEFAULT 'singleton',
  PRIMARY KEY (`pkey`)
);

Каждая статья в отмеченных данных разбивается на отдельные слова, и для каждой статьи для каждого объекта каждое слово добавляется к each_entity_word и/или его word_count увеличивается, а doc_count увеличивается на entity_word_sum, оба относительно entity_id. Это повторяется для каждого известного объекта, упомянутого в этой статье.

Для каждой статьи, независимо от объектов, содержащихся внутри, для каждого слова total_entity_word total_entity_word_sum увеличиваются аналогичным образом.

  • P(слово|любой документ) должен равняться word_count в total_entity_word для этого слова больше doc_count в total_entity_sum
  • P(слово|в документе упоминается сущность x) должно равняться word_count в each_entity_word для этого слова для entity_id x больше doc_count в each_entity_sum для entity_id x
  • P(word|document не упоминает объект x) должен быть равен (word_count в total_entity_word минус его word_count в each_entity_word для этого слова для этого объекта) больше (doc_count в total_entity_sum минус doc_count для этой сущности в each_entity_sum)
  • P(в документе упоминается объект x) должен равняться doc_count в each_entity_sum для этого идентификатора объекта больше doc_count в total_entity_word
  • P(в документе не упоминается объект x) должен равняться 1 минус (doc_count в each_entity_sum для идентификатора объекта x больше doc_count в total_entity_word).

Для поступающей новой статьи разделите ее на слова и просто выберите, где слово («я», «хочу», «чтобы», «использовать»...) напротив each_entity_word или total_entity_word. В платформе db, с которой я работаю (mysql), предложения IN относительно хорошо оптимизированы.

Также в sql нет агрегатной функции product(), поэтому, конечно, вы можете просто выполнить команду sum(log(x)) или exp(sum(log(x))), чтобы получить эквивалент продукта(x).

Итак, если я получаю новую статью, разбиваю ее на отдельные слова и помещаю эти слова в большое предложение IN() и потенциальный идентификатор объекта для проверки, как я могу получить наивную байесовскую вероятность того, что статья попадает в этот объект? класс id в sql?

РЕДАКТИРОВАТЬ:

Попробуйте №1:

set @entity_id = 1;

select @entity_doc_count = doc_count from each_entity_sum where entity_id=@entity_id;

select @total_doc_count = doc_count from total_entity_sum;

select 
            exp(

                log(@entity_doc_count / @total_doc_count) + 

                (
                    sum(log((ifnull(ew.word_count,0) + 1) / @entity_doc_count)) / 
                    sum(log(((aew.word_count + 1) - ifnull(ew.word_count, 0)) / (@total_doc_count - @entity_doc_count)))
                )

            ) as likelihood,
        from total_entity_word aew 
        left outer join each_entity_word ew on ew.word=aew.word and ew.entity_id=@entity_id

        where aew.word in ('I', 'want', 'to', 'use'...);

person ʞɔıu    schedule 13.04.2009    source источник


Ответы (5)


Используйте интерфейс R для Postgres (или MySQL и т. д.)

В качестве альтернативы я бы рекомендовал использовать установленный пакет статистики с коннектором к базе данных. Это сделает ваше приложение намного более гибким, если вы захотите переключиться с наивного Байеса на что-то более сложное:

http://rpgsql.sourceforge.net/

bnd.pr> data(airquality)

bnd.pr> db.write.table(airquality, no.clobber = F)

bnd.pr> bind.proxy("airquality")

bnd.pr> summary(airquality)
Table name: airquality 
Database: test 
Host: localhost
Dimensions: 6 (columns) 153 (rows)


bnd.pr> print(airquality)
   Day Month Ozone Solar.R Temp
1    1     5    41     190   67
2    2     5    36     118   72
3    3     5    12     149   74
4    4     5    18     313   62
5    5     5    NA      NA   56
6    6     5    28      NA   66
7    7     5    23     299   65
8    8     5    19      99   59
9    9     5     8      19   61
10  10     5    NA     194   69
Continues for 143 more rows and 1 more cols...

bnd.pr> airquality[50:55, ]
   Ozone Solar.R Wind Temp Month Day
50    12     120 11.5   73     6  19
51    13     137 10.3   76     6  20
52    NA     150  6.3   77     6  21
53    NA      59  1.7   76     6  22
54    NA      91  4.6   76     6  23
55    NA     250  6.3   76     6  24

bnd.pr> airquality[["Ozone"]]
  [1]  41  36  12  18  NA  28  23  19   8  NA   7  16  11  14  18  14  34   6
 [19]  30  11   1  11   4  32  NA  NA  NA  23  45 115  37  NA  NA  NA  NA  NA
 [37]  NA  29  NA  71  39  NA  NA  23  NA  NA  21  37  20  12  13  NA  NA  NA
 [55]  NA  NA  NA  NA  NA  NA  NA 135  49  32  NA  64  40  77  97  97  85  NA
 [73]  10  27  NA   7  48  35  61  79  63  16  NA  NA  80 108  20  52  82  50
 [91]  64  59  39   9  16  78  35  66 122  89 110  NA  NA  44  28  65  NA  22
[109]  59  23  31  44  21   9  NA  45 168  73  NA  76 118  84  85  96  78  73
[127]  91  47  32  20  23  21  24  44  21  28   9  13  46  18  13  24  16  13
[145]  23  36   7  14  30  NA  14  18  20

Затем вам нужно будет установить пакет e1071 для выполнения наивного байесовского анализа. В командной строке R:

[ramanujan:~/base]$R

R version 2.7.2 (2008-08-25)
Copyright (C) 2008 The R Foundation for Statistical Computing
ISBN 3-900051-07-0

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.


 ~/.Rprofile loaded.
Welcome at  Sun Apr 19 00:45:30 2009
> install.packages("e1071")  
> install.packages("mlbench")
> library(e1071)
> ?naiveBayes
> example(naiveBayes)

Больше информации:

http://cran.r-project.org/web/packages/e1071/index.html

person ramanujan    schedule 19.04.2009

Вот простая версия для SQL Server. Я запускаю его на бесплатной реализации SQL Express, и это довольно быстро.

http://sqldatamine.blogspot.com/2013/07/classification-using-naive-bayes.html

person colin campbell    schedule 25.02.2014
comment
Хотя эта ссылка может ответить на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, содержащие только ссылки, могут стать недействительными, если связанная страница изменится. - person S.L. Barth; 25.02.2014

У меня нет времени вычислять все выражения для формулы NB, но вот основная идея:

SET @entity = 123;

SELECT  EXP(SUM(LOG(probability))) / (EXP(SUM(LOG(probability))) + EXP(SUM(LOG(1 - probability))))
FROM    (
        SELECT  @entity AS _entity,
                /* Above is required for efficiency, subqueries using _entity will be DEPENDENT and use the indexes */
                (
                SELECT  SUM(word_count)
                FROM    total_entity_word
                WHERE   word = d.word
                )
                /
                (
                SELECT  doc_count
                FROM    each_entity_sum
                WHERE   entity_id = _entity
                ) AS pwordentity,
                /* I've just referenced a previously selected field */
                (
                SELECT  1 - pwordentity
                ) AS pwordnotentity,
                /* Again referenced a previously selected field */
                ... etc AS probability
        FROM    total_entity_word
        ) q

Обратите внимание, что вы можете легко ссылаться на предыдущее поле в SELECT, используя их в коррелированных подзапросах (как в примере).

person Quassnoi    schedule 13.04.2009

При использовании Oracle в него встроен интеллектуальный анализ данных

Я не уверен, какую базу данных вы используете, но если вы используете Oracle, возможности интеллектуального анализа данных встроены в базу данных:

http://www.oracle.com/technology/products/bi/odm/index.html

... в том числе Наивный Байес:

http://download.oracle.com/docs/cd/B28359_01/datamine.111/b28129/algo_nb.htm

и тонна других:

http://www.oracle.com/technology/products/bi/odm/odm_techniques_algorithms.html

Это было удивительно для меня. Определенно одно из конкурентных преимуществ Oracle по сравнению с альтернативами с открытым исходным кодом в этой области.

person ramanujan    schedule 19.04.2009
comment
К сожалению, маловероятно, что у автора есть лишняя тысяча долларов на покупку лицензии. Из любопытства я посмотрел пробную версию, и она весит более 2 ГБ. Я уверен, что это очень мило, но это почти наверняка излишне для того, что он ищет. - person Cerin; 23.02.2011

Вот сообщение в блоге с подробным описанием того, что вы ищете: http://nuncupatively.blogspot.com/2011/07/naive-bayes-in-sql.html

Я закодировал много версий классификаторов NB в SQL. Приведенные выше ответы, призывающие к изменению пакетов анализа, не соответствовали моим требованиям к большим данным и времени обработки. У меня была таблица со строкой для каждой комбинации слово/класс (nrows = слова * классы) и столбец коэффициентов. У меня была другая таблица со столбцом для document_id и слова. Я просто объединил эти таблицы вместе в слове, сгруппировал по документам, суммировал коэффициенты, а затем скорректировал суммы для вероятности класса. Это оставило меня с таблицей document_id, class, score. Затем я просто выбрал минимальный балл (поскольку я использовал наивный байесовский подход, который, как я обнаружил, работал лучше в ситуации с несколькими классами).

В качестве примечания я обнаружил, что многие преобразования/модификации алгоритмов значительно улучшили мои прогнозы удержания. Они описаны в работе Джейсона Ренни «Исследование неверных предположений наивных байесовских текстовых классификаторов» и кратко изложены здесь: http://www.ist.temple.edu/~vucetic/cis526fall2007/liang.ppt.

person Patrick McCann    schedule 22.02.2011