「text2vec」パッケージを使ってSCDVのようなことをやってみる

================================================
word2vecの代わりに「text2vec」パッケージのGloveを使用
GMMは「ClusterR」パッケージを使用
================================================

環境

Windows10 Pro 64bit
Microsoft R open 3.4.3

library(checkpoint)
checkpoint("2018-02-23", checkpointLocation = "F:/", scanForPackages = FALSE)
> packageVersion("text2vec")
[1] ‘0.5.1’
> packageVersion("tm")
[1] ‘0.7.3’
> packageVersion("ClusterR")
[1] ‘1.1.0’

本来の用途とは異なるが「checkpoint」パッケージを使用すると仮想環境作成に近いことが可能である。

データの準備

PubMedからXMLファイルをダウンロードしてAbstractTextを抽出する。
(注)なかには多言語でアブストラクトが記載されている場合がある。
(例えばこちら

using System;
using System.Text;
using System.Xml.Linq;
using System.IO;
using System.Diagnostics;
using System.Collections.Generic;
using System.Xml;

namespace pubmed
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("ファイル名を入力してください");
            string s;
            s = Console.ReadLine();

            string PMID = s.Replace(".xml", "_pmid.txt");
            string ABST = s.Replace(".xml", "_Absts.txt");

            Stopwatch watch = new Stopwatch();
            watch.Start();

            StreamWriter pmid = new StreamWriter(PMID, false, Encoding.GetEncoding("shift_jis"));

            StreamWriter absts = new StreamWriter(ABST, false, Encoding.GetEncoding("shift_jis"));

            foreach (XElement el in mystream(s))
            {
                if (el.Element("MedlineCitation").Element("Article").Element("Language").Value == "eng")
                {
                    string Absts = "";
                    foreach (XElement x2 in el.Element("MedlineCitation").Element("Article").Descendants("AbstractText"))
                    {
                        Absts = Absts + " " +  x2.Value;
                    }

                    if (Absts != "")
                    {
                        //アブストラクトに改行文字がふくまれることがある
                        //改行を消すときはスペースで置換しないと単語が連なることがある
                        Absts = Absts.Replace("\r", " ").Replace("\n", " ");
                        pmid.WriteLine(el.Element("MedlineCitation").Element("PMID").Value);
                        absts.WriteLine(Absts);
                    }
                }
            }
            pmid.Close();
            absts.Close();

            watch.Stop();

            Console.WriteLine("経過時間の合計 = {0}", watch.Elapsed);
            Console.ReadLine();
        }
        static IEnumerable<XElement> mystream(string file_name)
        {
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.DtdProcessing = DtdProcessing.Parse;

            using (XmlReader reader = XmlReader.Create(file_name, settings))
            {
                while (reader.Read())
                {
                    if (reader.Name == "PubmedArticle")
                    {
                        yield return XElement.ReadFrom(reader) as XElement;
                    }
                }
            }
        }
    }
}

GloVeでワードベクトル作成まで

library(text2vec)

Absts <- readLines("Absts_for_text2vec.txt")

it <- itoken(Absts, tolower, word_tokenizer)

#text2vec_vocabularyの作成
voc <- create_vocabulary(it)
voc <- prune_vocabulary(voc, doc_count_min = 3L)

library(tm)
new_stopwords <- c(stopwords("en"), "can", "could", "may", "might", "also", "however")

voc <- voc[!(voc$term %in% new_stopwords),]

#TCM(term-co-occurence matrix)の作成
tcm <- create_tcm(it, vocab_vectorizer(voc), skip_grams_window = 10L)

#ワードベクトルの作成
glove <- GloVe$new(word_vectors_size = 50, vocabulary = voc, x_max = 10)
main <- glove$fit_transform(tcm, n_iter = 50)
context <- glove$components
word_vectors <- normalize((main + t(context)), norm = "l2")

混合ガウスモデルクラスタリング

まずはクラスター数をいくつにするかの検討

library(ClusterR)
Optimal_Clusters_GMM(word_vectors, 100, criterion = "BIC", "maha_dist", "random_subset", km_iter = 10, em_iter = 10, plot_data = TRUE)

f:id:touch-sp:20180223120223p:plain:w600
元文献の通り60くらいが妥当なのかな?

gmm <- GMM(word_vectors, 60, "maha_dist", "random_subset", km_iter = 10, em_iter = 10)
pr <- predict_GMM(word_vectors, gmm$centroids, gmm$covariance_matrices, gmm$weights)
proba <- pr$cluster_proba

idfの計算

number_of_docs <- attr(voc, "document_count")
idf <- log((Number_of_docs + 1) / (voc$doc_count + 1)) + 1

この記事は書きかけです。