ヤフーニュースのタイトルからPythonでカテゴリ予測[いろいろ前処理編]

ヤフーニュースのカテゴリ予測の記事はこれで3記事目です。長いですね。

もしまだ前の2記事を読んでいない方は先にそっちを読んでおいてください。

https://magarikado0.com/yahoo-news-morphological-analysis/

今回すること

前回はjanomeで形態素解析をしてヤフーニュースのタイトルを名詞と形容詞だけにしましたね。

ということで今回はそこからさらにアルファベットの大文字と小文字や半角と全角とかを統一したりして前処理をします。

(これ前の記事に入れたほうが良かったかも)

はい、じゃあいきましょう

 

前処理のコード書きますよ

これまでの二回とは別にファイルに書いてください

とりあえず見てみてください

from mojimoji import zen_to_han#全角を半角にするメソッドをインポート
import string   #これも文字列関係のやつです
table = str.maketrans( '', '',string.punctuation)#記号を消すためのテーブル作成
f = open("titles.txt","r")#前回titles.txtに保存したリストを取得
titles= []
for x in f:
    titles.append(x.rstrip("\n"))
texts=[[word for word in document.lower().translate(table).split()]for document in titles]#タイトルに処理をしてから区切りを入れる
for i in range(len(texts)):#さらにいろいろ前処理
    for k,name in enumerate(texts[i]):
        if name.isdigit()==True:#数字はすべて0にする
            texts[i][k]="0"
        texts[i][k]=mojimoji.zen_to_han(texts[i][k])#半角にできるものは半角にする
        if len(texts[i][k])==1:#長さが1のものは消す
            texts[i][k]=""

はい、まず前半はこんな感じですね。

上から順番に解説していきまあす。

table = str.maketrans( '', '',string.punctuation) 

ですがいったんここはとばします。あとでにします。

titles.txtから名詞と形容詞だけのタイトルのリストを取得

f = open("titles.txt","r")#前回titles.txtに保存したリストを取得
titles= []
for x in f:
    titles.append(x.rstrip("\n"))

ここではいつもと同じようにテキストファイルからリストを取得しています。

前回形態素解析で名詞と形容詞だけになってしまったヤフーニュースのタイトルたちですね。今回はさらにきれいにしていきます

単語ごとに分割して2次元のリストを作る

texts=[[word for word in document.lower().translate(table).split()]for document in titles]#タイトルに処理をしてから区切りを入れる

一行ですけどいろいろ詰め込まれてますね。

これは見ての通り二重ループになっています。

titlesリストのなかの一つ一つのタイトルをdocumentとしてそれを.lower()で全部小文字に統一して、.translate(table)をして(これは後で説明します)、split()で空白ごとに別々にしてリストを作っています。

これでtextsという2次元のリストができました。

str.translate()って?

さっきtable = str.maketrans( ”, ”,string.punctuation)をしましたね。(「”」はダブルコーテーションじゃなくてシングルコーテーション二つです)

このmaketransとtranslateはセットで文字列の変換に使われるもので、maketransで変換の内容を定義してそれをtranslateで引数として使えば文字列が変換できます。

table=str.maketrans("変換前の文字列","変換後の文字列","削除したい文字列")
result=text.translate(table)

このように使います

str.split()って?

これは空白などの区切り文字があるところで文字列を分割してリストを作るものです。

たとえば

greet="おはよう こんにちは こんばんは おやすみ"
print(greet.split())
# ['おはよう','こんにちは','こんばんは','おやすみ']

こんな感じです。

前回タイトルを名詞と形容詞だけにしたときに単語の間に空白を入れていたと思います。それは.split()をつかうためです。

いろいろ前処理をする

for i in range(len(texts)):#さらにいろいろ前処理
    for k,name in enumerate(texts[i]):
        if name.isdigit()==True:#数字はすべて0にする
            texts[i][k]="0"
        texts[i][k]=mojimoji.zen_to_han(texts[i][k])#半角にできるものは半角にする
        if len(texts[i][k])==1:#長さが1のものは消す
            texts[i][k]=""

ここではさっき作った二次元のリストのそれぞれの要素に対して二重ループを使っていろいろ処理を行っていっています。

str.digit()って?

str.isdigit()というのはそのstr数字だったらTrueを返しそうでなければFalseを返すメソッドです。
よって数字だったらそれをすべて0にするということです。

なぜ全部0にするかというと数字自体に特に意味はないからです。
だったら0にするんじゃなくて消せばいいんじゃないかという人もいるかもしれませんが、数字自体に意味はなくても数字があるかどうかに意味があることがあるからです。

たとえば経済とスポーツのカテゴリだったらまあスポーツも多いかもしれませんが、私は経済のほうが数字は多いんじゃないかなと思います。(実際どうかは調べてません)

まあどっちが多いにしたって何かしら影響が出てくるんじゃないかということで0にしています。

 

あと下から2行目からは、長さが1の単語のものは消すというものです。
これをしとかないとあなた絶対存在価値ないでしょみたいな1文字がいっぱいでてきて精度に影響してきます。

 

とりあえずデータの前処理は終わり

いやー、やっぱり機械学習で一番大変なのはデータの前処理な気がする。

特に自然言語処理の前処理は大変。ひゃーー。

けど後はもうサラーっと行けると思うので頑張りましょー。

 

ありがとうございました