1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Zennのタグ情報を分析してみた

Posted at

概要

QiitaとZennってどんな特徴があるの?
前回Zennのスクレイピングを投稿したのですが、
そちらで取得した情報をPythonを用いて時系列順に分析してみました。

目次

1.タグ情報の時系列グラフ
2.実行環境
3.コード概要
4.感想
5.最後に

1.タグ情報の時系列グラフ

結果はこのようなグラフが得られました。
タグ情報の全体に占める割合の移動平均をとったグラフになります。
ratio_m_ave_half_1.png

2.実行環境

今回、Google Colaboratoryで実施しました。

3.コード概要

前回のスクレイピングで作成したcsvファイルを読み込みます。
まずはgoogle driveとの連携を作成します。

from google.colab import drive
drive.mount('/content/drive')

csvファイルを読み込みます。
pandasを利用して読み込みます。

import pandas as pd
#fileNoを定義
target_read_file = '/content/drive/MyDrive/csv/Zenn_allinfo_20220210_all.csv'
#csvからページ名を取得
df = pd.read_csv(target_read_file)
#データを確認
df.head(1)

下記の様なデータフレームが取得できます。

title  author  link  time tag_1 tag_2 tag_3 tag_4 tag_5 tag_6 tag_7 tag_8 tag_9 tag_10
0  ... ... ... ... ... ... ... ... ... ... ... ... ... ...

分析するにあたり、tag情報が1~10まで別のカラムに格納されているのが、都合が悪いので、
一つのtagというカラムにまとめます。

# 変数d_listに空のリストを作成する
d_list = []
#処理数nを定義
n=0
for time,tag_1,tag_2,tag_3,tag_4,tag_5,tag_6,tag_7,tag_8,tag_9,tag_10 in zip(df.time,df.tag_1,df.tag_2,df.tag_3,df.tag_4,df.tag_5,df.tag_6,df.tag_7,df.tag_8,df.tag_9,df.tag_10):
    d1 = {'time':time,
            'tag': tag_1}
    d_list.append(d1)
    d2 = {'time':time,
            'tag': tag_2}
    d_list.append(d2) 
    d3 = {'time':time,
            'tag': tag_3}
    d_list.append(d3) 
    d4 = {'time':time,
            'tag': tag_4}
    d_list.append(d4)
    d5 = {'time':time,
            'tag': tag_5}
    d_list.append(d5) 
    d6 = {'time':time,
            'tag': tag_6}
    d_list.append(d6) 
    d7 = {'time':time,
            'tag': tag_7}
    d_list.append(d7) 
    d8 = {'time':time,
            'tag': tag_8}
    d_list.append(d8) 
    d9 = {'time':time,
            'tag': tag_9}
    d_list.append(d9)                              
    d10 = {'time':time,
            'tag': tag_10}
    d_list.append(d10) 

# 変数d_listを使って、データフレームを作成する
df = pd.DataFrame(d_list)            
df.head(10)  

time tag
0 2022-02-14T00:42:44+00:00 Firebase
1 2022-02-14T00:42:44+00:00 TypeScript
2 2022-02-14T00:42:44+00:00 frourio
3 2022-02-14T00:42:44+00:00 railway
4 2022-02-14T00:42:44+00:00 tech
5 2022-02-14T00:42:44+00:00 NaN
6 2022-02-14T00:42:44+00:00 NaN
7 2022-02-14T00:42:44+00:00 NaN
8 2022-02-14T00:42:44+00:00 NaN
9 2022-02-14T00:42:44+00:00 NaN

Null値を削除します。

df2 = df[df['tag'].notnull()]
df2.head(10)
time tag
0 2022-02-14T00:42:44+00:00 Firebase
1 2022-02-14T00:42:44+00:00 TypeScript
2 2022-02-14T00:42:44+00:00 frourio
3 2022-02-14T00:42:44+00:00 railway
4 2022-02-14T00:42:44+00:00 tech
10 2022-02-14T00:42:24+00:00 JavaScript
11 2022-02-14T00:42:24+00:00 React
12 2022-02-14T00:42:24+00:00 Vue.js
13 2022-02-14T00:42:24+00:00 SWR
14 2022-02-14T00:42:24+00:00 tech

Null値が消えました。

続いてどういったタグがあるか確認します。

df2['tag'].value_counts()
tech             23387
idea              3547
JavaScript        1893
TypeScript        1671
Python            1656
                 ...  
研鑽                   1
セルフマネジメント            1
webex                1
回帰                   1
githubprofile        1
Name: tag, Length: 9000, dtype: int64

確認すると、「tech」が圧倒的に多く次いで、「idea」というタグが多いという結果です。
これはZennの仕様上、techかideaのどちらかのタグをつけるためなので、
これら二つのタグは省いて処理していきます。

またそのままですと日本語表示がされないので、
「japanize-matplotlib」というライブラリをインポートして活用します。

!pip install japanize-matplotlib
import japanize_matplotlib
import matplotlib.pyplot as plt

df2['tag'].value_counts()[2:22].plot.bar()
plt.title('ランキングALL')

value_counts()[2:22]とすることで、3位から22位までの20ランキングを取得します。

ダウンロード.png

次にタグ情報の移り変わりを時系列で整理します。
月単位で集計しようと思うので、月単位の日時情報でまとめます。

df2['date']=pd.to_datetime(df2['time']).dt.strftime('%Y-%m')
df2.head()
time tag date
0 2022-02-14T00:42:44+00:00 Firebase 2022-02
1 2022-02-14T00:42:44+00:00 TypeScript 2022-02
2 2022-02-14T00:42:44+00:00 frourio 2022-02
3 2022-02-14T00:42:44+00:00 railway 2022-02
4 2022-02-14T00:42:44+00:00 tech 2022-02

タグの数は月毎に総数が異なるため、3か月毎に移動平均をとります。
まず合計タグ数の移動平均を作成し、タグ数/合計タグ数を行うことでデータを偏りを減らします。

まず合計の移動平均を算出して、データフレームを作成し、
mergeで合算して必要なデータフレームを作成します。

df_sum=df2[['date','tag']].groupby(['date']).count()
df_sum.columns=['sum']

#移動平均
w_size=3
v = np.ones(w_size) / w_size
# a=df_sum['sum']
out = df_sum.apply(lambda x: np.convolve(x, v, mode='same'),axis=0)
out.columns=['sum_m_ave']

b=pd.DataFrame(out,columns=['sum_m_ave'])

df_sum2 = df_sum.merge(b,left_index=True, right_index=True, how='left')

できあがったセルはこのような形になります。

print(df_sum2)
date sum sum_ave
2020-09 3585 2858.333333
2020-10 4990 4145.000000
2020-11 3860 5095.666667
2020-12 6437 5245.000000
2021-01 5438 5679.333333
2021-02 5163 5495.333333
2021-03 5885 5468.666667
2021-04 5358 5806.000000
2021-05 6175 5589.000000
2021-06 5234 5617.333333
2021-07 5443 5324.000000
2021-08 5295 5483.000000
2021-09 5711 5351.000000
2021-10 5047 5270.666667
2021-11 5054 6587.666667
2021-12 9662 7275.333333
2022-01 7110 6783.666667
2022-02 3579 3563.000000

続いて個別のタグ情報も移動平均を算出し、
辞書型でデータを格納します。

result = {}
for i, t in enumerate(df2['tag'].value_counts().index):
    #tag情報と同一のデータのみで集計
    df_tmp = df2[df2['tag']==t]
    df_gb = df_tmp.groupby('date').count()
    df_gb = df_gb.drop('time',axis=1)

    #移動平均算出
    w_size=3
    v = np.ones(w_size) / w_size
    out = df_gb.apply(lambda x: np.convolve(x, v, mode='same'),axis=0)
    out.columns=['m_ave']
    df_m = df_gb.merge(out,left_index=True, right_index=True, how='left')
    df_m = df_m.merge(df_sum2,left_index=True, right_index=True, how='left')

    #割合算出
    df_m['ratio'] = df_m['tag'] / df_m['sum']
    df_m['ratio_m_ave'] = df_m['m_ave'] / df_m['sum_m_ave']

    #結果を格納
    r={'rank':i+1, 'df':df_m}
    result[t] = r

この結果をグラフ化します。
まずは単純な割合でグラフ化します。
グラフ作成時、横軸がかぶってしまって見えなくなってしまったので、
下記ページを参考にしました。

import matplotlib.pyplot as plt

plt.figure(figsize=(10, 10))
plt.ylabel('ratio',size=16)
#x軸ラベルを90度回転
plt.xticks(rotation=90)

i = 1
for k, v in result.items():

    rank = v['rank']
    df_tmp = v['df']

    if rank < 3:
        continue
    if rank > 22:
        continue
    plt.plot(df_tmp['ratio'],label=k)


plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0)
plt.show()

ratio_all.png

グラフの凡例数が多くて見づらいので、
凡例数を10個ずつにして、再度出力します。


plt.figure(figsize=(10, 10))
plt.ylabel('ratio',size=16)

#x軸ラベルを90度回転
plt.xticks(rotation=90)

i = 1
for k, v in result.items():
#    plt.clf()

    rank = v['rank']
    df_tmp = v['df']

    if rank < 3:
        continue
    if rank > 22:
        break
    plt.plot(df_tmp['ratio'],label=k)
    if i % 10 == 0:
        plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0)
        plt.show()
        plt.clf()
        if i // 10 < 2:
            plt.figure(figsize=(10, 10))
            plt.ylabel('ratio',size=16)
            #x軸ラベルを90度回転
            plt.xticks(rotation=90)
    i += 1

ratio_half_1.png

ratio_half_2.png

つづいて、移動平均での割合グラフを出力します。

全体グラフ出力

plt.figure(figsize=(10, 10))
plt.ylabel('ratio_m_ave',size=16)

#x軸ラベルを90度回転
plt.xticks(rotation=90)

i = 1
for k, v in result.items():


    rank = v['rank']
    df_tmp = v['df']

    if rank < 3:
        continue
    if rank > 22:
        continue
    plt.plot(df_tmp['ratio_m_ave'],label=k)

plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0)
plt.show()

ratio_m_ave_all.png

個別グラフ出力

plt.figure(figsize=(10, 10))
plt.ylabel('ratio_m_ave',size=16)

#x軸ラベルを90度回転
plt.xticks(rotation=90)

i = 1
for k, v in result.items():
#    plt.clf()

    rank = v['rank']
    df_tmp = v['df']

    if rank < 3:
        continue
    if rank > 22:
        continue
    plt.plot(df_tmp['ratio_m_ave'],label=k)
    if i % 10 == 0:
        plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0)
        plt.show()
        plt.clf()
        if i // 10 < 2:
            plt.figure(figsize=(10, 10))
            plt.ylabel('ratio_m_ave',size=16)
            #x軸ラベルを90度回転
            plt.xticks(rotation=90)

    i += 1

ratio_m_ave_half_1.png

ratio_m_ave_half_2.png

4.感想

移動平均にしてみると、上位層(TOP5)が安定していることがわかりました。
また、初めは初心者が2位だったにも関わらず、順位をかなり落としており、
玄人感が特徴として出ているのかなと感じました。

5.最後に

タグ情報をグラフかして見える化してみましたが、
視覚化すると見えてきたり、移動平均をとってみると、
違った見方ができて面白いなと思いました。

まだまだ、難しいですがそういったことが、
プログラム上でできてしまう、pythonは改めて便利だなとも感じました。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?