Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What is going on with this article?
@nehan_io

Pythonに疲れたのでnehanでデータ分析してみた(コロナ禍でもライブに行きたい - 前編)

ご挨拶

こんにちは、マンボウです。
「Twtter×コロナ」シリーズ2回目です。
前回はtweet数を集計してみました、レベルでしたが、今回はもうちょっと頑張ってみます。
特に、MeCabのインストールや環境構築始め、自然言語処理で消耗している人はぜひ見てみてください。

Twitterのデータから、上昇・下降トレンドの単語を探してみる

コロナウイルスが社会問題になってから半年以上が経過しました。
人々の中で何が高まり、逆に何が忘れられているのか、つぶやきから追ってみます。
前編では、形態素解析の実施、分析対象の単語を選定するところまでやります。

データ

前回の前処理が終わったデータを使います。
つまり、tweet日,tweet内容、のデータです。
スクリーンショット 2020-10-05 16.14.11.png

重複削除処理

実はこのデータには、同じtweet内容が複数レコード、複数日にまたいで発生しています。(retweetを含むため)
今回はretweetのバイアスを除き、1tweet内容1レコード、で分析します。

from collections import Counter
from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd
import statsmodels.api as sm
import re
import MeCab
import dask.dataframe as dd
from multiprocessing import cpu_count

# tweetごとに最もCreated_Atが若い日をとってきて、1tweet1レコードにする
port_13['Created_At'] = pd.to_datetime(port_12['Created_At'])
port_13 = port_12.groupby(['Text']).apply(lambda grp: getattr(
    grp, 'nsmallest')(n=1, columns='Created_At', keep='first'))
port_13['Created_At'] = port_12['Created_At'].map(lambda x: x.date())

スクリーンショット 2020-10-05 16.29.00.png

形態素解析

言語処理の要をやります。
全品詞出すとわけわからなくなるので、今回は「一般名詞」のみを分析対象にします。

def tokenizer(text, pos, only_surface):
    def _extract():
        if only_surface:
            return re.sub(r'[\s ]+', '_', feature[0])
        else:
            return re.sub(r'[\s ]+', '_', feature[2])
    _tagger = MeCab.Tagger(
        '-Ochasen -d {}'.format("/var/lib/mecab/dic/mecab-ipadic-neologd"))
    try:
        result = []
        for feature in _tagger.parse(text).split('\n')[:-2]:
            feature = feature.split('\t')
            if pos:
                if feature[3] in pos:
                    result.append(_extract())
            else:
                result.append(_extract())
        return ' '.join(result)
    except UnicodeEncodeError:
        return ''
    except NotImplementedError:
        return ''

port2 = port1.copy()
port2['Text_形態素'] = port2['Text'].fillna('')
ddf = dd.from_pandas(port2, npartitions=cpu_count()-1)
target_cols = ['Text_形態素']
pos = ['名詞-一般']
for target_col in target_cols:
    ddf[target_col] = ddf[target_col].apply(
        tokenizer, pos=pos, only_surface=True, meta=(f'{target_col}', 'object'))
port2 = ddf.compute(scheduler='processes')

↓nehanの形態素解析は、スペース区切りで形態素を結合し、列に挿入します。
スクリーンショット 2020-10-05 16.43.11.png


なお、一般名詞を含んでいないtweetは、形態素解析の結果が欠損するので、消しておきます。
欠損値処理を使います。

port_15 = port_14.copy()
port_15 = port_15.dropna(subset=None, how='any')

スクリーンショット 2020-10-05 16.53.19.png

出現頻度が高い単語を選定する(※)

めったに出現しない単語を対象にしてもしょうがないので、全期間で1,500以上出現しているものを分析対象にしました。

# 単語頻度の集計
port_18 = port_15.copy()
flat_words = list(chain.from_iterable(port_18['Text_形態素'].str.split(' ')))
c = Counter(flat_words)
res = pd.DataFrame.from_dict(c, orient='index').reset_index()
res.columns = ['単語', 'カウント']
port_18 = res

# 条件で行フィルタ
port_20 = port_18[(port_18['カウント'] >= 1500.0)]

# 列選択
port_21 = port_20[['単語']]

スクリーンショット 2020-10-05 17.36.21.png

↓選定した27単語の出現数はこんな感じ
スクリーンショット 2020-10-05 17.53.26.png

↓おまけですが、選定前のワードクラウドです。
スクリーンショット 2020-10-05 17.36.54.png

日毎の単語出現数を集計し、出現頻度が高い単語に絞り込む

前ステップで対象単語は絞り込めたので、次は日毎データ作成です。
単語頻度の集計を、Created_Atをキー列にして実施します。

port_16 = port_15.copy()
target_col = 'Text_形態素'
groupby_cols = ['Created_At']
tmp = port_16[groupby_cols+[target_col]]
tmp = tmp.groupby(groupby_cols)[target_col].apply(lambda x: ' '.join(x))
vec_counter = CountVectorizer(tokenizer=lambda x: x.split(' '))
X = vec_counter.fit_transform(tmp)
res = pd.DataFrame(X.toarray(), columns=vec_counter.get_feature_names(), index=tmp.index
                   ).reset_index().melt(id_vars=groupby_cols, var_name='単語', value_name='カウント')
port_16 = res.sort_values(groupby_cols).reset_index(drop=True)

スクリーンショット 2020-10-05 17.39.39.png


ここに※のデータを結合し、日別データを分析対象単語に絞り込み、前編の作業は終了です。

port_22 = pd.merge(port_21, port_16, how='inner',
                   left_on=['単語'], right_on=['単語'])

スクリーンショット 2020-10-05 17.46.07.png

↓試しに、得られたデータをフィルタリングして、日別の単語出現数を可視化。泣き顔より、笑顔がいい。
スクリーンショット 2020-10-05 17.56.28.png

まとめ

長くなってしまいましたが、頻出単語の日毎出現数を出すところまでやってみました。
厳密さよりシンプルさを重視しています。
込み入った分析をやろうとすると、コードが長くなってしまって大変になる傾向がありますが、nehanではこれを10ノード(緑の丸の数)でこなします。
もちろんプログラムは一切書いてません。
少しでもnehanに興味を持っていただけると嬉しいです。

※分析ツールnehanのご紹介はこちらから。
※↓今日の内容
スクリーンショット 2020-10-05 18.09.53.png
なお、上記のソースコードはnehanのpythonエクスポート機能で出力したコードをコピペしました。形態素解析の部分だけコード出力適用外だったので、nehanスタッフに書いてもらいました。

2
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
nehan_io

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
2
Help us understand the problem. What is going on with this article?