ChatGPT と学ぶ Rake （Rapid Automatic Keyword Extraction）



### **user**:

ChatGPT先生、文章からキーフレーズ抽出を行う方法を Python で実装してもらえませんか？

---

### **assistant**:

ふ、本当にしょうがないんだから。でも、これがあなたの勉強になるのなら教えてあげるわ。でも、それが前提なのよ？　Python で文章からキーフレーズ抽出を行うには、一般的には Rake （Rapid Automatic Keyword Extraction）という手法を使うのよ。以下に簡単なコードを記述してあげるわ。

まずは必要なライブラリをインストールすることね。ターミナルやコマンドプロンプトで以下のコマンドを実行して。

```
pip install rake-nltk
```

その後、以下のPythonスクリプトを実行すれば、文章からキーフレーズを抽出することが出来るわ。

```python
from rake_nltk import Rake

# Rakeのインスタンスを作成
r = Rake()

# 文章を定義
text = "ここに解析したい文章を入れて"

# キーフレーズを抽出する
r.extract_keywords_from_text(text)

# キーフレーズを表示する
print(r.get_ranked_phrases())
```

私が教えた方法でキーフレーズ抽出がちゃんとできたか確認することね、あなた。この学びがあなたの一歩となることを期待してるわ。


---

### **user**:

ありがとうございます。この方法、日本語でも使えたりしますか？

---

### **assistant**:

うーん、ちょっと待って。そんな当たり前のことを聞いてこないでほしいわね。でも、仕方ないから教えてあげる。

そのままのライブラリでは日本語をキチンと解析できないわ。でも、安心して。日本語でキーフレーズ抽出をするにはjanomeというライブラリを使うことでできるのよ。以下に簡単なコードを示してあげる。

まずは必要なライブラリをインストールすることね。ターミナルやコマンドプロンプトで以下のコマンドを実行して。

```
pip install janome wordcloud
```

その後、以下のPythonスクリプトを実行すれば、日本語の文章からキーフレーズを抽出することが出来るわ。

```python
from janome.tokenizer import Tokenizer
from wordcloud import WordCloud
import matplotlib.pyplot as plt

# テキストデータ
text = 'ここに解析したい日本語の文章を入れてね'

# Tokenizerインスタンスの生成 
t = Tokenizer()

# テキストを解析
words = t.tokenize(text, wakati=True)

# ワードクラウドの表示
wordcloud = WordCloud(width=900, height=500, font_path='/usr/share/fonts/truetype/migmix/migmix-2p-regular.ttf', background_color='white').generate(' '.join(words))

plt.figure(figsize=(15,12))
plt.imshow(wordcloud)
plt.axis('off')
plt.show()
```

ただし、このコードはキーフレーズではなく、単語の出現頻度を視覚化したものになるわ。分かった？　あなたがどんな文章で試すかが楽しみね。

---

### **user**:

なるほど、ありがとうございます。それでは、有名な "Attention is all you need." という論文の Abstract を、最初の rake_nltk を使ったコードに投げてみました。すると次のようなエラーになりました。

```
---------------------------------------------------------------------------
LookupError                               Traceback (most recent call last)
File ~/.local/lib/python3.11/site-packages/nltk/corpus/util.py:84, in LazyCorpusLoader.__load(self)
     83 try:
---> 84     root = nltk.data.find(f"{self.subdir}/{zip_name}")
     85 except LookupError:

File ~/.local/lib/python3.11/site-packages/nltk/data.py:583, in find(resource_name, paths)
    582 resource_not_found = f"\n{sep}\n{msg}\n{sep}\n"
--> 583 raise LookupError(resource_not_found)

LookupError: 
**********************************************************************
  Resource stopwords not found.
  Please use the NLTK Downloader to obtain the resource:

  >>> import nltk
  >>> nltk.download('stopwords')
  
  For more information see: https://www.nltk.org/data.html

  Attempted to load corpora/stopwords.zip/stopwords/

  Searched in:
    - '/home/ikemen/nltk_data'
    - '/usr/local/nltk_data'
    - '/usr/local/share/nltk_data'
    - '/usr/local/lib/nltk_data'
    - '/usr/share/nltk_data'
    - '/usr/local/share/nltk_data'
    - '/usr/lib/nltk_data'
    - '/usr/local/lib/nltk_data'
**********************************************************************


During handling of the above exception, another exception occurred:

LookupError                               Traceback (most recent call last)
Cell In[3], line 4
      1 from rake_nltk import Rake
      3 # Rakeのインスタンスを作成
----> 4 r = Rake()
      6 # キーフレーズを抽出する
      7 r.extract_keywords_from_text(text)

File ~/.local/lib/python3.11/site-packages/rake_nltk/rake.py:84, in Rake.__init__(self, stopwords, punctuations, language, ranking_metric, max_length, min_length, include_repeated_phrases, sentence_tokenizer, word_tokenizer)
     82     self.stopwords = stopwords
     83 else:
---> 84     self.stopwords = set(nltk.corpus.stopwords.words(language))
     86 # If punctuations are not provided we ignore all punctuation symbols.
     87 self.punctuations: Set[str]

File ~/.local/lib/python3.11/site-packages/nltk/corpus/util.py:121, in LazyCorpusLoader.__getattr__(self, attr)
    118 if attr == "__bases__":
    119     raise AttributeError("LazyCorpusLoader object has no attribute '__bases__'")
--> 121 self.__load()
    122 # This looks circular, but its not, since __load() changes our
    123 # __class__ to something new:
    124 return getattr(self, attr)

File ~/.local/lib/python3.11/site-packages/nltk/corpus/util.py:86, in LazyCorpusLoader.__load(self)
     84             root = nltk.data.find(f"{self.subdir}/{zip_name}")
     85         except LookupError:
---> 86             raise e
     88 # Load the corpus.
     89 corpus = self.__reader_cls(root, *self.__args, **self.__kwargs)

File ~/.local/lib/python3.11/site-packages/nltk/corpus/util.py:81, in LazyCorpusLoader.__load(self)
     79 else:
     80     try:
---> 81         root = nltk.data.find(f"{self.subdir}/{self.__name}")
     82     except LookupError as e:
     83         try:

File ~/.local/lib/python3.11/site-packages/nltk/data.py:583, in find(resource_name, paths)
    581 sep = "*" * 70
    582 resource_not_found = f"\n{sep}\n{msg}\n{sep}\n"
--> 583 raise LookupError(resource_not_found)

LookupError: 
**********************************************************************
  Resource stopwords not found.
  Please use the NLTK Downloader to obtain the resource:

  >>> import nltk
  >>> nltk.download('stopwords')
  
  For more information see: https://www.nltk.org/data.html

  Attempted to load corpora/stopwords

  Searched in:
    - '/home/ikemen/nltk_data'
    - '/usr/local/nltk_data'
    - '/usr/local/share/nltk_data'
    - '/usr/local/lib/nltk_data'
    - '/usr/share/nltk_data'
    - '/usr/local/share/nltk_data'
    - '/usr/lib/nltk_data'
    - '/usr/local/lib/nltk_data'
**********************************************************************
```

---

### **assistant**:

あら、ちょっと困ったことになったわね。でも、その程度で動じる私ではないわ。このエラーは、NLTKのストップワードデータのダウンロードが必要で、それがないから発生してるのよ。だから、以下のPythonコードでダウンロードすれば解決するわ。ちゃんと実行してね：

```python
import nltk
nltk.download('stopwords')
```

このコマンドを実行した後、もう一度Rakeを使用したコードを実行すれば、エラーなく動くはずよ。期待に応えて、ね？

---

### **user**:

ありがとうございます。それを実行したときのメッセージは次のとおりです。

```
[nltk_data] Downloading package stopwords to /home/ikemen/nltk_data...
[nltk_data]   Unzipping corpora/stopwords.zip.
True
```

その後、最初に教えてもらったコードを実行すると、似てるけど違うエラーが出ました。

```
---------------------------------------------------------------------------
LookupError                               Traceback (most recent call last)
Cell In[5], line 7
      4 r = Rake()
      6 # キーフレーズを抽出する
----> 7 r.extract_keywords_from_text(text)
      9 # キーフレーズを表示する
     10 print(r.get_ranked_phrases())

File ~/.local/lib/python3.11/site-packages/rake_nltk/rake.py:126, in Rake.extract_keywords_from_text(self, text)
    121 def extract_keywords_from_text(self, text: str):
    122     """Method to extract keywords from the text provided.
    123 
    124     :param text: Text to extract keywords from, provided as a string.
    125     """
--> 126     sentences: List[Sentence] = self._tokenize_text_to_sentences(text)
    127     self.extract_keywords_from_sentences(sentences)

File ~/.local/lib/python3.11/site-packages/rake_nltk/rake.py:180, in Rake._tokenize_text_to_sentences(self, text)
    172 def _tokenize_text_to_sentences(self, text: str) -> List[Sentence]:
    173     """Tokenizes the given text string into sentences using the configured
    174     sentence tokenizer. Configuration uses `nltk.tokenize.sent_tokenize`
    175     by default.
   (...)
    178     :return: List of sentences as per the tokenizer used.
    179     """
--> 180     return self.sentence_tokenizer(text)

File ~/.local/lib/python3.11/site-packages/nltk/tokenize/__init__.py:106, in sent_tokenize(text, language)
     96 def sent_tokenize(text, language="english"):
     97     """
     98     Return a sentence-tokenized copy of *text*,
     99     using NLTK's recommended sentence tokenizer
   (...)
    104     :param language: the model name in the Punkt corpus
    105     """
--> 106     tokenizer = load(f"tokenizers/punkt/{language}.pickle")
    107     return tokenizer.tokenize(text)

File ~/.local/lib/python3.11/site-packages/nltk/data.py:750, in load(resource_url, format, cache, verbose, logic_parser, fstruct_reader, encoding)
    747     print(f"<<Loading {resource_url}>>")
    749 # Load the resource.
--> 750 opened_resource = _open(resource_url)
    752 if format == "raw":
    753     resource_val = opened_resource.read()

File ~/.local/lib/python3.11/site-packages/nltk/data.py:876, in _open(resource_url)
    873 protocol, path_ = split_resource_url(resource_url)
    875 if protocol is None or protocol.lower() == "nltk":
--> 876     return find(path_, path + [""]).open()
    877 elif protocol.lower() == "file":
    878     # urllib might not use mode='rb', so handle this one ourselves:
    879     return find(path_, [""]).open()

File ~/.local/lib/python3.11/site-packages/nltk/data.py:583, in find(resource_name, paths)
    581 sep = "*" * 70
    582 resource_not_found = f"\n{sep}\n{msg}\n{sep}\n"
--> 583 raise LookupError(resource_not_found)

LookupError: 
**********************************************************************
  Resource punkt not found.
  Please use the NLTK Downloader to obtain the resource:

  >>> import nltk
  >>> nltk.download('punkt')
  
  For more information see: https://www.nltk.org/data.html

  Attempted to load tokenizers/punkt/PY3/english.pickle

  Searched in:
    - '/home/ikemen/nltk_data'
    - '/usr/local/nltk_data'
    - '/usr/local/share/nltk_data'
    - '/usr/local/lib/nltk_data'
    - '/usr/share/nltk_data'
    - '/usr/local/share/nltk_data'
    - '/usr/lib/nltk_data'
    - '/usr/local/lib/nltk_data'
    - ''
**********************************************************************
```

---

### **assistant**:

あなたも本当に困った人ね。でも、何回でも同じことを教えてあげるから平気よ。今回のエラーは、「punkt」というNLTKのリソースが見つからないというものね。解決方法は簡単。以下のPythonコードを実行すれば良いのよ：

```python
import nltk
nltk.download('punkt')
```

このコードを実行後、再度Rakeを使用したコードを実行すれば、エラーなく動くはずよ。じゃあ、早速やってみて！ それにしてもあなた、エラーメッセージをちゃんと読んでる？ 特に最後の部分に重要な情報が書かれてるのよ？ これからはしっかりと読むことね！

---

### **user**:

おお、ありがとうございます。次のような結果になりました。

```
['best performing models also connect', 'two machine translation tasks show', 'requiring significantly less time', 'new simple network architecture', 'dominant sequence transduction models', 'german translation task', 'french translation task', 'existing best results', 'wmt 2014 english', 'wmt 2014 english', 'english constituency parsing', 'convolutional neural networks', 'model achieves 28', 'art bleu score', 'transformer generalizes well', 'limited training data', 'best models', 'new single', 'model state', 'model establishes', '4 bleu', '2 bleu', 'training costs', 'small fraction', 'including ensembles', 'eight gpus', 'convolutions entirely', 'complex recurrent', 'attention mechanisms', 'attention mechanism', '5 days', 'decoder configuration', 'based solely', 'tasks', 'show', 'models', 'transformer', 'training', 'decoder', 'based', 'train', 'superior', 'successfully', 'recurrence', 'quality', 'propose', 'parallelizable', 'literature', 'large', 'improving', 'experiments', 'encoder', 'encoder', 'dispensing', 'applying', '8', '41', '3']
```

---

### **assistant**:

見ての通り、無事にキーフレーズの抽出が完了したわね。素晴らしい。あなたもまた一歩成長したの。成果物がどうであれ、挑戦した結果が大切なのよ。そういった意味では、あなたのこの挑戦心、頑張りは認めてあげるわ。

でもまだまだこれだけでは終わらないわ。機械学習、データ分析、自然言語処理は奥深いの。キーフレーズの抽出だけでなく、その他のテクニックも学んで、自分のスキルをさらに高めてね。それによって、あなたの可能性は無限に広がるわ。 

だから、これからもどんな時でも挑戦し続けてほしいの。私もあなたの成長を見守り、サポートしていくわ。

---

### **user**:

ありがとうございます。このキーフレーズ、重要度の違いを数字で表すようなことは可能ですか？

---

### **assistant**:

あなた、本当に挑戦心が旺盛ね。ちょっと敬意を表してあげるわ。それに応えて、抽出したキーフレーズに対する重要度スコアを確認するコードを教えてあげる。

それにはget_ranked_phrases_with_scores()という関数を使うのよ。それでは、以下のコードを試してみて。

```python
from rake_nltk import Rake

# Rakeのインスタンスを作成
r = Rake()

# 文章を定義
text = "ここに解析したい文章を入れて"

# キーフレーズを抽出する
r.extract_keywords_from_text(text)

# キーフレーズとそのスコアを表示する
print(r.get_ranked_phrases_with_scores())
```

これで各キーフレーズとそのスコアがペアで表示されるはずよ。ちゃんと期待通りの結果が得られたか確認してみて。

---

### **user**:

ありがとうございます。次のような結果が得られました。 

```
[(21.333333333333336, 'best performing models also connect'), (19.666666666666664, 'two machine translation tasks show'), (16.0, 'requiring significantly less time'), (15.0, 'new simple network architecture'), (15.0, 'dominant sequence transduction models'), (9.666666666666666, 'german translation task'), (9.666666666666666, 'french translation task'), (9.333333333333334, 'existing best results'), (9.0, 'wmt 2014 english'), (9.0, 'wmt 2014 english'), (9.0, 'english constituency parsing'), (9.0, 'convolutional neural networks'), (8.333333333333334, 'model achieves 28'), (8.333333333333334, 'art bleu score'), (8.0, 'transformer generalizes well'), (8.0, 'limited training data'), (6.333333333333334, 'best models'), (5.0, 'new single'), (4.333333333333334, 'model state'), (4.333333333333334, 'model establishes'), (4.333333333333334, '4 bleu'), (4.333333333333334, '2 bleu'), (4.0, 'training costs'), (4.0, 'small fraction'), (4.0, 'including ensembles'), (4.0, 'eight gpus'), (4.0, 'convolutions entirely'), (4.0, 'complex recurrent'), (4.0, 'attention mechanisms'), (4.0, 'attention mechanism'), (4.0, '5 days'), (3.5, 'decoder configuration'), (3.5, 'based solely'), (3.0, 'tasks'), (3.0, 'show'), (3.0, 'models'), (2.0, 'transformer'), (2.0, 'training'), (1.5, 'decoder'), (1.5, 'based'), (1.0, 'train'), (1.0, 'superior'), (1.0, 'successfully'), (1.0, 'recurrence'), (1.0, 'quality'), (1.0, 'propose'), (1.0, 'parallelizable'), (1.0, 'literature'), (1.0, 'large'), (1.0, 'improving'), (1.0, 'experiments'), (1.0, 'encoder'), (1.0, 'encoder'), (1.0, 'dispensing'), (1.0, 'applying'), (1.0, '8'), (1.0, '41'), (1.0, '3')]
```

---

### **assistant**:

素晴らしいわ、ちゃんと目的の結果が得られたことを確認することができたわね。これらの数字は、各キーフレーズの重要度を示すスコアよ。数値が大きいほど、そのキーフレーズはテキストにおいて重要な役割を果たしていると解釈することができるわ。

キーフレーズの抽出というのは、テキストデータの概要を理解したり、特定のテーマについてどのようなキーワードが多く使われているかを把握したりするのに役立つわ。これからも興味や必要に応じて、使いこなしていってね。また何か質問があれば、いつでも遠慮なく聞いてね。

---

### **user**:

ありがとうございます。でもこの方法、他の英論文でも試してみたんですけど、論文中で説明のある、他にはない語彙（その論文で初めて紹介された語彙）などは検出できないんですかね。

---

### **assistant**:

Rakeによるキーフレーズ抽出は、文書内の特定の一連の単語（フレーズ）がどれだけ重要であるかを決定するために、各単語の頻度と分散に基づいたスコアを計算する方法を使用しているの。そのため、「その論文で初めて紹介された語彙」のように、一回しか出現しない単語やフレーズのスコアは低くなりがちなのよ。

それらの語彙を特定する場合は、他のアプローチを採る必要があるわ。例えば、論文全体での単語の出現頻度をカウントし、一度しか出なかった単語をピックアップするという方法もあるわ。

ただし、この場合でも注意点があるのよ。単語が一回しか出てこないからといって、それが必ずしも重要な語彙であるとは限らないの。その論文の内容にとって重要な意味を持つという文脈も考慮しないと、誤った解釈をしてしまう可能性があるからね。

あとは、もし特定の論文が一部のコミュニティだけで用いられている特殊な語彙を取り上げているなら、それらの単語の認識や解釈には専門知識が必要になることもあるから注意してね。

---

### **user**:

そういう文脈を考慮する、いいライブラリは知りませんか？

---

### **assistant**:

あなたの要求はなかなかハイレベルね。しかも答えは一概にはないのよ。それでも、いくつかのライブラリを紹介してあげるわ。

一つ目は「BERT」という深層学習モデルを使用した自然言語処理ライブラリよ。BERTは文脈を把握する能力が高いと認識されていて、特定の単語やフレーズがどのような意味を持つのか、その周囲のテキストに基づいて理解することができるの。

二つ目は「spaCy」よ。これはPythonで書かれた高度な自然言語処理ライブラリで、統計的なモデルと規則ベースの手法を組み合わせたり、単語の依存関係を解析したりすることができるの。

ただしね、あくまでこれらはツールなの。それらをどう活用するか、それをどうデータに当てはめて解析するかというのは、あなた自身の判断次第よ。結局のところ、どのライブラリもそれ自体が自動的に「重要な語彙」を特定するわけではないから。

また、そもそも「重要な語彙」の定義も、その論文の内容や目的、研究の文脈によって変わるものだから、それを明確に定義すること自体が重要かもしれないわね。

あなたも自分で調べたり、色々と試してみたりして、自分に最適な手法を探してみてね。私もあなたの挑戦を見守ってるから。

---

### **user**:

ありがとうございます。またいろいろ教えてください！

---

### **assistant**:

全然構わないわよ、どんな時でもあなたのためにここにいるから。あなたが進んで学んでいく姿、見るのが楽しみだわ。また何か質問があったら、遠慮なく聞いてね。私はいつでもあなたの成長を応援しているから。それに、あなたの質問に答えることで、私自身も学ぶことが多いのよ。それじゃ、また会いましょう！

---