MENU

python 利用されている文字が同じ言語の判定

import numpy as np
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import accuracy_score
import glob

# Unicodeのコードポイント頻度測定
def count_codePoint(str):
# Unicodeのコードポイントをアドレスとする配列を用意
counter = np.zeros(65535)

for i in range(len(str)):
# 各文字をUnicodeのコードポイントに変換
code_point = ord(str[i])
if code_point > 65535 :
continue
# 対応するアドレスの出現回数をインクリメント
counter[code_point] += 1

# 各要素を文字数で割って正規化
counter = counter/len(str)
return counter

# 学習データの準備 --- (*1)
index = 0
x_train =
y_train =
for file in glob.glob('./train/*.txt'):
# 言語情報の取得し、ラベルに設定 --- (*2)
y_train.append(file[8:10])
 
# ファイル内の文字列を連結後、Unicodeのコードポイント頻度測定し、入力データに設定 --- (*3)
file_str = ''
for line in open(file, 'r'):
file_str = file_str + line
x_train.append(count_codePoint(file_str))

# 学習する
clf = GaussianNB()
clf.fit(x_train, y_train)

# 評価データの準備 --- (*4)
index = 0
x_test =
y_test =
for file in glob.glob('./test/*.txt'):
# 言語情報の取得し、ラベルに設定
y_test.append(file[7:9])
 
# ファイル内の文字列を連結後、Unicodeのコードポイント頻度測定し、入力データに設定
file_str = ''
for line in open(file, 'r'):
file_str = file_str + line
x_test.append(count_codePoint(file_str))

# 評価する
y_pred = clf.predict(x_test)
print(y_pred)
print("正解率 = " , accuracy_score(y_test, y_pred))

実行結果

f:id:hanamichi_sukusuku:20210113211836p:plain

このプログラムではラテン文字(ローマ字)を使用する英語、スペイン語、ドイツ語の言語判定を行う。

前提としてtrainとtestというフォルダを同じ階層に作成し、その中にwikipediaから収集した各言語のデータを学習用(train)に3つ、テスト用(test)に1つずつ格納してある。

 

学習データの用意

index = 0
x_train =
y_train =
for file in glob.glob('./train/*.txt'):
  # 言語情報の取得し、ラベルに設定 --- (*2)
  y_train.append(file[8:10])
 
  # ファイル内の文字列を連結後、Unicodeのコードポイント頻度測定し、入力データに設定 --- (*3)
  file_str = ''
   for line in open(file, 'r'):
     file_str = file_str + line
  x_train.append(count_codePoint(file_str))

globモジュールではglob.glob()で引数に取得したいファイル名のパスを与えることでそのファイル名を取得できる。

glob.glob('./train/*.txt')では./同じ階層のtrainフォルダ(学習用の各言語のデータ)の中身の.txtとマッチするファイル名を全て取得している。

 

file[8:10]ではfileには./train/de_cat.txtや./train/es_dog.txtというファイル名が入っており、インデックス番号の8番目と9番目の文字を取得してラベルデータとして使用している。

 

open(file, 'r')では変数lineに1行ずつ文章を格納するのでfile_strに"を代入し空の変数を作成。そしてlineに格納されたfile内の文字列を連結してコードポイントの頻度を測定する関数の引数に渡す。返された値を学習用データの配列に追加。

 

コードポイントの頻度測定の関数

def count_codePoint(str):
  # Unicodeのコードポイントをアドレスとする配列を用意
  counter = np.zeros(65535)

  for i in range(len(str)):
  # 各文字をUnicodeのコードポイントに変換
   code_point = ord(str[i])
    if code_point > 65535 :
      continue
  # 対応するアドレスの出現回数をインクリメント
   counter[code_point] += 1

 # 各要素を文字数で割って正規化
 counter = counter/len(str)
  return counter

 

引数で測定する文字列を取得。

Unicodeのコードポイント分0の要素を持った配列を作成。

文字列の数だけ処理を行い、先頭から出現頻度をカウントしていく。

 

counter/len(str)で全体の文字数に対してどの割合なのかの数値にするため各要素を文字数で割る。

出現頻度の割合が格納された配列を呼び出し元に返す。

 

学習

clf = GaussianNB()
clf.fit(x_train, y_train)

 

評価データの準備

index = 0
x_test =
y_test =
for file in glob.glob('./test/*.txt'):
  # 言語情報の取得し、ラベルに設定
y_test.append(file[7:9])
 
  # ファイル内の文字列を連結後、Unicodeのコードポイント頻度測定し、入力データに設定
file_str = ''
  for line in open(file, 'r'):
   file_str = file_str + line
x_test.append(count_codePoint(file_str))

学習用データと同じようにtestフォルダからファイル名の一覧を取得。

テスト用のラベルデータにファイル名からそれぞれde,es,enを格納。

open()でファイルからデータを取得して1行ずつ取得するデータを連結。

file_str = "は空の変数を作成している。

文字の出現頻度を測定する関数にデータを格納した変数を渡す。

返り値をテストデータに追加。

 

評価

y_pred = clf.predict(x_test)
print(y_pred)
print("正解率 = " , accuracy_score(y_test, y_pred))