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

[Aidemy](https://aidemy.net/)　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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/693ead18-245f-1050-07de-fe398abc1569.png)

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

・コード![スクリーンショット 2020-10-27 18.38.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/a115f91f-0811-1a2f-bbf3-5bb47e0c5430.png)

・wordsの中身![スクリーンショット 2020-10-27 18.39.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/b9d684fe-1bf6-78f9-64cb-aba87ea7f537.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/71666eae-8acf-2146-218f-a1a04ee76b5f.png)

・結果（一部のみ）![スクリーンショット 2020-10-27 20.37.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/1cbd9513-e394-12a4-4687-ed90a9ec809e.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/af152708-57ec-3735-fa90-16e3728c50f3.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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/69e4bdd0-0c2e-398f-ec5a-dee991526845.png)

・結果（一部のみ）![スクリーンショット 2020-10-27 22.52.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/907dc703-1da6-ec31-9c8a-5b964658ed11.png)

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

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