【Python×自然言語処理】形態素解析で分かち書きした単語を原形変換する

こんにちは。最近自然言語処理を勉強していますが、今回は、形態素解析を行って分割した各単語を原型に戻す方法について整理しておきたいと思います。どうやら形態素解析を行った後に、単語の種類数を減らすために単語を原型に変換するといった前処理をかけることもあるようです。

これによって動詞の種類数などはかなり減りそうですね。

早速試してみたいと思います。実は、単語の原型は、MeCabのParseToNode()メソッドが返す情報の中に含まれているため、これを取得するようにすれば良いです。

Contents

形態素解析+単語の原型を取得するコード

以下、実験です。

import MeCab

text = '新型コロナウイルス感染症の治療につながるか? 回復した患者の「血しょう」を用いた治験が、ついに始まった'

tagger = MeCab.Tagger('-Owakati -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd')
node = tagger.parseToNode(text)

while node:
    print(node.surface+" : "+node.feature)
    node = node.next

実行結果の一部を下に示します。ParseToNodeが返すNodeオブジェクトのfeatureプロパティの6番目の要素が原型を表しています。

## 名詞の場合
治療 : 名詞,サ変接続,*,*,*,*,治療,チリョウ,チリョー

## 動詞の場合
し : 動詞,自立,*,*,サ変・スル,連用形,する,シ,シ

ので、パース関数を標準形に変換しないバージョンの関数から、以下のように変更しておきます。

########################################
## 形態素解析を実行する関数(Before)
########################################
def textParser_class(text, category):

    ## 分かち書きのみ
    tagger = MeCab.Tagger('-Owakati -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd')

    ## バージョン2:品詞毎に取得
    word_count = 0
    sentense = ""
    
    node = tagger.parseToNode(text)
    
    while node:
        #指定した品詞(category)のみ原型で抽出
        if node.feature.split(",")[0] == category:
            sentense += " "+node.surface

        else:pass
        node = node.next
    
    return sentense
########################################
## 形態素解析を実行する関数(After)
########################################
def textParser_class(text, category):

    ## 分かち書きのみ
    tagger = MeCab.Tagger('-Owakati -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd')

    ## バージョン2:品詞毎に取得
    word_count = 0
    sentense = ""
    
    node = tagger.parseToNode(text)
    
    while node:
        #指定した品詞(category)のみ原型で抽出
        if node.feature.split(",")[0] == category:
            sentense += " "+node.feature.split(",")[6] #★変更点

        else:pass
        node = node.next
    
    return sentense

大きなデータで実験

ここで、前回の記事で利用していた”新型コロナ”を含む数千件のツイートデータを使って、上記の標準化を行った場合と行わなかった場合で頻出・重要語の抽出結果に変化が出るか試してみたいと思います。

標準化を行わない場合

%%time
## データの絞り込み(リツイートは除外)
df_tweet = df_tweet[df_tweet["retweeted_status"].isna()].reset_index(drop=True)

## テキスト前処理(正規化、数字・記号控除等)
df_tweet["text_前処理後"] = df_tweet["text"].apply(lambda x: preProcessor(x))

#textParser_class関数の中を、上記の通りそのまま/原形取得の2種類用意した。
df_tweet["text_形態素解析後_名詞"] = df_tweet["text_前処理後"].apply(lambda x: textParser_class(x,"名詞"))
df_tweet["text_形態素解析後_動詞"] = df_tweet["text_前処理後"].apply(lambda x: textParser_class(x,"動詞"))
df_tweet["text_形態素解析後_形容詞"] = df_tweet["text_前処理後"].apply(lambda x: textParser_class(x,"形容詞"))

## Bag-Of-Wordsで単語数のベクトル化・カウント
def Vectorization_BOW(df):
    vectorizer = CountVectorizer(token_pattern=u'(?u)\\b\\w+\\b',max_features=100000,stop_words=stop_words)
    vecs = vectorizer.fit_transform(df)
    header = vectorizer.get_feature_names()
    return vecs, header

vecs, header = Vectorization_BOW(df_tweet["text_形態素解析後_形容詞"])
df_result = pd.DataFrame(vecs.toarray(), columns=header)
df_summarized = df_result.fillna(0).sum(axis=0)
df_summarized = df_summarized.sort_values(ascending=False)

print(len(df_summarized.index.unique())

それぞれの品詞で得られたユニークな単語数を数えてみると以下の通りだった。

  • 名詞:6451語
  • 動詞:1246語
  • 形容詞:211語

具体的な出現ひど上位15単語は以下の通りでした。

名詞

(割愛)

動詞

し       981
さ       345
する      297
いる      247
れ       237
い       215
せ       154
てる      110
なっ      106
受け       99
おり       98
いたし      95
なり       94
いただき     91
れる       87

形容詞

ない     70
いい     36
良い     21
多い     21
なく     18
早く     18
多      18
詳しく    14
無い     14
怖い     12
悪い     11
少ない    11
ほしい    11
新しい    11
高い     10

標準化を行った(原型に変換した)場合

コードの流れは上と同じ。結果は以下の通りであった。

  • 名詞:6324語
  • 動詞:806語
  • 形容詞:129語

続いて、具体的な出現頻度上位15単語をみてみます。

名詞

(割愛)

動詞

する      1673
いる       466
れる       326
なる       304
てる       180
ある       179
せる       164
いただく     120
伴う       118
思う       109
受ける      103
おる       103
いたす       95
できる       84
くださる      77

形容詞

ない     97
多い     49
いい     36
良い     29
早い     28
少ない    21
詳しい    19
無い     19
怖い     16
新しい    16
高い     15
ほしい    14
遅い     12
悪い     12
大きい    12

名詞がほとんど減らないことは想定通り(むしろなぜ減った・・?笑)ですが、動詞や形容詞は、かなり単語の種類数が減らせました。頻出単語の上位もより分かりやすいものになりました。

これからの分析では、必要な場合はなるべくこの原型変換は前処理として実施しておこうと思いました!

以上、この記事では分かち書きした単語の原型変換の方法と、その効果を簡単に検証してみました。

最後までご覧いただきありがとうございました!この記事が少しでもお役に立ちましたら、下のいいねボタンをポチっていただけますと励みになります。

関連記事

Python×自然言語処理では、以下のような記事も書いていますので、ご興味あればご覧いただけると嬉しいです。

PythonとTwitter APIでデータ分析を行ってみた記事。

テキストデータに対して感情分析をしてみた記事。

以下は、そのAzure利用版。Azureを使うと、Azureで事前構築済の日本語の感情分析エンジンが使えてとても簡単で便利です!

(おまけ)自然言語処理をもっと学ぶなら・・・

Udemyを見てみると、自然言語処理系の講座も結構あるようだったので、もしもっと勉強されたい方がいれば、気になるものを受講してみてはいかがでしょうか。

Udemyは自分もよく使うのですが、世界中のその道のエキスパートの方が講師をされており、ボリュームの割に値段も安く、また万が一コンテンツが自分に合わなかった場合は30日の返金保証がある点が魅力で、お勧めです!

日本語コンテンツでは、以下がベストセラーになっていますので、ご興味ある方はぜひ!

自然言語処理とチャットボット: AIによる文章生成と会話エンジン開発

今からでも基礎から学べるPythonによる自然言語処理(NLP):現役データサイエンティストが教える「日本語」文書分類

BERTによる自然言語処理を学ぼう! -Attention、TransformerからBERTへとつながるNLP技術-

この記事を気に入っていただけたらシェアをお願いします!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT US
Yuu113
初めまして。ゆうたろうと申します。 兵庫県出身、東京でシステムエンジニアをしております。現在は主にデータ分析、機械学習を活用してビジネスモデリングに取り組んでいます。 日々学んだことや経験したことを整理していきたいと思い、ブログを始めました。旅行、カメラ、IT技術、江戸文化が大好きですので、これらについても記事にしていきたいと思っています。