Pandasを使ったデータ分析の実践例 - やはりQiitaアドベントカレンダーの「企業・学校・団体」カテゴリーにはヘビーライカーが多かった

# はじめに

[Qiitaアドベントカレンダー2017] のランキングを見ていて気づいたことがありました。
それは **[購読者数ランキング]の上位はいろんなカテゴリーがあるのに、[いいね数ランキング]の上位は「企業・学校・団体」カテゴリーが独占状態** だということです。
不思議だったので Python の Pandas と Jupyter Notebook を使って色々と分析してみました。

[Qiitaアドベントカレンダー2017]:https://qiita.com/advent-calendar/2017
[いいね数ランキング]:https://qiita.com/advent-calendar/2017/ranking/feedbacks/all
[購読者数ランキング]:https://qiita.com/advent-calendar/2017/ranking/subscriptions/all

# 調べたこと

主に２つの点を中心に調べてみました。

## 購読者数といいね数の関係

普通に考えれば購読者数が多ければそれだけいいね数も多くなるはずです。と思っていたのですが、ランキングを見る限りこのような関係は全くないように見えます。
この辺りをはっきりさせるために購読者数といいね数の相関関係を調べました。

## 「企業・学校・団体」カテゴリーについての仮説

とある「企業・学校・団体」のカレンダーにいいねしているユーザーを見ていたら、そのカレンダーの全記事にいいねしていることに気づきました。
このことから、「企業・学校・団体」カテゴリーのカレンダーでは大量にいいねしているユーザー＝「**ヘビーライカー**」の人数が多いのではないか、という仮説を立てました。
これを証明するべく上位カレンダーでのライカーの特徴を調べました。

# データ収集

分析するためにはデータを収集しなくてはなりません。
今回の分析では以下のデータが必要です。

- カレンダーの情報
    - カテゴリー
    - 購読者数
    - いいね数
- カレンダーの各記事の情報
    - いいね数
    - いいねしているユーザー(ライカー)

カレンダーの情報は[Qiita API](https://qiita.com/api/v2/docs)では取得できないので、カレンダーのページをクロール/スクレイピングしました。手順は以下の通りです。

1. カレンダー一覧ページ(https://qiita.com/advent-calendar/2017/calendars) からカレンダーのURLを取得する。
2. カレンダーページ(https://qiita.com/advent-calendar/2017/:calendar_id) から購読者数、いいね数、各投稿のURLを取得する。
3. 投稿のいいねしている人一覧ページ(https://qiita.com/:user_id/items/:item_id/likers) からいいねしている人のユーザー名を取得する。[^1]

[^1]: カレンダーのいいね数ランキングは12月1日から1月4日までにいいねされた数を対象としていますが、投稿のいいねしている人一覧ページには対象外のライカーも含まれます。このため、ランキングのいいね数とは若干異なる値になります。

実装はPython3.６で以下のライブラリを使用しました。

- [Requests](http://requests-docs-ja.readthedocs.io/en/latest/)
    - Httpクライアントのライブラリ
- [Beautiful Soup](https://www.crummy.com/software/BeautifulSoup/)
    - HTMLをパースするためのライブラリ
- [Click](http://click.pocoo.org/5/)
    - コマンドラインツールをいい感じに作れるライブラリ
- [tqdm](https://pypi.python.org/pypi/tqdm)
    - プログレスバーを表示するライブラリ

作ったものはgithubで公開してあります。
https://github.com/tag1216/qiita-adcal-crawler

# 収集したデータ

収集したデータはgistに公開してあります。
ファイルサイズが大きいのでブラウザで開くと重いです。必要な方はzipをダウンロードするか`git clone`して下さい。
https://gist.github.com/tag1216/10d6a9f73d9a092cc632a70fb6d80abb
https://gist.github.com/tag1216/10d6a9f73d9a092cc632a70fb6d80abb/archive/c9c947120cc54d44404cfab67d997dc9ec864237.zip

以下ファイルの先頭３行です。

[calendars.tsv](https://gist.githubusercontent.com/tag1216/10d6a9f73d9a092cc632a70fb6d80abb/raw/c9c947120cc54d44404cfab67d997dc9ec864237/calendars.tsv)(594行、70KB)

| year | calendar_id | title                                  | url                                             | category          | participants_count | likes_count | subscribers_count |
|------|-------------|----------------------------------------|-------------------------------------------------|-------------------|--------------------|-------------|-------------------|
| 2017 | haskell5    | Haskell (その5) Advent Calendar 2017   | https://qiita.com/advent-calendar/2017/haskell5 | Programming Langs | 5                  | 23          | 0                 |
| 2017 | vivaldi     | Vivaldiブラウザー Advent Calendar 2017 | https://qiita.com/advent-calendar/2017/vivaldi  | Web Technologies  | 1                  | 3           | 0                 |

[items.tsv](https://gist.githubusercontent.com/tag1216/10d6a9f73d9a092cc632a70fb6d80abb/raw/c9c947120cc54d44404cfab67d997dc9ec864237/items.tsv)(14826行、1.9MB)

| year | calendar_id | date | user_name | user_url                  | title                                        | url                                                                          |
|------|-------------|------|-----------|---------------------------|----------------------------------------------|------------------------------------------------------------------------------|
| 2017 | haskell5    | 1    | waddlaw   | https://qiita.com/waddlaw | [翻訳]Haskell のパフォーマンスをデバッグする | https://haskell.e-bigmoon.com/posts/2017-12-27-haskell-performance-debugging |
| 2017 | haskell5    | 2    | waddlaw   | https://qiita.com/waddlaw | haddock に Grid Table 記法が追加されました   | https://haskell.e-bigmoon.com/posts/2017-12-27-haddock-grid-table.html       |

[likers.tsv](https://gist.githubusercontent.com/tag1216/10d6a9f73d9a092cc632a70fb6d80abb/raw/c9c947120cc54d44404cfab67d997dc9ec864237/likers.tsv)(97085行、1.5MB)

| year | calendar_id | date | user_name   | user_url                      |
|------|-------------|------|-------------|-------------------------------|
| 2017 | haskell5    | 4    | takenobu-hs | https://qiita.com/takenobu-hs |
| 2017 | haskell5    | 4    | makoraru    | https://qiita.com/makoraru    |

## 分析

分析には以下を使用しました。

- [Pandas](https://pandas.pydata.org/)
    - データ分析を行うためのライブラリ
- [Jupyter Notebook](http://jupyter.org/)
    - ブラウザ上でコードを実行して結果を表示できるツール

作ったNotebookはgistに公開しています。
https://gist.github.com/tag1216/0675f00fb0824270c1cf97e4d997c4bd

データが大きいせいかプレビューが表示されないことがあるので、その場合はnbviewerで見て下さい。
http://nbviewer.jupyter.org/gist/tag1216/0675f00fb0824270c1cf97e4d997c4bd

# 分析結果

それでは分析結果を見ていきましょう。

## 購読者ランキングといいね数ランキングの比較

各ランキングのTOP10がもう一方のランキングで何位なのかを確認しました。

pandasで順位を調べるには`rank()`を使用します。

```py3
ranking = pd.DataFrame(calendars['category'])
ranking[['subscribers', 'likes']] = calendars[['subscribers_count', 'likes_count']].rank(ascending=False).astype(int)
ranking = ranking.reset_index()
display(ranking.set_index('subscribers').sort_index()[:10])
display(ranking.set_index('likes').sort_index()[:10])
```

### 購読者数ランキングTOP10

| subscribers | calendar_id | category | likes |
|:--|:--|:--|--:|
| 1 | vscode | Editors | 89 |
| 2 | javascript | Programming Langs | 32 |
| 2 | chromium | Web Technologies | 102 |
| 4 | vue | Libraries | 35 |
| 5 | docker | DevOps | 122 |
| 6 | slack | Services | 212 |
| 7 | smart-speaker | IoT | 15 |
| 8 | vim | Editors | 60 |
| 9 | go | Programming Langs | 50 |
| 9 | vue2 | Libraries | 27 |

### いいね数ランキングTOP10

| likes | calendar_id | category | subscribers |
|:--|:--|:--|--:|
| 1 | fromscratch | Company | 134 |
| 2 | tis | Company | 152 |
| 3 | crowdworks | Company | 218 |
| 4 | livesense-gaku | Company | 152 |
| 5 | ateam-lifestyle | Company | 258 |
| 6 | musashino | Company | 91 |
| 7 | ex-mixi | Company | 163 |
| 8 | mixi | Company | 136 |
| 9 | litalico | Company | 246 |
| 10 | increments | Company | 156 |

これだけを見ると購読者数といいね数には相関性があるとは思えませんが、まだ断定はできません。

## カテゴリー別総計

カテゴリー毎にカレンダー数、購読者数、いいね数の合計と、購読者数/カレンダー数、いいね数/カレンダー数、いいね数/購読者数を計算しました。

| category | cals | subs | likes | subs/cal | likes/cal | likes/sub |
|:--|--:|--:|--:|--:|--:|--:|
| Academic | 22 | 3015 | 2284 | 137 | 103 | 0.757546 |
| Company | 204 | 5934 | 56898 | 29 | 278 | 9.588473 |
| Databases | 9 | 570 | 492 | 63 | 54 | 0.863158 |
| DevOps | 19 | 1787 | 670 | 94 | 35 | 0.374930 |
| Editors | 10 | 1980 | 1068 | 198 | 106 | 0.539394 |
| IoT | 17 | 1795 | 2800 | 105 | 164 | 1.559889 |
| Libraries | 61 | 5656 | 7080 | 92 | 116 | 1.251768 |
| Miscellaneous | 63 | 2093 | 5255 | 33 | 83 | 2.510750 |
| Mobile | 13 | 1452 | 2306 | 111 | 177 | 1.588154 |
| OS | 6 | 548 | 379 | 91 | 63 | 0.691606 |
| Programming Langs | 89 | 8994 | 10690 | 101 | 120 | 1.188570 |
| Services | 40 | 3108 | 2184 | 77 | 54 | 0.702703 |
| Web Technologies | 40 | 3691 | 2909 | 92 | 72 | 0.788133 |

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35192/f6025abb-e508-71ca-fd7e-53ac7f8a7a41.png)

「企業・学校・団体」(Company)だけ値が突出しているのが目立ちます。カレンダー数が多いのでいいね数が多いのは当然ですが、1カレンダー当たりのいいね数、1購読者当たりのいいね数が多いのが気になります。

## 購読者数といいね数の相関関係

購読者数といいね数の相関関係を調べてみます。
pandasで2つの値の相関関係を調べるには`corr()`で相関係数を算出したり、散布図を出力したりします。

### 全カレンダーでの相関関係

まずは全カレンダーで相関係数と散布図を見てみます。

```py3
calendars[['likes_count', 'subscribers_count']].corr()
```

|   | corr |
|---|-----:|
|全体|0.196388|

```py3
calendars.plot.scatter(figsize=(4, 4), x='subscribers_count', y='likes_count')
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/35192/cdcf36d4-ce4a-30dd-0513-8280e3ccef4c.png)

相関係数は低いし散布図も一見バラバラに見えるのですが、よく見ると縦に伸びるグループと横に伸びるグループがあるのがわかります。

先ほどのカテゴリー別総計で「企業・学校・団体」カテゴリーだけいいね数/購読者数の値が突出していたのでこれを色分けしてみます。
赤が「企業・学校・団体」、青がその他です。

```py3:
colors = calendars['category'].apply(lambda x: 'red' if x == 'Company' else 'blue')
calendars.plot.scatter(figsize=(4, 4), x='subscribers_count', y='likes_count', color=colors)
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35192/95c08bd9-f016-c5a2-8342-bd33b93db7c2.png)

見事に分かれました。

### 「企業・学校・団体」カテゴリーとそれ以外での相関関係

改めて「企業・学校・団体」カテゴリーとそれ以外を分けて相関係数と散布図を出してみます。

```py3
fig, ax = plt.subplots(1, 2, figsize=(8, 4))
calendars[calendars['category'] == 'Company'].plot.scatter(ax=ax[0], x='subscribers_count', y='likes_count', color='red')
calendars[calendars['category'] != 'Company'].plot.scatter(ax=ax[1], x='subscribers_count', y='likes_count', color='blue')
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/35192/60307cc7-6708-5b8e-2e59-e90ba0d116fb.png)

```py3:
calendars.groupby(is_company)[['likes_count', 'subscribers_count']].corr()
```

|is_company   | corr |
|---|-----:|
|False| 0.574489 |
|True| 0.462269 |

全体で計算するより高い値になりました。
この値なら購読者数といいね数は相関関係にあるといって良さそうですね。

## いいね数上位カレンダー

ここからはいいね数トップ50のカレンダーのみを分析対象とします。

カテゴリー毎の件数は以下の通りです。

| category | calendars |
|:--|--:|
| Academic | 1 |
| Company | 35 |
| IoT | 2 |
| Libraries | 3 |
| Miscellaneous | 2 |
| Mobile | 2 |
| Programming Langs | 5 |

各カレンダーのいいね数、購読者数、いいね数、ライカーUU数、いいね数/購読者数、いいね数/ライカーUU数を算出します。
ライカーUU数とは、そのカレンダーをいいねしている人のユニークユーザー数のことです。
いいね数/ライカーUU数は、そのカレンダーをいいねしている人について、一人当たりいくつの記事にいいねしているかの平均値になります。

| calendar_id | category | subs | likes | uu | likes/sub | likes/uu |
|:--|:--|--:|--:|--:|--:|--:|
| fromscratch | Company | 94 | 3065 | 526 | 32.606383 | 5.826996 |
| tis | Company | 80 | 3041 | 2105 | 38.012500 | 1.444656 |
| crowdworks | Company | 52 | 2476 | 1765 | 47.615385 | 1.402833 |
| livesense-gaku | Company | 80 | 2439 | 1799 | 30.487500 | 1.355753 |
| ateam-lifestyle | Company | 43 | 2389 | 1481 | 55.558140 | 1.613099 |
| musashino | Company | 133 | 2368 | 1522 | 17.804511 | 1.555848 |
| ex-mixi | Company | 76 | 1941 | 1528 | 25.539474 | 1.270288 |
| mixi | Company | 91 | 1909 | 1666 | 20.978022 | 1.145858 |
| litalico | Company | 45 | 1489 | 1050 | 33.088889 | 1.418095 |
| increments | Company | 79 | 1366 | 1070 | 17.291139 | 1.276636 |
| livesense-kan | Company | 50 | 1361 | 906 | 27.220000 | 1.502208 |
| livesense-ji | Company | 59 | 1353 | 827 | 22.932203 | 1.636034 |
| kuso-app2017 | Miscellaneous | 186 | 1307 | 1200 | 7.026882 | 1.089167 |
| basicinc | Company | 28 | 1107 | 774 | 39.535714 | 1.430233 |
| smart-speaker | IoT | 421 | 1039 | 796 | 2.467933 | 1.305276 |
| wacul | Company | 15 | 1030 | 859 | 68.666667 | 1.199069 |
| globis | Company | 50 | 965 | 505 | 19.300000 | 1.910891 |
| dmm2 | Company | 161 | 934 | 695 | 5.801242 | 1.343885 |
| nttcom | Company | 73 | 902 | 646 | 12.356164 | 1.396285 |
| axe | Miscellaneous | 62 | 892 | 781 | 14.387097 | 1.142125 |
| justsystems | Company | 28 | 796 | 734 | 28.428571 | 1.084469 |
| cdatasoftware | Libraries | 16 | 788 | 760 | 49.250000 | 1.036842 |
| dwango | Company | 156 | 745 | 601 | 4.775641 | 1.239601 |
| m3 | Company | 27 | 739 | 446 | 27.370370 | 1.656951 |
| fujitsu | Company | 80 | 728 | 617 | 9.100000 | 1.179903 |
| fringe81 | Company | 43 | 704 | 206 | 16.372093 | 3.417476 |
| vue2 | Libraries | 395 | 653 | 508 | 1.653165 | 1.285433 |
| lifull2 | Company | 31 | 638 | 494 | 20.580645 | 1.291498 |
| lifull | Company | 50 | 605 | 461 | 12.100000 | 1.312364 |
| ut_ap | Company | 49 | 601 | 573 | 12.265306 | 1.048866 |
| math-and-computer | Academic | 385 | 593 | 481 | 1.540260 | 1.232848 |
| javascript | Programming Langs | 487 | 589 | 335 | 1.209446 | 1.758209 |
| hikkoshi | Company | 31 | 567 | 208 | 18.290323 | 2.725962 |
| dwango2 | Company | 110 | 560 | 433 | 5.090909 | 1.293303 |
| vue | Libraries | 460 | 554 | 431 | 1.204348 | 1.285383 |
| firstserver | Company | 18 | 542 | 286 | 30.111111 | 1.895105 |
| retty | Company | 44 | 537 | 365 | 12.204545 | 1.471233 |
| firebase | Mobile | 246 | 527 | 393 | 2.142276 | 1.340967 |
| okinawarb | Company | 9 | 500 | 484 | 55.555556 | 1.033058 |
| toreta | Company | 45 | 485 | 435 | 10.777778 | 1.114943 |
| accounting_saas_japan | Company | 16 | 467 | 80 | 29.187500 | 5.837500 |
| vasily | Company | 44 | 457 | 215 | 10.386364 | 2.125581 |
| webassembly | Programming Langs | 234 | 455 | 345 | 1.944444 | 1.318841 |
| rust-lang | Programming Langs | 267 | 444 | 210 | 1.662921 | 2.114286 |
| lit-mentor | Company | 45 | 441 | 148 | 9.800000 | 2.979730 |
| swift | Programming Langs | 239 | 433 | 279 | 1.811715 | 1.551971 |
| ios | Mobile | 198 | 429 | 229 | 2.166667 | 1.873362 |
| a-t-brides | Company | 26 | 422 | 157 | 16.230769 | 2.687898 |
| iotlt_neo | IoT | 104 | 408 | 331 | 3.923077 | 1.232628 |
| go | Programming Langs | 395 | 397 | 278 | 1.005063 | 1.428058 |

## いいね数/UU

カレンダー毎のいいね数/UUのグラフです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35192/d00dabfc-64bc-bf95-8b85-ffbdbae0a160.png)

ヒストグラムで表示してみます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35192/d604dab2-8bd0-2e82-0981-3bdf7a4b4c75.png)

ほぼ1〜2の範囲に収まっています。３を超えるものは異常値とみて良さそうですね。

```py3
cals[cals['likes/uu'] >= 3]
```

| calendar_id | category | subs | likes | uu | likes/sub | likes/uu |
|:--|:--|--:|--:|--:|--:|--:|
| fromscratch | Company | 94 | 3065 | 526 | 32.606383 | 5.826996 |
| fringe81 | Company | 43 | 704 | 206 | 16.372093 | 3.417476 |
| accounting_saas_japan | Company | 16 | 467 | 80 | 29.187500 | 5.837500 |

## 日別いいね数

各カレンダーの日別(記事別)いいね数のヒストグラムです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35192/2036fb32-035b-0d83-d098-1f0b719ba985.png)

ほとんどが100いいね程度まで、これを超えるのはバズった記事と言えそうです。これは普段の投稿と感覚的には同じですね。

### カテゴリー毎の基本統計量

カテゴリー毎に日別いいね数の基本統計量を見てみます。
左からカテゴリー、記事件数、平均いいね数、標準偏差、最小いいね数、四分位点、最大いいね数です。

| category | count | mean | std | min | 25% | 50% | 75% | max |
|:--|--:|--:|--:|--:|--:|--:|--:|--:|
| Academic | 14.0 | 42.642857 | 55.556772 | 1.0 | 10.0 | 19.0 | 63.75 | 208.0 |
| Company | 758.0 | 54.098945 | 131.516465 | 1.0 | 11.0 | 18.0 | 32.75 | 1437.0 |
| IoT | 43.0 | 34.627907 | 84.698913 | 3.0 | 6.0 | 12.0 | 22.50 | 497.0 |
| Libraries | 52.0 | 39.019231 | 116.758086 | 1.0 | 3.0 | 8.5 | 18.25 | 754.0 |
| Miscellaneous | 25.0 | 88.600000 | 237.404718 | 3.0 | 5.0 | 10.0 | 24.00 | 1092.0 |
| Mobile | 37.0 | 26.810811 | 40.496802 | 4.0 | 8.0 | 15.0 | 27.00 | 241.0 |
| Programming Langs | 87.0 | 24.919540 | 33.193309 | 2.0 | 7.0 | 16.0 | 25.00 | 210.0 |

「企業・学校・団体」で特に目立った特徴は見当たりません。

### カレンダー単位の基本統計量

カレンダー単位でみてみます。

| calendar_id | count | mean | std | min | 25% | 50% | 75% | max |
|:--|--:|--:|--:|--:|--:|--:|--:|--:|
| fromscratch | 25.0 | 123.560000 | 32.751692 | 95.0 | 104.00 | 112.0 | 131.00 | 248.0 |
| tis | 25.0 | 122.160000 | 226.398925 | 14.0 | 22.00 | 35.0 | 63.00 | 870.0 |
| crowdworks | 24.0 | 105.875000 | 280.889629 | 22.0 | 25.00 | 28.0 | 47.75 | 1402.0 |
| livesense-gaku | 25.0 | 98.880000 | 240.755464 | 6.0 | 20.00 | 26.0 | 35.00 | 901.0 |
| ateam-lifestyle | 25.0 | 96.120000 | 145.153459 | 18.0 | 28.00 | 34.0 | 70.00 | 585.0 |
| musashino | 22.0 | 107.863636 | 201.179923 | 21.0 | 31.25 | 53.0 | 90.50 | 983.0 |
| ex-mixi | 11.0 | 177.272727 | 249.809564 | 9.0 | 21.50 | 30.0 | 211.00 | 785.0 |
| mixi | 20.0 | 95.550000 | 316.941880 | 4.0 | 11.75 | 14.0 | 28.00 | 1437.0 |
| litalico | 24.0 | 62.250000 | 128.545796 | 13.0 | 17.00 | 19.0 | 25.50 | 573.0 |
| increments | 9.0 | 156.777778 | 191.897614 | 2.0 | 25.00 | 52.0 | 276.00 | 509.0 |
| livesense-kan | 25.0 | 54.600000 | 105.620389 | 9.0 | 18.00 | 22.0 | 29.00 | 455.0 |
| livesense-ji | 25.0 | 54.280000 | 95.060735 | 10.0 | 21.00 | 32.0 | 62.00 | 498.0 |
| kuso-app2017 | 16.0 | 82.375000 | 269.519047 | 3.0 | 5.75 | 11.5 | 22.50 | 1092.0 |
| basicinc | 24.0 | 46.291667 | 82.673522 | 3.0 | 10.00 | 16.0 | 27.00 | 344.0 |
| smart-speaker | 23.0 | 46.913043 | 101.306875 | 6.0 | 12.50 | 19.0 | 31.50 | 497.0 |
| wacul | 23.0 | 44.913043 | 106.530795 | 1.0 | 3.50 | 8.0 | 20.00 | 381.0 |
| globis | 21.0 | 46.380952 | 57.926226 | 15.0 | 22.00 | 26.0 | 29.00 | 256.0 |
| dmm2 | 20.0 | 46.900000 | 103.101840 | 5.0 | 9.25 | 14.0 | 28.00 | 470.0 |
| nttcom | 24.0 | 37.750000 | 77.884669 | 4.0 | 8.50 | 18.0 | 32.00 | 391.0 |
| axe | 9.0 | 99.666667 | 180.739453 | 3.0 | 3.00 | 8.0 | 51.00 | 503.0 |
| justsystems | 25.0 | 34.480000 | 134.730632 | 2.0 | 4.00 | 9.0 | 11.00 | 681.0 |
| cdatasoftware | 16.0 | 49.750000 | 187.803621 | 1.0 | 2.00 | 3.0 | 3.25 | 754.0 |
| dwango | 18.0 | 41.666667 | 59.978427 | 6.0 | 9.50 | 18.0 | 36.50 | 248.0 |
| m3 | 24.0 | 30.916667 | 58.471038 | 9.0 | 11.00 | 15.0 | 23.00 | 300.0 |
| fujitsu | 21.0 | 34.714286 | 110.747976 | 2.0 | 4.00 | 9.0 | 18.00 | 517.0 |
| fringe81 | 25.0 | 28.200000 | 9.451631 | 17.0 | 22.00 | 25.0 | 29.00 | 58.0 |
| vue2 | 18.0 | 37.444444 | 77.196634 | 2.0 | 7.75 | 14.5 | 28.75 | 337.0 |
| lifull2 | 25.0 | 25.560000 | 74.079394 | 3.0 | 5.00 | 7.0 | 11.00 | 375.0 |
| lifull | 23.0 | 25.652174 | 70.808711 | 3.0 | 6.00 | 9.0 | 15.00 | 349.0 |
| ut_ap | 18.0 | 35.222222 | 116.619823 | 1.0 | 5.50 | 7.5 | 8.75 | 502.0 |
| math-and-computer | 14.0 | 42.642857 | 55.556772 | 1.0 | 10.00 | 19.0 | 63.75 | 208.0 |
| javascript | 20.0 | 22.550000 | 27.169013 | 4.0 | 6.00 | 15.0 | 20.75 | 100.0 |
| hikkoshi | 25.0 | 22.720000 | 18.183142 | 9.0 | 15.00 | 18.0 | 23.00 | 103.0 |
| dwango2 | 15.0 | 35.733333 | 62.419625 | 1.0 | 9.00 | 11.0 | 20.00 | 240.0 |
| vue | 18.0 | 31.055556 | 60.325073 | 2.0 | 7.25 | 11.0 | 31.25 | 265.0 |
| firstserver | 24.0 | 22.625000 | 33.732725 | 8.0 | 11.00 | 13.0 | 17.00 | 162.0 |
| retty | 25.0 | 21.680000 | 28.988101 | 3.0 | 6.00 | 11.0 | 17.00 | 130.0 |
| firebase | 19.0 | 29.421053 | 54.398035 | 4.0 | 9.00 | 12.0 | 19.50 | 241.0 |
| okinawarb | 3.0 | 167.333333 | 219.730138 | 8.0 | 42.00 | 76.0 | 247.00 | 418.0 |
| toreta | 18.0 | 27.000000 | 89.658174 | 1.0 | 3.25 | 5.0 | 8.00 | 386.0 |
| accounting_saas_japan | 25.0 | 18.800000 | 6.474308 | 13.0 | 16.00 | 17.0 | 19.00 | 43.0 |
| vasily | 23.0 | 20.000000 | 16.234083 | 7.0 | 11.00 | 13.0 | 19.50 | 67.0 |
| webassembly | 14.0 | 32.500000 | 54.023855 | 2.0 | 8.00 | 12.0 | 24.50 | 210.0 |
| rust-lang | 19.0 | 22.789474 | 15.820447 | 4.0 | 15.00 | 21.0 | 26.00 | 71.0 |
| lit-mentor | 24.0 | 18.416667 | 6.021098 | 5.0 | 15.00 | 18.0 | 23.00 | 32.0 |
| swift | 18.0 | 24.555556 | 26.417958 | 2.0 | 5.25 | 14.5 | 37.75 | 98.0 |
| ios | 18.0 | 24.055556 | 18.001543 | 6.0 | 9.50 | 17.5 | 30.25 | 65.0 |
| a-t-brides | 25.0 | 17.000000 | 14.352700 | 8.0 | 12.00 | 15.0 | 16.00 | 84.0 |
| iotlt_neo | 20.0 | 20.500000 | 59.847614 | 3.0 | 4.00 | 5.5 | 10.50 | 274.0 |
| go | 16.0 | 24.187500 | 41.153726 | 4.0 | 7.75 | 14.0 | 22.00 | 175.0 |

先ほどの３つのカレンダーが今回も特徴的な値を示しています。

- 最小値が大きい
- 最大値が小さい
- 標準偏差が小さい(いいね数のばらつきが小さい)

## 最小いいね数

各カレンダーの最小いいね数です。
`fromscratch`だけ95というダントツの異常値を出しているのでグラフ最大値は30までにしてあります。

```py3
likes_by_date.groupby(level=0, sort=False)['item_likes'].min()[:50].plot.barh(figsize=(4, 10), color=colors, xlim=(0, 30)).invert_yaxis()
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35192/b459c33f-0a7f-146a-ee00-ce2d1216024a.png)

「企業・学校・団体」のカレンダーに大きい値が目立ちます。

## ライカー別いいね数

ライカー毎にそのカレンダーのいくつの記事にいいねしているかを集計した結果です。

```py3
likes_by_user = pd.DataFrame(likers.loc[cals.index].groupby('calendar_id')['user_name'].value_counts().rename('likes'))
likes_by_user = likes_by_user.join(cals['category'])
likes_by_user[:3]
```

| calendar_id | user_name | likes | category |
|:--|:--|:--|:--|
| a-t-brides | ueki05 | 24 | Company |
| a-t-brides | nishio1873 | 23 | Company |
| a-t-brides | rf_p | 22 | Company |

上の最終行は`a-t-brides`のカレンダー内で`rf_p`というユーザーが22件の記事にいいねしているということです。

ヒストグラムを表示してみます。Y軸は対数です。

```py3:
likes_by_user.plot.hist(logy=True, bins=50)
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35192/98edf8a2-2b95-803b-83f6-6f9091e2e2d1.png)

1カレンダー当たり1〜5件程度の記事にいいねしている人が最も多いですが、20〜25件の記事にいいねしている人もそこそこいるようです。

## ヘビーライカーの割合

先ほどのライカー別いいね数を更にいいね数で集計します。

```py3
uu_by_likes = likes_by_user.groupby('calendar_id')['likes'].value_counts(sort=False).rename('uu').reset_index('likes')
uu_by_likes['likes_total'] = uu_by_likes['likes'] * uu_by_likes['uu']

uu_by_likes = pd.DataFrame(uu_by_likes).join(cals[['category', 'likes']].rename(columns={'likes': 'cal_likes'}))
uu_by_likes = uu_by_likes.sort_values(['cal_likes', 'likes'], ascending=[False, True]).set_index('likes', append=True)
uu_by_likes = uu_by_likes.drop('cal_likes', axis=1)

uu_by_likes[:3]
```

| calendar_id | likes | uu | category | cal_likes | likes_total |
|:--|:--|:--|:--|--:|--:|
| fromscratch | 1 | 341 | Company | 3065 | 341 |
| fromscratch | 2 | 52 | Company | 3065 | 104 |
| fromscratch | 3 | 8 | Company | 3065 | 24 |

上の最終行は`fromscratch`のカレンダー内で３つの記事にいいねしている人が８人いて、この人たちのいいね数合計が8x3=24ということです。
これを円グラフにすることでいいね数が多いユーザー＝ヘビーライカーの割合を視覚化できます。

### 「企業・学校・団体」とその他

「企業・学校・団体」とその他でのヘビーライカーの割合です。
色の濃い部分がヘビーライカーを表してます。
赤が「企業・学校・団体」、その他が青、左がライカー数、右がいいね数合計です。

```py3
uu_by_likes.loc[uu_by_likes['category'] == 'Company'].groupby('likes')[['uu', 'likes_total']].sum().plot.pie(subplots=True, figsize=(12, 6), colormap='Reds', legend=None)
uu_by_likes.loc[uu_by_likes['category'] != 'Company'].groupby('likes')[['uu', 'likes_total']].sum().plot.pie(subplots=True, figsize=(12, 6), colormap='Blues', legend=None)
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35192/be60bfbc-6913-2480-2d5c-2f22c607d230.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/35192/7eb5b634-efb6-b754-fe37-6d3ed2f6e73d.png)

ライカー数では違いがわかりませんが、いいね数合計で見ると「企業・学校・団体」のほうがヘビーライカーの影響が大きいことがわかります。

### カレンダー毎のヘビーライカーの割合

次はカレンダー毎に見ていきます。
まずはライカー数の割合です。

```py3:
fig, ax = plt.subplots(5, 10, figsize=(12, 6))
for axes, (calendar_id, df) in zip(ax.flatten(), uu_by_likes.groupby(level=0, sort=False)['uu']):
    colormap = 'Reds' if is_company[calendar_id] else 'Blues'
    df.plot.pie(ax=axes, title=calendar_id, colormap=colormap, labels=None)
    axes.get_yaxis().set_visible(False)
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35192/26c92a1a-0b15-946f-91e6-23a35f01de58.png)

ヘビーライカーが多いカレンダーがいくつか存在します。

### カレンダー毎のヘビーライカーいいね数合計の割合

いいね数割合です。

```py3:
fig, ax = plt.subplots(5, 10, figsize=(12, 6))
for axes, (calendar_id, df) in zip(ax.flatten(), uu_by_likes.groupby(level=0, sort=False)['likes_total']):
    colormap = 'Reds' if is_company[calendar_id] else 'Blues'
    df.plot.pie(ax=axes, title=calendar_id, colormap=colormap, labels=None)
    axes.get_yaxis().set_visible(False)
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/35192/bfdaf92d-1c02-24eb-deb2-c02a036a8b33.png)

ライカー数で見るより特徴が顕著に現れました。ヘビーライカーによるいいね数が3/4以上というカレンダーも存在しますね。

# わかったこと

- 購読者数といいね数の関係
    - 購読者数といいね数は相関関係にあり、購読者が多ければいいね数も多い
    - 「企業・学校・団体」カテゴリーは購読者一人当たりのいいね数が多い
- 「企業・学校・団体」カテゴリーの特徴
    - 1カレンダー当たりのいいね数が多い
    - 1購読者当たりのいいね数が多い
    - 最小いいね数が大きい
- 「企業・学校・団体」カテゴリーの一部カレンダーの特徴
    - 1ライカー当たりのいいね数が多い
    - 記事別いいね数のばらつきが小さい
    - ヘビーライカーによるいいね数への影響が大きい

# 考察

「企業・学校・団体」カテゴリーの購読者には、その組織に所属している人が多いのでしょう。そういう人たちは内容に関わらず同僚の記事はひいき目にいいねすると思うので、結果的にヘビーライカーが多くなりいいね数が伸びるのではないでしょうか。

# 感想

Pandas と Jupyter Notebook を使ったのは今回がほぼ初めてです。
今までこういうことをやるのは Excel や Googleスプレッドシート でピボットテーブルやグラフを作っていました。それと比べると格段にやりやすいですね。
でもPandasは覚えたてなのでまだ使いこなせていない所もあり、もっと簡単に書けたりわかりやすくビジュアライズできる所もあるかもしれません。
この辺りはこれから徐々に覚えていきたいと思います。