質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Mecab

Mecabは、オープンソースの形態素解析エンジンです。 言語、辞書、コーパスに依存しない汎用的な設計を基本方針としています。 Mecabの由来は、開発者の好物である和布蕪(めかぶ)から名づけられました。

自然言語処理

自然言語処理は、日常的に使用される自然言語をコンピューターに処理させる技術やソフトウェアの総称です。

Q&A

解決済

1回答

869閲覧

特徴ベクトル化の過程のアルゴリズムがわかりません

ryuki

総合スコア8

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Mecab

Mecabは、オープンソースの形態素解析エンジンです。 言語、辞書、コーパスに依存しない汎用的な設計を基本方針としています。 Mecabの由来は、開発者の好物である和布蕪(めかぶ)から名づけられました。

自然言語処理

自然言語処理は、日常的に使用される自然言語をコンピューターに処理させる技術やソフトウェアの総称です。

0グッド

0クリップ

投稿2022/04/12 14:11

編集2022/04/13 22:00

全体コード

tokenizer.py

import MeCab tagger = MeCab.Tagger() def tokenize(text): node = tagger.parseToNode(text) tokens = [] while node: if node.surface != '': tokens.append(node.surface) node = node.next return tokens

bow.py

from tokenizer import tokenize def calc_bow(tokenized_texts):#bag of words関数 #辞書生成のループ vocabulary = {} for tokenized_text in tokenized_texts: for token in tokenized_text: if token not in vocabulary: vocabulary[token] = len(vocabulary)#(1) n_vocab = len(vocabulary) #単語の出現回数をカウントするためのループ bow = [[0] * n_vocab for i in range(len(tokenized_texts))] #(2) for i,tokenized_text in enumerate(tokenized_texts): for token in tokenized_text: index = vocabulary[token] bow[i][index] += 1 return vocabulary,bow texts = [ '私は私のことが好きなあなたが好きです', '私はラーメンが好きです', '富士山は日本一高い山です', ] tokenized_texts = [tokenize(text) for text in texts]#textsから各々の文章をわかち書き vocabulary,bow = calc_bow(tokenized_texts)

わからないこと(コードに番号振っています。)

(1)「token:vocablaryに登録した順」、となる辞書として代入していく意味でしょうか?
(2)コード全体の意味がわかりません。また [0] * n_vocabの意味が特に分かりません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

・このコードの短期的な目的は、下記です。
「文章をおのおの形態素に分け、各文章内での各形態素の出現回数をカウントする」


試しに、質問のコードの最後に

py

1print(vocabulary) 2print(bow)

という2行を追加して実行してみましょう。

すると、下記のような結果が出力されます。

txt

1{'私': 0, 'は': 1, 'の': 2, 'こと': 3, 'が': 4, '好き': 5, 'な': 6, 'あなた': 7, 'です': 8, 2'ラーメン': 9, '富士山': 10, '日本一': 11, '高い': 12, '山': 13} 3 4 [[2, 1, 1, 1, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0], 5[1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0], 6[0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1]]

1つ目(vocabulary)は、「形態素(token)がキー、連番が値」となっている辞書です。
2つ目(bow)は、長さ14の配列が3つ格納されています。
実は2つ目(bow)は、1つ目の token の、3つの文章における出現回数を表しています。

整理すると下記のような表になります。

token(キー)こと好きあなたですラーメン富士山日本一高い
インデックス(値)012345678910111213
文章121112211100000
文章211001100110000
文章301000000101111

・2行目は、各 token に対して、(数字がかぶらないように)割り振った一意のID番号のようなものです。
・3行目以降は、各文章における各 token の出現回数を表しています。


質問文のコードは、言ってしまえば結局上のような表を作る処理に過ぎません。

ではなぜこのように整理するか=長期的な目的はなにかというと、
・各文章を特徴づけている単語を抽出し、文書の類似度を比較可能にする
といったようなことです。(TF-IDF等を利用)

この目的のため、文書の集合/文書/形態素を、一定のルールでもって、計算しやすいように数値化し整理している、ということです(ベクトル化)


上の表とコードをよく見比べると、コードの意味が分かってくると思います。

(1)「token:vocablaryに登録した順」、となる辞書として代入していく意味でしょうか?

コードのこの部分ですね

if token not in vocabulary: vocabulary[token] = len(vocabulary)#(1)

見てお分かりの通り、token(形態素)をキーとする辞書として vocabulary を作成しています。

新しい token が見つかる度、その時点の vocablary の長さを、token の値として設定しています。
キーが追加されるたび、辞書 vocablary の長さは1ずつ増えていきます。
つまりこの部分は、tokenに一意のindexを付番しているということです。

(2)コード全体の意味がわかりません。また [0] * n_vocabの意味が特に分かりません。

#2の部分は、内包表記を使用した、2次元配列の初期化処理です。
参照:
https://qiita.com/oyoshi0022/items/7475951f465d20ad4970#%E8%A7%A3%E6%B1%BA%E6%B3%95

#単語の出現回数をカウントするためのループ bow = [[0] * n_vocab for i in range(len(tokenized_texts))] #(2) for i,tokenized_text in enumerate(tokenized_texts): for token in tokenized_text: index = vocabulary[token] bow[i][index] += 1

[[0] * n_vocab for i in range(len(tokenized_texts))]
を分解すると
・len(tokenized_texts)) は 文章の数=文章は全部で3つなので「3」
・n_vocab は、前述のコードを見ると、tokenを格納完了後の辞書vocabulary内のキー(token)の数=「14個」

これによって
bow = [[0] * 14 for i in range(3)]
となります。
これにより、14列×3行の2次元配列が作られます。(冒頭の[0]は初期化する値ですので、中身がゼロで初期化された2次元配列になっています)

作成直後のbow(初期化された2次元配列):

インデックス012345678910111213
[0]00000000000000
[1]00000000000000
[2]00000000000000

 
あとは、直後の

for i,tokenized_text in enumerate(tokenized_texts): for token in tokenized_text: index = vocabulary[token] bow[i][index] += 1

の部分で、各文章ごとに token の出現回数をカウントし、2次元配列に格納しています。

処理後のbow:

インデックス012345678910111213
[0]21112211100000
[1]11001100110000
[2]01000000101111

※インデックスとtokenの関係は、辞書vocabularyによって保持されています。

投稿2022/04/12 15:21

編集2022/04/13 13:00
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ryuki

2022/04/13 12:52

詳細な説明ありがとうございます!よく見直します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問