
はじめに
Kaggleは、英語のページしかありません。そこで、日本語で読みたい方向けに記事を作成しました。
Natural Language Processing with Disaster Tweetsの概要の説明が前の記事で済みました。
次に実際にGoogle Colabを動かしてみましょう(https://www.kaggle.com/code/shahules/basic-eda-cleaning-and-gloveを参考にして説明)。
Google Colaboratoryについては知りたい方は、以下のブログ記事を参考にしてください。
>>Google Colaboratoryとは? いつできた? mount、ファイルの読み込み等の使い方
>>Google Colaboratoryよく使う便利なショートカットキー
データのインポート
必要なものをインポートします。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline
ドライブをマウントしてください。
from google.colab import drive
drive.mount('/content/drive')
そして、データをインポートします。
train = pd.read_csv('/content/drive/MyDrive/kaggle/Natual Language/train.csv')
test = pd.read_csv('/content/drive/MyDrive/kaggle/Natual Language/test.csv')
sub = pd.read_csv('/content/drive/MyDrive/kaggle/Natual Language/sample_submission.csv')
注意:‘/kaggle/Digit Recognizer/train.csv’←の部分はドライブのフォルダ構成によって内容が異なるので注意してください。



EDA
trainのtargetの数を可視化します。
t = train.target.value_counts()
sns.barplot(t.index,t)
targetが0(災害なし)のツイートが1(災害のツイート)よりも多いことがわかります。

次に、ツイートの文字数を可視化します。
まず、targetが1のtextの文字数を見てみます。
train_len_1 = train[train['target']==1]['text'].str.len()
train_len_1

そして、targetが0のtextの文字数を見てみます。
train_len_0 = train[train['target']==0]['text'].str.len()
train_len_0

textの文字数のヒストグラムを見てみます。
fig,(ax1,ax2) = plt.subplots(1,2,figsize=(10,5))
ax1.hist(train_len_1,color='red')
ax1.set_title('disaster_tweets')
ax2.hist(train_len_0,color='blue')
ax2.set_title('Not disaster_tweets')
fig.suptitle('Characters in tweets')
plt.show()

ツイートのtextの単語数を可視化します。
まず、targetが1のtextの単語数を見てみます。
train_len_1 = train[train['target']==1]['text'].str.split().map(lambda x: len(x))
train_len_1

そして、targetが0のtextの単語数を見てみます。
train_len_0 = train[train['target']==0]['text'].str.split().map(lambda x: len(x))
train_len_0

textの単語数のヒストグラムを見てみます。
fig,(ax1,ax2) = plt.subplots(1,2,figsize=(10,5))
ax1.hist(train_len_1,color='red')
ax1.set_title('disaster tweets')
ax2.hist(train_len_0,color='blue')
ax2.set_title('Not disaster tweets')
fig.suptitle('Words in a tweet')
plt.show()

ツイート内の各単語の平均の文字数を可視化します。
まず、targetが1のtextの各単語の文字数を見てみます。
word_1 = train[train['target']==1]['text'].str.split().apply(lambda x : [len(i) for i in x])
word_1

そして、targetが0のtextの各単語の文字数を見てみます。
word_0 = train[train['target']==0]['text'].str.split().apply(lambda x : [len(i) for i in x])
word_0

textの各単語の平均の文字数のヒストグラムを見てみます。
fig,(ax1,ax2) = plt.subplots(1,2,figsize=(10,5))
sns.distplot(word_1.map(lambda x : np.mean(x)),ax=ax1,color='red')
ax1.set_title('disaster')
sns.distplot(word_0.map(lambda x : np.mean(x)),ax=ax2,color='blue')
ax2.set_title('Not disaster')
fig.suptitle('Average word length in each tweet')

次は、textを単語ごとに区切って分析してみます。
単語ごとのリスト化した関数を作成します。
def create_corpus(target):
corpus = []
for x in train[train['target'] ==target]['text'].str.split():
for i in x:
corpus.append(i)
return corpus
targetが0のtextを単語ごとに区切って、表示します。
corpus = create_corpus(0)
corpus

自然言語処理の解析の精度を上げるために、不要な記号や単語等をデータセットから除去する必要があります。
そこで、ツイートに含まれるストップワードを抽出します。
ストップワードとは、情報量が少ない単語,出現頻度が少ない単語,タスクに関係が無い単語です。日本語でいうと、「は」、「です」等です。
from nltk.corpus import stopwords
import nltk
nltk.download('stopwords')
stop = set(stopwords.words('english'))
from collections import defaultdict
dic = defaultdict(int)
for word in corpus:
if word in stop:
dic[word]+=1
なお、defaultdictは、どのようなキーがきても指定したデフォルト値を初期値として要素を追加します。
dicにストップワードとその数を格納しているので、見てみます。

上位10のストップワードを表示します。
top = sorted(dic.items(),key = lambda x:x[1],reverse=True)[:10]
top

こちらを可視化してみます。
x,y = zip(*top)
plt.bar(x,y)

次は、targetが1のtextのストップワードを可視化してみます。
corpus = create_corpus(1)
dic = defaultdict(int)
for word in corpus:
if word in stop:
dic[word]+=1
top = sorted(dic.items(), key = lambda x : x[1],reverse=True)[:10]
x,y = zip(*top)
plt.bar(x,y)

次は、句読点を見てみます。
targetが1のtextの句読点を確認します。
corpus = create_corpus(1)
dic = defaultdict(int)
import string
special = string.punctuation
for i in (corpus):
if i in special:
dic[i]+=1

可視化してみます。
plt.figure(figsize=(10,5))
x,y = zip(*dic.items())
plt.bar(x,y,color='red')

次は、targetが0のtextの句読点を可視化します。
plt.figure(figsize=(10,5))
corpus = create_corpus(0)
dic = defaultdict(int)
for i in (corpus):
if i in special:
dic[i]+=1
x,y = zip(*dic.items())
plt.bar(x,y,color='blue')

さて、今度は、単語上位40を可視化(ストップワードを除く)してみます。
from collections import Counter
counter = Counter(corpus)
most = counter.most_common()
x=[]
y=[]
for word,count in most[:40]:
if (word not in stop):
x.append(word)
y.append(count)
sns.barplot(x=x,y=y)

N-gram解析をしてみます。
N-gram解析とは、テキストをN文字単位で分解して解析することをいいます。
たとえば、abcdefgというテキストがあるとき、N=2とするとab, bc, cd, de, ef, fgと2文字づつ分解して解析します。
from sklearn.feature_extraction.text import CountVectorizer
def get_top_tweet_bigrams(corpus,n=None):
vec = CountVectorizer(ngram_range=(2,2)).fit(corpus)
bag_of_words = vec.transform(corpus)
sum_words = bag_of_words.sum(axis=0)
words_freq = [(word,sum_words[0,idx]) for word,idx in vec.vocabulary_.items() ]
words_freq = sorted(words_freq,key = lambda x:x[1],reverse=True)
return words_freq[:n]
trainのtextを可視化します。
plt.figure(figsize=(10,5))
top_tweet_bigrams = get_top_tweet_bigrams(train['text'])[:10]
x,y = map(list,zip(*top_tweet_bigrams))
sns.barplot(x=x,y=y)

データ前処理~スペルチェック、句読点の除去、htmlタグや絵文字の除去
まずは、URLを除去します。
example = "New competition launched :https://www.kaggle.com/c/nlp-getting-started"
import re
def remove_URL(text):
url = re.compile(r'https?://\S+|www\.\S+')
return url.sub(r'',text)
remove_URL(example)

df_train['text'] = df_train['text'].apply(lambda x : remove_URL(x))
df_train

次は、htmlタグを除去します。
example = """<div>
<h1>Real or Fake</h1>
<p>Kaggle </p>
<a href="https://www.kaggle.com/c/nlp-getting-started">getting started</a>
</div>"""
def remove_html(text):
html=re.compile(r'<.*?>')
return html.sub(r'',text)
print(remove_html(example))

df_train['text'] = df_train['text'].apply(lambda x : remove_html(x))
df_train

絵文字を除去します(https://gist.github.com/slowkow/7a7f61f495e3dbb7e3d767f97bd7304b)。
def remove_emoji(text):
emoji_pattern = re.compile("["
u"\U0001F600-\U0001F64F"
u"\U0001F300-\U0001F5FF"
u"\U0001F680-\U0001F6FF"
u"\U0001F1E0-\U0001F1FF"
u"\U00002702-\U000027B0"
u"\U000024C2-\U0001F251"
"]+", flags=re.UNICODE)
return emoji_pattern.sub(r'', text)
remove_emoji("Omg another Earthquake 😔😔")

df_train['text'] = df_train['text'].apply(lambda x: remove_emoji(x))
句読点を除去する。
def remove_punct(text):
table = str.maketrans('','',string.punctuation)
return text.translate(table)
example="I am a #king"
print(remove_punct(example))

df_train['text'] = df_train['text'].apply(lambda x : remove_punct(x))
スペルチェック(今回はないので、#(コメントアウト)しています。)
!pip install pyspellchecker
from spellchecker import SpellChecker
spell = SpellChecker()
def correct_spellings(text):
corrected_text = []
misspelled_words = spell.unknown(text.split())
for word in text.split():
if word in misspelled_words:
corrected_text.append(spell.correction(word))
else:
corrected_text.append(word)
return " ".join(corrected_text)
text = 'corect me plese'
correct_spellings(text)
#df_train['text'] = df_train['text'].apply(lambda x : correct_spellings(x))
次は、GloVeによるベクトル化します。
GloVeは、テキストのベクトル表現を取得するための教師なし学習アルゴリズムです。
GloVeは50D、100D、200Dと3種類ありますが、ここでは100Dで試してみます。
import nltk
nltk.download('punkt')
from nltk.tokenize import word_tokenize
from tqdm import tqdm
def create_corpus(df_train):
corpus = []
for train in tqdm(df_train['text']):
words = [word.lower() for word in word_tokenize(train) if((word.isalpha()==1) & (word not in stop))]
corpus.append(words)
return corpus
corpus = create_corpus(df_train)
glove.6B.100d.txtは、以下からダウンロードしてください。https://www.kaggle.com/datasets/rtatman/glove-global-vectors-for-word-representation
embedding_dict={}
with open('/content/drive/MyDrive/kaggle/Natual Language/glove.6B.100d.txt','r') as f:
for line in f:
values=line.split()
word=values[0]
vectors=np.asarray(values[1:],'float32')
embedding_dict[word]=vectors
f.close()
注意:‘/content/drive/MyDrive/kaggle/Natual Language/glove.6B.100d.txt’←の部分はドライブのフォルダ構成によって内容が異なるので注意してください。
from tensorflow import keras
from keras.preprocessing.text import Tokenizer
MAX_LEN=50
tokenizer_obj=Tokenizer()
tokenizer_obj.fit_on_texts(corpus)
sequences=tokenizer_obj.texts_to_sequences(corpus)
tweet_pad = keras.utils.pad_sequences(sequences,maxlen=MAX_LEN,truncating='post',padding='post')
word_index = tokenizer_obj.word_index
print('Number of unique words:',len(word_index))

num_words=len(word_index)+1
embedding_matrix=np.zeros((num_words,100))
for word,i in tqdm(word_index.items()):
if i > num_words:
continue
emb_vec=embedding_dict.get(word)
if emb_vec is not None:
embedding_matrix[i]=emb_vec

モデルの作成
from keras.models import Sequential
from keras.layers import Embedding,LSTM,Dense,SpatialDropout1D
from keras.initializers import Constant
from keras.optimizers import Adam
model=Sequential()
embedding=Embedding(num_words,100,embeddings_initializer=Constant(embedding_matrix),
input_length=MAX_LEN,trainable=False)
model.add(embedding)
model.add(SpatialDropout1D(0.2))
model.add(LSTM(64, dropout=0.2, recurrent_dropout=0.2))
model.add(Dense(1, activation='sigmoid'))
optimzer=Adam(learning_rate=1e-5)
model.compile(loss='binary_crossentropy',optimizer=optimzer,metrics=['accuracy'])
model.summary()

train_ = tweet_pad[:train.shape[0]]
test_ = tweet_pad[train.shape[0]:]
データを訓練用とテスト用に分割します。
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(train_,train['target'].values,test_size=0.15)
print('Shape of train',X_train.shape)
print("Shape of Validation ",X_test.shape)

訓練
history = model.fit(X_train,y_train,batch_size=4,epochs=15,validation_data=(X_test,y_test),verbose=2)

予測し、ファイルを提出します。
y_pred = model.predict(test_)
y_pred = np.round(y_pred).astype(int).reshape(3263)
sub = pd.DataFrame({'id':sub['id'].values.tolist(),'target':y_pred})

sub.to_csv('sub.csv',index=False)
Kaggleで悩んだら
「Kaggle で勝つデータ分析の技術」
以下の書籍は、Kaggleを始める方には本当にオススメの書籍です。Kaggleでわからないことや悩んだことがあった方は、購入を検討してみください。
本だけでは物足りないという方は、動画のプラットフォームで学ぶこともオススメです。興味がございましたら、以下の無料のオンライン説明会に参加してみてはいかがでしょうか。

