LoginSignup
3
2

More than 3 years have passed since last update.

ネガポジ分析2 Twitterのネガポジ分析(1)

Posted at

Aidemy 2020/10/30

はじめに

 こんにちは、んがょぺです!バリバリの文系ですが、AIの可能性に興味を持ったのがきっかけで、AI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます!
 今回は、ネガポジ分析の2つ目の投稿になります。どうぞよろしくお願いします。

*本記事は「Aidemy」での学習内容を「自分の言葉で」まとめたものになります。表現の間違いや勘違いを含む可能性があります。ご了承ください。

今回学ぶこと
・RNNを使ったTwitterのネガポジ分析
・データベースの作成

RNN

・極性辞書を使うことでネガポジ分析を行うことができるが、文脈に即した判断をすることは難しい。そこで「日本語テキストのトピック抽出1」で扱った「RNN(再帰型ニューラルネットワーク)」を使って文脈に即した判断を可能にする。
・また、日本語でもRNNの文脈推定は行えるが、今回は英語を使っていく

Twitterのネガポジ分析

Twitterは140字という短い文章で構成されているので、自然言語処理の分析に適している。今回はUSAirlineのTwitterデータを使っていく。
・まずはTweetデータが記録されたcsvファイルを開き、そこから'text'の列と'airline_sentiment'全行を抽出する。方法は「loc[:,[列名]]」で行う。

データベースの作成

頻出単語の削除

・RNNで単語間の関連性を分析するにあたり、「@」や「I」などの頻出単語は分析の妨げになる「ストップワード」と呼ばれる。今回はこのストップワードを削除していく
・前項で読み込んだツイートデータに対し、まずは形態素解析で単語ごとに分け、それを「lower()」で全て小文字にする(正規化)。
・また、nltkのstopwordsモジュールをダウンロードし、「set(stopwords.words("english"))」で「stops」という変数に英語のストップワードの情報をセットする。
・wordsの中の各単語wについて、「stopsに入っていない(ストップワードでない)」かつ「@とflightが入っていない」単語のみを「meaningful_words」として返す。
・条件のうち、前者は「if not w in stops」、後者は「not re.match('^[文字列]',w)」で記述することができる。

・コードスクリーンショット 2020-10-27 18.04.28.png

単語のデータベース作成

・次に、Tweetの全単語をデータベースにまとめる。これを行うことで、単語の出現頻度の確認やネガポジのタグ付けをまとめて行うことができるようになる
・「cleanTweet」はTweetデータのtext部分に、前項で作成した「tweet_to_words」関数を適用した物である。「apply(lambda x: 関数)」で、各要素に関数を適用することができる。これの中身は、各単語がスペース区切りで格納された物であるので、「' '.join(リスト)」を使うことで単語ごとに分けることができる。さらに「split()」を使うことでこの各単語を一つ一つリストに格納した物を取得できる。

・コードスクリーンショット 2020-10-27 18.38.27.png

・wordsの中身スクリーンショット 2020-10-27 18.39.07.png

単語の数値化

・単語の出現回数をベースに、それぞれの単語に数値のタグをつける。また、cleanTweetの文字列を数値に変換した新しいリストを作成する
・単語の出現回数は「Counter()」で計算することができる。出現回数が多い順(降順)に単語を並べ替え、「{word:出現回数}」となるように辞書を作る。出現回数は「for ii, word in enumerate(vocab, 1)」で取得できる。enumerate()は引数にリストを渡してfor文にすると、一つ目の変数(ⅱ)にindexが、二つ目の変数(word)にcolumnが入る。したがって、このコードでは「vocab」の出現回数が多い単語から順にインデックス番号が振り分けられたものを辞書として作成するものと言える。

・次にcleanTweetの文字列を数値に変換して新しいリストを作成する。まずは空のリスト「tweet_ints」を作成する。
・cleanTweetの各行(each)を単語ごとに分割したもの(word)について、直前に振り分けたインデックス番号に変換してそのまま空のリストtweet_intsに格納する。するとtweet_intsには各行(ツイート)ごとにインデックス番号が格納されたリストが入っている。
・変換の仕方は、直前に作った辞書の値を、wordごとに参照すれば良い。

・コードスクリーンショット 2020-10-27 20.36.39.png

・結果(一部のみ)スクリーンショット 2020-10-27 20.37.08.png

ネガポジの数値化

・このChapterの最初の方で抽出したtweetDataの'airline_sentiment'という列には、各ツイートがネガティブかポジティブかニュートラルか、という情報が格納されている。これらの情報について、「ネガティブ=0、ポジティブ=1、ニュートラル=2」というように数値に変換する。数値にすることで学習の際に使うことができるようになる
・'airline_sentiment'の各行をeachとすると、「each=='negative'」ならば値は「0」というif文を他2つでも表し、それらをまとめて1つのnp.array形式にする。

・コードスクリーンショット 2020-10-27 21.01.40.png

列の数を揃える

・前々項で作成した「tweet_ints」には各ツイートの単語のインデックス番号が入っているが、その各リストの長さはバラバラである。しかし、学習する際には長さを揃える必要がある。また、cleanTweetの処理で単語数が0になった行も削除しておく
・まずは各リストの長さを「Counter()」で取得する。直後の処理で、長さが最大のものに合わせて他のリストの長さを揃えていくので、最大のもののみ「max()」で取得し変数「seq_len」に格納する。
・次に、長さが0の行を削除する。直接drop()などで削除するのではなく、tweet_intsの
column(tweet)について、len(tweet)>0のもののみを取得するという手法で行う。len(tweet)>0の条件を満たす行のindexを「tweet_index」に格納し、labelsとtweetDataもこれに合わせて格納し直す。最終的にはtweet_intsも条件に合わせて格納し直せばOK。
各リストの長さを揃えていく。先述の通り、長さは一番長いものに合わせる。長さが足りないものについては「その行の数値化した単語を右から埋めていき、足りない分は0で置き換える」という手法で補完する。(例えば[1,2,3]のリストをこの手法で長さを5にするときは[0,0,3,2,1]というふうになる)
・以下のコードの「np.zeros((len(tweet_ints), seq_len), dtype=int)」の部分は行がtweet_intsの長さで列が最大の列数である、要素が全て0の配列を作成していることを示す。tweet_intsのそれぞれの行をi列をrowとした時、要素が0の配列の行がi、列が-len(row)の部分にrowを入れることで、上記の補完方法が実現する。

・コードスクリーンショット 2020-10-28 15.23.00.png

・結果(一部のみ)スクリーンショット 2020-10-27 22.52.30.png

まとめ

・RNNを使うことで、文脈の流れを考慮に入れたネガポジ分析を行うことが可能になる
・データに頻出する単語は「ストップワード」と言って分析の妨げになるので、削除する必要がある。
・Twitterのデータにある単語をデータベース化することで、単語ごとにネガポジ分析を行うことが可能になる
・単語データは頻度順にIDを付与して数値化し、極性辞書を使って対応するPN値も格納する。また、モデル実装時に教師ラベルとなるネガティブポジティブの区別についても数値で行えるようにしておく。
・学習データとなるデータは、リストごとに列の長さを揃える

今回は以上です。最後まで読んでいただき、ありがとうございました。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2