Bag of Words(BoW)は自然言語処理(NLP)における技術です。これは、文法的構造や語順を考慮することなく、テキストデータを機械が読み取れる形式、具体的には数値に変換するために広く使用されています。BoWの理解はテキストデータを扱うすべての人にとって重要です。PythonにはBag of Wordsを効果的に実装するための複数のツールとライブラリが提供されています。
このチュートリアルでは、BoWに詳しく入り込み、その概念を紹介し、その用法をカバーし、Pythonでの詳細な実装を説明します。このチュートリアルの終わりには、実際の問題に対してBag of Wordsモデルを適用できるようになるでしょう。NLPが初めての人は、私たちのPythonでの自然言語処理スキルトラックをチェックして更多信息を学んでください。
Bag of Wordsとは何か?
Bag of Wordsは、テキストデータから特徴を抽出する技術で、テキスト分類や感情分析などの機械学習タスクに使用されます。これは、機械学習アルゴリズムがテキストデータを処理できないため、重要です。テキストを数値に変換するプロセスは、特徴抽出または特徴符号化と呼ばれます。
Bag of Wordsは、ドキュメント内の単語の発生に基づいています。プロセスは、テキストの語彙を見つけてその発生を測定することから始まります。順序や単語の構造は考慮されず、発生だけが考慮されるため、バッグと呼ばれます。
Bag of Wordsモデルは、周囲の単語を使ってターゲット単語を予測することで、単語間の意味関係を捉えるデンシな単語エンコーディングを学習するContinuous Bag of Words Model(CBOW)とは異なります。CBOWは大規模なコーパスでの学習を必要とし、単語の文脈が重要な複雑なNLPアプリケーションに価値のある低次元のベクトルを生成します。
アスペクト |
BOW |
CBOW |
目的 |
各単語の頻度を数える |
文脈に基づいて対象単語を予測する |
出力タイプ |
高次元で.sparseなベクトル |
低次元で dens なエンコーディング |
文脈を考慮する |
いいえ(単語の順序を無視する) |
はい(周囲の単語を使用する) |
表現 |
.sparseな頻度ベクトル |
意味を捉える dens なベクトル |
複雑さ |
低(トレーニング不要) |
高(大量のコーパスでのトレーニングが必要) |
典型的なアプリケーション |
テキスト分類、感情分析 |
単語ベクトル、文脈を必要とするNLPタスク |
なぜBag of Wordsを使うのか?
Bag of Wordsは多くのNLPタスクに役立ち、その使用理由には以下のものがあります:
- 特徴抽出:非構造化のテキストデータを構造化データに変換し、さまざまな機械学習アルゴリズムの入力として使用できます。
- シンプリシティーと効率性:BoWは計算がシンプルで実装しやすく、小規模から中規模のテキストコーパスに適しています。
- ドキュメントの類似性:コサイン類似度などの技術を使用して、テキストドキュメント間の類似性を計算するために使用できます。
- テキスト分類:ナイーブベイズなどの技術と組み合わせると、BoWはスパム分類などのテキスト分類タスクに有効であり、感情分析。
しかし、意味論、語の構造、語の順序を考慮しないなどの欠点もあります。
PythonでBag of Wordsを実装する手順
ボキャブラリモデルを作成するために、コーパス内のすべての単語を取り出し、それぞれの単語ごとに列を作成します。行は文を表しています。特定の単語が文中に存在する場合、1で表され、存在しない場合は0で表されます。各列の単語は一つの特徴を表しています。
最終的に、スパースマトリックスを得ます。スパースマトリックスとは、多くの零を含むマトリックスです。
データ前処理
Pythonでボキャブラリモデルを作成するためには、いくつかの前処理ステップを踏む必要があります。これらのステップにはトークン化とストップワードの除去が含まれます。
トークン化は、テキストを小さなユニット、通常は単語に分解するプロセスです。NLTKを使用してトークン化を実行できます。
ストップワードは、「the」、「that」、「a」と 같い英語の一般的な単語で、文のポラリティに寄与しません。
import nltk from nltk.corpus import stopwords from nltk.tokenize import word_tokenize # スtopwordsとトーケナイザをまだダウンロードしていない場合はこちら nltk.download("punkt") nltk.download("stopwords") # 例文 sentence = "This is an example showing how to remove stop words from a sentence." # 文を単語にトーケナイズする words = word_tokenize(sentence) # 英語のストップワードのリストを取得する stop_words = set(stopwords.words("english")) # 文からストップワードを削除する filtered_sentence = [word for word in words if word.lower() not in stop_words] # 単語を再び文に結合する filtered_sentence = " ".join(filtered_sentence) print(filtered_sentence)
出力:
example showing remove stop words sentence.
語彙の作成
語彙とは、テキストのコーパスに見つかるユニークな単語の集合です。語彙の構築は、コーパスからすべてのユニークな単語を集め、その出現回数を数えることに関わります。この語彙は、言語モデル、単語エンコーディング、テキスト分類などのさまざまなNLPタスクに役立ちます。
以下のコードは、コーパス内の単語のシンプルな頻度分布を作成し、語彙の構築やテキストの内容理解などの基本的なNLPタスクに役立ちます:
- The コーパス 変数にはいくつかの例文が格納されています。実際のアプリケーションでは、これはより大きな、より多様なテキストデータを含むことになります。
- vocab =
defaultdict(int)
は単語の頻度を数えるのを簡素化し、新しい単語は自動的に0で初期化され、チェックなしで直接インクリメントすることができます。 - 各文は小文字に変換し、正規表現を使用して単語を抽出することでトークン化されます。
\b\w+\b
は、アルファニュメリカラ文字のみで構成される単語を識別し、句読点や他の記号は無視します。 - 各単語のカウントは、vocab辞書に更新されます。
- 語彙は頻度の降順で並べ替えられ、最も一般的な単語が上に表示されるようにされ、参照のため表示されます。
import re 正規表現モジュールをインポートしてテキスト処理を助ける from collections import ( defaultdict, ) defaultdictをインポートして単語頻度のカウントを簡単にする テキストのサンプルコーパス - 分析するための文章の小さなデータセット corpus = [ "Tokenization is the process of breaking text into words.", "Vocabulary is the collection of unique words.", "The process of tokenizing is essential in NLP.", ] defaultdictを整数値で初期化して単語の頻度を保存する defaultdict(int)は新しいキーのデフォルト整数値を0に初期化する vocab = defaultdict(int) コーパスの各文章をトークン化して正規化するループ for sentence in corpus: 文章を小文字に変換してカウントの一致性を確保する(例:'Tokenization'と'tokenization'は同じ単語として扱う) 正規表現を使ってアルファニュメリカラ文字のみで構成された単語を見つける words = re.findall(r"\b\w+\b", sentence.lower()) 見つかった各単語の辞書内のカウントをインクリメントする for word in words: vocab[word] += 1 defaultdictのvocabを通常の辞書に変換して簡単に操作・ソートする 辞書を単語の頻度で降順にソートして新しい辞書に変換する sorted_vocab = dict(sorted(vocab.items(), key=lambda x: x[1], reverse=True)) ソートされた語彙と各単語の頻度カウントを表示する print("Vocabulary with Frequencies:", sorted_vocab)
出力:
Vocabulary with Frequencies: {'is': 3, 'the': 3, 'of': 3, 'process': 2, 'words': 2, 'tokenization': 1, 'breaking': 1, 'text': 1, 'into': 1, 'vocabulary': 1, 'collection': 1, 'unique': 1, 'tokenizing': 1, 'essential': 1, 'in': 1, 'nlp': 1}
語彙を手動で構築することは時間がかかることが多く、特に大きなコーパスの場合更是そうです。Scikit-learnのCountVectorizerはこのプロセスを自動化し、後で見るようにより柔軟なテキスト処理を可能にします。
PythonでのBag of Words実装(からだし)
まず、Bag of Wordsの基本的な実装から始めます。Pythonでの実装です。これにより、その背後の構成要素と動作機構を理解する手助け becomes.
手動実装
ステップ1: テキストデータの前処理
まず、トークン化、小文字化、句読点の除去を含むシンプルなテキスト処理関数を定義します。
from collections import defaultdict import string # サンプルテキストデータ: 文章 corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # テキスト前処理の関数 def preprocess(text): # 小文字化 text = text.lower() # 句読点の除去 text = text.translate(str.maketrans("", "", string.punctuation)) # トークン化: テキストを単語に分割 tokens = text.split() return tokens # サンプルコーパスに前処理を適用 processed_corpus = [preprocess(sentence) for sentence in corpus] print(processed_corpus)
出力:
[['python', 'is', 'amazing', 'and', 'fun'], ['python', 'is', 'not', 'just', 'fun', 'but', 'also', 'powerful'], ['learning', 'python', 'is', 'fun']]
ステップ2: 単語リストの構築
次に、すべてのドキュメントをスキャンして、ユニークな単語の完全なリストを作成します。これが私たちの語彙です。
語彙の空集合を初期化する vocabulary = set() 語彙を構築する for sentence in processed_corpus: vocabulary.update(sentence) ソートされたリストに変換する vocabulary = sorted(list(vocabulary)) print("Vocabulary:", vocabulary)
ステップ3: 単語の頻度を計算しベクトル化する
今、処理されたコーパスの各ドキュメントにおける語彙の各単語の頻度を計算する。
def create_bow_vector(sentence, vocab): vector = [0] * len(vocab) 零ベクトルを初期化する for word in sentence: if word in vocab: idx = vocab.index(word) 単語の語彙内のインデックスを見つける vector[idx] += 1 そのインデックスのカウントをインクリメントする return vector
この時点で、コーパスの各ドキュメントに対するBag of Words表現を作成したことになる。
処理されたコーパスの各文に対してBoWベクトルを作成する bow_vectors = [create_bow_vector(sentence, vocabulary) for sentence in processed_corpus] print("Bag of Words Vectors:") for vector in bow_vectors: print(vector)
出力:
Bag of Words Vectors: [0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1] [1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1] [0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1]
Scikit-learnのCountVectorizerを使用する
手動でBag of Wordsモデルを構築することは学習には良いですが、実運用では効率的で最適化されたライブラリ、例えばScikit-learnを使用するべきです。
私たちがトークン化に使用するPython関数はCountVectorizerで、これはsklearn.feature_extraction.text
からインポートされます。CountVectorizer
の特徴の1つはmax_features
で、これはボー・オブ・ワーズモデルに使用したい最大の単語数を表します。この場合、Noneを使用しており、すべての特徴を使用することを意味します。
CountVectorizer
のインスタンスを作成した後、.fit_transform(
)メソッドを使用してボー・オブ・ワーズモデルを作成します。次に、.toarray()
を使用してボー・オブ・ワーズモデルを機械学習モデルに渡せるようnumpy配列に変換します。
一旦フィッティングされると、CountVectorizerは特徴インデックスの辞書を構築します。語彙内の単語のインデックス値は、全体のトレーニングコーパスにおけるその頻度にリンクされています。
from sklearn.feature_extraction.text import CountVectorizer # 元のコーパス corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # CountVectorizerオブジェクトを作成する vectorizer = CountVectorizer() # コーパスをフィットおよび変換する X = vectorizer.fit_transform(corpus) # 生成された語彙を表示する print("Vocabulary:", vectorizer.get_feature_names_out()) # Bag-of-Wordsマトリックスを表示する print("BoW Representation:") print(X.toarray())
出力:
markdownVocabulary: ['also' 'amazing' 'and' 'but' 'fun' 'is' 'just' 'learning' 'not' 'powerful' 'python'] BoW Representation: [[0 1 1 0 1 1 0 0 0 0 1] [1 0 0 1 1 1 1 0 1 1 1] [0 0 0 0 1 1 0 1 0 0 1]]
例: Bag of Wordsの適用
さて、3つの映画レビューで構成された小さなテキストコーパスにBoWモデルを適用して、全体のプロセスを説明しましょう。
Scikit-learnのCountVectorizerを使用して、この小さなテキストコーパスにBoWモデルを適用します。
以下に、私たちが取るステップを挙げます:
CountVectorizer
はテキストをトークン化し、句読点を削除し、単語を小文字に自動的にします。.fit_transform(コーパス)
は、コーパスをドキュメント項目マトリックスに変換します。各行はドキュメントを表し、各列は語彙からの単語を表します。X_dense
は、各ドキュメントにおける各単語の頻度を表す dense マトリックスです。
from sklearn.feature_extraction.text import CountVectorizer # 映画レビューのサンプルコーパス corpus = [ "I loved the movie, it was fantastic!", "The movie was okay, but not great.", "I hated the movie, it was terrible.", ] # CountVectorizerを初期化する vectorizer = CountVectorizer() # コーパスをドキュメント項目マトリックスにフィットおよび変換する X = vectorizer.fit_transform(corpus) # ドキュメント項目マトリックスをdense形式に変換する(可視化のためにオプション) X_dense = X.toarray() # 語彙(単語からインデックス位置へのマッピング)を取得する vocab = vectorizer.get_feature_names_out() # 語彙とドキュメント項目マトリックスを印刷する print("Vocabulary:", vocab) print("Document-Term Matrix:\n", X_dense)
出力:
Vocabulary: ['but' 'fantastic' 'great' 'hated' 'it' 'loved' 'movie' 'not' 'okay' 'terrible' 'the' 'was'] Document-Term Matrix: [[0 1 0 0 1 1 1 0 0 0 1 1] 初回レビュー: 「映画が大好きでした、素晴らしかった!」 [1 0 1 0 1 0 1 1 1 0 1 1] 二回目のレビュー: 「映画はまずまずだけど、素晴らしいわけじゃない。」 [0 0 0 1 1 0 1 0 0 1 1 1]] 三回目のレビュー: 「映画が嫌いでした、ひどかった。」
以下のように上記のアウトプットを解釈することができます:
- コーパス内のそれぞれのユニークな単語にインデックスが割り当てられ、単語はアルファベット順に並べられています。例えば、「but」はインデックス0、「fantastic」はインデックス1、「movie」はインデックス6などです。
- ドキュメント行列の各行は映画レビューを表し、各列は語彙の単語に対応しています。行列の値はその特定のドキュメントにおける各単語の頻度を表しています。
- 初回レビュー: [0 1 0 0 1 1 1 0 0 0 1 1]は以下を示しています:
- 単語「fantastic」が1回出現(インデックス1の1)、
- 単語「loved」が1回出現(インデックス5の1)、
- 単語「movie」が1回出現(インデックス6の1)、
- 単語「it」が1回出現(インデックス4の1)、
- などです。
BoWベクトルは以下のように解釈できます:
- 各ドキュメントは単語の数を表す数値のベクトルです。ベクトルの次元は語彙のサイズに等しいです。この場合、語彙には12単語ありますので、各レビューは12次元のベクトルに変換されます。
- 各行のほとんどの単語がゼロなのは、すべてのドキュメントが語彙のすべての単語を含んでいないからです。したがって、BoWモデルはしばしばスパースで、多くのゼロを含んでいます。
Bag of Wordsの利点と限界
まずBag of Wordsモデルの利点と限界について見ていきましょう。
利点
- 実装しやすく解釈が簡単:Bag of Wordsモデルは最もシンプルなテキスト表現技法の一つで、初心者にとって最適です。そのシンプルさにより、複雑な前処理や特別なモデルが必要なく、迅速に実装できます。
- テキスト分類タスクに簡単に使用可能:Bag of Wordsは基本的なタスク nhưテキスト分類、感情分析、スパム検出に適しています。これらのタスクは高度な言語モデルを必要としないことが多いので、BOW表現は十分で効率的です。
限界
- 語彙のサイズが表現のスパarsityに影響を与える:語彙が大きいほど、表現はスパースで高次元になります。このスパarsityはモデルが効果的に学習するのを難しくし、過度な計算コストを避けるために語彙のサイズを慎重に調整する必要があります。
- 計算コストが高くなるスパースな行列を生成する:各ドキュメントは、潜在的に大きな語彙の各単語の頻度で表現されるため、結果として得られる行列はしばしばほとんどがゼロであり、機械学習パイプライン内での保存や処理が非効率的になります。スパースな行列は多大なメモリを消費し、特に大規模データセットの場合、効率的な保存と計算には特別なツールやライブラリが必要です。
- 意味と文脈を失う:BOWは単語の順序と文の構造を無視し、文法的な関係と意味が失われる結果となります。この制限により、文脈、ニュアンス、単語の順序が重要な翻訳や複雑な文の感情分析などのタスクには適していません。
以下の戦略を使用して、Bag of Wordsの語彙のサイズを縮小することができます:
- 大文字小文字を無視する。
- 句読点を削除する。
- ストップワードを削除する、つまり「the」や「a」などの一般的な単語。
- 全ての単語が適切にスペルされていることを確認する。
- 語幹処理技術を使用して単語を語根形に還元する。
次のステップ:Bag of Wordsを超えて
Bag of Wordsモデルの1つの制限は、全ての単語を平等に扱うことです。残念ながら、これは頻繁に現れる単語が不当に重要視される問題につながる可能性があります。
TF-IDF(用語頻度-逆文档頻度)はこの問題に対する解決策で、全てのドキュメントにわたる単語の頻度に基づいて単語の重みを調整します。
TF-IDF:Bag of Wordsの拡張
用語頻度(TF)は、ドキュメント内での用語の頻度を示します。逆文档頻度(IDF)は、複数のドキュメントにわたって頻繁に現れる単語の影響を減少させます。TF-IDFスコアは、この2つのメトリクスを乗算して計算されます。
200語のドキュメントがあり、その中で「love」という単語が5回出現すると仮定します。この場合、「love」のTFは(5 / 200)= 0.025です。100万のドキュメントがあり、そのうち「love」という単語が1000のドキュメントに出現する場合、逆ドキュメント頻度(IDF)はlog(1000000 / 1000) = 3と計算されます。TF-IDFの重みはこれらの値の積で、0.025 * 3 = 0.075です。
Scikit-learnでは、これをTfidfVectorizerクラスを使用して比較的簡単に計算できます。
from sklearn.feature_extraction.text import TfidfVectorizer # サンプルコーパス corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # Tf-idfベクタライザーを作成 tfidf_vectorizer = TfidfVectorizer() # コーパスに適合し変換 X_tfidf = tfidf_vectorizer.fit_transform(corpus) # ボキャブラリーを表示 print("Vocabulary:", tfidf_vectorizer.get_feature_names_out()) # TF-IDF行列を表示 print("TF-IDF Representation:") print(X_tfidf.toarray())
出力:
Vocabulary: ['also' 'amazing' 'and' 'but' 'fun' 'is' 'just' 'learning' 'not' 'powerful' 'python'] TF-IDF Representation: [[0. 0.57292883 0.57292883 0. 0.338381 0.338381 0. 0. 0. 0. 0.338381 ] [0.40667606 0. 0. 0.40667606 0.24018943 0.24018943 0.40667606 0. 0.40667606 0.40667606 0.24018943] [0. 0. 0. 0. 0.41285857 0.41285857 0. 0.69903033 0. 0. 0.41285857]]
上記で実装されたTF-IDF行列は、生の頻度の代わりに重み付きの測定値を提供します。
バッグオブワードモデルには限界がありますが、特に大きな複雑なデータセットにおいては、それでも多くのNLPアプリケーションにおいて必須の構成要素です。これを理解することで、単語埋め込みやトランスフォーマーのようなより高度なモデルを探求する際に助け becomes.
ここから、スパム検知、感情分析、ドキュメントクラスタリングなど、あなたのプロジェクトでBoWを試してみることができます。
バッグオブワードを超える改善を求める場合、Word2VecやGloVeのような方法、またはBERTのようなディープラーニングモデルを探ることもできます。
最後の考え
バッグオブワード技術は自然言語処理に使用される基本的な技術です。これは、構造のないテキストを機械学習アルゴリズムに使用できる数値的特徴量に変換する簡単で効果的な方法です。このチュートリアルでは以下をカバーしました:
- バッグオブワード(BoW)モデルとは?
- バッグオブワードモデルを機械学習モデル構築に使用する利点。
- Pythonでバッグオブワードモデルを実装する方法。
- バッグオブワードの利点と限界。
- バッグオブワードモデルの理論と動機。
- 従来のバッグオブワードアプローチを改善するTF-IDFの紹介。
自然言語処理に深く挖り込むために、私たちのPythonでの自然言語処理スキルトラックをチェックしてください。
Source:
https://www.datacamp.com/tutorial/python-bag-of-words-model