こんにちは!
テービーテックの村松です。
Kaggleやってみよう第2弾は「Sentiment Analysis on Movie Reviews」映画レビューの感情分析です。
自然言語系の課題に取り組んだことがなかったので選んでみました。
いつも以上に覚束なくなりそうですが、Notebooksの偉大な先輩方の胸を借りてチャレンジしてまいります。
さっそくやってみよう
例のごとく
・GoogleColab
・Python3
で作業していきます。
データの読み込み
こちらから
・train.tsv
・test.tsv
・sampleSubmission.csv
をダウンロードしてきます。
sampleSubmission.csvは提出ファイルの例ですね。
#必要なライブラリのインポート import numpy as np import pandas as pd #読み込み #タブ区切りのファイルなのでsep='\t'と指定します。 train = pd.read_csv('train.tsvのパス', sep='\t') test = pd.read_csv('test.tsvのパス', sep='\t') print(train.shape, test.shape)
##結果 (156060, 4) (66292, 3)
中身の確認
train.head()
test.head()
データセットは丸々ひとつのレビュー文がひとつずつ入ってるわけではなくて、1文を何パターンかのフレーズに分割して格納されているようです。
trainにはフレーズごとに感情ラベル(今回の教師データ)が割り当てられています。
ラベルの意味としては、
1→否定的な感情
2→やや否定的な感情
3→中立
4→やや肯定的な感情
5→肯定的な感情
となっています。
testのフレーズに対してこれらを予測していきます。
試しに1フレーズ中身を確認してみましょう。
train['Phrase'][0]
##結果 'A series of escapades demonstrating the adage that what is good for the goose is also good for the gander , some of which occasionally amuses but none of which amounts to much of a story .'
後半部分が「面白いと感じるところは少ない(意訳)」って意味合いなので「1」判定のようですね。
何の映画なのかは知らないんですが、結構辛口ですね・・・。
前処理
さて、このままの文章・単語のままでは都合が悪いので前処理を行っていきます。
自然言語系の前処理のざっくりとした大まかな流れは、
・余分な要素の排除
・小さな単位(文字・単語など)にバラバラにする
・文字・単語のベクトル化(文字を数字にする)
となります。
Notebooks先輩達が行っている前処理を一通りやってみます。
今回は、適当に抜き出した1フレーズを使って前処理の動作を確認していきましょう。
#1フレーズを抜出し sent = train['Phrase'][156021] sent
##結果 "-LRB- Tries -RRB- to parody a genre that 's already a joke in the United States ."
HTMLコンテンツの削除
from bs4 import BeautifulSoup review_text = BeautifulSoup(sent).get_text() review_text
"-LRB- Tries -RRB- to parody a genre that 's already a joke in the United States ."
Webから取得した文章などの場合、HTMLのコンテンツが含まれている場合に行う処理です。
今回の文には含まれていないのでどう変わったかわかりにくいですね・・・。
後日「本日の関数」で詳しく取り上げますね。
アルファベット以外の文字を削除
import re review_text = re.sub("[^a-zA-Z]"," ", review_text) review_text
##結果 ' LRB Tries RRB to parody a genre that s already a joke in the United States '
「-」や「.」などが無くなりましたね。
単語ごとにばらす
import nltk from nltk.tokenize import word_tokenize nltk.download('punkt') words = word_tokenize(review_text.lower()) words
##結果 ['lrb', 'tries', 'rrb', 'to', 'parody', 'a', 'genre', 'that', 's', 'already', 'a', 'joke', 'in', 'the', 'united', 'states']
#単語の数を確認 len(words) ##結果 16
16個の単語にばらせました。
細切れになったものを見出し語化
見出し語化というのは単語が複数形になっていたり過去形になっていたりするものを基本形に戻すことを指します。
from nltk.stem import WordNetLemmatizer lemmatizer = WordNetLemmatizer() nltk.download('wordnet') lemma_words = [lemmatizer.lemmatize(i) for i in words] lemma_words
##結果 ['lrb', 'try', 'rrb', 'to', 'parody', 'a', 'genre', 'that', 's', 'already', 'a', 'joke', 'in', 'the', 'united', 'state']
先ほどの単語一覧と比べてみると'tries'が 'try'となったり、 'states'が 'state'になっていますね。
自然言語の前処理方法は他にも色々ありますし、日本語の場合はまた具合が違ったりするので追々チャレンジしていきたいです。
関数化
ここまでをtrainとtestに適用するために関数化します。
#関数化 from tqdm import tqdm def clean_sentences(df): reviews = [] for sent in tqdm(df['Phrase']): #HTMLコンテンツの削除 review_text = BeautifulSoup(sent).get_text() #アルファベット以外の文字を削除 review_text = re.sub("[^a-zA-Z]"," ", review_text) #文章を細切れにする words = word_tokenize(review_text.lower()) #細切れになったものを見出し語化, レンマ化 lemma_words = [lemmatizer.lemmatize(i) for i in words] reviews.append(lemma_words) return(reviews)
#trainとtestに適用
train_sentences = clean_sentences(train)
test_sentences = clean_sentences(test)
0%| | 0/156060 [00:00<?, ?it/s]/usr/local/lib/python3.6/dist-packages/bs4/__init__.py:273: UserWarning: "b'.'" looks like a filename, not markup. You should probably open this file and pass the filehandle into Beautiful Soup. ' Beautiful Soup.' % markup) 66%|██████▋ | 103589/156060 [00:42<00:20, 2511.30it/s]/usr/local/lib/python3.6/dist-packages/bs4/__init__.py:273: UserWarning: "b'drive'" looks like a filename, not markup. You should probably open this file and pass the filehandle into Beautiful Soup. ' Beautiful Soup.' % markup) 100%|██████████| 156060/156060 [01:04<00:00, 2409.83it/s] 100%|██████████| 66292/66292 [00:26<00:00, 2490.07it/s]
これでフレーズ内の単語を綺麗に整えるところまで完了しました。
ちょっと長くなってきたので本日はここまで。
次回はこの単語たちを数字に変換してLSTMを使って学習していきます。
お楽しみに。