Архив за месяц: Июнь 2019

Классификация текстов методом Doc2vec в python

Используя любой метод классификации текстов, первоночально необходимо придумать способ перевода текстового документа в набор чисел. Ранее уже был рассмотрен метод на основе TF-IDF, в этот раз рассмотрим метод DOC2VEC. Из названия сразу понятно, что метод переводит документ в вектор, причём делается это просто. Сразу приведу код:

# определим датасет
some_texts = [
   'текст номер один',
   'Текст следуюйщих под номером два',
   'третий набор слов',
   'что-то ещё для полноценного дата-сета',
   'пример текстового документа'
]

from gensim.models.doc2vec import Doc2Vec, TaggedDocument
documents = [TaggedDocument(doc, [i]) for i, doc in enumerate(some_texts)]

model = Doc2Vec(documents, vector_size=5, workers=4, epochs=3)

Обучение, в данном примере (взятом из документации), происходит сразу при создании объекта. (Мне это показалось немного странным, после sklearn с методами fit и transform).
Некоторые основные параметры:
vector_size — какой конечный размер будет у вектора. Тонкий параметр, который придётся подбирать. Чем больше выборка и длиннее каждый документ — тем имеет смысл ставить параметр больше, порядка 100-300. Для небольших текстов и датасетов может хватить размерности 5-10.
epoch — кол-во эпох на обучении. Тоже потребует настройки, обычно 10-20

workers — сколько ядер хотите задействовать на обучении. (Узнать кол-во: from multiprocessing import cpu_count)
Стоит также отметить, что начальные веса для документов берутся случайно, и в дальнейшем происходит утряска-оптимизация весов. Поэтому после каждого обучения результирующий вектор для одного и того же документа будет разным.

Полезные методы Doc2Vec

# сохранение модели для дальнейшего использования
model.save("my_doc2vec_model")
# загрузка модели
model = Doc2Vec.load("my_doc2vec_model")
# нахождение наиболее похожего документа
vector_to_search = model.infer_vector(["ищем", "похожий", "текст"])
# три наиболее похожих
similar_documents = model.docvecs.most_similar([vector_to_search], topn=3)
for s in similar_documents:
    print(some_texts[s[0]])

И так, модель Doc2vec обучена, теперь можно любой документ перевести в вектор и обучить вашим любимым классификатором. Давайте для пример возьмем RandomForest

from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier()
clf.fit([model.infer_vector([x.words]) for x in documents], [1, 1, 1, 0, 0])
 
res = clf.predict([model.infer_vector(['текст', 'номер', 'три'])])
print(res)  # [1]

По своему опыту могу сказать, что doc2vec несколько капризная штука и по настоящему хорошо работать этот метод мне не удалось заставить. Особенно неприятно удивили результаты с находением наиболее похожих документов в датасете. Однако, т.к. это другой подход, отличный от классического bag of words, tf-idf а также от LDA и подходов на нейронных сетях, то можно его смело рекомендовать использовать в дополнение с другими алгоритмами для достижения максимальной точности классификации.

Скачать список доменов в зоне .ru

В доменной зоне .ru находится примерно 5 000 000 зарегистрированных доменов. Если учитывать домены третьего уровня, то эта цифра увеличивается примерно до восьми миллионов. Файл для скачивания представлят собой .txt файл в архиве, в нём находится примерно 1 000 000 доменов актуальных на май 2019. Думаю миллиона вполне хватит для проверки статистических гипотез, которые возникают в ходе исследовательских задач. (ссылка на скачиване находится чуть ниже)

Так же для интереса приведу данные по количеству доменов в других расспространённых зонах, а всего в мире зарегистрировано порядка 400 000 000 доменов.
зона .com 150 миллионов
зона .net 14 миллионов
зона .org 11 миллионов
зона .info 7 миллионов
зона .uk 12 миллионов
зона .de 5 миллионов

Как быстро получить информацию со всех сайтов, указанных в базе доменов? Для этого воспользуемся python скриптом. Обходить все домены лучше всего не поочереди, а асинхронно или в несколько потоков, т.к. задержки, возникающие при запросе будут тормозить следующий запрос и накапливаться, а это нам не к чему. Самый быстрый и мощный вариан asyncio, однако уровень вхождения в библиотеку чуть выше среднего, поэтому ниже показан самый простой вариант как быстро обойти все домены. С помощью данного скрипта можно обойти миллион доменов из списка за 3-4 часа. В качестве информации, которую будем брать с сайтов, давайте возьмем данные о IP адресе, где расположен хостинг.

скрипт на python для парсинга инфорамации о сайтах из базы доменов на примере ip:

import socket
# с помощью multiprocessing сможем обходить сайты не последовательно
from multiprocessing.dummy import Pool as ThreadPool
import dns.resolver
import pandas as pd

# определим функцию для получения IP адреса
def get_ip(url):
    try:
        data_ip = socket.gethostbyname(url)
    except:
        return None
    return data_ip


df_all_ru = pd.read_csv('all_ru.csv')
sites_list = df_all_ru['domain_name'].tolist()

# за раз давайте будем брать сразу 100 доменов
# имеет смысл подобрать этот параметр в зависимости от скорости вашего интернета и задачи которую решаете
p = ThreadPool(100)
result_ip = p.map(get_ip, sites_list)
p.close()
p.join()

df_all_ru['ip'] = result_ip
df_all_ru.to_csv('ru_domains_ips.csv', index=False)

С помощью данного простого скрипта можно быстро получить данные с большого количества сайтов.

Непосредственно скачать файл со списком ру доменов здесь