1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

梶井基次郎『檸檬』をMeCabで形態素解析:ワードクラウドの作成まで

1
Last updated at Posted at 2025-10-23

はじめに

形態素ってなに?

 形態素は元来言語学の用語で、意味を持つ最小の言語単位のことです[1]。単語も「意味を持つ最小単位」として紹介されることがあり、形態素は単語に似ています。しかし、一般的には形態素は単語以上に細かい単位です。
 例えば、文「私たちは山頂でおにぎりを食べました」における主語「私たち」は一つの単語と考えられます。しかし、単語「私たち」は「私」と「たち」というより細かい形態素に分解することもできます。つまり、単語は一つ以上の形態素から構成される言語の構成単位と言えます。
 言語学的な議論にはこれ以上深入りしません(と言うより私の力不足でできません)が、この記事の範囲では単語と形態素を明確に区別しなくてもあまり実際的な問題はないと思います。
 ちなみにLLMの世界では形態素のことをトークンと言います。

keiyoushi.png

 SNSかなにかでこのような画像を見たことがあるという方もいるのではないでしょうか。これはワードクラウドと呼ばれるもので文章中の形態素を取り出し、多いものを大きく表示することで、可視化したものです。本記事では最終的に梶井基次郎の『檸檬』でこのワードクラウドを作ります。

形態素解析の意味

 形態素解析とは自然言語で書かれた文や文章を形態素に分解し、そこから様々な特徴を抽出することを意味します。
 ITの世界、特に自然言語処理において形態素解析は重要な意味を持ちます。自然言語処理とは人が使う自然言語をコンピュータに処理させるというタスクです。形態素解析ができれば記述式の膨大なアンケートやSNSの投稿を定量的な方法で分析することができます。しかし、なぜ自然言語の分析において形態素解析が重要なのでしょうか。これは実は日本語特有の事情に由来しています。
 次の二つの文を例に考えてみましょう

これはペンです。

This is a pen.

 文としての難易度はあまり変わらないように感じますが、コンピュータにとっては大違いです。英語の文章ではすべての単語がスペース区切りという明確な規則によって分割されています。したがって、英語の場合Pythonで、

text = "This is a pen"
words = text.split()

のように書くだけで直ちにテキスト全体が格納された文字列textを単語のリストwordsに分割できます。ピリオドやカンマの処理もここに少しルールを加えるだけです。
 同じことを日本語の文章で行おうとすると、全ての単語、形態素がべっとり繋がっているので簡単にはいきません。私達が日本語の文章を自然と理解できるのは文法的な規則の知識だけでなく、ある程度の単語の知識があるからと言えるかもしれません。
 「なぜ人間が言語を理解できるのか」という問題は言語学における超難問なので「〜しれません」という、ちょっとぼかした表現にしました。しかし、日本語の文を機械的に形態素にするため単語の知識を使う、つまり辞書を使うというのは一つの良いアイデアに思えます。代名詞「これ」、助詞「は」、一般名詞「ペン」などという言葉を知っていれば例文をなんとか形態素に分割できそうです。
 実際にはより複雑な仕組みがあるのですが、MeCabをつかった形態素解析はまさに日本語の辞書を使って日本語の文章を自動的に形態素の配列に分割することから始まります。

実践

ライブラリのインストール

 ライブラリのインストールを行います。コマンドプロンプトで操作をしている方は最初の!は不要です。GoogleColabの方は下のように打ち込んで、MeCabをインストールしてください。

! pip install mecab-python3

 MeCabを使うためにはMeCabだけでなく、unidicも必要です。続けて以下のコマンドを実行してください。

! pip install unidic-lite

形態素に分割

ではまず短い文を形態素に分解することから始めましょう

私は、その男の写真を三葉、見たことがある。
——太宰治『人間失格』

これを形態素に分割するにはこのようにします。

import MeCab

mecab = MeCab.Tagger("-Owakati")
text = "私は、その男の写真を三葉、見たことがある。"
tokens = mecab.parse(text)
print(tokens)

出力はこのようになります。

私 は 、 その 男 の 写真 を 三 葉 、 見 た こと が ある 。 

形態素と形態素の間に半角スペースが入っています。もちろんsplit()を使って、

print(tokens.split())

とすれば、

['私', 'は', '、', 'その', '男', 'の', '写真', 'を', '三', '葉', '、', '見', 'た', 'こと', 'が', 'ある', '。']

のようにリストで受け取ることもできます。句読点も入っていまうので、これを除きたいという方はこの記事の後半で紹介しているテキスト処理の小技集をご参照ください。

形態素の品詞を見る

 形態素分析ライブラリはなにも単に文章を形態素に分割するだけではありません。品詞も示してくれるのです。

import MeCab

mecab = MeCab.Tagger()
text = "私は、その男の写真を三葉、見たことがある。"
tokens = mecab.parse(text)
print(tokens)

先ほどのコードと似ていますが、-Owakatiを指定しないとすべての情報を出力してくれます。

私	ワタクシ	ワタクシ	私-代名詞	代名詞			0
は	ワ	ハ	は	助詞-係助詞			
、			、	補助記号-読点			
その	ソノ	ソノ	其の	連体詞			0
男	オトコ	オトコ	男	名詞-普通名詞-一般			3
の	ノ	ノ	の	助詞-格助詞			
写真	シャシン	シャシン	写真	名詞-普通名詞-一般			0
を	オ	ヲ	を	助詞-格助詞			
三	サン	サン	三	名詞-数詞			0
葉	ヨー	ヨウ	葉	名詞-普通名詞-助数詞可能			1
、			、	補助記号-読点			
見	ミ	ミル	見る	動詞-非自立可能	上一段-マ行	連用形-一般	1
た	タ	タ	た	助動詞	助動詞-タ	連体形-一般	
こと	コト	コト	事	名詞-普通名詞-一般			2
が	ガ	ガ	が	助詞-格助詞			
ある	アル	アル	有る	動詞-非自立可能	五段-ラ行	終止形-一般	1
。			。	補助記号-句点			
EOS

ここにはその形態素の品詞、そして活用、原形などが入っています。

import MeCab

text = "私は、その男の写真を三葉、見たことがある。"

mecab = MeCab.Tagger()
node = mecab.parseToNode(text)

while node:
  print(node.feature)
  node = node.next

として、

BOS/EOS,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*
代名詞,*,*,*,*,*,ワタクシ,私-代名詞,私,ワタクシ,私,ワタクシ,和,*,*,*,*,ワタクシ,ワタクシ,ワタクシ,ワタクシ,*,*,0,*,*
助詞,係助詞,*,*,*,*,ハ,は,は,ワ,は,ワ,和,*,*,*,*,ハ,ハ,ハ,ハ,*,*,*,"動詞%F2@0,名詞%F1,形容詞%F2@-1",*
補助記号,読点,*,*,*,*,,、,、,,、,,記号,*,*,*,*,,,,,*,*,*,*,*
連体詞,*,*,*,*,*,ソノ,其の,その,ソノ,その,ソノ,和,*,*,*,*,ソノ,ソノ,ソノ,ソノ,*,*,0,*,*
名詞,普通名詞,一般,*,*,*,オトコ,男,男,オトコ,男,オトコ,和,*,*,*,*,オトコ,オトコ,オトコ,オトコ,*,*,3,C2,*
助詞,格助詞,*,*,*,*,ノ,の,の,ノ,の,ノ,和,*,*,*,*,ノ,ノ,ノ,ノ,*,*,*,名詞%F1,*
名詞,普通名詞,一般,*,*,*,シャシン,写真,写真,シャシン,写真,シャシン,漢,シ濁,基本形,*,*,シャシン,シャシン,シャシン,シャシン,*,*,0,C2,*
助詞,格助詞,*,*,*,*,ヲ,を,を,オ,を,オ,和,*,*,*,*,ヲ,ヲ,ヲ,ヲ,*,*,*,"動詞%F2@0,名詞%F1,形容詞%F2@-1",*
名詞,数詞,*,*,*,*,サン,三,三,サン,三,サン,漢,*,*,*,*,サン,サン,サン,サン,N3,*,0,C3,*
名詞,普通名詞,助数詞可能,*,*,*,ヨウ,葉,葉,ヨー,葉,ヨー,漢,*,*,*,*,ヨウ,ヨウ,ヨウ,ヨウ,*,B,1,C3,*
補助記号,読点,*,*,*,*,,、,、,,、,,記号,*,*,*,*,,,,,*,*,*,*,*
動詞,非自立可能,*,*,上一段-マ行,連用形-一般,ミル,見る,見,ミ,見る,ミル,和,*,*,*,*,ミ,ミル,ミ,ミル,*,*,1,C1,*
助動詞,*,*,*,助動詞-タ,連体形-一般,タ,た,た,タ,た,タ,和,*,*,*,*,タ,タ,タ,タ,*,*,*,"動詞%F2@1,形容詞%F4@-2",*
名詞,普通名詞,一般,*,*,*,コト,事,こと,コト,こと,コト,和,コ濁,基本形,*,*,コト,コト,コト,コト,*,B1WS2WB3WB6SjShS,2,C3,*
助詞,格助詞,*,*,*,*,ガ,が,が,ガ,が,ガ,和,*,*,*,*,ガ,ガ,ガ,ガ,*,*,*,"動詞%F2@0,名詞%F1",*
動詞,非自立可能,*,*,五段-ラ行,終止形-一般,アル,有る,ある,アル,ある,アル,和,*,*,*,*,アル,アル,アル,アル,*,*,1,C3,*
補助記号,句点,*,*,*,*,,。,。,,。,,記号,*,*,*,*,,,,,*,*,*,*,*
BOS/EOS,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*

と分析するとさらに便利です。
 これを応用してnode.featureをリスト化し、その先頭に格納された品詞の情報から形態素の分類もできます。そのためにはそれぞれの品詞のリスト作成し、

import MeCab

mecab = MeCab.Tagger()
node = mecab.parseToNode(text)

meishi_list = list()
doushi_list = list()
keiyoushi_list = list()

while node:
  if node.feature.split(",")[0] == "名詞":
    meishi_list.append(node.surface)
  elif node.feature.split(",")[0] == "動詞":
    doushi_list.append(node.feature.split(",")[7])# 動詞の原型を取る
  elif node.feature.split(",")[0] == "形容詞":
    keiyoushi_list.append(node.feature.split(",")[7])# 形容詞の原型を取る
  node = node.next

print(" 名詞: " + str(meishi_list))
print(" 動詞: " + str(doushi_list))
print("形容詞: " + str(keiyoushi_list))

と書きます。これにより、

 名詞: ['男', '写真', '三', '葉', 'こと']
 動詞: ['見る', '有る']
形容詞: []

と品詞ごとに分類し、さらには活用を原形にすることもできました。これはより長い文章の定量的な分析や膨大なテキストアンケートの集計において役に立ちます。
 品詞には名詞、動詞、形容詞の他に代名詞、助詞、連体詞、補助記号などがあります。しかし、それらの品詞は多くの場合単体で重要な意味を持たないのでここでは拾っていません。ただ、代名詞の量や補助記号の量は文体に影響されるので、文体を解析したいというモチベーションであれば拾ってみても面白いかもしれません。

梶井基次郎『檸檬』を形態素解析

 では、いよいよ梶井基次郎の『檸檬』の中で最も多く使われている名詞、動詞、形容詞は何でしょうか。

まずは、BeautifulSoupを使って青空文庫からスクレイピングを行います。

import requests
from bs4 import BeautifulSoup

# URLを指定
url = 'https://www.aozora.gr.jp/cards/000074/files/424_19826.html'

# ページを取得
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')

# <ruby>タグ内の<rt>を削除
for ruby in soup.find_all('ruby'):
    rt = ruby.find('rt')
    if rt:
        rt.decompose()

# テキストを抽出
text = soup.get_text()

# 改行コードを統一
text = text.replace('\r\n', '\n').replace('\r', '\n')

# ファイルに保存
with open('output.txt', 'w', encoding='utf-8') as f:
    f.write(text)
print("テキストがoutput.txtに保存されました。")

これでルビを取り除いたテキストをoutput.txtとして保存することができました。
 ここで、すべてのWebサイトがスクレイピングを許可しているわけではないことに注意しましょう。スクレイピングは場合によってはサーバーに負荷をかけてしまいます。スクレイピングを行う前に目的のサイトがスクレイピングを許可しているかどうかを確認しましょう。
 さて、ここからは別のファイルで、解析を行います。先ほど取得したoutput.txtのディレクリに注意して、

import collections
import MeCab

#output.txtのディレクトリに注意
f = open("output.txt", "r", encoding="utf-8")

text = f.read()

f.close()

mecab = MeCab.Tagger()
node = mecab.parseToNode(text)

meishi_list = list()
doushi_list = list()
keiyoushi_list = list()

while node:
 if node.feature.split(",")[0] == "名詞":
   meishi_list.append(node.surface)
 elif node.feature.split(",")[0] == "動詞":
   doushi_list.append(node.feature.split(",")[7])
 elif node.feature.split(",")[0] == "形容詞":
   keiyoushi_list.append(node.feature.split(",")[7])
 node = node.next

#各品詞の出現頻度上位10件を表示
c_meishi = collections.Counter(meishi_list)
print(c_meishi.most_common(10))
c_doushi = collections.Counter(doushi_list)
print(c_doushi.most_common(10))
c_keiyoushi = collections.Counter(keiyoushi_list)
print(c_keiyoushi.most_common(10))

とすると、各品詞の出現頻度上位10件を表示できます。結果は、

[('もの', 20), ('こと', 19), ('一', 16), ('街', 12), ('檸檬', 9), ('心', 8), ('二', 7), ('中', 7), ('丸善', 7), ('果物', 7)]
[('為る', 46), ('居る', 42), ('言う', 29), ('有る', 26), ('行く', 20), ('来る', 19), ('成る', 16), ('見る', 15), ('思う', 9), ('出る', 9)]
[('無い', 15), ('美しい', 10), ('良い', 5), ('暗い', 5), ('重い', 5), ('見窄らしい', 2), ('冷たい', 2), ('熱い', 2), ('慌ただしい', 2), ('擽ったい', 2)]

となりました。
 名詞は「もの」や「こと」が最上位に食い込みました。タイトルでもある「檸檬」やそれに関連していそうな「果物」も上位です。個人的に少し意外だったのは「丸善」より「街」が頻出だったことでしょうか。
 また、形容詞は多くの説明的な文章よりも多く含まれているようです。全体として、装飾的で華美な文章と言えるかも知れません。「美しい」「良い」というような肯定的価値判断を意味する形容詞と、「暗い」「見窄らしい」などの否定的な形容詞が競い合うように同じようなバランスで上位に食い込んでいるのも面白いと思いました。この作品の絶妙なアンビバレンスを反映しているような気がします。

ワードクラウドを作る

 ここまで作ってきた動詞のリストdoushi_list、名詞のリストmeishi_list、形容詞のリストkeyoushiのリストをまとめてall_wordsとして、それらのワードクラウドを作りましょう。ワードクラウドを作るには日本語フォントをダウンロードする必要があります。今回はLinuxで使われるフリー日本語フォントであるIPAexゴシックを使います。

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

try:
    subprocess.run(['sudo', 'apt-get', '-y', 'install', 'fonts-ipaexfont-gothic'], check=True)
except subprocess.CalledProcessError as e:
    print(f"Error installing fonts: {e}")

all_words = meishi_list + keiyoushi_list + doushi_list
text_for_wordcloud = ' '.join(all_words)

fpath = "/usr/share/fonts/opentype/ipaexfont-gothic/ipaexg.ttf"

wordcloud = WordCloud(background_color="white", font_path=fpath, width=800, height=600).generate(text_for_wordcloud)

plt.figure(figsize=(10, 8))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off")
plt.show()

結果は、

all_word.png

となりました。もちろんall_wordsを少しいじれば名詞だけのワードクラウドや形容詞だけのワードクラウドを作ることができます。例えば動詞だけのワードクラウドは次のようになります。

doushi.png

また、名詞だけのワードクラウドは次のようになります。

meishi.png

ワードクラウドの手法はアンケート集計やSNSでよく使われます。
 ちなみに記事の冒頭で示したワードクラウドは形容詞だけを抽出したワードクラウドです。

テキスト処理の小技集

大文字小文字の表記ゆれを解消

大文字と小文字が混ざった英文を大文字のみ、小文字のみに変換することで表記ゆれを防ぐことができます。

text = "Songs of Innocence and of Experience"
print(text)
print(text.upper())
print(text.lower())

出力は、

Songs of Innocence and of Experience
SONGS OF INNOCENCE AND OF EXPERIENCE
songs of innocence and of experience

です。

日本語の表記ゆれに対応

日本語の表記ゆれを解消するにはmojimojiライブラリが便利です。

!pip install mojimoji

mojimojiをインポートして全角と半角を指定します。

import mojimoji

text = "ABC123アイウエオ"
print(text)
print(mojimoji.han_to_zen(text))
print(mojimoji.zen_to_han(text))

出力は下のようになり、全角半角による表記ゆれを解消することができます。

ABC123アイウエオ
ABC123アイウエオ
ABC123アイウエオ

正規表現で複数の区切り文字を指定

 正規表現を使うためのライブラリはreです。

import re

text = "おはよう、こんにちは、こんばんは。また明日。"
words = re.split(r"[、。]", text)
print(words)

結果はこのようになります。

['おはよう', 'こんにちは', 'こんばんは', 'また明日', '']

区切り文字の置き換え

 replaceを使って区切り文字を置き換えることもできます。

text = "おはよう、こんにちは、こんばんは。また明日。"
print(text.replace("", ", ").replace("", ". "))

結果はこのようになります。

おはよう, こんにちは, こんばんは. また明日. 
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?