Main Content

トピック モデルを使用したテキスト データの解析

この例では、潜在的ディリクレ配分 (LDA) トピック モデルを使用してテキスト データを解析する方法を示します。

潜在的ディリクレ配分 (LDA) モデルは、文書のコレクションに内在するトピックを発見し、トピック内の単語の確率を推測するトピック モデルです。

テキスト データの読み込みと抽出

サンプル データを読み込みます。ファイル factoryReports.csv には、各イベントの説明テキストとカテゴリカル ラベルを含む工場レポートが格納されています。

data = readtable("factoryReports.csv",TextType="string");
head(data)
ans=8×5 table
                                 Description                                       Category          Urgency          Resolution         Cost 
    _____________________________________________________________________    ____________________    ________    ____________________    _____

    "Items are occasionally getting stuck in the scanner spools."            "Mechanical Failure"    "Medium"    "Readjust Machine"         45
    "Loud rattling and banging sounds are coming from assembler pistons."    "Mechanical Failure"    "Medium"    "Readjust Machine"         35
    "There are cuts to the power when starting the plant."                   "Electronic Failure"    "High"      "Full Replacement"      16200
    "Fried capacitors in the assembler."                                     "Electronic Failure"    "High"      "Replace Components"      352
    "Mixer tripped the fuses."                                               "Electronic Failure"    "Low"       "Add to Watch List"        55
    "Burst pipe in the constructing agent is spraying coolant."              "Leak"                  "High"      "Replace Components"      371
    "A fuse is blown in the mixer."                                          "Electronic Failure"    "Low"       "Replace Components"      441
    "Things continue to tumble off of the belt."                             "Mechanical Failure"    "Low"       "Readjust Machine"         38

フィールド Description からテキスト データを抽出します。

textData = data.Description;
textData(1:10)
ans = 10×1 string
    "Items are occasionally getting stuck in the scanner spools."
    "Loud rattling and banging sounds are coming from assembler pistons."
    "There are cuts to the power when starting the plant."
    "Fried capacitors in the assembler."
    "Mixer tripped the fuses."
    "Burst pipe in the constructing agent is spraying coolant."
    "A fuse is blown in the mixer."
    "Things continue to tumble off of the belt."
    "Falling items from the conveyor belt."
    "The scanner reel is split, it will soon begin to curve."

解析用のテキスト データの準備

解析に使用できるように、テキスト データをトークン化して前処理する関数を作成します。この例の前処理関数セクションにリストされている関数 preprocessText は、以下の手順を順番に実行します。

  1. tokenizedDocument を使用してテキストをトークン化します。

  2. normalizeWords を使用して単語をレンマ化します。

  3. erasePunctuation を使用して句読点を消去します。

  4. removeStopWords を使用して、ストップ ワード ("and"、"of"、"the" など) のリストを削除します。

  5. removeShortWords を使用して、2 文字以下の単語を削除します。

  6. removeLongWords を使用して、15 文字以上の単語を削除します。

関数 preprocessText を使用して、解析用のテキスト データを準備します。

documents = preprocessText(textData);
documents(1:5)
ans = 
  5×1 tokenizedDocument:

    6 tokens: item occasionally get stuck scanner spool
    7 tokens: loud rattling bang sound come assembler piston
    4 tokens: cut power start plant
    3 tokens: fry capacitor assembler
    3 tokens: mixer trip fuse

トークン化された文書から bag-of-words モデルを作成します。

bag = bagOfWords(documents)
bag = 
  bagOfWords with properties:

          Counts: [480×338 double]
      Vocabulary: [1×338 string]
        NumWords: 338
    NumDocuments: 480

合計で 2 回以上出現しない単語を bag-of-words モデルから削除します。単語を含まない文書すべてを bag-of-words モデルから削除します。

bag = removeInfrequentWords(bag,2);
bag = removeEmptyDocuments(bag)
bag = 
  bagOfWords with properties:

          Counts: [480×158 double]
      Vocabulary: [1×158 string]
        NumWords: 158
    NumDocuments: 480

LDA モデルを当てはめる

トピック数 7 の LDA モデルを当てはめます。トピック数を選択する方法を示す例については、LDA モデルのトピック数の選択を参照してください。詳細出力を抑制するために、Verbose オプションを 0 に設定します。再現性を確保するために、関数 rng"default" オプションと共に使用します。

rng("default")
numTopics = 7;
mdl = fitlda(bag,numTopics,Verbose=0);

大規模なデータセットがある場合は、通常、適切なモデルを当てはめるために渡すデータがより少なくて済む、確率的近似変分ベイズ ソルバーが適しています。fitlda の既定のソルバー (崩壊型ギブス サンプリング) は、実行にかかる時間は長くなりますが、より正確になります。確率的近似変分ベイズを使用するには、Solver オプションを "savb" に設定します。LDA ソルバーを比較する方法を示す例については、Compare LDA Solversを参照してください。

ワード クラウドを使用したトピックの可視化

ワード クラウドを使用して、各トピックで最も確率の高い単語を表示できます。ワード クラウドを使用してトピックを可視化します。

figure
t = tiledlayout("flow");
title(t,"LDA Topics")

for i = 1:numTopics
    nexttile
    wordcloud(mdl,i);
    title("Topic " + i)
end

文書内のトピックの混合率の表示

学習データと同じ前処理関数を使用して、まだ見ていない文書のセットについて、トークン化された文書の配列を作成します。

str = [
    "Coolant is pooling underneath assembler."
    "Sorter blows fuses at start up."
    "There are some very loud rattling sounds coming from the assembler."];

newDocuments = preprocessText(str);

関数 transform を使用して、文書をトピック確率のベクトルに変換します。非常に短い文書の場合、トピックの混合率は文書のコンテンツを強力に表現するものではない可能性があることに注意してください。

topicMixtures = transform(mdl,newDocuments);

最初の文書の文書トピック確率を棒グラフにプロットします。トピックにラベルを付けるには、対応するトピックの上位 3 語を使用します。

for i = 1:numTopics
    top = topkwords(mdl,3,i);
    topWords(i) = join(top.Word,", ");
end

figure
bar(topicMixtures(1,:))

xlabel("Topic")
xticklabels(topWords);
ylabel("Probability")
title("Document Topic Probabilities")

積み上げ棒グラフを使用して、複数のトピックの混合率を可視化します。文書のトピック混合率を可視化します。

figure
barh(topicMixtures,"stacked")
xlim([0 1])

title("Topic Mixtures")
xlabel("Topic Probability")
ylabel("Document")

legend(topWords, ...
    Location="southoutside", ...
    NumColumns=2)

前処理関数

関数 preprocessText は、以下の手順を順番に実行します。

  1. tokenizedDocument を使用してテキストをトークン化します。

  2. normalizeWords を使用して単語をレンマ化します。

  3. erasePunctuation を使用して句読点を消去します。

  4. removeStopWords を使用して、ストップ ワード ("and"、"of"、"the" など) のリストを削除します。

  5. removeShortWords を使用して、2 文字以下の単語を削除します。

  6. removeLongWords を使用して、15 文字以上の単語を削除します。

function documents = preprocessText(textData)

% Tokenize the text.
documents = tokenizedDocument(textData);

% Lemmatize the words.
documents = addPartOfSpeechDetails(documents);
documents = normalizeWords(documents,Style="lemma");

% Erase punctuation.
documents = erasePunctuation(documents);

% Remove a list of stop words.
documents = removeStopWords(documents);

% Remove words with 2 or fewer characters, and words with 15 or greater
% characters.
documents = removeShortWords(documents,2);
documents = removeLongWords(documents,15);

end

参考

| | | | | | | | |

関連するトピック