今さらながら自然言語分類を試してみる①(データ準備)

はじめに

文章を固定長のベクトルで表現することにチャレンジ

使用するデータ

livedoor ニュースコーパス」を使用させて頂く。
「ldcc-20140209.tar.gz」をダウンロードして「ldcc-20140209.tar」に名前を変更して解凍する。

tar xvf ldcc-20140209.tar

「text」フォルダが作成され、さらにその中に「dokujo-tsushin」「it-life-hack」「kaden-channel」「livedoor-homme」「movie-enter」「peachy」「smax」「sports-watch」「topic-news」の9個のフォルダが作成される。
それぞれのフォルダ内には各記事のデータが含まれるテキストファイルが入っている。
また、それぞれのフォルダ内に「LICENSE.txt」というテキストファイルも含まれる。開いて読んだのちに今回はファルダ外の任意の場所に移動させる。

ファイルの読み込み

1行目、2行目は記事のURL、日付なので3行目から読み込む。

with open("dokujo-tsushin\dokujo-tsushin-6877711.txt", encoding="utf-8_sig") as f:
    next(f)
    next(f)
    #全角スペースや改行の削除
    w = f.read().replace('\u3000','').replace('\n','')

または

with open("dokujo-tsushin\dokujo-tsushin-6877711.txt", encoding="utf-8_sig") as f:
    a = f.readlines()
    aa = ''.join(a[2:])
    #全角スペースや改行の削除
    w = aa.replace('\u3000','').replace('\n','')

下のほうがわずかに速い。

形態素解析と単語のID化→その後保存

形態素解析は「Janome」ライブラリを使用。(pipでインストール可能)
Janome」と「MeCab」の違いは公式ページに記載あり。

解析結果の精度は。
辞書,言語モデルともに MeCab のデフォルトシステム辞書をそのまま使わせていただいているため,バグがなければ,MeCab と同等の解析結果になると思います。
形態素解析の速度は。
文章の長さによりますが,手元の PC では 1 センテンスあたり数ミリ〜数十ミリ秒でした。mecab-python の10倍程度(長い文章だとそれ以上)遅い,というくらいでしょうか。今のところは,大量の文書を高速にバッチ処理する用途には向いていません。MeCab をお使いください。

インストールが簡単なので「Janome」を選択した。
単語のID化は「collections」の「Counter」を使用。

import glob
import os
from collections import Counter
from janome.tokenizer import Tokenizer

tk = Tokenizer()
freq = Counter()

category = []   #カテゴリー
news_txt = []   #記事

for fn in glob.glob('*/*.txt'):
    (dirname,filename)=os.path.split(fn)
    
    with open(fn, encoding="utf-8_sig") as f:
        a = f.readlines()
        aa = ''.join(a[2:])
        #全角スペースや改行の削除
        w = aa.replace('\u3000','').replace('\n','')

    t = tk.tokenize(w)
    l = [p.surface for p in t]

    freq.update(set(l))
    category.append(dirname)
    news_txt.append(l) 

#単語IDを出現回数の順に並べる(collections.Counterからlistに変換される)
common = freq.most_common()

#最小出現回数
min_df = 10

#最大出現回数
max_df = int(common[0][1] * 0.3)

#辞書を作成
vocab = sorted([t for t, c in common if c>=min_df and c < max_df])
index = {t:i+1 for i,t in enumerate(vocab)}

#学習用データと評価用データに分ける
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(news_txt, category, test_size=0.3)

#データをcsvで保存する(ヘッダーなし)
termc = max(index.values()) + 1

with open('train.csv', 'w') as f:    
    for i in range(len(X_train)):
        t = X_train[i]
        #辞書から単語IDのリストにする
        v = [index[c] for c in t if c in index]
        #リストの長さを250にそろえる
        if(len(v)<250):
            w = v + [termc] * int(250 - len(v))
        else:
            w = v[:250]
        f.write(Y_train[i])
        f.write(',')
        f.write(','.join(list(map(str,w))))
        f.write('\n')

with open('test.csv', 'w') as f:    
    for i in range(len(X_test)):
        t = X_test[i]
        #辞書から単語IDのリストにする
        v = [index[c] for c in t if c in index]
        #リストの長さを250にそろえる
        if(len(v)<250):
            w = v + [termc] * int(250 - len(v))
        else:
            w = v[:250]
        f.write(Y_test[i])
        f.write(',')
        f.write(','.join(list(map(str,w))))
        f.write('\n')    

参考文献

MXNetで作る データ分析AIプログラミング入門

MXNetで作る データ分析AIプログラミング入門