見出し画像

PythonのpysummarizationでWikipediaの記事から要約文を生成してみた

先日の記事では青空文庫からワードクラウドを作成してみました。文書にどんなキーワードが頻出するのかを把握するのには向いていますが、それらの関係性はわかりませんでした。

本記事では、キーワードの相互関係がわかるように、Pythonのpysummarizationライブラリを用いて、ある程度まとまった要約文を生成してみます。

pusummarizationで青空文庫を要約する場合

先日の記事では、PythonのWordCloudライブラリを用いてワードクラウドを生成したところ、夏目漱石の『こころ』はこんな感じになりました。

ひとまず具体的なPythonコードは置いておいて、同様にPythonのpysummarizationライブラリで要約文を作成してみました。

【pysummarizationによる要約】
私はその人を常に先生と呼んでいた。だからここでもただ先生と書くだけで本名は打ち明けない。これは世間を憚かる遠慮というよりも、その方が私にとって自然だからである。私はその人の記憶を呼び起すごとに、すぐ「先生」といいたくなる。私が先生と知り合いになったのは鎌倉である。暑中休暇を利用して海水浴に行った友達からぜひ来いという端書を受け取ったので、私は多少の金を工面して、出掛ける事にした。私は金の工面に二、三日を費やした。ところが私が鎌倉に着いて三日と経たないうちに、私を呼び寄せた友達は、急に国元から帰れという電報を受け取った。私にはただ卒業したという自覚があるだけで、これから何をしようという目的もなかった。私はそれを兄の手から受け取った時、すぐその書留である事に気が付いた。

すると、次のような一見違和感の無い文章が出来上がります。でもよく見ると、物語の雰囲気はなんとなく分かるけど、核心には全く触れていないフワフワした感じの文章です。

どうもこの結果にはpysummarizationのアルゴリズムが関連しているようです。

pusummarizationのアルゴリズムと相性の良い文書形式

詳細は、PyPiHakkyで詳しく説明されていますが、まとめると、「単語の出現頻度から文の重要度を計算し、これに基づき、冗長な文章などを短くまとめて新たな要約文を生成する」といったところでしょうか。つまり、pysummarizationの要約文は、元の文書の頻出単語に引っ張られます。

物語のような形式の文書の構成上、pysummarizationによって生成される文章は、よく出てくる人物や場面描写などをまとめた文章にはなりますが、物語の核心はわかりません。

「要約」するときには、「要するに何なの?」というように「結論を知りたい」ことが多いと思います。その場合、元の文書に結論に関するキーワードが多く含まれている必要があります。

つまり、物語のような「結論はあるけど勿体ぶる」文書にはpysummarizationは向いていません。「結論ゴリ押し」な宣伝記事なんかは向いています。

逆に、「結論がない」箇条書きの辞書の記事なんかもpysummarizationのアルゴリズムは向いていると思います。

pusummarizationでWikipediaを要約する場合

というわけで、pysummarizationとWikipediaの記事との相性は比較的良いと思われます。

Pythonコード

Wikipediaから「鶴藤長天」の4人の記事を検索して、pysummarizationで要約文を生成するPythonコードを以下のように書いてみました。ついでにワードクラウドも生成します。

################################################################################
# ライブラリをインポート
################################################################################
from bs4 import BeautifulSoup
import requests as req
from wordcloud import WordCloud
from janome.tokenizer import Tokenizer
import matplotlib.pyplot as plt
import pandas as pd
import MeCab
import re
from pysummarization.nlpbase.auto_abstractor import AutoAbstractor
from pysummarization.tokenizabledoc.mecab_tokenizer import MeCabTokenizer
from pysummarization.abstractabledoc.top_n_rank_abstractor import TopNRankAbstractor
from pysummarization.nlp_base import NlpBase
from pysummarization.similarityfilter.tfidf_cosine import TfIdfCosine
import wikipediaapi
################################################################################
# 要約するWikipediaの記事名
################################################################################
titles = ['ジャンボ鶴田',
          '藤波辰爾',
          '長州力',
          '天龍源一郎']
################################################################################
# WordCloud用に除外する単語リスト
################################################################################
except_list = ['年',
               '月',
               '日']
################################################################################
# 類似性フィルターカットオフ設定
################################################################################
# 類似性フィルターカットオフ設定(Defalt = 0.25) { run: "auto" }
similarity_limit = 0.25 #@param {type:"slider", min:0.05, max:0.5, step:0.05}
################################################################################
# 記事ごとに繰り返し
################################################################################
for i in range(len(titles)):
    #-------------------------------------------------------------------------------
    # Wikipediaから本文を取得する
    #-------------------------------------------------------------------------------
    wiki_test = wikipediaapi.Wikipedia("ja",extract_format=wikipediaapi.ExtractFormat.WIKI)
    page_test = wiki_test.page(titles[i])
    text = page_test.text
    text = ''.join(text).replace(' ', '').replace(' ', '')
    
    ################################################################################
    # WordCloud
    ################################################################################
    #-------------------------------------------------------------------------------
    # 本文を分割
    #-------------------------------------------------------------------------------
    t = Tokenizer()
    tokens = t.tokenize(text)
    words = []
    for token in tokens:
        word = token.surface
        part_of_speech = token.part_of_speech.split(',')[0]
        part_of_speech2 = token.part_of_speech.split(',')[1]
        if part_of_speech == "名詞":
            if(part_of_speech2 != "非自立") and (part_of_speech2 != "代名詞"):
                words.append(word)
    
    #-------------------------------------------------------------------------------
    # 除外リストを反映
    #-------------------------------------------------------------------------------
    for j in range(len(words)):
        if words[j] in except_list:
            words[j] = ''
    word_list = ' '.join(words)
    
    #-------------------------------------------------------------------------------
    # ワードクラウドを描画
    #-------------------------------------------------------------------------------
    wordcloud = WordCloud(
        font_path='C:\Windows\Fonts\meiryo.ttc',
        width=2000, height=1000, 
        background_color="white",
    ).generate(word_list)
    plt.figure(figsize=(100,50))
    plt.imshow(wordcloud)
    plt.axis("off")
    plt.savefig("./image/" + titles[i] + " - Wikipedia.png")  ## 変更ポイント ##
    plt.show()
    
    ################################################################################
    # pysummarization
    ################################################################################
    #-------------------------------------------------------------------------------
    # 要約処理
    #-------------------------------------------------------------------------------
    # 自動要約のオブジェクト
    auto_abstractor = AutoAbstractor()
    # トークナイザー設定(MeCab使用)
    auto_abstractor.tokenizable_doc = MeCabTokenizer()
    # 区切り文字設定
    auto_abstractor.delimiter_list = ["。", "\n"]
    # 抽象化&フィルタリングオブジェクト
    abstractable_doc = TopNRankAbstractor()
    # 文書要約
    result_dict1 = auto_abstractor.summarize(text, abstractable_doc)
    # NLPオブジェクト
    nlp_base = NlpBase()
    # トークナイザー設定(MeCab使用)
    nlp_base.tokenizable_doc = MeCabTokenizer()
    # 類似性フィルター
    similarity_filter = TfIdfCosine()
    # NLPオブジェクト設定
    similarity_filter.nlp_base = nlp_base
    # 類似性limit:limit超える文は切り捨て
    similarity_filter.similarity_limit = similarity_limit
    # 自動要約のオブジェクト
    auto_abstractor = AutoAbstractor()
    # トークナイザー設定(MeCab使用)
    auto_abstractor.tokenizable_doc = MeCabTokenizer()
    # 区切り文字設定
    auto_abstractor.delimiter_list = ["。", "\n"]
    # 抽象化&フィルタリングオブジェクト
    abstractable_doc = TopNRankAbstractor()
    # 文書要約(similarity_filter機能追加)
    result_dict2 = auto_abstractor.summarize(text, abstractable_doc, similarity_filter)
    #-------------------------------------------------------------------------------
    # データフレーム化
    #-------------------------------------------------------------------------------
    doc1 = result_dict1["summarize_result"]
    doc2 = result_dict2["summarize_result"]
    doc0 = ''.join(s for s in text)
    doc1 = ''.join(s for s in doc1)
    doc2 = ''.join(s for s in doc2)
    lst1 = ["原文",
            "pysummarizationによる要約",
            "pysummarizationによる要約(類似性フィルター)"]
    lst2 = [doc0, doc1, doc2]
    df = pd.DataFrame(list(zip(lst1, lst2)), columns = ['Class.','Content'])
    df = df.replace( '\n', '', regex=True)
    with pd.option_context('display.max_rows', None, 'display.max_columns', None, 'display.colheader_justify','light', 'display.width', 2000, 'display.max_colwidth', 500):
        df = df.stack().str.lstrip().unstack()
        df = df.style.set_properties(**{'text-align': 'left'})
        
    #-------------------------------------------------------------------------------
    # 要約したテキストをファイルに保存する
    #-------------------------------------------------------------------------------
    file_path = './text/' + titles[i] + '.txt'
    f = open(file_path, 'w', encoding='UTF-8')
    f.write(titles[i] + ' - Wikipedia\n')
    f.write('--------------------------------------------------------------------------------\n')
    f.write('【' + lst1[1] + '】\n')
    f.write(lst2[1].replace( '\n', '') + '\n')
    f.write('--------------------------------------------------------------------------------\n')
    f.write('【' + lst1[2] + '】\n')
    f.write(lst2[2].replace( '\n', '') + '\n')
    f.write('--------------------------------------------------------------------------------\n')
    f.close()
    
    #-------------------------------------------------------------------------------
    # 要約したテキストを表示する
    #-------------------------------------------------------------------------------
    print(titles[i] + ' - Wikipedia')
    print('--------------------------------------------------------------------------------')
    print('【' + lst1[1] + '】')
    print(lst2[1].replace( '\n', ''))
    print('--------------------------------------------------------------------------------')
    print('【' + lst1[2] + '】')
    print(lst2[2].replace( '\n', ''))
    print('--------------------------------------------------------------------------------')

出力結果

ジャンボ鶴田 - Wikipedia
--------------------------------------------------------------------------------
【pysummarizationによる要約】
ジャンボ鶴田(ジャンボつるた、1951年3月25日-2000年5月13日)は、日本のプロレスラー・スポーツ科学研究者。本名及び旧リングネーム:鶴田友美(つるたともみ)。全日本プロレスで活躍した、三冠ヘビー級王座の初代王者であり、日本人初の第30代AWA世界ヘビー級王者である。1972年ミュンヘンオリンピックのレスリングである、グレコローマンスタイル最重量級日本代表を経て、その後全日本プロレスへ入門する。ジャイアント馬場の後を継ぐ次世代・全日本プロレスの若き大型エースとしても期待され、順調に頭角を現しトップレスラーの1人として活躍した。デビュー当初は本名の鶴田友美をリングネームに用いていた。またファンからの公募により、1973年10月27日にリングネームをジャンボ鶴田へと改名する。1989年4月には、シングルタイトルであるインター・PWF・UNの三冠を統一し、初代三冠ヘビー級王者となる。その3ヶ月後の1990年9月、三冠ヘビー級王座への挑戦権をかけて再度三沢と戦うが、今度は鶴田がジャンボラリアットからのバックドロップ・ホールドで三沢から完璧な3カウントを奪っている。その後、AWA王座を同年5月13日にリック・マーテルに敗れるまで16回の防衛を果たした。
--------------------------------------------------------------------------------
【pysummarizationによる要約(類似性フィルター)】
ジャンボ鶴田(ジャンボつるた、1951年3月25日-2000年5月13日)は、日本のプロレスラー・スポーツ科学研究者。血液型O型。全日本プロレス入団しかしこの抜擢については試合前に「彼はまだデビューしてから半年だし、150試合のアメリカ修行で一体、どれだけ成長が出来るというのか?プロはそんなに甘い世界ではないだろう」と、内外含めてメディアからも猛批判が上がったが、アメリカで鶴田の成長ぶりを実際に確認していた馬場は「まあまあ、とにかく彼の試合を観てから判断しましょう」と、自信たっぷりに答えている。
--------------------------------------------------------------------------------

藤波辰爾 - Wikipedia
--------------------------------------------------------------------------------
【pysummarizationによる要約】
藤波辰爾(ふじなみたつみ、本名:藤波辰巳、1953年12月28日-)は、日本の男性プロレスラー。大分県東国東郡武蔵町(のちの国東市)出身。第77代NWA世界ヘビー級王者。日本人2人目のWWE殿堂入りレスラー。海外武者修行時のリングネームは、アメリカではドクター・フジナミ、メキシコではドクトル・フヒナミおよびリング・フヒナミとしていた。1953年12月28日、大分県国東郡に生まれる。中学時代は陸上競技を行っていた。この頃にアントニオ猪木に憧れ、プロレスラーを目指す。日本人ではアントニオ猪木に続き2人目の殿堂入りである。また、当時はドラゴン・フジナミを名乗っていた事と、細身で引き締まった肉体から「君はブルース・リーの親戚か何かか?」と転戦先でプロモーターや記者達に必ずといっていいほど質問されたそうである。
--------------------------------------------------------------------------------
【pysummarizationによる要約(類似性フィルター)】
藤波辰爾(ふじなみたつみ、本名:藤波辰巳、1953年12月28日-)は、日本の男性プロレスラー。YouTuber。中学時代は陸上競技を行っていた。当時の猪木が「いつでもどこでも俺のことを見ている」と言うほど猪木につきっきりであり、猪木は妻の倍賞美津子より藤波の方が自分のことを分かってくれていると評していた。新日本プロレス旗揚げ、海外修行ジュニアヘビー級時代は割と多用していたのだが、フルネルソン状態で真後ろに投げられるという習慣が当時のレスラーにはほとんど皆無だったこともあり、受身を取りそこなうレスラーも多く(1980年の『ビッグ・ファイト・シリーズ』においてアーマンド・ゲレロに放った際には、アーマンドは舌を出して失神しTKO負けとなり、首を負傷してシリーズ途中で帰国したが、これはドラゴン・スープレックスの破壊力を演出するためのアングルであり、このシリーズではアンヘル・ブランコも同様の負傷アングルで途中帰国している)、当時新日本が提携していたWWFから1982年に「3年間(1985年まで)禁じ手とする」旨の要請を受けたとして、この技は封印された。
--------------------------------------------------------------------------------

【pysummarizationによる要約】
長州力(ちょうしゅうりき、1951年12月3日-)は、日本の元プロレスラー。山口県徳山市(現・周南市)出身。在日韓国人2世として生まれ、2016年に日本へ帰化した。韓国名は郭光雄(かくこうゆう、クァク・クァンウン、곽광웅)。現在の本名(日本名及び旧リングネーム)は吉田光雄(よしだみつお)。入場曲は異母犯抄作曲のオリジナルテーマ曲『パワーホール』(後述も参照)。1951年12月3日、山口県徳山市で四人兄弟の末っ子として生まれる。「噛ませ犬」という言葉が取り上げられるようになったのは、長州が雑誌『ビッグ・レスラー』1982年12月号(立風書房)における造反直後の単独インタビューの中で「だけど、ここで自分を主張できなかったら、僕は一生”かませ犬”のままで終わってしまうんですよ」とコメントしたことに対し「藤波のかませ犬になるのは、もうごめんだ!」というインタビュータイトルが付けられたことが発端であった。長州個人としては2007年にパチスロ「革命戦士長州力」(トリビー)が発売された。前田日明、ミスター高橋、大仁田厚、藤原喜明、金本浩二ほか『証言長州力「革命戦士」の虚と実』(2019年5月27日、宝島社)ISBN978-4800294593
--------------------------------------------------------------------------------
【pysummarizationによる要約(類似性フィルター)】
長州力(ちょうしゅうりき、1951年12月3日-)は、日本の元プロレスラー。北海道猿払村ふるさと納税大使。同王座はハリウッド・ブロンズ(ジェリー・ブラウン&バディ・ロバーツ)、タイガー・ジェット・シン&マサ斎藤、アイアン・シーク&スーパー・デストロイヤー、バッドニュース・アレン&ゲシュタポ、ワイルド・サモアンズ(アファ・アノアイ&シカ・アノアイ)などのチームを相手に防衛を続けたが、猪木の提唱するIWGP構想により、1981年3月のシン&ドン・ムラコとの防衛戦を最後に返上となった。ジャパンプロレス旗揚げ-全日本プロレス参戦スタン・ハンセンの流れを汲む、試合開始から終了まで走り回るハイスパート・レスリングの象徴とされ、基本的な技であっても差別化を図る工夫がなされている。)。
--------------------------------------------------------------------------------

天龍源一郎 - Wikipedia
--------------------------------------------------------------------------------
【pysummarizationによる要約】
天龍源一郎(てんりゅうげんいちろう、1950年2月2日-)は、日本の男性タレント、元プロレスラー、元大相撲力士。本名は嶋田源一郎(しまだげんいちろう)。身長189cm、体重120kg(力士時代は身長186cm、体重112kg)。業務提携エクセリング[1]。多くの同年代レスラーが年齢と共に前座でファンを楽しませる役割に回る、または引退する中、天龍は65歳まで第一線で活躍し続け、日本のプロレス界において「生ける伝説(LivingLegend)」として一目置かれる存在だった。SWS崩壊後の1992年6月28日、天龍はWARを設立して新日本との対抗戦に活路を見出した。2011年3月6日、ユニオンプロレスにおいて高木三四郎がプロデュースするプロジェクト「TKG48」に最高顧問として加入することが発表され、4月3日のユニオンプロレス新木場大会に参戦した。島田源一郎(しまだげんいちろう)1964年1月場所-1970年9月場所1980年代までは天龍チョップというと相撲の突っ張りを応用したもので「突っ張り連発で相手をコーナーポストやロープ際に追い込む」だけのものを指したが、多様なチョップへ変化し、現役晩年は「天龍チョップ」と呼ばれることが多かった。1978年のフロリダ地区での再修行時代には、「テン・ルー」として素顔で闘うだけでなく白地に鷹をあしらったマスクを被り、パートナーに現地のレスラー(ソニー・ドライバー)、マネージャーにタイガー服部を従え、「ライジング・サンズ」として活動したこともある。
--------------------------------------------------------------------------------
【pysummarizationによる要約(類似性フィルター)】
天龍源一郎(てんりゅうげんいちろう、1950年2月2日-)は、日本の男性タレント、元プロレスラー、元大相撲力士。本名は嶋田源一郎(しまだげんいちろう)。農家の生まれであることから幼少期より米をたくさん食べて大きく育ち、中学2年の身体検査では182cm、82kgを記録した。16歳の時のある巡業では、移動の際に兄弟子から大鵬の双眼鏡を持って行くよう命じられたが、それを聞き忘れたためその巡業中にかわいがりに遭い、竹刀や青竹、さらに角材で殴られたが「これで俺も一人前の力士だ」と却って自信をつけたといい、かわいがりを行った兄弟子たちも「どうだい、きつかったか?これでお前も一人前だよ」と翌日からは何事もなかったかのように接していた。全日本プロレスタイトル初戴冠を果たした。
--------------------------------------------------------------------------------

まとめ

4人それぞれ特徴や、細かいエピソードを良い感じに抽出できたように思います。

WordCloudやpysummarizationはWikipedia記事とは相性が良さそうですね。

この記事が気に入ったらサポートをしてみませんか?