Python -JANOME快速拆解日文的方法

Sean Yeh
Python Everywhere -from Beginner to Advanced
16 min readMar 18, 2022
Rui Fang, Taiwan, photo by Sean Yeh

當我們聽到「すもももももももものうち」的一句話時,能分出意思是什麼嗎?我想,除非你不懂日文,不然對於這樣一句話應該不會太難。人類對於自然語言本身,就有能力可以理解與分辨出中間的差異性。但是,對電腦來說,這個繞口令般的句子,看起來就像是一堆「も」的集合,如果要透過電腦來分析人類的句子,就必須讓電腦可以分出哪幾個「も」應該放在一起,而哪幾個「も」又必須與其他的「も」分開。

要能夠理解上面的句子,就必須透過自然語言處理裡面的語素分析了。

自然語言處理(NLP,全名Natural Language Processing)這門科學是將人類語言中各種微妙差異以及模糊不清的含義,轉換成精確且具備結構化,讓電腦可以處理的型態。到目前為止NLP應用在垃圾郵件檢查、自動翻譯、聲音辨識、搜尋引擎問題以及預測使用者輸入文字等等方面。本文要討論的「語素分析」屬於這個領域中的一個基本應用。

語素分析

我們平常說的話,被稱作是自然語言。相對於自然語言者,為機器語言(程式語言)。透過自然語言寫成的句子中,「語素」(morpheme)可說是其中的最小單位了。

而所謂語素分析,是透過分析方式將自然語言寫成的句子分割成一個個「語素」,並確定每個詞的詞性和它的變化。

語素分析是基於目標語言的語法和被稱為字典的單詞的部分單詞等信息,從自然語言中的文本數據(句子)中提取的,沒有語法信息的註釋。語素(一般來說,具有語言中的意義),以及區分每個語素部分的工作。

什麼是JANOME

Janome是日文「蛇の目」的意思,是一個透過Python編寫的日語形態分析引擎,包括內建的字典和語言模型,是自然語言處理的一種,可以被簡單安裝的一個元件庫。用於假名漢字轉換、全文檢索、機器翻譯等。由於Janome的字典和模型都使用 MeCab 的預設系統字典,其分析結果將與 MeCab 相同。

Janome的原始下載PYPI區與英文說明文件。執行Janome套件需要至少Python3.7以上的版本。

安裝方式

安裝Janome很間單,在terminal中使用 pip 指令就可以安裝Janome。

$ pip install janome

基本使用方式

Janome可以將日文字串轉成一組 tokens(詞彙和標點符號)。以下面原始檔來說,我們將前面提到的字串「すもももももももものうち」進行分析:

先匯入janome套件。如果沒有錯誤訊息的話,就表示前面的pip安裝成功了。

import janome

接下來,要janome套件中選用tokenizer,我們要使用裡面的Tokenizer 這項工具。

from janome.tokenizer import Tokenizer

使用Tokenizer 的時候需要先實體化。我們建立一個 Tokenizer 實例(Tokenizer()),並指定一個變數t

t = Tokenizer()

假定我們有一個字串「すもももももももものうち」,被指定為變數sample。

sample='すもももももももものうち'

使用 Tokenizer 實例中的tokenize方法分析sample裡面的字串。並且試圖將結果印出來。

tokens = t.tokenize(sample)
print(tokens)

結果,我們發現直接將tokens印出來是看不到內容的:

只能看到一個物件。

我們可以利用迴圈來解決這個問題。再次使用 Tokenizer 實例中的tokenize方法(t.tokenize)並利用for迴圈把「すもももももももものうち」字串的變數sample轉成 tokens詞彙和標點符號。

for token in t.tokenize(sample):
print(token)

執行後的結果

執行上面的程式碼後,可以發現Janome將「すもももももももものうち」的字串,分割為下面的結果。

並且提供每個語素的詞性語發音方式。最左邊為分割出來的各個語素「すもも」、「」、「もも」、「」、「もも」、「」、「うち」,除此之外還提供了其他的資訊。

以第一行來說「すもも」為分割除來的語素,第二行開始依序為:詞性(名詞、動詞、形容詞等)、詞性的細分類、原形、訓讀發音、音讀發音等等。

すもも	名詞,一般,*,*,*,*,すもも,スモモ,スモモ

其他詳細功能可以參考英文說明文件或是日文說明文件

進階使用方式

到目前為止,我們可以把一句日文字串,拆解為不同的詞彙(既然可以拆解一句話,也當然可以拆解一段話,甚至於一篇文章或者是一本書)。接下來,還可以對它做進一步的分析。再回到前面提的すもも字串。如果想要近一步從(t.tokenize)分割出的結果中,取出部分資料,該如何處理?

surface 取出語素

可以使用surface來取出分割出來的語素。

for token in t.tokenize(sample):
print(token.surface)

結果如下,只顯示出字串中的所有語素。

part_of_speech 取出詞性

如果想要取出語素的各種詞性,可以使用part_of_speech。

for token in t.tokenize(sample):
print(token.part_of_speech)

結果如下,顯示出所有語素的詞性以及詞性的細分類。

取出單字的詞素表面、詞性、讀音等

對於分析的對象,Token可以透過以下幾種不一樣的方法產出結果:

  • surface (詞素表面)
  • part_of_speech (詞性)
  • infl_type (活用型)
  • infl_form (活用形)
  • base_form (基本形)
  • reading (讀音)
  • phonetic (發音)
  • node_type

讓我們仔細看看分類的部分。

from janome.tokenizer import Tokenizert = Tokenizer()text = '令和元年'for token in t.tokenize(text):
print('-'*40)
print('詞素表面:', token.surface)
print('詞性:', token.part_of_speech.split(',')[0])
print('詞性細分類1:', token.part_of_speech.split(',')[1])
print('詞性細分類2:', token.part_of_speech.split(',')[2])
print('詞性細分類3:', token.part_of_speech.split(',')[3])
print('活用型:', token.infl_type)
print('活用形:', token.infl_form)
print('原型:', token.base_form)
print('讀音:', token.reading)
print('發音:', token.phonetic)
print('-'*40)

結果:

split 分割語素的詞性

為了近一步使用這些詞性來進行分析,我們可以先透過split來將詞性用逗號( , )分別出來。

for token in t.tokenize(sample):
print(token.part_of_speech.split(','))

結果,可以看到下面呈現的是一個個list串列,串列裡面則是一個個獨立開來的詞性。(其中 * 表示空白)

我們可以使用如下方式取出第ㄧ項詞性:

for token in t.tokenize(sample):
print(token.part_of_speech.split(',')[0])

結果只呈現第ㄧ項的詞性。

暸解以上的使用方式後,就可以正式進入分析階段。

分析:取出名詞

要取出名詞語素,只需要在前面的方式上加一個if判斷式。透過下面的函式可以取出「すもももももももものうち」的字串中屬於名詞的詞彙。

sample='すもももももももものうち't = Tokenizer()for token in t.tokenize(sample):
if token.part_of_speech.split(',')[0]=='名詞':
print(token)

結果:只顯示出字串中屬於名詞的詞彙。

分析:僅取出一般名詞

如果要再進一步篩選出一般名詞的話,可以在if的條件裡面加上另一個條件。

for token in t.tokenize(sample):
if (token.part_of_speech.split(',')[0]=='名詞')&(token.part_of_speech.split(',')[1]=='一般'):
print(token)

結果:

分析:取出多種名詞

近一步的把上面的概念寫成一個函式,以便於以後使用方便。在函式裡面可以放入url參數。這個參數代表的是想要被分析的字串,前面我們提到過,Janome可以既然分析一個字串,當然可以分析整段文章。因此,可以把一段文章存在一個txt文字檔中,並且透過open的方式一行行的讀入文字,並且分析。

下面的函式不僅可以取出名詞,並且它的細分類為「一般」、「固有名詞」、「サ変接続」、「形容動詞語幹」,而且我們在後面將各種符號都排除掉'*', '.', '%', '(', ')', ',', '?', '!', '......'

def get_words(url):
"""取出名詞"""
t = Tokenizer()
word=[]
with open(url,'r') as f:
for line in f:
#print(line)
for token in t.tokenize(line):
if(token.part_of_speech.split(',')[0]=='名詞') & (token.part_of_speech.split(',')[1] in ['一般','固有名詞','サ変接続','形容動詞語幹']):
if(token.surface not in ['*','.','%','(',')',',','?','!','......']):
word.append(token.surface)

return word

自定義的詞庫

此外,Jamone也可以使用自定義的詞庫。只要把詞庫存在一個csv檔案裡面。就可以讓實體化的Tokenizer使用這個詞庫。下面是csv的檔案:

在使用的時候,要在Tokenizer的地方加入csv檔案做為參數。例如下面程式碼中的userdic.csv檔案,就是存成csv檔案的詞庫。

t = Tokenizer("userdic.csv", udic_enc="utf8")  for token in t.tokenize(src_url):
if token.part_of_speech.split(',')[0]=='名詞':
print(token)

應用:計算單字出現頻率

前面已經使用Jamone將字串分割成一個個的語素。接下來就可以來計算出該文章或段落中,每個字出現的頻率。雖然我們無法單純以某一個詞彙頻繁的出現在文章中,就一口斷定該文章內容主旨與那個詞彙有關。然而,透過這個方式,多少可以探知該文章的主要內容在討論什麼。

計算出現次數需要引入collections套件,collections套件為Python內建的套件,不需要另外安裝。

import collections

collections套件的用法

在正式開始前,我們先使用一個串列來測試一下collections套件。

fruits = ['apple','banana','cherry','dates','elderberry','cherry','apple','apple','cherry','cherry','banana','banana','banana',]

再使用Counter方法來計算fruits中同樣水果出現的次數。

import collectionscounter = collections.Counter(fruits)print(counter)

印出來的結果如下,可以看到banana出現4次、cherry出現4次、apple出現3次等等:

透過most_common還可以找出次數排名前幾名的字串。

import collectionscounter = collections.Counter(fruits)
most_comm = counter.most_common(3)
print(most_comm)

如上面程式碼,這樣子可以找到次數最多的前三名:

套用到Janome

暸解了collections上述的用法之後,就可以開始套用到前面的Janome程式碼中。

在下面的程式碼裡面,我們修改前面的程式碼,並且加上一個words串列( words =[] )。這個串列用來儲存janome分割出來的詞素。我們透過append的方式,將詞素的表面詞素(token.surface)一個個的添加入words串列中。再透過 collections.Counter 來計算出每個詞素的出現頻率,最後使用 counter.most_common(2) 找出頻次最高的前兩名詞素。

import collections
from janome.tokenizer import Tokenizer
sample='すもももももももものうち'
t = Tokenizer()
words =[]
for token in t.tokenize(sample):
words.append(token.surface)

counter = collections.Counter(words)
print(counter)
print('-'*30)
most_comm = counter.most_common(2)
print(most_comm)

執行上面的程式碼,會得到下面的結果:

從結果可以看出,在字串中出現的頻率最高的兩項為「もも」與「も」。當然,您可以將字串改成更長更大的一段文字,看到得出的結果可能會更有感覺。

應用:畫出雲圖

透過WordCloud套件可以視覺化前面的分析結果。WordCloud需要透過pip安裝,並且引入套件。

from wordcloud import WordCloud

此外,由於WordCloud的格式與前面我們使用Janome產出以逗點(, )分割詞素的方式有點不同。需要先進行格式上的轉換,才可以使用。

WordCloud的格式,是以空白鍵區分字串。因此,我們要先在分字串與字串之間加上空白鍵,才可以使用WordCloud進行視覺化。

我們利用 join在分字串與字串之間加上空白鍵:

' '.join(words)

另外,在WordCloud裡面可以放入各種參數:

  • background_color:圖片背景顏色
  • width:圖片寬度
  • height:圖片高度
  • random_state:隨機參數
  • font_path:字體路徑

接著就依照上面的說明,逐一加入WordCloud()裡面。最後再透過generate方法產出圖片,並且輸出(to_file)成為png圖檔。

words_formated = ' '.join(words)
font_path= './font/NotoSansJP-Bold.otf'
visual_output = WordCloud(font_path=font_path, background_color='white',width=400, height=400, random_state=1).generate(words_formated)visual_output.to_file('./output.png')

值得注意的是,這裡的字體路徑(font_path)一定要指定,因為Janome是以分析日文為主,一般我們的電腦裡面可能沒有日文字體,必須先在電腦上面安裝日文字體,才有辦法使用。不然產出的圖片會出現一個個的方框。

執行上面的程式碼後,將產出下面的圖檔:

在這裡沒有辦法感受到,原則上詞彙出現的頻率越高,該詞彙就會用越大的字體顯示。

因此,我們可以利用同樣的程式碼,拿一段日本歌星米希亞的「僕はペガサス 君はポラリス」的歌詞放進去試試,下面就是歌詞分析後的結果:

可見這首歌主要在說的是「believe」、「love」、「ポラリス」、「ペガサス」。可能歌詞主要是在述說對方,所以「ペガサス」的字體比「ポラリス」小一點。

其他應用

Janome套件不只是上面的應用方式,如果您在經營電子商務,還可以針對網路上使用者對產品的各種評價,來進行客戶回饋分析,藉以優化自家的產品。

在作法上,可先將網路上使用者的評價蒐集到一個檔案裡面(例如csv檔案),再透過Pandas讀取檔案,並產生DataFrame。接著就可以針對DataFrame使用前面提到的Janome來分析各個單字的出現頻率。

筆者會發現這個套件,是因為個人正在學習日語。透過這個套件,不論文章大小,可以「瞬間」將整篇文裡面的每個字,不論是讀音與詞性全部查出來,對於學習日語的我來說是很方便的。除了 Janome這樣的套件外,如果您正在學習其他外語,也可以試著上網找找看,符合該語言的詞素解析套件。

--

--

Sean Yeh
Python Everywhere -from Beginner to Advanced

# Taipei, Internet Digital Advertising,透過寫作讓我們回想過去、理解現在並思考未來。並樂於分享,這才是最大贏家。