<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-34676872</id><updated>2012-02-03T00:09:04.153+04:00</updated><category term='mtj'/><category term='clustering'/><category term='yahoo'/><category term='data quality'/><category term='sparse matrices'/><category term='live'/><category term='hakia'/><category term='translate'/><category term='double'/><category term='search engines'/><category term='java'/><category term='books'/><category term='headhunting'/><category term='seminar'/><category term='ромип'/><category term='text mining explained'/><category term='sparse arrays'/><category term='k-means'/><category term='memory'/><category term='open source'/><category term='yandex'/><category term='ms sql'/><category term='data preparation'/><category term='hadoop'/><category term='classification'/><category term='decision tree'/><category term='eigenvalue problem'/><category term='msn'/><category term='hashmap'/><category term='sql'/><category term='information extraction'/><category term='treemap'/><category term='shingles'/><category term='natural language processing'/><category term='gate'/><category term='java-ir-utils'/><category term='performance'/><category term='vector space model'/><category term='multirow insert'/><category term='multiword features'/><category term='map-reduce'/><category term='bayes'/><category term='learning'/><category term='svm'/><category term='rit2007'/><category term='google'/><category term='nutch'/><title type='text'>Text Mining Explained</title><subtitle type='html'>Практические советы по реализации систем извлечения информации</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>29</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-34676872.post-4304342554032423992</id><published>2007-06-14T11:27:00.000+04:00</published><updated>2007-06-14T11:28:50.754+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='seminar'/><category scheme='http://www.blogger.com/atom/ns#' term='yandex'/><title type='text'>Supporting Search in a Multilingual World</title><content type='html'>21 июня 2007 г. (четверг), 17:00-18:30&lt;br /&gt;&lt;br /&gt;Douglas W. Oard (http://www.glue.umd.edu/~oard/)&lt;br /&gt;Associate Dean for Research&lt;br /&gt;College of Information Studies&lt;br /&gt;University of Maryland, USA&lt;br /&gt;&lt;br /&gt;Title:&lt;br /&gt;&lt;br /&gt;Supporting Search in a Multilingual World&lt;br /&gt;&lt;br /&gt;Abstract:&lt;br /&gt;&lt;br /&gt;The Internet is a vast multilingual commons, and the past decade has seen a dramatic acceleration of research on the construction of systems to support multilingual information access. In this talk, I will describe the key advances in cross-language information retrieval and machine translation that now enable us to build systems that span language barriers to some degree for some purposes. With that as background, I will then step back and look at the problem from the perspective of an application developer to identify critical gaps in the present technology that could inhibit adoption in Web and enterprise search applications.&lt;br /&gt;&lt;br /&gt;About the Speaker:&lt;br /&gt;&lt;br /&gt;Douglas Oard is Associate Dean for Research at the College of Information Studies of the University of Maryland, College Park, where he holds joint appointments as Associate Professor in the College of Information Studies and in the Institute for Advanced Computer Studies. He earned his Ph.D. in Electrical Engineering from the University of Maryland, and his research interests center around the use of emerging technologies to support information seeking by end users. Dr. Oard's recent work has focused on interactive techniques for cross-language information retrieval, searching conversational media, and leveraging observable behavior to improve user modeling. Additional information is available at http://www.glue.umd.edu/~oard/.&lt;br /&gt;&lt;br /&gt;Язык - английский.&lt;br /&gt;&lt;br /&gt;Если вы хотите посетить семинар, пожалуйста, предварительно зарегистрируйтесь по тел. +7 495 739-7000. Количество мест ограничено.&lt;br /&gt;&lt;br /&gt;Место: Яндекс, Москва, ул. Самокатная, дом 1, стр. 21&lt;br /&gt;Как добраться: см. &lt;a href="http://company.yandex.ru/inside/contacts.xml"&gt;http://company.yandex.ru/inside/contacts.xml&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Запись семинара будет выложена в открытый доступ.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-4304342554032423992?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/4304342554032423992/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=4304342554032423992' title='Комментарии: 127'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/4304342554032423992'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/4304342554032423992'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2007/06/supporting-search-in-multilingual-world.html' title='Supporting Search in a Multilingual World'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>127</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-2129369342403985543</id><published>2007-05-12T13:01:00.000+04:00</published><updated>2007-05-12T13:11:29.722+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='seminar'/><category scheme='http://www.blogger.com/atom/ns#' term='yandex'/><title type='text'>Web Content Mining</title><content type='html'>Во вторник 15-го мая в Яндексе состоится второй открытый семинар. Вести его будет Bing Liu, автор вышедшей в январе 2007-го года книги &lt;a href="http://www.amazon.com/Web-Data-Mining-Data-Centric-Applications/dp/3540378812/ref=pd_bbs_sr_1/103-0354475-5323042?ie=UTF8&amp;s=books&amp;qid=1178960629&amp;sr=8-1"&gt;Wed Data Mining&lt;/a&gt;, а также автор однодневного учебного курса &lt;a href="http://www.cs.uic.edu/~liub/WebContentMining.html"&gt;Web Content Mining&lt;/a&gt; для участников конференции &lt;a href="http://www2005.org/index.html"&gt;WWW2005&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Семинар будет состоять из двух частей:&lt;ol&gt;&lt;li&gt;Template detection, data extraction (выделение шаблонов страниц, извлечение "записей данных"), 16:00&amp;nbsp;&amp;mdash; 17:30&lt;li&gt;Opinion mining ("выявление мнений"), 18:00&amp;nbsp;&amp;mdash; 19:30&lt;/ol&gt;Участие в семинаре бесплатное, нужна предварительная запись по телефону +7 495 739 7 000, количество мест ограничено.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-2129369342403985543?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/2129369342403985543/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=2129369342403985543' title='Комментарии: 44'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/2129369342403985543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/2129369342403985543'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2007/05/web-content-mining.html' title='Web Content Mining'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>44</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-3264795108157118946</id><published>2007-05-04T01:55:00.000+04:00</published><updated>2007-05-04T02:24:20.392+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='java-ir-utils'/><category scheme='http://www.blogger.com/atom/ns#' term='multirow insert'/><category scheme='http://www.blogger.com/atom/ns#' term='ms sql'/><title type='text'>Multirow inserts</title><content type='html'>Немного в сторону от основной темы блога, но, думаю, многим будет полезно.&lt;br /&gt;&lt;br /&gt;Очень часто в моей работе приходится вставлять сравнительно большое число строк (несколько миллионов) в какую-нибудь таблицу. Причем делать это регулярно. Если делать отдельный insert на каждую строчку, миллион будет вставляться очень и очень долго. В MySQL поддерживается специальный синтаксис для multirow inserts: &lt;code&gt;INSERT INTO my_table (col1, col2) values (1, 2), (3, 4), ... (99, 100)&lt;/code&gt;. Такой запрос вставит сразу 50 строчек. Причем очень быстро. Число строчек, которые можно вставить за один запрос очень велико и ограничено сверху, если я не ошибаюсь, максимальным размером пакета, который может принять MySQL. На практике, я обычно вставляю по несколько десятков тысяч строк одним запросом.&lt;br /&gt;&lt;br /&gt;К сожалению, ни Oracle, ни MS SQL не поддерживают этот замечательный синтаксис. Долгий поиск дал всего две рекомендации: использовать sqlldr, &lt;code&gt;LOAD DATA&lt;/code&gt; или &lt;code&gt;INSERT INTO &amp;lt;table name&amp;gt; SELECT FROM &amp;lt;table name&amp;gt;&lt;/code&gt;. Практически отчаявшись, я заглянул в Википедию и нашел там &lt;a href="http://en.wikipedia.org/wiki/Insert_%28SQL%29"&gt;спасение&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Во-первых, оказалось, что чудесный синтаксис из MySQL это часть стандарта SQL 92 (это, действительно, &lt;a href="http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt"&gt;так&lt;/a&gt;&amp;nbsp;&amp;mdash; ключевые слова "query expression", "insert statement", "table value constructor") и он поддерживается также в DB2 и PostgreSQL.&lt;br /&gt;&lt;br /&gt;Во-вторых, &lt;code&gt;INSERT INTO &amp;lt;table name&amp;gt; SELECT FROM &amp;lt;table name&amp;gt;&lt;/code&gt; может выглядеть так (пример для MS SQL):&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;INSERT INTO my_table (col1, col2)&lt;br /&gt;SELECT 1, 2&lt;br /&gt;UNION ALL&lt;br /&gt;SELECT 3, 4&lt;/code&gt;&lt;/blockquote&gt;Такой запрос вставит в таблицу сразу две строчки. С воодушевлением я принялся за тестирование. Сначала попробовал вставлять 50 строчек за раз. Скорость возрасла, но не сильно. Потом попробовал 200&amp;nbsp;&amp;mdash; стало медленнее! Попробовал 1000 и получил ошибку от MS SQL! Дальнейшие эксперименты позволили сделать следующие выводы:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Оптимальное количество строчек в одном запросе&amp;nbsp;&amp;mdash; 5-10. Так иногда удается достичь, практически, линейного роста скорости вставки.&lt;br /&gt;&lt;li&gt;Скорость вставки очень сильно зависит от размера строчки. В одном из экспериментов я убрал из запроса одну колонку типа bit и скорость возросла на 30%!&lt;br /&gt;&lt;li&gt;Если какую-то колонку можно вставить небольшим количеством update'ов, возможно, так будет заметно быстрее.&lt;/ul&gt; Для удобной работы с multirow inserts я сделал простой интерфейс &lt;code&gt;BulkInserter&lt;/code&gt; с реализацией пока только для MS SQL. В ближайшее время сделаю реализацию для MySQL, допишу документацию и выложу в &lt;a href="http://krondix.blogspot.com/search/label/java-ir-utils"&gt;Java IR Utils&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-3264795108157118946?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/3264795108157118946/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=3264795108157118946' title='Комментарии: 87'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/3264795108157118946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/3264795108157118946'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2007/05/multirow-inserts.html' title='Multirow inserts'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>87</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-8104518305659305807</id><published>2007-05-03T13:37:00.000+04:00</published><updated>2007-05-03T15:29:09.951+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='svm'/><category scheme='http://www.blogger.com/atom/ns#' term='shingles'/><category scheme='http://www.blogger.com/atom/ns#' term='gate'/><title type='text'>Text Mining Libraries</title><content type='html'>Один из читателей блога спросил у меня по электронной почте про известные мне библиотеки с реализациями разных алгоритмов IR. В частности его интересовала кластеризация шинглами. Неплохая реализация шинглов на C++ есть в библиотеке &lt;a href="http://www.di.unipi.it/%7Egulli/clustBoost.html"&gt;ClustBoost&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Вообще хороших библиотек, а тем более open source, не так много. Среди тех с кем мне приходилось сталкиваться можно выделить:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://gate.ac.uk/"&gt;GATE&lt;/a&gt;&amp;nbsp;&amp;mdash; как они пишут про себя  это "the Eclipse of Natural Language Engineering, the Lucene of Information Extraction, the leading toolkit for Text Mining". С &lt;a href="http://jakarta.apache.org/lucene/"&gt;Lucene&lt;/a&gt;, конечно, они себя зря сравнивают. Коротко говоря, GATE это более-менее удобная графическая среда, к которой можно плагинами подключить практически любую библиотеку для обработки текста.&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.aktors.org/technologies/annie/"&gt;ANNIE&lt;/a&gt;&amp;nbsp;&amp;mdash; распространяется как часть GATE. Включает в себя: токенайзер, sentence splitter, part-of-speech tagger и named entity recogniser. Последний может выделять такие сущности как имена, организации, места, даты, адреса и др.  Утверждается что ведутся работы по портированию ANNIE для русского языка.&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.cs.waikato.ac.nz/ml/weka/"&gt;WEKA&lt;/a&gt;&amp;nbsp;&amp;mdash; в этой библиотеке реализованы многие алгоритмы классификации плюс есть хорошие визуализаторы результатов. Есть wrapper в GATE.&lt;br /&gt;&lt;li&gt;&lt;a href="http://minorthird.sourceforge.net/"&gt;MinorThird&lt;/a&gt;&amp;nbsp;&amp;mdash; позволяет работать с аннотированным текстом, используя эти аннотации можно классифицировать документы с помощью множества реализованных алгоритмов (начиная от &lt;a href="http://en.wikipedia.org/wiki/K-nearest_neighbor_algorithm"&gt;k-nn&lt;/a&gt;, заканчивая &lt;a hef="http://en.wikipedia.org/wiki/Support_vector_machine"&gt;SVM&lt;/a&gt; и &lt;a href="http://www.cs.ucsd.edu/~yfreund/papers/LargeMarginsUsingPerceptron.pdf"&gt;voted perceptron&lt;/a&gt;. Что интересно, в MinorThird помимо обычной supervised классификации есть реализации и semi-supervised алгоритмов.&lt;br /&gt;&lt;li&gt;&lt;a href="http://svmlight.joachims.org/"&gt;SVM&lt;sup&gt;light&lt;/sup&gt;&lt;/a&gt;&amp;nbsp;&amp;mdash; хорошая и быстрая реализация SVM на C. Есть wrapper в GATE.&lt;/ul&gt;Буду рад добавлениям в список.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-8104518305659305807?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/8104518305659305807/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=8104518305659305807' title='Комментарии: 15'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/8104518305659305807'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/8104518305659305807'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2007/05/text-mining-libraries.html' title='Text Mining Libraries'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-6075748444762605668</id><published>2007-04-15T12:30:00.000+04:00</published><updated>2007-04-15T13:36:31.886+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rit2007'/><category scheme='http://www.blogger.com/atom/ns#' term='yandex'/><category scheme='http://www.blogger.com/atom/ns#' term='classification'/><category scheme='http://www.blogger.com/atom/ns#' term='headhunting'/><title type='text'>РИТ-2007 и новости</title><content type='html'>Завтра будет первый день конференции &lt;a href="http://www.rit2007.ru"&gt;РИТ-2007&lt;/a&gt;. В 18:00 я буду читать доклад про классификацию товарных предложений Яндекс.Маркета. Те, кто не идут на РИТ, смогут посмотреть среди прочих и мой доклад на сайте конференции (&lt;a href="http://rit2007.ru/news/2165.html"&gt;расписание трансляций&lt;/a&gt;). &lt;br /&gt;&lt;br /&gt;После небольшой рекламы, хочу сказать еще несколько вещей:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Блог после долгого перерыва возобновляет свою работу&lt;br /&gt;&lt;li&gt;В ближайшее время я завершу серию постов "&lt;a href="http://krondix.blogspot.com/search/label/text%20mining%20explained"&gt;Введение в Text Mining&lt;/a&gt;"&lt;br /&gt;&lt;li&gt;Будет несколько постов про базы данных, конкретно, как быстро вставлять очень много строчек в разные таблицы&lt;br /&gt;&lt;li&gt;Расскажу про свои впечатления от &lt;a href="http://krondix.blogspot.com/search/label/nutch"&gt;Nutch&lt;/a&gt; и &lt;a href="http://krondix.blogspot.com/search/label/hadoop"&gt;Hadoop&lt;/a&gt; &lt;br /&gt;&lt;/ol&gt;И самое важное. Нам в Яндекс нужны люди, хорошо знающие Java и с большим желанием заниматься text mining. На &lt;a href="http://company.yandex.ru/inside/job/index.xml"&gt;сайте&lt;/a&gt; вакансии пока нет&amp;nbsp;&amp;mdash; все вопросы можно и нужно задавать мне по адресу &lt;a href="mailto:krondix@yandex-team.ru"&gt;krondix@yandex-team.ru&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-6075748444762605668?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/6075748444762605668/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=6075748444762605668' title='Комментарии: 12'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/6075748444762605668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/6075748444762605668'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2007/04/2007.html' title='РИТ-2007 и новости'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-3819785513220453189</id><published>2007-01-11T10:14:00.000+03:00</published><updated>2007-01-11T12:40:59.598+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='msn'/><category scheme='http://www.blogger.com/atom/ns#' term='search engines'/><category scheme='http://www.blogger.com/atom/ns#' term='yahoo'/><category scheme='http://www.blogger.com/atom/ns#' term='google'/><category scheme='http://www.blogger.com/atom/ns#' term='hakia'/><category scheme='http://www.blogger.com/atom/ns#' term='live'/><title type='text'>How Long Is The Nile River?</title><content type='html'>Понадобилось недавно узнать точную длину реки Нил, и, вместо Википедии, я решил спросить об этом у поисковиков. Сначала я задавал вопрос "how long is Nile?". Правильным ответом будем считать &lt;a href="http://en.wikipedia.org/wiki/Nile"&gt;6695 км или 4160 (4184) миль&lt;/a&gt;. Вот что получилось:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.google.com/search?q=how+long+is+nile&amp;ie=utf-8&amp;amp;oe=utf-8&amp;rls=org.mozilla:ru:official&amp;amp;client=firefox-a"&gt;Google&lt;/a&gt;: правильный ответ в втором и третьем сниппетах &lt;/li&gt;&lt;li&gt;&lt;a href="http://search.yahoo.com/search?p=how+long+is+nile%3F&amp;fr=yfp-t-501&amp;toggle=1&amp;cop=mss&amp;ei=UTF-8"&gt;Yahoo&lt;/a&gt;: правильный ответ в четвертом сниппете&lt;/li&gt;&lt;li&gt;&lt;a href="http://search.live.com/results.aspx?q=how+long+is+nile%3F&amp;mkt=ru-ru&amp;FORM=LVSP&amp;go.x=0&amp;go.y=0&amp;go=Search"&gt;Live&lt;/a&gt;:  первый сниппет показывает нам длину реки Атбара, которая впадает в Нил, длина Нила лишь в восьмом сниппете&lt;/li&gt;&lt;li&gt;&lt;a href="http://search.msn.com/results.aspx?q=how+long+is+nile%3F&amp;FORM=MSNH"&gt;MSN&lt;/a&gt;: как самый хитрый показал перед выдачей "Nile River length: 6695 km/4160 mi" с ссылкой на &lt;a href="http://encarta.msn.com/media_461524422/World%E2%80%99s_Longest_Rivers.html?ENCMauth=FIbT7vFXbffbZx12%2f0w8zdu3HRdSBZCVk22Q5ws4ZPZXjBMDBYCbtH2wmchKukN3zQPU5tnovWs%3d"&gt;Encarta&lt;/a&gt;, при этом первый сниппет также содержит вносящую путаницу длину реки Атбара, но в третьем, шестом и седьмом&amp;nbsp;&amp;mdash; правильный ответ!&lt;/li&gt;&lt;li&gt;&lt;a href="http://hakia.com/search.aspx?q=how+long+is+nile%3F"&gt;Hakia&lt;/a&gt;: правильный ответ в пятом и седьмом сниппетах, при этом ни там ни там ответ не подсвечен, что ожидалось&lt;/li&gt;&lt;/ul&gt;Удивительной для меня показалась разница в выдаче Live и MSN, при том что MSN использует тот же Live Search. Кто может объяснить в чем дело? Огорчила Hakia, которая не смогла подсветить в сниппете правильный ответ. Впрочем, если задать грамматически правильный вопрос "how long is the Nile river?", Hakia &lt;a href="http://hakia.com/search.aspx?q=how+long+is+the+nile+river%3F"&gt;покажет себя&lt;/a&gt; с наилучшей стороны: ответ содержится в восьми сниппетах, в семи из них он даже подсвечен! Плюс перед выдачей стоит правильный ответ с &lt;a href="http://library.thinkquest.org/J0112722/NileRiver/General%20Facts/miscellaneous.htm"&gt;ссылкой&lt;/a&gt; на Thinkquest. Остальные поисковики также лучше справляются с грамматически правильным вопросом, даже Live показывает ответ на первой странице.&lt;br /&gt;&lt;br /&gt;Выводов никаких делать не буду, использовать MSN вместо Google тоже не начну, только лишь &lt;a href="http://mycroft.mozdev.org/download.html?name=hakia&amp;sherlock=yes&amp;opensearch=yes&amp;submitform=Search"&gt;добавлю Hakia&lt;/a&gt; в список поисковиков в Firefox.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-3819785513220453189?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/3819785513220453189/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=3819785513220453189' title='Комментарии: 8'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/3819785513220453189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/3819785513220453189'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2007/01/how-long-is-nile-river.html' title='How Long Is The Nile River?'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-2829605175131138095</id><published>2007-01-03T12:52:00.000+03:00</published><updated>2007-01-03T14:31:17.835+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='search engines'/><category scheme='http://www.blogger.com/atom/ns#' term='clustering'/><category scheme='http://www.blogger.com/atom/ns#' term='hakia'/><title type='text'>Hakia — поиск смысла</title><content type='html'>&lt;p&gt;Продолжая тему &lt;a href="http://krondix.blogspot.com/2006/11/blog-post.html"&gt;кластерного поиска&lt;/a&gt;. Новый поисковик Hakia (&lt;a href="http://www.hakia.com"&gt;http://www.hakia.com&lt;/a&gt;) делает, пожалуй, самые интересные шаги в этом направлении. &lt;a href="http://www.hakia.com/about.html"&gt;"The basic promise is to bring search results by meaning match - similar to the human brain's cognitive skills - rather than by the mere occurrence (or popularity) of search terms."&lt;/a&gt; &lt;p&gt;Я, конечно же, захотел проверить Hakia на своем любимом запросе &lt;a href="http://www.hakia.com/search.aspx?q=nokia+6230i"&gt;"nokia 6230i"&lt;/a&gt;. К моему удивлению, я увидел самую обыкновенную плоскую выдачу! Вернее, почти обыкновенную. В сниппетах выделены не просто ключевые слова запроса, а иногда и целые предложения или их части. Например, "The Nokia 6230i imaging phone combines advanced image and video features", "downloads and customer service information for your Nokia 6230i phone.", "to separate the Nokia 6230i from the 6230 apart from the vastly improved joystick" и др. Видно, что Hakia пытается понять о чем страница и показать самый релевантный смыслу &lt;i&gt;страницы&lt;/i&gt; кусок в сниппете (не забывая, конечно, о поисковом запросе). Вполне возможно, это может сэкономить некоторое время&amp;nbsp;&amp;mdash; надо читать не весь сниппет, а заранее выделенный кусок&amp;nbsp;&amp;mdash; чтобы это проверить, надо попользоваться Hakia подольше.&lt;p&gt;Где же обещанный кластерный поиск? На наш запрос "nokia 6230i" маленькая зеленая голова под строкой поиска ответила (текст выбирается случайно): "Tough question! See if the results below help. ...See the hakia gallery for &lt;a href="http://www.hakia.com/search.aspx?q=Nokia"&gt;Nokia&lt;/a&gt;". Идем по ссылке (запрос "Nokia"), первая страница выдачи это, так называемая, галерея&amp;nbsp;&amp;mdash; набор кластеров с двумя ссылками в каждом. Headlines; Stock Quote and Company Website ; News, Company Profile; Company Heritage; Press Releases; Investors Page; Corporate Leadership; Employment and Career Opportunities; Brands; Industry and Peers; Criticism, Commentary, and Interpretations; Community Outreach and Philanthropy; Location and Contact Information&amp;nbsp;&amp;mdash; кластера хорошие, с правильными названиями и правильными ссылками в них. Смущают только две вещи. Во-первых, hakia gallery выдается не по всем запросам. Во-вторых, я не нашел способа посмотреть что еще есть в том или ином кластере. Имя кластера это не ссылка, а если набрать запрос &lt;a href="http://www.hakia.com/search.aspx?q=Nokia+headlines"&gt;"Nokia headlines"&lt;/a&gt;, мы увидим совсем не те новости, которые нам предлагали в галерее.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-2829605175131138095?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/2829605175131138095/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=2829605175131138095' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/2829605175131138095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/2829605175131138095'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2007/01/hakia.html' title='Hakia&amp;nbsp;&amp;mdash; поиск смысла'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-1183086012462836667</id><published>2006-12-27T19:37:00.000+03:00</published><updated>2006-12-27T21:57:01.572+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='open source'/><category scheme='http://www.blogger.com/atom/ns#' term='map-reduce'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='search engines'/><category scheme='http://www.blogger.com/atom/ns#' term='nutch'/><category scheme='http://www.blogger.com/atom/ns#' term='hadoop'/><title type='text'>Nutch и Hadoop, первые впечатления</title><content type='html'>&lt;div style="text-align: justify;"&gt;Давно уже собирался как следует посмотреть на &lt;a href="http://lucene.apache.org/nutch"&gt;Nutch&lt;/a&gt; — open-source поисковый движок на Java — сегодня наконец поставил, буду по-тихоньку делиться впечатлениями.&lt;br /&gt;&lt;p&gt;Nutch построен на основе Hadoop — это фреймворк, реализующий идею &lt;a href="http://labs.google.com/papers/mapreduce.html"&gt;MapReduce&lt;/a&gt;.  Расскажу кратко основную идею. Термины map и reduce пришли из функционального программирования, где они означают следующее: reduce это функция  типа α -&gt; β, map — функция типа (α -&gt; β) -&gt; [α] -&gt; [β]. То есть map применяет переданную ей первым аргументом функцию reduce к списку элементов типа α и на выходе получается список элементов типа β. Например, если мы определим функцию &lt;code&gt;square x = x ∗ x&lt;/code&gt;, вызов &lt;code&gt;map square[1,2,3]&lt;/code&gt; вернет &lt;code&gt;[1,4,9]&lt;/code&gt;. Если reduce функция без побочных эффектов (то есть она не изменяет ничего за пределами своей области видимости), то применять ее можно одновременно к нескольким элементам входного списка. Гугловый фреймворк MapReduce позволяет прозрачно для программы разносить эти вычисления по многим машинам. Hadoop представляет собой open-source реализацию этой же идеи на Java.&lt;br /&gt;&lt;p&gt;Итак, исходники скачаны, первое, что необходимо сделать — настроить запуск их среды разработки. Как это сделать для Eclipse описано &lt;a href="http://wiki.apache.org/nutch/RunNutchInEclipse"&gt;здесь&lt;/a&gt;, перескажу вкратце с одним дополнительным шагом для IDEA.&lt;br /&gt;&lt;/div&gt;&lt;ol style="text-align: justify;"&gt;&lt;li&gt;При создании нового проекта IDEA найдет все папки с исходниками (их там много).&lt;/li&gt;&lt;li&gt;В dependencies надо добавить все *.jar из lib и src/plugin/*/lib. К hadoop-*.jar лучше подключить исходники или (лучше) настроить Hadoop соседним модулем в проекте.&lt;/li&gt;&lt;li&gt;Пометить папку conf как source folder. В настройках компилятора в Resource Patterns добавить ?*.txt, если этого не сделать *.txt файлы из conf, не будут видны в рантайме и Nutch работать не будет.&lt;/li&gt;&lt;li&gt;В nutch-site.xml (или nutch-defaults.xml) прописать свойство plugin.folders как src/plugin&lt;/li&gt;&lt;li&gt;Прописать в defaults VM arguments: -Dhadoop.log.dir=logs -Dhadoop.log.file=hadoop.log&lt;/li&gt;&lt;/ol&gt;&lt;div style="text-align: justify;"&gt;После этого можно попробовать запустить Injector с соответствующими параметрами (см. &lt;a href="http://wiki.apache.org/nutch/NutchTutorial"&gt;tutorial&lt;/a&gt;), все должно работать.&lt;p&gt;К сожалению, какая-либо внятная и полная документация по Nutch и Hadoop отсутствует, API также практически не задокументирован, а код не слишком читабелен. Без дебагера разобраться сложно. Плюс эти товарищи повсеместно используют конструкцию, за которую надо просто отрывать руки:&lt;blockquote style="text-indent:0px"&gt;&lt;pre&gt;&lt;code&gt;try {&lt;br /&gt;    url = urlNormalizers.normalize(url, URLNormalizers.SCOPE_INJECT);&lt;br /&gt;    url = filters.filter(url);&lt;br /&gt;} catch (Exception e) {&lt;br /&gt;    if (LOG.isWarnEnabled()) { LOG.warn("Skipping " +url+":"+e); &lt;br /&gt;    url = null;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;p&gt;Если произойдет исключение, то мы увидим только его класс, а stacktrace нам не покажут. Нам даже не скажут на какой строчке какого класса оно произошло. Метод &lt;code&gt;warn&lt;/code&gt; у логгера (и все остальные тоже) специально перегружены, чтобы корректно обрабатывать такую ситуацию, достаточно вместо плюса поставить запятую — &lt;code&gt;LOG.warn("Skipping " +url+":", e)&lt;/code&gt; — и будет выведен нормальный stacktrace, из которого легко понять что происходит.&lt;br /&gt;&lt;p&gt;В целом же, Nutch работает: качает и ищет. В дальнейших планах написать пару плагинов к нему для особого парсинга скачанных страниц, развернуть его на кластере и разобраться с API Hadoop. Обо всем это, естественно, напишу.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-1183086012462836667?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/1183086012462836667/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=1183086012462836667' title='Комментарии: 33'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/1183086012462836667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/1183086012462836667'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/12/nutch-hadoop.html' title='Nutch и Hadoop, первые впечатления'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>33</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-2596774132531126003</id><published>2006-12-18T00:15:00.000+03:00</published><updated>2006-12-18T00:15:15.849+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='decision tree'/><category scheme='http://www.blogger.com/atom/ns#' term='text mining explained'/><category scheme='http://www.blogger.com/atom/ns#' term='svm'/><category scheme='http://www.blogger.com/atom/ns#' term='classification'/><category scheme='http://www.blogger.com/atom/ns#' term='bayes'/><title type='text'>Классификация документов</title><content type='html'>&lt;div style="text-align: justify;"&gt;Продолжение серии &lt;a href="http://krondix.blogspot.com/search/label/text%20mining%20explained"&gt;"Введение в text mining"&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;С результатами автоматической классификации документов встречались, практически, все, кто пользовался электронной почтой. Спам-фильтры классифицируют входящую почту по двум категориям "спам"/"не спам" с помощью самых разных алгоритмов, начиная от простых decision trees задаваемых пользователем до сложных статистических методов. Далее мы рассмотрим несколько самых распространенных алгоритмов классификации и поймем как можно оценить и сравнить результаты работы этих алгоритмов.&lt;br /&gt;&lt;br /&gt;Начнем с формулировки задачи. У нас есть некоторый набор категорий и документы, про которые известно, что они принадлежат одной из категорий. Пример: любой веб-каталог (&lt;a href="http://yaca.yandex.ru/"&gt;Яндекс.Каталог&lt;/a&gt;, &lt;a href="http://dir.yahoo.com/"&gt;Yahoo Directory&lt;/a&gt; и другие), где сайты классифицированы по тематике. Эти документы составляют обучающую выборку для классификатора. Задача заключается в определении (точнее, предсказании с определенной вероятностью) категории для документов не входящих в обучающую выборку.&lt;br /&gt;&lt;br /&gt;Очевидный способ классифицировать документ известный под названием алгоритм ближайшего соседа (nearest neighbour, NN) — найти в обучающей выборке наиболее схожий с ним и предположить, что их категории совпадают. В качестве меры похожести обычно используют расстояние или косинус угла между векторами. Самый простой в реализации, этот алгоритм оказывается и самым медленным, он линейно зависит от числа документов в обучающей выборке. На практике обычно используется модификация алгоритма ближайшего соседа — алгоритм &lt;a href="http://en.wikipedia.org/wiki/K-nearest_neighbor_algorithm"&gt;k-ближайших соседей&lt;/a&gt; (k-nearest neighbours, k-NN). Здесь ищутся k наиболее близких документов из обучающей выборки и в качестве искомой категории выбирается встречающаяся чаще других в найденных документах. Так поступают, чтобы снизить влияние шума в обучающей выборке на результат. Шумом могут быть как просто неправильно классифицированные документы, так и документы, которые содержат много слов характерных для другой категории. Из-за невысоких показателей качества и, в первую очередь, низкой скорости алгоритм k-ближайших соседей редко применяется в промышленных разработках.&lt;br /&gt;&lt;br /&gt;Следующий алгоритм, который мы рассмотрим, многие применяли и применяют в повседневной жизни. Создавая правило "always trust e-mails sent from address name@company.com" в почтовом клиенте, мы неявно управляем деревом принятия решений (decision tree), с помощью которого работают многие спам-фильтры. В нелистовых узлах дерева решений содержатся своего рода "вопросы" к документу, в листьях — ответы в виде результирующей категории. "Вопросы" могут задаваться самим пользователем, как в примере выше, так и вычисляться на основе обучающей выборки — в этом случае они обычно имеют вид "присутствуют ли в документе такие слова?" Простота идеи компенсируется сложностью построения такого дерева вопросов из набора документов, если интересно — напишу об этом отдельный пост. Кроме классификации, построенное дерево решений можно использовать для анализа структуры документов и категорий, что может может оказаться ценным само по себе. На практике, деревья решений используют в основном с этой целью, потому что по качеству классификации они сильно проигрывают классификаторам Байеса и линейным моделям, о которых пойдет речь дальше.&lt;br /&gt;&lt;br /&gt;Про классификаторы Байеса я уже неоднократно &lt;a href="http://krondix.blogspot.com/search/label/bayes"&gt;писал&lt;/a&gt;, напомню основную идею. Для каждого слова мы считаем вероятность его принадлежности к каждой категории, вероятность принадлежности документа к категории считается как произведение вероятностей входящих в него слов. Несмотря на кажущуюся сложность такой формулы, по своей структуре это всего лишь линейная комбинация определенного числа параметров.&lt;br /&gt;&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center;" src="http://2.bp.blogspot.com/_ZL2WoqwbdI4/RYWiLRdtabI/AAAAAAAAAA4/qnqNZ6pdiTw/s400/image003.png" alt="" id="BLOGGER_PHOTO_ID_5009588475069819314" border="0" /&gt;Здесь &lt;code&gt;x&lt;sub&gt;i&lt;/sub&gt;&lt;/code&gt; равно &lt;code&gt;1&lt;/code&gt;, если слово &lt;code&gt;i&lt;/code&gt; присутствует в документе &lt;code&gt;x&lt;/code&gt;, и &lt;code&gt;0&lt;/code&gt; в противном случае. Таким образом задача классификации сводится к вычислению весов &lt;code&gt;w&lt;sub&gt;i&lt;/sub&gt;&lt;/code&gt; и смещения &lt;code&gt;b&lt;/code&gt; для каждой категории и метод Байеса лишь один из многих способов их вычисления, причем не самый лучший. Заметим, что веса &lt;code&gt;(w&lt;sub&gt;i&lt;/sub&gt;,b)&lt;/code&gt; образуют гиперплоскость в пространстве слов, по одну сторону от которой лежат документы принадлежащие категории, по другую — не принадлежащие. Очевидно, что существует бесконечно много таких гиперплоскостей разделяющих документы из обучающей выборки. Идея, лежащая в основе &lt;a href="http://en.wikipedia.org/wiki/Support_vector_machine"&gt;метода опорных векторов&lt;/a&gt; (support vector machines, SVM), заключается в выборе разделяющей гиперплоскости, которая максимально удалена от всех документов. На данный момент, SVM считается самым точным алгоритмом классификации документов.&lt;br /&gt;&lt;br /&gt;Для оценки качества классификации обычно используют следующий метод. Набор документов с известными категориями делят на две части: на одной обучаются, на другой тестируют. При этом предполагается, что документы, которые придется в будущем классифицировать, будут похожи на документы из тестовой выборки. Это, конечно, может оказаться совсем не так, но, к сожалению, другого способа оценить качество классификации пока нет. Общепринятыми характеристиками качества классификации являются точность и полнота. Точность вычисляется как отношение числа правильных положительных предсказаний классификатора (когда документу была присвоена какая-либо категория) к числу общему числу положительных предсказаний. Полнота это отношение числа правильных положительных предсказаний к числу документов, которым должна была быть присвоена категория. У классификаторов с высокой точностью, обычно, низкая полнота и наоборот. Например, если спам-фильтр работает с высокой точностью и низкой полнотой, он будет очень редко класть в папку spam хорошее письмо, но при этом некоторая часть спама может остаться в inbox. Для каждого алгоритма классификации, как правило, есть возможность управлять соотношением точность-полнота.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-2596774132531126003?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/2596774132531126003/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=2596774132531126003' title='Комментарии: 141'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/2596774132531126003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/2596774132531126003'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/12/blog-post_18.html' title='Классификация документов'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_ZL2WoqwbdI4/RYWiLRdtabI/AAAAAAAAAA4/qnqNZ6pdiTw/s72-c/image003.png' height='72' width='72'/><thr:total>141</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-3067730416780330738</id><published>2006-12-11T13:43:00.000+03:00</published><updated>2006-12-11T13:43:42.022+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='text mining explained'/><category scheme='http://www.blogger.com/atom/ns#' term='vector space model'/><category scheme='http://www.blogger.com/atom/ns#' term='data preparation'/><title type='text'>Представление текстовых данных</title><content type='html'>&lt;div style="text-align: justify;"&gt;Продолжение серии &lt;a href="http://krondix.blogspot.com/search/label/text%20mining%20explained"&gt;"Введение в text mining"&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Перед применением какого-либо алгоритма text mining набор текстовых документов надо преобразовать в более удобный вид. Общепринятым представлением является векторная модель (vector space model). Пусть у нас есть &lt;code&gt;n&lt;/code&gt; документов, которые все вместе состоят из &lt;code&gt;m&lt;/code&gt; уникальных слов. Каждому документу можно поставить в соответствие вектор &lt;code&gt;d ∈ R&lt;sup&gt;m&lt;/sup&gt;&lt;/code&gt;, такой что &lt;code&gt;d&lt;sub&gt;i&lt;/sub&gt; = 1&lt;/code&gt;, если слово &lt;code&gt;i&lt;/code&gt; содержится в документе, и &lt;code&gt;d&lt;sub&gt;i&lt;/sub&gt; = 0&lt;/code&gt; в противном случае. Мы получили самую простую двоичную векторную модель. Как я уже говорил, важным свойством такого представления является разреженность, действительно, &lt;code&gt;m&lt;/code&gt; может быть очень большим числом (несколько сотен тысяч), в то время как число единиц в каждом векторе может не превышать нескольких десятков. Это позволяет хранить в памяти не всю матрицу &lt;code&gt; n ∗ m&lt;/code&gt; (1 000 000 ∗ 100 000 = 100 000 000 000 бит = 12.5 гигабайт), а лишь очень малую ее часть, обычно около 0.01-0.1%.&lt;br /&gt;&lt;br /&gt;Недостатки двоичной модели очевидны: мы никак не учитываем важность слов для документа. Согласитесь, слова "новый" и "телефон" вносят совершенно разный вклад в определении тематики документа (если мы рассматриваем описания различных товаров). Очевидное развитие двоичной модели для решения этой проблемы: учитывать не только наличие/отсутствие слова, но и его встречаемость в документе. Таким образом, вместо единицы, в качестве элемента вектора, будет число раз, которое данное слово встречается в документе.&lt;br /&gt;&lt;br /&gt;К сожалению, попробовав такую модель, мы сразу увидим, что самыми частыми словами будут союзы и предлоги, которые, в то же время, не оказывают практически никакого влияния на тематику документа. Такие слова называются &lt;i&gt;стоп-слова (stopwords)&lt;/i&gt; и их удаляют из документов перед преобразованием в векторную модель. Помимо общего словаря стоп-слов (куда входят союзы, предлоги, некоторые наречия, одиночные буквы и цифры и т.д.), для каждой конкретной задачи будет полезным составить свой собственный словарь (&lt;a href="http://www.fips.ru/russite/documents/other/m2_19.html"&gt;пример&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Еще одной техникой препроцессинга, помимо удаления стоп-слов, является стемминг (или лемматизация): выделение значимой части слова. С помощью стемминга слова "телефоны" и "телефона" приведутся к одному слову "телефон", что, помимо улучшения качества работы выбранного алгоритма, еще и значительно сократит словарь (а значит вырастет скорость работы). Хорощий обзор свободно доступных морфологических анализаторов можно найти в &lt;a href="http://www.rcdl2006.uniyar.ac.ru/papers/paper_67_v2.pdf"&gt;статье&lt;/a&gt; Губина и Морозова.&lt;br /&gt;&lt;br /&gt;Описанная частотная модель, тем не менее, тоже не лишена недостатков. Некоторые слова могут встречаться в почти во всех документах и, соответственно, оказывать малое влияние на принадлежность документа к той или иной категории. Для понижения значимости таких слов используют модель TF∗IDF. TF (term frequency) это отношение числа раз, которое слово &lt;code&gt;t&lt;/code&gt; встретилось в документе &lt;code&gt;d&lt;/code&gt;, к длину документа. Нормализация длиной документа нужна, чтобы уравнять в правах короткие и длинные (в которых абсолютная встречаемость слов может быть гораздо больше) документы. IDF (inverse document frequency) — это логарифм отношения числа всех документов к числу документов содержащих слово &lt;code&gt;t&lt;/code&gt;.&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center;" src="http://4.bp.blogspot.com/_ZL2WoqwbdI4/RX0hTpOigKI/AAAAAAAAAAM/yhjrd54pwoA/s320/tf-idf.gif" alt="" id="BLOGGER_PHOTO_ID_5007194982073925794" border="0" /&gt;Таким образом, для слов, которые встречаются в большом числе документов IDF будет близок к нулу (если слово встречается во всех документах IDF равен нулю), что помогает выделить важные слова. Коэффициент TF∗IDF равен произведению TF и IDF. TF играет роль повышающего множителя, IDF — понижающего. Соответственно, вместо простой частоты встречаемости элементами векторов-документов будут значения TF∗IDF. Во многих задачах (но не во всех) это позволяет заметно улучшить качество.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-3067730416780330738?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/3067730416780330738/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=3067730416780330738' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/3067730416780330738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/3067730416780330738'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/12/blog-post.html' title='Представление текстовых данных'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_ZL2WoqwbdI4/RX0hTpOigKI/AAAAAAAAAAM/yhjrd54pwoA/s72-c/tf-idf.gif' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-1381393390342961397</id><published>2006-12-06T17:06:00.000+03:00</published><updated>2006-12-06T17:40:03.125+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='natural language processing'/><category scheme='http://www.blogger.com/atom/ns#' term='google'/><category scheme='http://www.blogger.com/atom/ns#' term='translate'/><category scheme='http://www.blogger.com/atom/ns#' term='information extraction'/><title type='text'>Google Translate, Russian</title><content type='html'>&lt;div style="text-align: justify;"&gt;Google запустил бета-версию переводов русский-английский и английский-русский. Качество перевода достаточно высокое, например, вот так выглядит часть предыдущего поста переведенная на английский:&lt;blockquote&gt;&lt;font size="-1"&gt;Text mining, in contrast to his elder brother, data mining, a relatively young field of computer science, the most significant results were obtained in the past 10 to 15 years. It seems to me that this is linked primarily to the emergence of a very large number of available each text and the appearance of the volume computing power. For the data mining input are some facilities with a small number of properties, which made certain conclusions. For example, the object could be history, characteristics, the results of tests and examinations, and the findings accordingly diagnosis. The text mining operate with a set of documents, the words of which are the same as properties. The size of such documents can be very large (several thousand words), and the size of the dictionary for all documents can reach several hundreds of thousands of words. Here, it should be noted, an important feature set of documents : if present it in the form of a matrix dokumentslovo (where there is &lt;code&gt;a&lt;sub&gt;ij&lt;/sub&gt;&lt;/code&gt; &lt;code&gt;1&lt;/code&gt; ,if the word &lt;code&gt;j&lt;/code&gt; contained in document &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;0&lt;/code&gt; otherwise), we see that it is highly razrejennouu structure, the majority of well &lt;code&gt;0&lt;/code&gt;. This enables us to develop effective (memory and speed) algorithms for processing very large volumes of data.&lt;/font&gt;&lt;/blockquote&gt;Критерием достижения стопроцентного результата в машинном переводе считается двойной перевод, например, русский-английский-русский:&lt;blockquote&gt;&lt;font size="-1"&gt;Текстовая добыча - в отличие от своего старшего брата, добыча данных, что является относительно молодым области применения компьютерной техники,наиболее важные результаты были получены в последние 10-15 лет.Мне кажется, что это прежде всего связано с появлением очень большого числа доступных каждому тексту, а также появлением большого объема вычислительной мощности.За добычу данных материалов некоторые объекты с небольшим числом свойств, что сделало определенные выводы.Например, объект может быть история, характеристики, результаты тестов и экзаменов, а выводы, соответственно, диагноза.Текст горного работать с пакетом документов, словами это те же свойства.Размеры таких документов может быть очень большим (несколько тысяч слов),и размер словарь для всех документов может достигать нескольких сотен тысяч слов.Здесь надо отметить, одной из важных особенностей комплекса документов :Если представить ее в виде матрицы, dokumentslovo (где есть &lt;code&gt;a&lt;sub&gt;ij&lt;/sub&gt;&lt;/code&gt; &lt;code&gt;1&lt;/code&gt;, если выражение й содержащихся в документе я не &lt;code&gt;0&lt;/code&gt;),Вы видите, что это весьма razrejennouu структуре, а большинство из &lt;code&gt;0&lt;/code&gt;.Это позволяет создавать эффективные (память и скорость) алгоритмы для обработки очень больших объемов информации.&lt;/font&gt;&lt;/blockquote&gt;Как видно, результат получился гораздо хуже &lt;a href="http://krondix.blogspot.com/2006/12/text-mining.html"&gt;оригинала&lt;/a&gt;. Тем не менее, основной смысл сохранен, если догадаться что такое "текстовая добыча" и "добыча данных" понятно, практически, все.&lt;br /&gt;&lt;br /&gt;Машинный перевод (machine translation) является частью более общей задачи обработки текстов на естественных языках (natural language processing, NLP) и, возможно, наиболее сложной. Среди прочих задач NLP можно выделить распознавание речи, ответы на вопросы,  авто-реферирование, проверка правильности текстов. Существует два главных направления в NLP: семантическое (когда мы пытаемся понять семантику слов и предложений) и статистическое (обучение на каком-либо корпусе текстов, для получения различной статистики взаимодействия слов). Статистические методы в NLP пришли из text mining, семантические методы NLP в свою очередь применимы в области извлечения информации (information extraction).&lt;br /&gt;&lt;br /&gt;Возращаясь к Google Translate, забавный факт: почему-то заголовок "Text Mining Explained" был &lt;a href="http://66.249.93.104/translate_c?hl=ru&amp;langpair=ru%7Cen&amp;u=http://krondix.blogspot.com/"&gt;переведен&lt;/a&gt; (&lt;i&gt;с&amp;nbsp;русского&amp;nbsp;на&amp;nbsp;английский&lt;/i&gt;) как "Text Mining Casino".&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-1381393390342961397?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/1381393390342961397/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=1381393390342961397' title='Комментарии: 7'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/1381393390342961397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/1381393390342961397'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/12/google-translate-russian.html' title='Google Translate, Russian'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-7863593334491233961</id><published>2006-12-03T12:23:00.000+03:00</published><updated>2006-12-03T13:34:09.283+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='text mining explained'/><category scheme='http://www.blogger.com/atom/ns#' term='clustering'/><category scheme='http://www.blogger.com/atom/ns#' term='classification'/><category scheme='http://www.blogger.com/atom/ns#' term='information extraction'/><title type='text'>Что такое text mining</title><content type='html'>&lt;div style="text-align: justify;"&gt;Решил написать небольшую серию постов, некоторое введение в text mining. Что это такое, какие задачи ставятся, как решаются, какие направления сейчас развиваются. Начну с общего обзора.&lt;br /&gt;&lt;br /&gt;Text mining, в отличие от своего старшего брата data mining, сравнительно молодая область computer science, большинство значительных результатов было получено в последние 10-15 лет. Как мне кажется, связано это в первую очередь с появлением очень большого количества доступной каждому текстовой информации и появлением соответствующих таким объемам вычислительных мощностей. Для задач data mining входной информацией являются некоторые объекты с небольшим числом свойств, на основании которых делаются определенные выводы. Например, объектом может быть история болезни, свойствами — результаты анализов и осмотров, а выводы, соответственно, диагноз. Системы text mining оперируют с набором документов, слова из которых можно аналогичным образом считать свойствами. При этом размер таких документов может быть очень большим (несколько тысяч слов), а размер общего словаря по всем документам может достигать нескольких сотен тысяч слов. Здесь нужно отметить одно важное свойство набора документов: если представить его в виде матрицы документ-слово (где элемент &lt;code&gt;a&lt;sub&gt;ij&lt;/sub&gt;&lt;/code&gt; равен &lt;code&gt;1&lt;/code&gt;, если слово &lt;code&gt;j&lt;/code&gt; содержится в документе &lt;code&gt;i&lt;/code&gt; и &lt;code&gt;0&lt;/code&gt; в противном случае), мы увидим, что она имеет сильно разреженную структуру, то есть большинство элементов равно &lt;code&gt;0&lt;/code&gt;. Это позволяет создавать эффективные (по памяти и скорости) алгоритмы обработки очень больших объемов данных.&lt;br /&gt;&lt;h4&gt;Задачи text mining&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;&lt;i&gt;Классификация (classification)&lt;/i&gt;. Задача заключается в отнесении документа к одной из нескольких заранее определенных категорий, основываясь на содержании документа. Для построения классификаторов используется обучающая выборка из документов с присвоенными им категориями. Классический пример: классификация писем по категориям спам/не спам. Самые простые классификаторы: метод &lt;a href="http://en.wikipedia.org/wiki/K-nearest_neighbor_algorithm"&gt;k ближайших соседей&lt;/a&gt; и &lt;a href="http://krondix.blogspot.com/2006/10/blog-post.html"&gt;классификатор Байеса&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;i&gt;Кластеризация (clustering)&lt;/i&gt; отличается от классификации тем, что мы не знаем какие существуют категории. У нас нет никакой обучающей выборки, есть только документы, которые надо попытаться определенным образом сгруппировать в кластеры (категории). Причем, как правило, неизвестно даже число возможных категорий (хотя его можно более-менее точно оценить. Существует два типа алгоритмов кластеризации: одни работают с заранее определенным числом категорий (например, алгоритм &lt;a href="http://krondix.blogspot.com/2006/10/k.html"&gt;k-средних&lt;/a&gt;), другие с неизвестным (например, &lt;a href="http://en.wikipedia.org/wiki/Hierarchical_clustering#Hierarchical_clustering"&gt;иерархическая кластеризация&lt;/a&gt;). Известные примеры использования кластеризации: &lt;a href="http://news.yandex.ru/about.html"&gt;Яндекс.Новости&lt;/a&gt; и &lt;a href="http://nigma.ru/index_menu.php?action=click_menu&amp;menu_element=cluster"&gt;Nigma&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;i&gt;Извлечение фактов (fact/information extraction)&lt;/i&gt;. Название говорит за себя, задача заключается в извлечении из неструктурированного текста информации определенного вида, например &lt;a href="http://news.yandex.ru/people-search-tech.html"&gt;пресс-портрета&lt;/a&gt; или &lt;a href="http://opinion.news.yandex.ru/"&gt;цитат&lt;/a&gt;. &lt;/li&gt;&lt;/ol&gt;В следующих постах расскажу подробно о каждой из задач.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-7863593334491233961?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/7863593334491233961/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=7863593334491233961' title='Комментарии: 120'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/7863593334491233961'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/7863593334491233961'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/12/text-mining.html' title='Что такое text mining'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>120</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-380660602180749704</id><published>2006-12-01T15:06:00.000+03:00</published><updated>2006-12-03T13:35:07.676+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eigenvalue problem'/><category scheme='http://www.blogger.com/atom/ns#' term='clustering'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><category scheme='http://www.blogger.com/atom/ns#' term='classification'/><category scheme='http://www.blogger.com/atom/ns#' term='k-means'/><category scheme='http://www.blogger.com/atom/ns#' term='information extraction'/><title type='text'>Text Mining Books</title><content type='html'>&lt;div style="text-align: justify;"&gt;Хочу порекомендовать вам две замечательные книги по text mining.&lt;br /&gt;&lt;/div&gt;&lt;ol style="text-align: justify;"&gt;&lt;li&gt;&lt;a href="http://www.amazon.co.uk/Text-Mining-Predictive-Unstructured-Information/dp/0387954333/sr=8-7/qid=1164974839/ref=sr_1_7/202-6697192-9495824?ie=UTF8&amp;s=books"&gt;Text Mining: Predictive Methods for Analyzing Unstructured Information&lt;/a&gt; (Sholom&amp;nbsp;M.&amp;nbsp;Weiss, Nitin&amp;nbsp;Indurkhya, Tong&amp;nbsp;Zhang, Frederick&amp;nbsp;Damerau). Эта книга — краткое, но в то же время достаточно полное введение в text mining. Подготовка данных, классификация, кластеризация, поиск, извлечение информации — всему нашлось место в книге, причем некоторые алгоритмы описаны очень подробно. Самой интересной мне показалась шестая глава, посвященная статистическим методам в извлечении информации (information extraction). Резюме: специалистам в text mining книга поможет структурировать имеющийся объем знаний, для новичков же она прекрасное введение в область.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.co.uk/Survey-Text-Mining-Clustering-Classification/dp/0387955631/sr=8-6/qid=1164974839/ref=sr_1_6/202-6697192-9495824?ie=UTF8&amp;amp;s=books"&gt;Survey of Text Mining: Clustering, Classification, and Retrieval&lt;/a&gt; (под редакцией Michael&amp;nbsp;W.&amp;nbsp;Berry). Здесь собраны лучшие работы участников &lt;a href="http://www.cs.utk.edu/tmw02/"&gt;Text Mining Workshop проведенного в рамках &lt;/a&gt;&lt;a href="http://www.siam.org/meetings/sdm02/"&gt;Second SIAM International Conference on Data Mining&lt;/a&gt; (SDM) в 2002-ом году. Наиболее интересные, на мой взгляд: мягкий (soft) алгоритм &lt;a href="http://krondix.blogspot.com/2006/10/k.html"&gt;k-средних&lt;/a&gt; с автоматической расстановкой весов отдельным словам, алгоритмы кластеризации PDDP (Principal Direction Divisive Partitioning) и sPDDP( spherical PDDP), &lt;a href="http://en.wikipedia.org/wiki/Latent_Semantic_Indexing"&gt;Latent Semantic Indexing&lt;/a&gt; и Covariance Matrix Analysis (известный также как &lt;a href="http://en.wikipedia.org/wiki/Principal_components_analysis"&gt;Principal Component Analysis&lt;/a&gt;) и их модификации для лучшей обработки маленьких кластеров. Три перечисленных алгоритма кластеризации (кроме LSI) используют по сути один и тот же метод: нахождение одного или нескольких собственных векторов матрицы ковариантности. Чуть позже напишу об этом подробнее, это действительно очень интересно.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div style="text-align: justify;"&gt;Стоит отметить, что 28-апреля 2007-го года в рамках очередной SDM пройдет Text Mining Workshop, лучшие работы с которого будут опубликованы во втором издании Survey of Text Mining. Работы &lt;a href="http://www.cs.utk.edu/tmw07/"&gt;принимаются&lt;/a&gt; до 8-го января.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-380660602180749704?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/380660602180749704/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=380660602180749704' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/380660602180749704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/380660602180749704'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/12/text-mining-books.html' title='Text Mining Books'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-6420166404265094742</id><published>2006-11-29T12:10:00.000+03:00</published><updated>2006-11-29T12:15:33.169+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='java-ir-utils'/><title type='text'>Java IR Utils</title><content type='html'>Я создал на &lt;a href="http://code.google.com/"&gt;Google Code&lt;/a&gt; проект &lt;a href="http://code.google.com/p/java-ir-utils/"&gt;Java IR Utils&lt;/a&gt;, куда буду выкладывать всякие полезности вроде SparseArrayList.&lt;br /&gt;&lt;br /&gt;Анонимный доступ:&lt;blockquote&gt;&lt;code&gt;svn checkout http://java-ir-utils.googlecode.com/svn/trunk/ java-ir-utils&lt;/code&gt;&lt;/blockquote&gt;Если есть желание участвовать в проекте, пишите.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-6420166404265094742?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/6420166404265094742/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=6420166404265094742' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/6420166404265094742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/6420166404265094742'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/11/java-ir-utils.html' title='Java IR Utils'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-2836084989370246687</id><published>2006-11-28T10:27:00.000+03:00</published><updated>2006-11-28T10:40:41.609+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='search engines'/><category scheme='http://www.blogger.com/atom/ns#' term='clustering'/><title type='text'>Контроль над поисковой выдачей</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;a href="http://www.nigma.ru/"&gt;Nigma&lt;/a&gt; первой в рунете сделала удивительно полезную вещь: возможность управлять результатами поиска в зависимости от цели запроса. Не секрет, что большинство интернет-магазинов очень хорошо оптимизированы и занимают первые места в выдаче, хотя нам очень часто нужна только информация о товаре, обзоры, отзывы с форумов. Теперь при поиске в Нигме есть возможность отключать целые кластеры результатов, например &lt;a href="http://nigma.ru/index.php?retry=1&amp;passed_time=0%2C0247631072998&amp;amp;retry=1&amp;passed_time=0%2C0268068313599&amp;amp;q=hp+nx6125&amp;0=1&amp;amp;1=1&amp;2=1&amp;amp;3=1&amp;4=1&amp;amp;5=1&amp;6=1&amp;amp;7=1&amp;amp;cr0=0"&gt;"интернет-магазины"&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Стоит отметить, что &lt;a href="http://www.yahoo.com/"&gt;Yahoo&lt;/a&gt; запустил &lt;a href="http://mindset.research.yahoo.com/"&gt;подобную поиск&lt;/a&gt; больше года назад и он как раз целиком направлен на исключение (или включение) магазинов из результатов.&lt;br /&gt;&lt;br /&gt;Дальнейшим развитием этой идей должны быть уточняющие вопросы, то есть при запросе "слон" у пользователя должны спросить "вы хотите купить слона, посмотреть на слона или узнать про слона?" и, в зависимости от ответа, отсортировать результаты.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-2836084989370246687?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/2836084989370246687/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=2836084989370246687' title='Комментарии: 15'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/2836084989370246687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/2836084989370246687'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/11/blog-post.html' title='Контроль над поисковой выдачей'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-5945272826207172591</id><published>2006-11-26T14:14:00.001+03:00</published><updated>2006-11-26T14:19:58.249+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='double'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='memory'/><title type='text'>Как хранить double</title><content type='html'>&lt;div style="text-align: justify;"&gt;Задался вчера интересным &lt;a href="http://community.livejournal.com/ru_ir/33402.html?thread=145530#t145530"&gt;вопросом&lt;/a&gt;, как экономнее всего хранить числа с плавающей точкой. Понятно, что выиграют примитивы, интересно было сравнить &lt;code&gt;double[]&lt;/code&gt; (массив из одного элемента) и &lt;code&gt;Double&lt;/code&gt;. Результат для меня был неожиданный: &lt;code&gt;double/Double/double[]&amp;nbsp;=&amp;nbsp;1/2/3&lt;/code&gt;. Получается, что в контейнерах эффективнее хранить класс-обертку, а не массив. Если же можно использовать массивы вместо контейнеров, лучше использовать массивы: выигрыш в памяти составит более 100%!&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-5945272826207172591?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/5945272826207172591/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=5945272826207172591' title='Комментарии: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/5945272826207172591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/5945272826207172591'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/11/double.html' title='Как хранить double'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-8641659519749973604</id><published>2006-11-26T14:02:00.000+03:00</published><updated>2006-11-26T14:27:37.828+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='java-ir-utils'/><category scheme='http://www.blogger.com/atom/ns#' term='hashmap'/><category scheme='http://www.blogger.com/atom/ns#' term='treemap'/><category scheme='http://www.blogger.com/atom/ns#' term='sparse matrices'/><category scheme='http://www.blogger.com/atom/ns#' term='sparse arrays'/><category scheme='http://www.blogger.com/atom/ns#' term='memory'/><title type='text'>SparseArrayList, новая версия</title><content type='html'>&lt;div style="text-align: justify;"&gt;Выложил &lt;a href="http://krondix.narod.ru/SparseArrayList.zip"&gt;новую версию&lt;/a&gt; &lt;a href="http://krondix.blogspot.com/2006/11/sparsearraylist.html"&gt;SparseArrayList&lt;/a&gt;. Добавил возможность итерации по паре индекс-значение в порядке возрастания индекса. Очень удобно, когда надо слить несколько списков в один.&lt;br /&gt;&lt;br /&gt;Заодно провел несколько измерений расхода памяти и скорости доступа по сравнению с HashMap и TreeMap.&lt;br /&gt;&lt;/div&gt;&lt;ul style="text-align: justify;"&gt;&lt;li&gt;SparseArrayList позволяет сэкономить около 5% памяти по сравнению с HashMap&lt;/li&gt;&lt;li&gt;Скорость произвольного доступа к элементам выше у HashMap при маленьком числе элементов (100-200) и становится одинаковой при большом числе (&gt;5000)&lt;/li&gt;&lt;li&gt;Скорость последовательного (по возрастанию индекса) доступа у SparseArrayList выше чем у TreeMap более чем в 2 раза&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-8641659519749973604?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/8641659519749973604/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=8641659519749973604' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/8641659519749973604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/8641659519749973604'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/11/sparsearraylist_26.html' title='SparseArrayList, новая версия'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-3716168183030216042</id><published>2006-11-24T15:16:00.000+03:00</published><updated>2006-11-24T15:27:15.883+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java-ir-utils'/><category scheme='http://www.blogger.com/atom/ns#' term='hashmap'/><category scheme='http://www.blogger.com/atom/ns#' term='sparse matrices'/><category scheme='http://www.blogger.com/atom/ns#' term='sparse arrays'/><category scheme='http://www.blogger.com/atom/ns#' term='mtj'/><category scheme='http://www.blogger.com/atom/ns#' term='memory'/><title type='text'>SparseArrayList</title><content type='html'>&lt;div style="text-align: justify;"&gt;Бывают такие ситуации, когда стандартный HashMap слишком медленный и затратный по памяти, а возможностей &lt;a href="http://rs.cipr.uib.no/mtj/doc/no/uib/cipr/matrix/sparse/SparseVector.html"&gt;SparseVector&lt;/a&gt; из &lt;a href="http://rs.cipr.uib.no/mtj/"&gt;MTJ&lt;/a&gt; не хватает, поскольку надо хранить произвольные объекты. Для таких случаев я написал простой класс &lt;a href="http://krondix.narod.ru/SparseArrayList.zip"&gt;SparseArrayList&lt;/a&gt;, который практически идентичен SparseVector за вычетом, собственно, векторных операций. Плюс для хранения данных используется не массив, а ArrayList, и размер контейнера не ограничивается в конструкторе.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:-1;"&gt;В архиве лежит еще и класс Arrays (дополнение к стандартному) из MTJ. В библиотеке он package-local, для реализации SparseArrayList пришлось сделать его public.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-3716168183030216042?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/3716168183030216042/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=3716168183030216042' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/3716168183030216042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/3716168183030216042'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/11/sparsearraylist.html' title='SparseArrayList'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-8937463351057112331</id><published>2006-11-20T20:49:00.000+03:00</published><updated>2006-11-20T20:51:18.346+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multiword features'/><category scheme='http://www.blogger.com/atom/ns#' term='shingles'/><category scheme='http://www.blogger.com/atom/ns#' term='classification'/><category scheme='http://www.blogger.com/atom/ns#' term='bayes'/><title type='text'>Multiword Features</title><content type='html'>&lt;div style="text-align: justify;"&gt;В ситуациях когда различиях между категориями проявляются не на уровне различных слов, а на уровне сочетаний этих слов, классические классификаторы Байеса могут показывать не очень удовлетворительные результаты. Справиться с этой проблемой можно используя шинглы (shingles) или multiword features.&lt;br /&gt;&lt;br /&gt;В общем случае, шинглы — это уникальные последовательности символов одинаковой длины выделенные из документа. Для задач классификации можно рассматривать последовательности не символов, а слов. Например, для документа "a rose is a rose is a rose" шинглами длиной в четыре слова будут: { (a,rose,is,a), (rose,is,a,rose), (is,a,rose,is) }. Построить все шинглы для документа можно за &lt;code&gt;O(w(n-w))&lt;/code&gt;, где &lt;code&gt;w&lt;/code&gt; — длина шингла. Дальше шинглы используются как обычные слова в классификаторе Байеса, за счет чего заметно вырастает точность, особенно когда мы работаем с иерархической структурой категорий.&lt;br /&gt;&lt;br /&gt;К сожалению шинглы нам не помогут в случае, когда слова из характерных сочетаний идут в документах не подряд, а на различном расстоянии друг от друга. В таком случае можно использовать обобщение идеи шинглов: multiword features. Собственно, что это такое уже понятно, весь вопрос в том, как эффективно эффективно найти характерные для категории multiword features. Действительно, наивный алгоритм, который находит все возможные сочетания слов, скорее всего просто не влезет в память. Очевидно, что нам нужны не все возможные сочетания слов, а только наиболее характерные для категории, то есть которые встречаются, например, как минимум в 10% документов. Это позволяет нам последовательно вычислять корреляцию для очередного набора слов и хранить в памяти только удовлетворяющие условию. Тем не менее, временная сложность такого алгоритма все равно будет &lt;code&gt;O(m&lt;sup&gt;k&lt;/sup&gt;)&lt;/code&gt;, где &lt;code&gt;m&lt;/code&gt; — число слов в категории, &lt;code&gt;k&lt;/code&gt; — число слов в наборе. Очевидно, что вычислять наборы более чем из двух слов неэффективно, да и, как правило, это не даст большого выигрыша в точности.&lt;br /&gt;&lt;br /&gt;Таким образом, нам осталось решить задачу вычисления корреляции между двумя словами в наборе документов, то есть число документов, в которых эти слова встречаются одновременно. Опять же, самый простой способ, когда мы проходим все документы и считаем вхождения слов в них будет достаточно медленным. Можно использовать следующий алгоритм вычисления корреляции:&lt;br /&gt;&lt;/div&gt;&lt;ol style="text-align: justify;"&gt;&lt;li&gt;Каждое слово представляется вектором, элементы которого равны нулю или единице, в зависимости от присутствия слова в документе с соответствующим номером.&lt;/li&gt;&lt;li&gt;Этот вектор хранится в виде &lt;code&gt;long[]&lt;/code&gt;, длина массива равна &lt;code&gt;[n / sizeof(long)] + 1&lt;/code&gt;, где &lt;code&gt;n&lt;/code&gt; — число документов.&lt;/li&gt;&lt;li&gt;Вычисление корреляции между двумя документами сводится к последовательному побитовому умножению элементов двух массивов и вычислению числа единиц в результате.&lt;/li&gt;&lt;/ol&gt;&lt;div style="text-align: justify;"&gt;Хороший практический результат на многих задачах может дать совместное использование шинглов длиной в 3-5 слов и 2-word features.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-8937463351057112331?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/8937463351057112331/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=8937463351057112331' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/8937463351057112331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/8937463351057112331'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/11/multiword-features.html' title='Multiword Features'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-5711389353825953837</id><published>2006-11-06T21:06:00.000+03:00</published><updated>2006-11-06T22:41:56.360+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eigenvalue problem'/><category scheme='http://www.blogger.com/atom/ns#' term='mtj'/><title type='text'>Eigenvalue Decomposition</title><content type='html'>&lt;div style="text-align: justify;"&gt;После более детального исследования оказалось, что других хороших библиотек кроме &lt;a href="http://rs.cipr.uib.no/mtj/"&gt;Matrix Toolkits for Java&lt;/a&gt; для работы с матрицами и векторами на Java попросту нет. Ни по набору функций, ни по производительности. MTJ построена поверх &lt;a href="http://www.netlib.org/blas/"&gt;BLAS&lt;/a&gt;/&lt;a href="http://www.netlib.org/lapack"&gt;LAPACK&lt;/a&gt; и может использовать оптимизированные под определенную платформу реализации этих библиотек (инструкции для &lt;a href="http://rs.cipr.uib.no/mtj/nni.html"&gt;Linux&lt;/a&gt; и &lt;a href="http://albert.bagasie.com/MTJonWindows"&gt;Windows&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Достаточно часто в задачах IR требуется найти собственные вектора какой-либо матрицы &lt;code&gt;n&lt;sub&gt;x&lt;/sub&gt;n&lt;/code&gt; (eigenvalue decomposition, EVD), причем обычно нам нужны только &lt;code&gt;k &amp;lt;&amp;lt; n&lt;/code&gt; векторов соответствующих &lt;code&gt;k&lt;/code&gt; наибольшим собственным числам матрицы. Но существующие в MTJ классы для вычисления EVD находят сразу все вектора, что приводит к совершенно неоправданным временным затратам.  Для решения этой задачи я немного модифицировал класс &lt;code&gt;SymmDenseEVD&lt;/code&gt;, который находит собственные вектора у симметричной матрицы. Теперь в конструкторе можно задать какие собственные числа (по убыванию) и соответствующие им вектора нам нужны.&lt;br /&gt;&lt;br /&gt;Binaries: &lt;a href="http://krondix.narod.ru/mtj.jar"&gt;mtj.jar&lt;/a&gt;&lt;br /&gt;Source code: &lt;a href="http://krondix.narod.ru/mtj-src.tar.gz"&gt;mtj-src.tar.gz&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-5711389353825953837?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/5711389353825953837/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=5711389353825953837' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/5711389353825953837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/5711389353825953837'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/11/eigenvalue-decomposition.html' title='Eigenvalue Decomposition'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-8018977135027467970</id><published>2006-10-31T10:32:00.000+03:00</published><updated>2006-10-31T13:01:55.761+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='sparse matrices'/><category scheme='http://www.blogger.com/atom/ns#' term='mtj'/><title type='text'>Не делайте лишнего</title><content type='html'>&lt;div style="text-align: justify;"&gt;В &lt;a href="http://krondix.blogspot.com/2006/10/k_22.html"&gt;реализации&lt;/a&gt; алгоритма &lt;a href="http://krondix.blogspot.com/2006/10/k.html"&gt;k-средних&lt;/a&gt; основная операция —  вычисление расстояния между двумя векторами &lt;code&gt;||a - c||&lt;/code&gt;. Очевидный способ это сделать, используя библиотеку &lt;a href="http://rs.cipr.uib.no/mtj/"&gt;MTJ&lt;/a&gt;&lt;div style="text-align: left;"&gt;&lt;blockquote&gt;&lt;code&gt;new SparseVector(vector).add(-1, centroid).norm(Vector.Norm.Two)&lt;/code&gt;&lt;/blockquote&gt;&lt;/div&gt;Увидев в профайлере, что на метод &lt;code&gt;add()&lt;/code&gt; приходится около 90% всех вычислений, возникает естественное желание попытаться его ускорить. Как работает этот метод? Для этого нам надо понять, как вообще устроен SparseVector.&lt;br /&gt;&lt;br /&gt;Для хранения разреженного вектора заводится два массива: массив индексов и массив значений.&lt;br /&gt;&lt;blockquote&gt;  &lt;table class="MsoTableGrid" style="border: medium none ; border-collapse: collapse;" border="1" cellpadding="0" cellspacing="0"&gt;  &lt;tbody&gt;&lt;tr style="height: 12.3pt;"&gt;   &lt;td style="border: 1pt solid windowtext; padding: 0cm 5.4pt; width: 37.6pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;index&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.6pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;12&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.6pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;15&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.6pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;86&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.6pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;87&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.65pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;90&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.65pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;125&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.65pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;234&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: solid solid solid none; border-color: windowtext windowtext windowtext -moz-use-text-color; border-width: 1pt 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.65pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;235&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;  &lt;/tr&gt;  &lt;tr style="height: 12.3pt;"&gt;   &lt;td style="border-style: none solid solid; border-color: -moz-use-text-color windowtext windowtext; border-width: medium 1pt 1pt; padding: 0cm 5.4pt; width: 37.6pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;value&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.6pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;1.42&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.6pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;1.2&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.6pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;0.01&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.6pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;0.43&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.65pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;1.23&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.65pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;2.41&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.65pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;2.55&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;   &lt;td style="border-style: none solid solid none; border-color: -moz-use-text-color windowtext windowtext -moz-use-text-color; border-width: medium 1pt 1pt medium; padding: 0cm 5.4pt; width: 37.65pt; height: 12.3pt;" valign="top" width="50"&gt;   &lt;p class="MsoNormal"&gt;&lt;span style="" lang="EN-US"&gt;0.143&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;   &lt;/td&gt;  &lt;/tr&gt; &lt;/tbody&gt;&lt;/table&gt;  &lt;/blockquote&gt;Индексы отсортированы по возрастанию. При чтении элемента вектора бинарным поиском ищется его индекс, потом выбирается соответствующий индексу элемент из массива значений. Запись элемента происходит следующим образом: если по этому индексу уже есть элемент, то он просто перезаписывается, если же элемента нет, то оба массива раздвигаются в нужном месте (при необходимости увеличивается их длина) и сохраняется новый индекс и значение для него.&lt;br /&gt;&lt;br /&gt;Как можно складывать такие вектора? Самый очевидный способ (который и реализован в классе &lt;code&gt;SparseVector&lt;/code&gt;) выглядит так:&lt;blockquote&gt;&lt;code&gt;&lt;/code&gt;&lt;pre&gt;public void add(int index, double value) {&lt;br /&gt; check(index);&lt;br /&gt;&lt;br /&gt; int i = getIndex(index);&lt;br /&gt; data[i] += value;&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;В getIndex() ищется место индекса в массиве и, при необходимости, создается место под новый. Его алгоритмическая сложность &lt;code&gt;O(log(n))&lt;/code&gt;, где &lt;code&gt;n&lt;/code&gt; длина вектора, &lt;i&gt;к которому&lt;/i&gt; мы добавляем. При этом нельзя забывать о достаточно большой константе связанной с раздвижением массива. Соответственно, общая сложность получается &lt;code&gt;O(m log(n))&lt;/code&gt;, где &lt;code&gt;m&lt;/code&gt; длина вектора, &lt;i&gt;который&lt;/i&gt; мы добавляем.&lt;br /&gt;&lt;br /&gt;Конечно же, сразу хочется реализовать сложение векторов с помощью слияния двух массивов за &lt;code&gt;O(m + n)&lt;/code&gt;. Вот только для некоторых &lt;code&gt;m&lt;/code&gt; и &lt;code&gt;n&lt;/code&gt; такое слияние будет даже медленнее чем первый способ. Например, для &lt;code&gt;n = 100&lt;/code&gt; и &lt;code&gt;m = 20&lt;/code&gt; (самые обычные значения во многих задачах).&lt;br /&gt;&lt;br /&gt;Как же нам улучшить производительность вычисления нормы разности векторов? Ответ прост, нам же совершенно не нужно вычислять разность векторов, это лишняя операция. Надо лишь на каждом шаге алгоритма слияния массивов вычислять очередное слагаемое нормы. Так мы избавляемся от затратной операции записи в массив и лишней операции чтения. После такой оптимизации скорость работы выросла в 3-4 раза.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-8018977135027467970?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/8018977135027467970/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=8018977135027467970' title='Комментарии: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/8018977135027467970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/8018977135027467970'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/10/blog-post_30.html' title='Не делайте лишнего'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-5604503592657799732</id><published>2006-10-22T14:55:00.000+04:00</published><updated>2006-10-22T16:51:18.800+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='sparse matrices'/><category scheme='http://www.blogger.com/atom/ns#' term='clustering'/><category scheme='http://www.blogger.com/atom/ns#' term='mtj'/><category scheme='http://www.blogger.com/atom/ns#' term='k-means'/><title type='text'>Реализация алгоритма k-средних</title><content type='html'>Документы-вектора можно представить несколькими способами, выбрав разные значения в качестве их элементов:&lt;br /&gt;&lt;ol style="text-align: justify;"&gt;&lt;li&gt;0 или 1, в зависимости от наличия слова в документе&lt;/li&gt;&lt;li&gt;Число слов в документе&lt;/li&gt;&lt;li&gt;TF*IDF данного слова&lt;/li&gt;&lt;/ol&gt;&lt;div style="text-align: justify;"&gt;Как правило для документов с малым числом слов (или же просто с набором атрибутов) лучше подходят первые два способа, а для более-менее больших документов на естественном языке TF*IDF.&lt;br /&gt;&lt;br /&gt;Полученную сильно разреженную матрицу надо не только хранить в памяти, но и иметь возможность эффективно выполнять разные операции над ними. Библиотек для работы со sparse matrices на Java не так много, а самое плохое, что я не нашел никаких benchmarks. Достаточно удобной в использовании мне показалась &lt;a href="http://rs.cipr.uib.no/mtj/"&gt;Matrix Toolkits for Java&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Радикально ускорить алгоритм можно с помощью уменьшения словаря, убрав из него слова мало влияющие на результат. Как правило, достаточно всего 20-30% слов, чтобы алгоритм работал с практически такой же точностью. Один из самых простых cпособов уменьшения словаря состоит в том, чтобы выбирать слова с наибольшей функцией качества:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/136/4233/1600/term-q.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger2/136/4233/320/term-q.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:85%;"&gt;&lt;code&gt;n&lt;/code&gt; — число всех документов&lt;br /&gt;&lt;code&gt;f&lt;sub&gt;i&lt;/sub&gt;&lt;/code&gt; — частота встречаемости слова в &lt;code&gt;i&lt;/code&gt;-ом документе.&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;Существует некий порог размера словаря, начиная с которого алгоритм k-средних начинает работать очень плохо. Обычно он лежит как раз в диапазоне 20-30%. Нужный размер проще всего подобрать экспериментальным путем.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-5604503592657799732?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/5604503592657799732/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=5604503592657799732' title='Комментарии: 17'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/5604503592657799732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/5604503592657799732'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/10/k_22.html' title='Реализация алгоритма k-средних'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-6425323655850704676</id><published>2006-10-21T14:14:00.000+04:00</published><updated>2006-10-21T22:50:47.693+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='learning'/><category scheme='http://www.blogger.com/atom/ns#' term='clustering'/><category scheme='http://www.blogger.com/atom/ns#' term='classification'/><category scheme='http://www.blogger.com/atom/ns#' term='bayes'/><category scheme='http://www.blogger.com/atom/ns#' term='k-means'/><title type='text'>Метод k-средних для обучения классификаторов Байеса</title><content type='html'>&lt;div style="text-align: justify;"&gt;Алгоритм k-средних (k-means clustering) — очень быстрый, простой и достаточно точный метод кластеризации объектов. Идея заключается в минимизации суммарного отклонения по каждому кластеру:&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger2/136/4233/320/k-means.gif" alt="" border="0" /&gt;Здесь, &lt;code&gt;S&lt;sub&gt;i&lt;/sub&gt;&lt;/code&gt; — &lt;code&gt;k&lt;/code&gt; кластеров, &lt;code&gt;μ&lt;sub&gt;i&lt;/sub&gt;&lt;/code&gt; — центроид &lt;code&gt;i&lt;/code&gt;-го кластера. На каждой итерации алгоритма мы перемещаем каждый вектор в кластер с ближайшим центроидом. Хотя не существует каких-либо оценок сложности алгоритма, на практике хватает он сходится за достаточно малое число итераций.&lt;br /&gt;&lt;br /&gt;У метода k-средних есть два серьезных недостатка:&lt;br /&gt;&lt;/div&gt;&lt;ol style="text-align: justify;"&gt;&lt;li&gt;Необходимо заранее знать точное число кластеров.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Качество результата сильно зависит от выбора начального разбиения.&lt;/li&gt;&lt;/ol&gt;&lt;div style="text-align: justify;"&gt;Поэтому, обычно, сначала применяют какой-либо другой метод кластеризации (например, Principal Direction Divisive Partitioning) для определения числа кластеров и получения начального разбиения.&lt;br /&gt;&lt;br /&gt;Что будет если применить метод k-средних к задаче обучения классификаторов Байеса на некачественных данных? Действительно, ведь у нас уже есть готовы набор категорий-кластеров и начальное разбиение по ним. Я провел простой эксперимент. Тестовый набор включал в себя три категории документов, условно их можно назвать "Information Retrieval" (С&lt;sub&gt;1&lt;/sub&gt;), "Java" (C&lt;sub&gt;2&lt;/sub&gt;) и "HTML" (C&lt;sub&gt;3&lt;/sub&gt;).  Сами документы представляют собой короткие (несколько предложений) отрывки из статей в Википедии. Обучающую выборку я составил следующим образом: к каждой категории были отнесены 100 документов из нее самой и по 15  документов из двух других. После чего я применил Байеса ко всем 390 документам: 62 из них были классифицированны неправильно. Алгоритм k-средних разложил документы в обучающей выборке следующим образом:&lt;br /&gt;&lt;blockquote&gt;C&lt;sub&gt;1&lt;/sub&gt; = 129 * C&lt;sub&gt;1&lt;/sub&gt; + 2 * C&lt;sub&gt;2&lt;/sub&gt;&lt;br /&gt;C&lt;sub&gt;2&lt;/sub&gt; = 1 * C&lt;sub&gt;1&lt;/sub&gt; + 127 * C&lt;sub&gt;2&lt;/sub&gt; + 4 * C&lt;sub&gt;3&lt;/sub&gt;&lt;br /&gt;C&lt;sub&gt;3&lt;/sub&gt; = 1 * C&lt;sub&gt;2&lt;/sub&gt; + 126 * C&lt;sub&gt;3&lt;/sub&gt;&lt;/blockquote&gt;Заново обученный Байес ошибся уже всего в 5 случаях!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-6425323655850704676?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/6425323655850704676/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=6425323655850704676' title='Комментарии: 38'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/6425323655850704676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/6425323655850704676'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/10/k.html' title='Метод k-средних для обучения классификаторов Байеса'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>38</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-1826298969474600452</id><published>2006-10-18T20:51:00.000+04:00</published><updated>2006-10-21T15:20:57.436+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='decision tree'/><category scheme='http://www.blogger.com/atom/ns#' term='classification'/><category scheme='http://www.blogger.com/atom/ns#' term='bayes'/><title type='text'>Байес для сужения области поиска</title><content type='html'>&lt;div style="text-align: justify;"&gt;Одним из главных достоинств классификаторов Байеса является скорость работы. Это позволяет использовать их для сужения области работы другого, более сложного и затратного механизма классификации и распознования. Идея очень простая: мы обрабатываем входные данные Байесом и выбираем &lt;code&gt;k&lt;/code&gt; результатов с наибольшей вероятностью, среди которых уже ищем окончательный ответ.&lt;br /&gt;&lt;br /&gt;Если копнуть чуть глубже, с помощью такого метода можно превратить линейную зависимость скорости работы самого Байеса от числа категорий в логарифмическую. Для этого надо построить классификатор похожий на decision tree, в котором решение в узлах будет приниматься с помощью Байеса. Формула для расчета вероятностей в таком классификаторе остается точно такой же, мы просто подставляем туда другие данные.  Если объект принадлежит какой-либо категории, то он принадлежит и всем ее родителям, соответственно, слово описывающее объект также принадлежит всем родителям категории. При этом вероятность для каждого слова в категории надо считать относительно "братьев" этой категории, а не всех категорий сразу.&lt;br /&gt;&lt;br /&gt;Есть еще один момент отличающий полученный классификатор от decision tree. Из каждого узла мы спускаемся вниз не по одному направлению, а сразу по нескольким, наиболее вероятным. Это нужно, чтобы не потерять маленькие категории внутри больших.&lt;br /&gt;&lt;br /&gt;Результатом работы этого классификатора будет набор категорий, которые были им пройдены в спуске по дереву. Дальше мы применяем классического Байеса к этому набору и получаем искомый ответ за гораздо меньшее время.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-1826298969474600452?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/1826298969474600452/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=1826298969474600452' title='Комментарии: 7'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/1826298969474600452'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/1826298969474600452'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/10/blog-post_18.html' title='Байес для сужения области поиска'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-3841859128529472556</id><published>2006-10-16T12:22:00.000+04:00</published><updated>2006-10-16T12:30:34.789+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ромип'/><title type='text'>РОМИП'2006</title><content type='html'>19-го октября в Суздале пройдет четвертый &lt;a href="http://romip.narod.ru/"&gt;РОМИП&lt;/a&gt;. Тем временем, на сайте &lt;a href="http://romip.narod.ru/romip2006/"&gt;семинара&lt;/a&gt; уже доступны труды участников. Приятного чтения!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-3841859128529472556?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/3841859128529472556/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=3841859128529472556' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/3841859128529472556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/3841859128529472556'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/10/2006.html' title='РОМИП&apos;2006'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-544582285014361172</id><published>2006-10-13T19:20:00.000+04:00</published><updated>2006-10-21T15:21:18.734+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='data quality'/><category scheme='http://www.blogger.com/atom/ns#' term='learning'/><category scheme='http://www.blogger.com/atom/ns#' term='classification'/><category scheme='http://www.blogger.com/atom/ns#' term='bayes'/><title type='text'>Обучение классификатора на некачественных данных</title><content type='html'>&lt;div style="text-align: justify;"&gt;В идеальном мире все наши данные точные и полные, в них нет ошибок, пользователи счастливы, а специалисты по data quality торгуют пирожками. Как вы уже догадались, мы живем далеко не в идеальном мире и у наших данных большие проблемы с качеством. Эти проблемы встают особенно остро, когда мы хотим использовать эти данные для обучения систем наподобие классификаторов Байеса. Ведь все очень просто, правильные знания, скорее всего, дадут правильный результат, неправильные — совершенно непредсказуемый.&lt;br /&gt;&lt;br /&gt;Напомню нашу задачу. Необходимо классифицировать некие сущности (например, книги или вообще любые товары) по дереву категорий. Для обучения у нас есть некоторый входной массив данных. Нас подстерегают две проблемы с качеством:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Неточная или неправильная классификация сущностей по категориям.&lt;/li&gt;&lt;li&gt;Само дерево категорий может недостаточно точно и/или избыточно отражать реальный мир.&lt;/li&gt;&lt;/ol&gt;Вторая задача достаточно сложная и достойна отдельного исследования, первую же можно решить достаточно просто и эффективно.&lt;br /&gt;&lt;br /&gt;Первое, что необходимо сделать (если это возможно, конечно), это попытаться выделить каким-либо образом среди всего обучающего массива записи, которые отклассифицированы правильно. Как правило, для этого используются какие-либо внешние источники данных или результаты обработки массива другой системой. Все, конечно, сильно зависит от конкретного случая. После выделения таких записей, словам из них можно дать больший вес, например, умножить их частоту встречаемости на 2.&lt;br /&gt;&lt;br /&gt;Если же у нас не очень много данных (или очень много свободного времени), их можно вообще классифицировать вручную. Не очень много это, действительно, не очень много, у меня не получалось заставить себя обработать больше двух тысяч записей. Соответственно, для больших массивов нам нужно попытаться сделать некоторую выборку таким образом, чтобы в нее попало как можно большее число плохих записей. Использовать в качестве критерия "нехорошести" итоговую вероятность не получится, как большие, так и маленькие ее значения в данном случае очень мало говорят о качестве результата классификации. Гораздо лучшей выборкой оказываются те записи, для которых полученная категория отличается от исходной. На практике, размер такой выборки может быть от 1 до 10 процентов от общего числа обучающих записей. Что же она поможет нам узнать:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Если классификатор сработал правильно, можно предположить, что большая часть подобных записей уже лежит в правильной категории.  Для слов из этой записи можно немного повысить вес, пометить ее как "подтвержденную".&lt;/li&gt;&lt;li&gt;Если же классификатор выдал неправильный результат, как правило, это означает обратное: значительной части похожих записей присвоена неправильная категория. Чтобы как можно быстрее вытащить их на белый свет, стоит повысить вес для слов гораздо сильнее, чем в предыдущем случае. На практике, хороший результат достигался умножением на 25.&lt;/li&gt;&lt;/ol&gt;Результаты такой обработки загружаются в базу знаний, меняются категории у записей, помечается как нужно повысить вес и повторно запускается классификатор. Далее мы делаем точно такую же выборку, которая может быть чуть больше предыдущей, и повторям процесс обработки. Чтобы добиться хороших результатов, обычно достаточно 4-5 таких циклов.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-size:85%;"&gt;Если данных совсем много, можно применить несколько приемов, которые помогут ускорить процесс обработки:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Выборку можно разделить на две части. Первая, где произошло уточнение категории, то есть мы спустились ниже по дереву. Эта часть обрабатывается гораздо быстрее, так как проще принять решение о правильности результата. Вторая — все остальное. Обработать ее будет тоже чуть проще, потому что она станет значительно меньше.&lt;/li&gt;&lt;li&gt;Можно отдельно стрелять классификатором по &lt;span style="font-style: italic;"&gt;подозрительным&lt;/span&gt; категориям. Это, в первую очередь, категории, в которые записи были ошибочно отнесены. Так мы сможем достаточно быстро выявить большие некачественные регионы в обучающем массиве.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-544582285014361172?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/544582285014361172/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=544582285014361172' title='Комментарии: 7'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/544582285014361172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/544582285014361172'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/10/blog-post_12.html' title='Обучение классификатора на некачественных данных'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-383155579379275601</id><published>2006-10-12T17:44:00.000+04:00</published><updated>2006-10-15T02:01:41.131+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='hashmap'/><title type='text'>Поправки к прошлому посту</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;a href="http://stepancheg.livejournal.com/"&gt;Степа&lt;/a&gt; указал мне на две мои ошибки в прошлом &lt;a href="http://krondix.blogspot.com/2006/10/hashmap.html"&gt;посте&lt;/a&gt;:&lt;br /&gt;&lt;/div&gt;&lt;ol style="text-align: justify;"&gt;&lt;li&gt;Не нужно делать специальный класс обертку над &lt;code&gt;String&lt;/code&gt;, можно использовать метод &lt;code&gt;intern()&lt;/code&gt;, который как раз и вернет нужную нам строку-синглтон.&lt;/li&gt;&lt;li&gt;Оказывается результат работы &lt;code&gt;hashCode()&lt;/code&gt; у класса &lt;code&gt;String&lt;/code&gt; кэшируется. Это, кстати, объясняет почему прирост производительности получился таким маленьким. Я ожидал на порядок больше.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-383155579379275601?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/383155579379275601/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=383155579379275601' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/383155579379275601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/383155579379275601'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/10/string-intern.html' title='Поправки к прошлому посту'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-6610897881981225812</id><published>2006-10-11T23:49:00.000+04:00</published><updated>2006-10-15T02:03:41.289+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='hashmap'/><category scheme='http://www.blogger.com/atom/ns#' term='bayes'/><title type='text'>HashMap со строковыми ключами</title><content type='html'>&lt;div style="text-align: justify;"&gt;В реализации классификатора Байеса, в классе &lt;code&gt;Category&lt;/code&gt; вполне может встретиться следующий метод:&lt;br /&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;code&gt;&lt;/code&gt;&lt;pre&gt;public double calculateProbability(String[] tokens) {&lt;br /&gt;   double probability = this.probability;&lt;br /&gt;   for (String token : tokens) {&lt;br /&gt;       Double partProbability = words.get(token);&lt;br /&gt;       if (partProbability != null) {&lt;br /&gt;           probability *= partProbability;&lt;br /&gt;       } else {&lt;br /&gt;           probability *= LOW_PROBABILITY;&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;   return probability;&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;&lt;div style="text-align: justify;"&gt;В данном случае &lt;code&gt;words&lt;/code&gt; это &lt;code&gt;HashMap&amp;lt;String, Double&amp;gt;&lt;/code&gt;, вероятности для каждого слова в данной категории. Получение элемента по ключу в &lt;code&gt;HashMap&lt;/code&gt; работает быстро, за константное время.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Если прогнать классификатор под профайлером, то основное время придется как раз на вызов метода &lt;code&gt;get()&lt;/code&gt;. Как он работает: для ключа вычисляется его хэш-код, по этому хэшу достается список пар ключ-значение, который последовательно проходится в поисках ключа равного данному. Как можно ускорить работу &lt;code&gt;hashCode()&lt;/code&gt; и &lt;code&gt;equals()&lt;/code&gt; для класса &lt;code&gt;String&lt;/code&gt;? Ответ прост! Надо заменить их на  &lt;code&gt;Object.hashCode()&lt;/code&gt; и &lt;code&gt;Object.equals()&lt;/code&gt; (что эквивалентно &lt;code&gt;==&lt;/code&gt;). Для этого нужно всего лишь вместо объектов &lt;code&gt;String&lt;/code&gt; хранить в &lt;code&gt;words&lt;/code&gt; обертку-синглтон над &lt;code&gt;String&lt;/code&gt; и передавать в &lt;code&gt;calculateProbability()&lt;/code&gt; массив таких оберток вместо &lt;code&gt;String[]&lt;/code&gt;. Это простое решение дает прирост производительности примерно на 100%.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-6610897881981225812?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/6610897881981225812/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=6610897881981225812' title='Комментарии: 11'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/6610897881981225812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/6610897881981225812'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/10/hashmap.html' title='HashMap со строковыми ключами'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-34676872.post-3765450470183672360</id><published>2006-10-11T16:20:00.000+04:00</published><updated>2006-10-21T15:21:37.813+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='classification'/><category scheme='http://www.blogger.com/atom/ns#' term='bayes'/><title type='text'>Классификация по Байесу</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;span style="font-size:100%;"&gt;Свой классификатор Байеса, кажется, не написал только ленивый. На удивление простая модель с допущениями, от которых у любого математика начинают шевелиться уши, на практике работает с потрясающей точностью. Определение спама, классификация текстов по жанрам, товарных предложений по категориям или даже поиск модели ноутбука в наборе строк — со всеми этими задачами успешно справляются классификаторы Байеса.&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-size:100%;"&gt;Расскажу на примере как работает самый простой классификатор Байеса. Допустим, мы хотим классифицировать книги на основе их краткого описания. У нас есть исходная база знаний в виде дерева категорий и набора уже классифицированных книг. На основе этих данных мы можем посчитать для каждого слова, которое встречается в описаниях, вероятность его принадлежности к определенной категории по следующей формуле:&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/136/4233/1600/bayes.2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger2/136/4233/320/bayes.1.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-size:78%;"&gt;&lt;code&gt;W&lt;/code&gt; — слово, &lt;code&gt;C&lt;/code&gt; — категория&lt;br /&gt;&lt;code&gt;count(C, W)&lt;/code&gt; — количество слов &lt;code&gt;W&lt;/code&gt; в описаниях книг из категории &lt;code&gt;C&lt;/code&gt;&lt;br /&gt;&lt;code&gt;count(C, books)&lt;/code&gt; — количество книг в категории &lt;code&gt;C&lt;/code&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-size:100%;"&gt;Нормализация по числу книг нужна, чтобы не терять в общей массе маленькие категории с большой встречаемостью слова. Например, в категории &lt;code&gt;C1&lt;/code&gt; "Тракторы в поэзии 20-го века" есть 30 книг, в описаниях которых слово "трактор" встречается 60 раз. А в категории &lt;code&gt;C2&lt;/code&gt; "Спецтехника", соответственно, 6000 книг и 1000 раз встречается слово "трактор". Таким образом, без нормализации:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;P(C1, "трактор") = 60 / (1000 + 60) ~ 0.056&lt;/code&gt;&lt;br /&gt;&lt;code&gt;P(C2, "трактор") = 1000 / (1000 + 60) ~ 0.944&lt;/code&gt;&lt;/blockquote&gt;Что однозначно относит слово "трактор" в категорию &lt;code&gt;С2&lt;/code&gt;. Если использовать нормализацию, мы получаем:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;P(C1, "трактор") ~ 0.925&lt;br /&gt;P(C2, "трактор") ~ 0.075&lt;/code&gt;&lt;/blockquote&gt;Эти числа уже гораздо ближе к жизни.&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-size:100%;"&gt;Посчитав вероятности для каждого слова из нашей базы знаний, мы готовы классифицировать книги. Вероятность принадлежности книги &lt;code&gt;book&lt;/code&gt; к категории &lt;code&gt;C&lt;/code&gt; равна:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/136/4233/1600/bayes2.0.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger2/136/4233/320/bayes2.0.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:100%;"&gt;Здесь &lt;code&gt;P(C)&lt;/code&gt; это &lt;span style="font-style: italic;"&gt;априорная&lt;/span&gt; вероятность встречаемости категории &lt;code&gt;C&lt;/code&gt;, которая равна отношению числа книг в &lt;code&gt;C&lt;/code&gt; к общему числу книг. С помощью этого множителя мы учитываем, что книги о "Спецтехнике" встречаются гораздо чаще, чем "Тракторы в поэзии". Необходимо отметить, что &lt;code&gt;P(C|word)&lt;/code&gt; может быть нулем, если слово не встретилось в категории ни одного раза, в таком случае обычно подставляют в формулу какое-либо маленькое значение.&lt;br /&gt;&lt;br /&gt;Все! Классификатор Байеса готов работе. В следующий раз я расскажу о некоторых методиках обучения на некачественных данных и о двух интересных способах применения полученного классификатора.&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/34676872-3765450470183672360?l=krondix.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://krondix.blogspot.com/feeds/3765450470183672360/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=34676872&amp;postID=3765450470183672360' title='Комментарии: 7'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/3765450470183672360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/34676872/posts/default/3765450470183672360'/><link rel='alternate' type='text/html' href='http://krondix.blogspot.com/2006/10/blog-post.html' title='Классификация по Байесу'/><author><name>krondix</name><uri>http://www.blogger.com/profile/16757443590873884684</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry></feed>
