Skip to content

8. テキストデータ処理 (1)

第 8 回では、テキストデータ処理の基本について学びます。

8.1 テキストデータ処理とは

テキストデータ処理は、情報をテキスト形式で保存、編集、分析するための手法であり、多くの分野で頻繁に利用されています。テキストデータ処理には、以下のような操作が含まれます。

  • テキストの基本操作: 文字列の結合や分割、抽出など
  • テキストのクリーニング: 不要なデータやノイズ除去、欠損データ補完など
  • テキストの変換: 文字コードの変換や正規化
  • テキストの分析: テキスト内容の理解やパターン・傾向の抽出

8.2 基本的な文字列操作

Python には、文字列を操作するための便利な関数やメソッドがさまざま用意されています。以下ではその代表例を紹介します。

8.2.1 文字列の結合

文字列の結合を行うには、join メソッドを用います。[区切り文字].join([文字列のリスト]) のようにすることで、文字列のリスト(または他のイテラブル)を区切り文字で連結し、一つの文字列にすることができます。

words = ["Python", "は", "強力です"]
print("".join(words))
print(" ".join(words))
Output
Pythonは強力です
Python は 強力です

8.2.2 文字列の分割

文字列を分割したい場合は、split メソッドを用います。[文字列].split([区切り文字]) のようにすることで、文字列を指定した区切り文字で分割し、リストにすることができます。区切り文字を省略した場合は、スペースで分割されます。

text = "Python is simple, powerful, and widely used."
print(text.split(","))
print(text.split())
Output
['Python is simple', ' powerful', ' and widely used.']
['Python', 'is', 'simple,', 'powerful,', 'and', 'widely', 'used.']

8.2.3 文字列の置換

特定の文字列を別の文字列に置換したり、除去したりしたい場合は、replace メソッドを用います。[文字列].replace([置換前の文字列], [置換後の文字列]) のようにすることで、文字列の置換を行うことができます。

text = "Pythonは楽しいです。"
print(text.replace("Python", "プログラミング"))
Output
プログラミングは楽しいです。

replace による文字列の除去

置換後の文字列を空文字列 ("") にすることで、指定した文字列を取り除くことができます。

8.2.4 テキストデータの読み込み

テキストファイル (.txt) を開いてデータを読み込むには、with openread() メソッドを用います。例えば、Rapunzel.txt というファイルを読み込んで text という変数に格納するには、以下のようにします。

with open("Rapunzel.txt", "r") as f:
    text = f.read()
print(text[:100])
Output
There once lived a man and his wife, who had long wished for a child, but in vain. Now there was at

ここで "r" は、ファイルを「読み取り専用」モード (read mode) で開こうとしていることを意味します。その他にも「書き込み」「追記」「新規作成」などいくつかのモードが存在しますが、本講義では扱いませんので、興味のある方は各自で調べるようにしてください。

CHIKUWA Editor におけるファイルの書き込みについて

CHIKUWA Editor では、セキュリティの都合上、Python プログラムからファイルの作成や書き込みを行うことができないようになっています。

8.3 形態素解析

形態素解析とは、文を意味を持つ最小単位の単語(形態素)に分割する操作のことです。日本語の文章に対して自然言語処理を適用する場合、文章を単語単位に分割する分かち書き(形態素解析)が必要になります。形態素解析器には、MeCab や Juman++、Janome などがよく使用されます。

例えば、「吾輩は猫である」という文は、「吾輩」「は」「猫」「で」「ある」に分割されます。

8.3.1 MeCab と辞書データのインストール

形態素解析を実際に実行するには、形態素解析器と辞書データをインストールする必要があります。例えば、Google Colaboratory などで以下のコマンドを実行することで、高性能な形態素解析器である MeCab と、軽量の辞書データ unidic-lite をインストールすることができます。

!pip install mecab-python3 unidic-lite

インストール後、以下のようにインポートすることで、MeCab を使えるようになります。

import MeCab

CHIKUWA Editor における形態素解析器と辞書データについて

CHIKUWA Editor には、形態素解析器として「MeCab」が、日本語辞書として「mecab-ipadic-utf8」が標準でインストールされており、これらを用いて形態素解析の練習ができるようになっています。

8.3.2 MeCab による形態素解析の基礎

MeCab を用いた形態素解析の基本的な流れを見ていきましょう。

まずは、MeCab の解析器(Tagger)のインスタンスを作成します。日本語の文章を解析してくれる、実際の道具を準備する(工具箱から工具を取り出す)イメージです。

tagger = MeCab.Tagger()

そして、Tagger のインスタンスから parse() メソッドを呼び出すことで、形態素解析が実行されます。

result = tagger.parse("テキスト")

例えば、「すもももももももものうち」という文を MeCab で形態素解析する一連の流れは以下のようになります。

MeCab による形態素解析
import MeCab

# MeCab のインスタンス生成
tagger = MeCab.Tagger()

# 解析するテキスト
text = "すもももももももものうち"

# 形態素解析を実行し、結果を表示
result = tagger.parse(text)
print(result)
Output
すもも 名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も   助詞,係助詞,*,*,*,*,も,モ,モ
もも  名詞,一般,*,*,*,*,もも,モモ,モモ
も   助詞,係助詞,*,*,*,*,も,モ,モ
もも  名詞,一般,*,*,*,*,もも,モモ,モモ
の   助詞,連体化,*,*,*,*,の,ノ,ノ
うち  名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
EOS

8.3.3 形態素解析のオプション

MeCab では、MeCab.Tagger() にオプションの文字列を渡すことで、形態素解析の出力結果を細かく制御することができます。

分かち書き (-Owakati)

-Owakati を指定することで、単語ごとにスペースで区切った単純な分かち書きの結果を出力することができます。

tagger = MeCab.Tagger("-Owakati")
result = tagger.parse("すもももももももものうち")
print(result)
Output
すもも も もも も もも の うち

単語の読み (-Oyomi)

-Oyomi を指定することで、単語の読み(カタカナ)だけを出力することができます。

tagger = MeCab.Tagger("-Oyomi")
result = tagger.parse("すもももももももものうち")
print(result)
Output
スモモモモモモモモノウチ

その他の形態素解析オプション

その他にも、詳細な内部データをすべて出力する -Odump や、読みとシンプルな品詞を含む -Ochasen (別の形態素解析器である ChaSen 互換の出力フォーマット)などのオプションを指定することができます。

8.3.4 特定の品詞の抽出

形態素解析ができたら、特定の品詞を抽出してみましょう。文書の解析でよく利用される重要な品詞は、「名詞」「形容詞」「動詞」です。

まずは、parseToNode() メソッドを用いて、形態素解析の結果をノードに変換します。ノードとは、数珠つなぎの要素のようなイメージで、nextprev によって隣り合うノードを順番に見て回ることができる仕組みを指します。

node = tagger.parseToNode(text)

次に、while 文を使用し、ノード化された形態素解析の結果を一つ一つ参照していきます。このとき、ノードの surface 属性には単語が、feature 属性には単語の特徴に関する情報が入っています。形態素解析をした後、単語のリストと品詞のリストを作成するプログラムは以下のようになります。

単語と品詞のリストを作成
import MeCab

# MeCab のインスタンス生成
tagger = MeCab.Tagger()

# 解析するテキスト
text = "すもももももももものうち"

# 形態素解析を実行し、ノードに変換
node = tagger.parseToNode(text)

# 単語と品詞を格納するためのリスト
words = []
types = []

# ノードがなくなるまで解析結果を表示
while node:
    if node.surface: # surface 属性(単語)が存在する場合
        words.append(node.surface)
        types.append(node.feature.split(",")[0])
    node = node.next # 次のノードに移動

print("単語:", words)
print("品詞:", types)
Output
単語: ['すもも', 'も', 'もも', 'も', 'もも', 'の', 'うち']
品詞: ['名詞', '助詞', '名詞', '助詞', '名詞', '助詞', '名詞']

node.feature の中には、"名詞,一般,*,*,*,*,すもも,スモモ,スモモ" のように、複数の情報がまとめて入っています。ここから "名詞" という情報だけ抽出したい場合には、上のコードで示しているように、split メソッドでテキストをカンマで区切り、生成されたリストの先頭を参照すれば良いというわけです。

feature の構造について

本講義で利用することを想定している IPA 辞書を利用する場合、feature は以下の 9 つの要素で構成されます。

品詞, 品詞細分類1, 品詞細分類2, 品詞細分類3, 活用形, 活用型, 原形, 読み, 発音

本項のサンプルコードでは surface を用いてテキスト中の単語そのものを取得していますが、実際の分析においては語の活用の影響を排除するため、「原形」を使うことが望ましいケースが多いことを覚えておいてください。なお、相当する要素が存在しない場合には * が入ります。

品詞が「名詞」の単語のみを抽出してリスト化するには、以下のようにループの中で if 文を使用します。

名詞のみを抽出
import MeCab

# MeCab のインスタンス生成
tagger = MeCab.Tagger()

# 解析するテキスト
text = "すもももももももものうち"

# 形態素解析を実行し、ノードに変換
node = tagger.parseToNode(text)

# 単語を格納するためのリスト
nouns = []

# ノードがなくなるまで解析結果を表示
while node:
    pos = node.feature.split(",")[0] # 品詞を取得
    if pos == "名詞": # 品詞が「名詞」であった場合
        nouns.append(node.surface)
    node = node.next # 次のノードに移動

print("名詞:", nouns)
Output
名詞: ['すもも', 'もも', 'もも', 'うち']

8.4 WordCloud

形態素解析ができるようになったら、WordCloud を使用して文章の可視化をしてみましょう。WordCloud では、文章の中で出現頻度の高い単語を大きく、あまり出ない単語を小さく表示します。

8.4.1 WordCloud のインポート

WordCloud を使用するには、wordcloud ライブラリの中から、WordCloud クラスをインポートします。

from wordcloud import WordCloud

8.4.2 WordCloud の生成

WordCloud を生成するには、WordCloud クラスの generate() メソッドに対し、スペースで区切られたテキストを渡します。また、WordCloud のインスタンスを生成する際は、width(画像の幅)や height(画像の高さ)、background_color(背景色)、random_state(乱数のシード値)などを指定することができます(詳細はこちら)。

以下は、英語のテキストに対して WordCloud を生成する基本的なコードの例です。

from wordcloud import WordCloud
import matplotlib.pyplot as plt

# テキスト(「Rapunzel」の冒頭)
text = "There once lived a man and his wife, who had long wished for a child, but in vain. Now there was at the back of their house a little window which overlooked a beautiful garden full of the finest vegetables and flowers; but there was a high wall all round it, and no one ventured into it, for it belonged to a witch of great might, and of whom all the world was afraid."

# WordCloud の生成
wordcloud = WordCloud(
    width=600,
    height=400,
    background_color="white",
    random_state=42
).generate(text)

# WordCloud の表示
plt.imshow(wordcloud)
plt.axis("off")
plt.tight_layout()
plt.show()

WordCloud の例(英語)

乱数のシード値 (randam_state) について

WordCloud ではデフォルトでランダムに単語の配置を行うため、実行するたびに結果が変わってしまいます。これを防ぎ、結果の再現性を担保するためには、上記コードのように乱数のシード値 (randam_state) を設定します。

英文のストップワードについて

英語のテキストに対する WordCloud の結果を見て気が付いた人もいるかもしれませんが、出現頻度が高いはずの a, the, of などの単語は一切表示されていません。これは、WordCloud では、あまりにも一般的な英単語がストップワードとして、デフォルトで除外されるようになっているためです。どのような英単語がストップワードとして登録されているかは、以下のコードで確認することができます。

from wordcloud import STOPWORDS
print(STOPWORDS)

WordCloud をストップワードなしで生成したい場合には、インスタンス生成のパラメータで stopwords=set() を指定します。逆にストップワードを追加したい場合には、union メソッドを用いて stopwords=STOPWORDS.union({"man", "wife"}) のように書きます。

8.4.3 日本語文章の WordCloud

英語の場合は元から単語がスペースで区切られているため、そのまま WordCloud を生成することができましたが、日本語の場合はそうはいきません。まずは形態素解析を行い、単語をスペースで区切った形に変換する必要があります。以下は、MeCab を用いて形態素解析(分かち書き)を行い、日本語の WordCloud を生成するコードの例です。

CHIKUWA Editor を使用している場合、日本語のフォントパスは以下のように /usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc を指定するようにしてください。

import MeCab
from wordcloud import WordCloud
import matplotlib.pyplot as plt

# MeCab のインスタンス生成(分かち書き)
tagger = MeCab.Tagger("-Owakati")

# 解析するテキスト(「吾輩は猫である」の冒頭)
text = "吾輩は猫である。名前はまだ無い。どこで生れたかとんと見当がつかぬ。何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。吾輩はここで始めて人間というものを見た。"

# 形態素解析を実行
words = tagger.parse(text)

# 日本語フォントのパス
font_path = "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc"

# WordCloud の生成
wordcloud = WordCloud(
    font_path=font_path,
    width=600,
    height=400,
    background_color="white",
    random_state=42
).generate(words)

# WordCloud の表示
plt.imshow(wordcloud)
plt.axis("off")
plt.tight_layout()
plt.show()

WordCloud の例(日本語)

日本語の WordCloud を作成することができました。しかし、「は」や「で」など、それ自体は意味を持たない「助詞」が図の大半を占めており、有意義な WordCloud になっているとは言えません。より有意義な WordCloud にするためにはどのようにすればよいか、考えてみましょう。

演習

演習 8-1

英語のテキストを対象とした WordCloud を作成してください。ただし、テキストに含まれる1つ以上の単語を replace メソッドで除去してください。

演習 8-2

日本語のテキストを対象とした WordCloud を作成してください。ただし、「名詞」「形容詞」「動詞」の単語のみを抽出して使用してください。