Поиск энтропийных всплесков в потоке новостей

606 days ago by kpp

Источник данных (лента новостей):

#auto #url = "http://rss.feedsportal.com/c/803/f/413231/index.rss" #CNews url = "http://www.rian.ru/export/rss2/index.xml" # РИА-новости # google group Магистранты БИ ГУ-ВШЭ'12: #url = "http://groups.google.com/group/hse-bi-12/feed/rss_v2_0_msgs.xml?num=50" #url = "http://www.ixbt.com/export/utf8/news.rss" # IXBT-все новости #url = "http://www.ixbt.com/export/marketnews.rss" # IXBT-новости IT рынка #url = "http://habrahabr.ru/rss/39ff36faddf404ca10046382efd8f151/" # Хабрахабр 
       

Игнорируемые слова:

#auto ignore_words = [u"БЕЗ", u"БЕЗО", u"ОТ", u"У", u"ИЗ", u"ДЛЯ", u"ДО", u"ВНЕ", u"ВВИДУ", u"ВГЛУБЬ", u"ВДОЛЬ", u"ВЗАМЕН", u"ВКЛЮЧАЯ", u"ВНИЗУ", u"ВНУТРИ", u"ВПЕРЕДИ", u"ВРОДЕ", u"ВСЛЕДСТВИЕ", u"БЛАГОДАРЯ", u"К", u"ПО", u"ВОПРЕКИ", u"ВСЛЕД", u"НА", u"ЗА", u"ПРО", u"ВМЕСТО", u"ВНУТРЬ", u"С", u"СО", u"О", u"В", u"ВО", u"ОБ", u"А", u"НО", u"И", u"ИЛИ", u"ЧТО", u"КАК", u"ГДЕ", u"КОГДА", u"ПОТОМУ", u"СКОЛЬКО", u"ЧТОБЫ", u"КОТОРЫЙ", u"НЕ", u"БЫ", u"ЛИ", u"ЖЕ", u"УЖЕ", u"Я", u"МЫ", u"МОЙ", u"НАШ", u"ТЫ", u"ТВОЙ", u"ВЫ", u"ВАШ", u"ОН", u"ОНА", u"ОНИ", u"ОНО", u"ЕГО", u"ЕЁ", u"ЕЕ", u"ИХ", u"ИМ", u"СЕБЯ", u"СВОЙ", u"ЭТО", u"ТО", u"ЭТОТ", u"ТОТ", u"ВЕСЬ", u"ВСЁ", u"ВСЕ" ] 
       

Требуемые стандартные модули:

#auto import tempfile import zipfile import urllib2 import codecs import os import sqlite3 import re import string import cPickle import pylab 
       

Функция загрузки и распаковки файлов:

#auto def get_and_unzip(url, destdir): (fzip, name) = tempfile.mkstemp(); file = os.fdopen(fzip, 'wb'); file.write(urllib2.urlopen(url).read()); file.close() zipfile.ZipFile(name).extractall(destdir) os.remove(name) 
       

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

#auto if not os.path.exists(DATA + "/pymorphy/"): get_and_unzip("http://bitbucket.org/kmike/pymorphy/get/tip.zip", DATA) get_and_unzip("http://bitbucket.org/kmike/pymorphy/downloads/ru.sqlite.zip", DATA + "/dicts/ru") else: html("Pymorphy найдена") if not os.path.exists(DATA + "/feedparser/"): get_and_unzip("http://feedparser.googlecode.com/files/feedparser-4.1.zip", DATA + "/feedparser") else: html("Feedparser найден") # Разбор морфологии sys.path.append(DATA+"/pymorphy/") from pymorphy import get_morph sys.path.pop(-1) m = get_morph(DATA+"/dicts/ru/") # Разбор RSS и Atom sys.path.append(DATA+"/feedparser/") import feedparser sys.path.pop(-1) 
       
Pymorphy найдена
Feedparser найден
'/home/sage/sagenb/sage_notebook-alpha.sagenb/home/kpp/6/data//feedparse\
r/'
Pymorphy найдена
Feedparser найден
'/home/sage/sagenb/sage_notebook-alpha.sagenb/home/kpp/6/data//feedparser/'

Игнорируем всю html разметку в потоке:

#auto feedparser._HTMLSanitizer.acceptable_elements = [] 
       

Подключение или создание базы данных:

#auto conn = sqlite3.connect(DATA+ "/base.sqlite") c = conn.cursor() c.execute('''SELECT * FROM sqlite_master WHERE type='table' AND name='words';''') if c.fetchone() == None: # Начальные формы: c.execute('''CREATE TABLE infins (id INTEGER PRIMARY KEY, infin TEXT UNIQUE);''') # Запись количества упоминаний: c.execute( r'''CREATE TABLE words (id INTEGER PRIMARY KEY, word1 INTEGER NOT NULL, word2 INTEGER, word3 INTEGER, mentions INTEGER);''' ) c.execute( r'''CREATE TABLE news (id INTEGER PRIMARY KEY, title TEXT, link TEXT, words TEXT);''' ) conn.commit() else: html(u"Таблицы уже существуют".encode('utf-8')) c.close() 
       
Таблицы уже существуют
Таблицы уже существуют

Функция приведения слова к нормальной форме с помощью pymorphy:

#auto def normalize(word): if word == "": return word; r = m.normalize(word); if type(r)== set: r = r.pop() if r == "": r = word; return r; 
       

Функция добавления начальной формы слова в базу данных:

#auto def add_word(dbcursor, word): word = normalize(word); t = (word, ) dbcursor.execute(r'''INSERT OR IGNORE INTO infins VALUES (NULL, ?);''', t) conn.commit() return word; 
       

Функция для сбора информации о том, сколько раз в тексте встретились слово, пара слов и триада слов:

#auto def add_triple (dbcursor, w1, w2, w3): t3 = tuple([w for w in [w1, w2, w3] ]) insql = r'''IFNULL((SELECT `id` FROM infins WHERE `infin`=?), 0)''' sql = r'''SELECT `id` FROM words WHERE `word1`='''+ insql +''' AND `word2`='''+ insql +''' AND `word3`='''+ insql +''' ;''' sql2 = r'''INSERT INTO words VALUES (NULL, ''' + insql + ''', ''' + insql +''', ''' + insql + ''', 1);''' dbcursor.execute(sql, t3) result = dbcursor.fetchone(); if result == None: dbcursor.execute(sql2, t3) conn.commit() return row = result['id']; t = (row, ) dbcursor.execute(r'''UPDATE words SET mentions=mentions+1 WHERE id = ? ;''', t) conn.commit() 
       

Функция сопоставления списку слов в нормальной форме соответствующего списка номеров этих слов базе данных:

#auto def words2ids (dbcursor, words): sql = r'''SELECT `id` FROM infins WHERE ''' if len(words) < 1: return for i in range(0, len(words)-1): sql = sql + r''' `infin`=? OR ''' sql = sql + r''' `infin`=? ; ''' result = [r['id'] for r in dbcursor.execute(sql, tuple(words))] return result 
       

Загрузка в базу данных новостей и информации о том, сколько раз были использованы каждое слово, каждая последовательная пара и каждая триада слов:

regexp = re.compile('[' +string.punctuation+string.whitespace+ r'«»]+', re.UNICODE) conn.row_factory = sqlite3.Row c = conn.cursor() feed = feedparser.parse(url) for item in feed['items']: html (item.title.encode('utf-8')) line = (item.title + '\n' + item.summary).upper() w1 = ""; w2 = ""; w3 = ""; words = [] for word in regexp.split(line): if word == "": continue; if word in ignore_words: continue word = add_word(c, word) if word in ignore_words: continue w3 = w2 w2 = w1 w1 = word words.append(w1); add_triple(c, w1, "", "") if w2 != "": add_triple(c, w1, w2, "") if w3 != "": add_triple(c, w1, w2, w3) data = cPickle.dumps(words2ids(c, words)).decode() t = ( item.title, item.link, data ) c.execute(r'''INSERT INTO news VALUES(NULL, ?, ?, ?) ;''', t) c.close() 
       
Россиянин Сорокин совершит велопробег Вашингтон-Аляска в честь Победы
Пожар в кафе на севере Москвы локализован
Самолет вылетит из Улан-Удэ для эвакуации людей с аварийно севшего Ан-2
Поиск самолета Ан-2, пропавшего в Бурятии
"Обменники" в Москве работают под новыми вывесками в прежнем режиме
Три человека пострадали в ДТП с милицейской "Газелью" в Москве
Роскосмос, ЕКА и НАСА согласовали сроки запусков кораблей к МКС
Глава дипломатии ЕС призвала Израиль продлить поселенческий мораторий
Ан-2 в Бурятии совершил экстренную посадку из-за грозовой тучи - МЧС
Фондовые рынки США закрылись ростом на 0,09-0,44%
Ситуация на мировых фондовых рынках. Октябрь 2010
Все пилоты и пассажиры пропавшего в Бурятии Ан-2 живы
Лучшие самбисты мира соберутся в Москве на турнире на призы Аслаханова
Задержание россиян в США по обвинению в банковском мошенничестве
ФБР сообщило консульству РФ о задержании лишь четверых россиян
Испанские баскетболистки вышли в полуфинал ЧМ, где сыграют с США
Цены на нефть. Октябрь 2010
Мировые цены на нефть продолжают ощутимый рост
"Каролина" одолела "Атланту" в контрольной игре перед вылетом в Россию
Парижский автосалон открывает двери для широкой публики
Российский парусник "Надежда" отправляется из Шанхая в Японию
Партии, защищающие русскоязычных, могут победить на выборах в Латвии
"Санкт-Паули" обыграл "Ганновер" в первом матче 7-го тура бундеслиги
Ледокол "Россия" отправится в Арктику для высадки на лед станции СП-38
Греческие дальнобойщики прекратили многодневную забастовку
Президент Сирии Асад встретится в Тегеране с Ахмадинежадом
23-й тур чемпионата России по футболу-2010
Лидеры ЧР по футболу в 23-м туре постараются развить успех еврокубков
Арестованные в США по делу о хищении - "дети, которых использовали"
Ресин как врио мэра Москвы впервые проведет объезд строек столицы
Церемония развода караулов в Кремле в эту субботу не состоится
Катынский рейд завершился в Польше
Вице-премьер РФ Иванов обсудит вопросы госполитики в Арктике
Буксир ЧФ пресек опасное маневрирование вблизи от яхты Федора Конюхова
Сборная Чехии вышла в полуфинал женского баскетбольного ЧМ
Путин выразил соболезнования родным и близким писателя Михаила Рощина
Пакистанцы в Афинах провели демонстрацию, требуя политического убежища
Онищенко объявил о начале прививочной кампании против гриппа в России
Путин поздравил премьера Госсовета Китая с годовщиной образования КНР
Достойных преемников Лужкова оказалось слишком много
Подозреваемую в хищении 3 млн СМИ назвали "самым сексуальным хакером"
Бывший футболист "Локомотива" стал игроком месяца в Англии
Моуринью заявил, что не будет тренером сборной Англии
Похороны алтайского депутата, погибшего в ДТП, пройдут в субботу
Военные не задерживали журналистов на месте катастрофы под Смоленском
РИА Новости выбрало главные события недели в экологии
Возвращенный из Доминиканы мальчик отстает в развитии на 5 лет - Астахов
Россиянин Сорокин совершит велопробег Вашингтон-Аляска в честь Победы
Пожар в кафе на севере Москвы локализован
Самолет вылетит из Улан-Удэ для эвакуации людей с аварийно севшего Ан-2
Поиск самолета Ан-2, пропавшего в Бурятии
"Обменники" в Москве работают под новыми вывесками в прежнем режиме
Три человека пострадали в ДТП с милицейской "Газелью" в Москве
Роскосмос, ЕКА и НАСА согласовали сроки запусков кораблей к МКС
Глава дипломатии ЕС призвала Израиль продлить поселенческий мораторий
Ан-2 в Бурятии совершил экстренную посадку из-за грозовой тучи - МЧС
Фондовые рынки США закрылись ростом на 0,09-0,44%
Ситуация на мировых фондовых рынках. Октябрь 2010
Все пилоты и пассажиры пропавшего в Бурятии Ан-2 живы
Лучшие самбисты мира соберутся в Москве на турнире на призы Аслаханова
Задержание россиян в США по обвинению в банковском мошенничестве
ФБР сообщило консульству РФ о задержании лишь четверых россиян
Испанские баскетболистки вышли в полуфинал ЧМ, где сыграют с США
Цены на нефть. Октябрь 2010
Мировые цены на нефть продолжают ощутимый рост
"Каролина" одолела "Атланту" в контрольной игре перед вылетом в Россию
Парижский автосалон открывает двери для широкой публики
Российский парусник "Надежда" отправляется из Шанхая в Японию
Партии, защищающие русскоязычных, могут победить на выборах в Латвии
"Санкт-Паули" обыграл "Ганновер" в первом матче 7-го тура бундеслиги
Ледокол "Россия" отправится в Арктику для высадки на лед станции СП-38
Греческие дальнобойщики прекратили многодневную забастовку
Президент Сирии Асад встретится в Тегеране с Ахмадинежадом
23-й тур чемпионата России по футболу-2010
Лидеры ЧР по футболу в 23-м туре постараются развить успех еврокубков
Арестованные в США по делу о хищении - "дети, которых использовали"
Ресин как врио мэра Москвы впервые проведет объезд строек столицы
Церемония развода караулов в Кремле в эту субботу не состоится
Катынский рейд завершился в Польше
Вице-премьер РФ Иванов обсудит вопросы госполитики в Арктике
Буксир ЧФ пресек опасное маневрирование вблизи от яхты Федора Конюхова
Сборная Чехии вышла в полуфинал женского баскетбольного ЧМ
Путин выразил соболезнования родным и близким писателя Михаила Рощина
Пакистанцы в Афинах провели демонстрацию, требуя политического убежища
Онищенко объявил о начале прививочной кампании против гриппа в России
Путин поздравил премьера Госсовета Китая с годовщиной образования КНР
Достойных преемников Лужкова оказалось слишком много
Подозреваемую в хищении 3 млн СМИ назвали "самым сексуальным хакером"
Бывший футболист "Локомотива" стал игроком месяца в Англии
Моуринью заявил, что не будет тренером сборной Англии
Похороны алтайского депутата, погибшего в ДТП, пройдут в субботу
Военные не задерживали журналистов на месте катастрофы под Смоленском
РИА Новости выбрало главные события недели в экологии
Возвращенный из Доминиканы мальчик отстает в развитии на 5 лет - Астахов

Вывод наиболее часто встретившихся слов, пар и триад:

conn.row_factory = sqlite3.Row c = conn.cursor() c1 = conn.cursor() s = u"<table>" for r in c.execute('''SELECT * FROM words WHERE `mentions`>3;'''): s = s + u"<tr>" for v in [r['word1'], r['word2'], r['word3']]: c1.execute(r'''SELECT * FROM infins WHERE `id`=? ;''', (v,)) conn.commit() result = c1.fetchone() if result == None: infin = u"-" if v!=0: print v else: infin = result['infin'] s = s + u"<td>" + infin + u"</td>" s = s + u"<td>" + unicode(r['mentions']) + u"<td></tr>" s = s + u"</table>" html(s.encode('utf-8')) c.close() c1.close() 
       
ПОБЕДА--4
СТРАНА--5
МОСКВА--10
СУББОТА--4
2--11
САМОГОД--6
ЧЕЛОВЕК--6
АНА--6
2АНА-6
СООБЩИТЬ--6
РИА--6
РИАСООБЩИТЬ-4
НОВОСТЬ--6
НОВОСТЬРИА-6
НОВОСТЬРИАСООБЩИТЬ4
МЧС--4
БУРЯТИЯ--7
МЕСТО--5
ТАКЖЕ--6
ПОД--7
НОВЫЙ--4
ТРИ--5
ДТПНУТЬ--4
ОДИН--5
ДВА--5
БЫТЬ--10
ГОВОРИТЬСЯ--4
МИРО--5
ВРЕМЯ--6
СКАЗАТЬ--4
ИТОГ--4
НАХОДИТЬСЯ--4
США--5
0--6
ПУНКТ--4
ПЯТНИЦА--6
ОКТЯБРЬ--4
2010--7
АЭРОПОРТ--4
ГОД--6
ЧИСЛО--4
РОССИЯ--13
РФ--6
СЕНТЯБРЬ--5
НЕФТЬ--4
1--4
СТАТЬ--4
ПРОВЕСТИ--5
ИМЕТЬ--4
ТУРА--4
НЕДЕЛИ--4
МОСКОВСКИЙ--5
САМЫЙ--4
РЕСИН--4
СМОЛЕНСК--4
ПРЕМЬЕРА--4
СБОРНЫЙ--5
АНГЛИЯ--4
ПОБЕДА--4
СТРАНА--5
МОСКВА--10
СУББОТА--4
2--11
САМОГОД--6
ЧЕЛОВЕК--6
АНА--6
2АНА-6
СООБЩИТЬ--6
РИА--6
РИАСООБЩИТЬ-4
НОВОСТЬ--6
НОВОСТЬРИА-6
НОВОСТЬРИАСООБЩИТЬ4
МЧС--4
БУРЯТИЯ--7
МЕСТО--5
ТАКЖЕ--6
ПОД--7
НОВЫЙ--4
ТРИ--5
ДТПНУТЬ--4
ОДИН--5
ДВА--5
БЫТЬ--10
ГОВОРИТЬСЯ--4
МИРО--5
ВРЕМЯ--6
СКАЗАТЬ--4
ИТОГ--4
НАХОДИТЬСЯ--4
США--5
0--6
ПУНКТ--4
ПЯТНИЦА--6
ОКТЯБРЬ--4
2010--7
АЭРОПОРТ--4
ГОД--6
ЧИСЛО--4
РОССИЯ--13
РФ--6
СЕНТЯБРЬ--5
НЕФТЬ--4
1--4
СТАТЬ--4
ПРОВЕСТИ--5
ИМЕТЬ--4
ТУРА--4
НЕДЕЛИ--4
МОСКОВСКИЙ--5
САМЫЙ--4
РЕСИН--4
СМОЛЕНСК--4
ПРЕМЬЕРА--4
СБОРНЫЙ--5
АНГЛИЯ--4

Функция для подсчёта вероятности встретить в тексте слово, пару или триаду:

#auto def get_prob(dbcursor, w1, w2=0, w3=0): sql = r'''SELECT SUM(`mentions`) FROM words WHERE `word2`=? AND `word3`=?;''' t = (int(w2), int(w3)) dbcursor.execute(sql, t) total = dbcursor.fetchone()['SUM(`mentions`)']; if total == None: return 0; sql = r'''SELECT `mentions` FROM words WHERE `word1`=? AND `word2`=? AND `word3`=?;''' t = (int(w1), int(w2), int(w3)) dbcursor.execute(sql, t) result = dbcursor.fetchone() mentions = 0 if result != None: mentions = result['mentions'] return float(mentions)/total; 
       

Выделение энтропийного всплеска:

conn.row_factory = sqlite3.Row c = conn.cursor() cw = conn.cursor() ent0 = {} for r in c.execute(r'''SELECT `id`, `words` FROM news;'''): result = cPickle.loads( r['words'].encode() ) probs = [ get_prob(cw, w) for w in result ] ent0[r['id']] = sum([ -p*log(p,2) for p in probs ]).n() #print ent0[r['id']] cw.close() maxid = max(ent0) minid = min(ent0) c.execute(r'''SELECT `title`, `link` FROM news WHERE `id`=?;''', (maxid, )) result = c.fetchone(); smax = (ur'''<a href="'''+ result['link'] + ur'''">''' + result['title'] + ur'''</a>''') c.execute(r'''SELECT `title`, `link` FROM news WHERE `id`=?;''', (minid, )) result = c.fetchone(); smin = (ur'''<a href="'''+ result['link'] + ur'''">''' + result['title'] + ur'''</a>''') pylab.figure(edgecolor='w') b=pylab.boxplot(ent0.values()) pylab.savefig("result0.png",) html("Максимум энтропии соответствует новости:") html(smax.encode('utf-8')) html("Минимум энтропии соответствует новости:") html(smin.encode('utf-8')) c.close() 

Выделение энтропийного всплеска для условной энтропии первого порядка:

conn.row_factory = sqlite3.Row c = conn.cursor() cw = conn.cursor() ent1 = {} for r in c.execute(r'''SELECT `id`, `words` FROM news;'''): result = cPickle.loads( r['words'].encode() ) entropy1 = 0 for word in result: temp = 0; for w in result: p = get_prob(cw, word, w) if p == 0: continue temp = temp - n(p*log(p, 2)) entropy1 = entropy1 + temp * get_prob(cw, word) ent1[r['id']] = entropy1 #print entropy1 cw.close() pylab.figure(edgecolor='w') b=pylab.boxplot(ent1.values()) pylab.savefig("result1.png",) maxid = max(ent1) minid = min(ent1) c.execute(r'''SELECT `title`, `link` FROM news WHERE `id`=?;''', (maxid, )) result = c.fetchone(); smax = (ur'''<a href="'''+ result['link'] + ur'''">''' + result['title'] + ur'''</a>''') c.execute(r'''SELECT `title`, `link` FROM news WHERE `id`=?;''', (minid, )) result = c.fetchone(); smin = (ur'''<a href="'''+ result['link'] + ur'''">''' + result['title'] + ur'''</a>''') html("Максимум энтропии соответствует новости:") html(smax.encode('utf-8')) html("Минимум энтропии соответствует новости:") html(smin.encode('utf-8')) c.close() 
#auto import os @interact def _(delete_base=['no', 'yes']): if delete_base == 'yes': os.remove(DATA +"/base.sqlite") print "База удалена" 
       

Click to the left again to hide and once more to show the dynamic interactive window