Qiitaのタグを2018/12～2019/3の記事数、フォロワー数、いいね数で比較してみた

※tag1216さんの指摘により、集計期間間違っていることに気付いたので、タイトル等を修正しました。

先日、「[Qiitaタグの記事数とフォロワー数を比較してみた](https://qiita.com/j5c8k6m8/items/b184ca0f43517ad5fcf3)」を初投稿した。
投稿後に自身の関連記事を見てみると、、
最上位の記事「[Qiitaの投稿をNVD3で可視化してみるとRuby人気なんだなと改めて分かった。](https://qiita.com/ganezasan/items/a8b2e48b6da7f7eafc7d)」と、グラフの形式が完全に被っていることと、グラフの見やすさも私の方が劣っていた。
~~正規化や、記事投稿の動機の1つにもなった「#migrated」などオリジナルな観点もあったけど。~~

そのため、今回は下記、投稿後に思った下記改善を考慮し、**完全オリジナル**な内容にアップデートする。

- 全数では5年以上のデータとなり、トレンドがわからないため、**2018/12～2019/3**のデータでグラフを作成する。フォロワーは、集計期間に記事を投稿したユーザのみを対象とする。
- バブルチャートでは3軸の可視化ができるため、**いいね数も評価**する。
- 傾向からグループを決定して**チャートの色分け**を行う。
- chart.jsがスマホ環境では崩れていたため、不要なラベルを消して**スマホでも結果を見やすく**する。

# やったこと

- Qiita apiの記事一覧を日付毎に2018/12～2019/3まで取得し、タグ毎の記事数と、タグ毎のいいね数、投稿ユーザ一覧を集計する。
- 上記で取得した全てのユーザについて、フォローしているタグを集計し、タグ毎のフォロワー数を集計する。（今回投稿ユーザが15,178ユーザいたので、1,000回/1hのAPI制限があるので、15時間以上APIを動かし続けてデータを取得した）
- 記事数、フォロワー数、いいね数を、正規化し、同じ重み付けで上位10を決定し、前回の全数のランキングと比較する
- 上位100について、記事数、フォロワー数、いいね数の傾向でタグを19個のグループに分ける
- 上位100について、バブルチャートで、いいね数を大きさで表して、グループ毎に色分けしてグラフ化する。

# 結果

総タグ数: 15,649, 
総記事数: 43,684, 
総投稿者数: 15,178, 
総タグ記事数: 12,1912, 
総タグフォロワー数: 91,046, 
総タグいいね数: 1,307,100 

## 集計方法の変更による違い(全数 vs 2018/12～2019/3)

前回記事と順位の差異を含めて下記の通り。

前回記事と比較して、フォロワー数側に大きく変化が生じたのは、フォロワー数をその期間に記事を投稿している人に限っているのが大きいかもしれないが、前回の結果はフォロワー数側に引っ張られて評価値順位が高いものもあったため、今回の修正は妥当（期間を区切った集計の方が有意な結果となる）だと考える。

なお、Railsが評価+8は少し意外だが、それだけRailsのフォロワーに投稿者が多いのではないかと推測する。

| タグ名 | 評価値順位 | フォロワー数順位 | 記事数順位 | 評価値(%) | フォロワー数 | 記事数 | 評価値差分(%) |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
Python|1<font color="blue">(+1)</font>|1<font color="blue">(+1)|1(-)|3.35|3175|3928|0.27
JavaScript|2<font color="red">(-1)</font>|2<font color="red">(-1)</font>|2(-)|2.76|3106|2583|1.29
Ruby|3(-)|4<font color="blue">(+10)</font>|3(-)|1.72|1829|1747|0.58
PHP|4(-)|9(-)|6<font color="red">(-2)</font>|1.48|1642|1405|0.65
Rails|5<font color="blue">(+8)</font>|15<font color="blue">(+14)</font>|4<font color="blue">(+1)</font>|1.40|1355|1603|0.17
Java|6<font color="red">(-1)</font>|6<font color="blue">(+1)</font>|12<font color="red">(-3)</font>|1.34|1715|972|1.09
GitHub|7<font color="blue">(+3)</font>|3<font color="blue">(+2)</font>|30(-)|1.33|2032|522|1.80
Git|8<font color="blue">(+3)</font>|5<font color="blue">(+8)</font>|21<font color="red">(-7)</font>|1.28|1812|689|1.43
Linux|9<font color="red">(-1)</font>|8<font color="blue">(+4)</font>|18<font color="red">(-6)</font>|1.28|1709|826|1.20
Android|10<font color="red">(-4)</font>|13<font color="red">(-2)</font>|14<font color="red">(-6)</font>|1.19|1471|927|0.86

# いいね数も含めたTOP100

タグ名|評価値順位|フォロワー数順位|記事数順位|いいね数順位|評価値|フォロワー数|記事数|いいね数
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
Python|1|1|1|2|3.54 |3175|3928|51004
JavaScript|2|2|2|1|3.25 |3106|2583|55042
Ruby|3|4|3|14|1.43 |1829|1747|10901
PHP|4|9|6|18|1.22 |1642|1405|9305
Rails|5|15|4|24|1.16 |1355|1603|8946
HTML|6|7|28|6|1.14 |1710|544|14513
Git|7|5|21|22|1.08 |1812|689|9142
Vue.js|8|41|13|3|1.07 |587|966|23240
Linux|9|8|18|27|1.06 |1709|826|8186
Java|10|6|12|35|1.04 |1715|972|5684
GitHub|11|3|30|36|1.03 |2032|522|5666
CSS|12|11|24|12|1.02 |1518|633|11473
AWS|13|29|5|16|1.01 |869|1597|10088
Docker|14|26|8|8|1.01 |931|1187|13399
Node.js|15|14|17|20|0.99 |1412|851|9250
Android|16|13|14|30|0.98 |1471|927|7521
iOS|17|18|11|9|0.98 |1122|975|11733
機械学習|18|40|20|4|0.91 |597|765|18793
C++|19|24|23|17|0.77 |978|636|9339
初心者|20|101|9|5|0.77 |125|1012|17543
C#|21|23|16|32|0.76 |994|857|6222
Swift|22|37|10|29|0.72 |688|980|7880
Go|23|36|19|26|0.69 |697|786|8723
HTML5|24|10|68|82|0.69 |1525|225|2700
Mac|25|21|22|52|0.67 |1083|640|3708
MySQL|26|16|27|161|0.65 |1260|556|1546
Python3|27|62|7|28|0.65 |314|1210|7945
Qiita|28|12|88|142|0.65 |1508|182|1731
Unity|29|48|15|25|0.62 |422|864|8859
DeepLearning|30|52|32|7|0.61 |372|491|13471
TypeScript|31|49|29|11|0.60 |417|540|11608
Vim|32|17|59|53|0.58 |1145|260|3696
React|33|45|26|19|0.58 |483|621|9264
jQuery|34|19|54|56|0.57 |1107|265|3667
Firebase|35|65|37|10|0.53 |303|428|11687
Chrome|36|25|86|51|0.50 |962|183|3735
iPhone|37|20|193|123|0.48 |1106|84|1930
新人プログラマ応援|38|67|55|13|0.46 |258|263|11383
Xcode|39|32|41|92|0.45 |779|350|2536
Twitter|40|30|92|75|0.44 |863|170|2939
CSS3|41|22|174|167|0.43 |1002|94|1429
Ubuntu|42|34|38|285|0.42 |767|427|816
Laravel|43|63|25|41|0.41 |309|632|4765
C|44|33|52|118|0.41 |768|266|2049
kubernetes|45|58|31|37|0.40 |335|494|5651
ポエム|46|123|43|15|0.39 |85|338|10632
MacOSX|47|27|96|567|0.39 |909|165|332
RaspberryPi|48|59|34|42|0.37 |332|463|4734
CentOS|49|35|52|215|0.37 |727|266|1109
ShellScript|50|31|114|575|0.36 |846|146|329
正規表現|51|28|188|473|0.36 |877|87|418
Kotlin|52|53|35|74|0.33 |366|446|3023
自然言語処理|53|91|106|23|0.32 |138|155|9032
TensorFlow|54|57|55|43|0.31 |338|263|4628
Heroku|55|46|44|119|0.31 |465|309|2040
nuxt.js|56|91|44|31|0.31 |138|309|6682
VSCode|57|68|42|40|0.30 |231|344|4798
golang|58|51|47|73|0.30 |382|300|3032
MachineLearning|59|75|58|33|0.30 |190|262|6096
SSH|60|38|115|420|0.29 |656|145|498
Apache|61|39|118|599|0.29 |654|138|314
個人開発|62|214|167|21|0.28 |44|99|9247
nginx|63|42|85|398|0.28 |578|185|543
Slack|64|69|49|55|0.26 |228|288|3688
Scala|65|44|90|214|0.26 |487|178|1113
Django|66|71|36|111|0.25 |198|433|2175
Rust|67|65|79|98|0.23 |303|198|2448
Windows|68|124|33|101|0.22 |84|475|2403
Haskell|69|50|156|139|0.22 |390|105|1741
gcp|70|83|47|71|0.22 |149|300|3095
Keras|71|80|65|54|0.22 |162|226|3689
Emacs|72|47|187|257|0.21 |457|88|924
docker-compose|73|181|64|39|0.21 |53|242|5072
数学|74|89|82|45|0.21 |139|189|4394
Objective-C|75|43|360|421|0.21 |504|45|492
SQL|76|98|39|134|0.19 |129|371|1797
lambda|77|107|40|126|0.19 |109|359|1914
OpenCV|78|84|65|77|0.19 |147|226|2778
GoogleAppsScript|79|78|63|106|0.19 |167|243|2281
Bash|80|98|55|87|0.18 |129|263|2581
Elixir|81|72|74|110|0.18 |197|205|2177
Flutter|82|85|70|93|0.18 |143|217|2534
ネタ|83|500|379|34|0.17 |14|43|6037
Elm|84|107|128|60|0.17 |109|131|3631
Zsh|85|55|273|262|0.17 |348|61|898
競技プログラミング|86|121|80|68|0.17 |89|193|3193
IoT|87|96|59|131|0.17 |132|260|1843
MongoDB|88|56|202|329|0.17 |341|82|705
Azure|89|86|46|205|0.16 |142|301|1163
データ分析|90|130|109|62|0.16 |79|154|3571
設計|91|262|308|38|0.16 |33|53|5262
アルゴリズム|92|130|124|64|0.16 |79|134|3517
UX|93|248|188|44|0.15 |36|87|4563
初心者向け|94|901|106|46|0.15 |6|155|4235
GoogleCloudPlatform|95|93|76|130|0.15 |135|202|1848
pandas|96|146|74|79|0.15 |66|205|2754
R|97|77|78|192|0.15 |170|200|1268
PostgreSQL|98|94|51|287|0.15 |134|280|801
api|99|199|68|89|0.14 |47|225|2572
AI|100|194|119|65|0.14 |48|136|3501


# グループの決定

~~多次元データ分析に全く詳しくないため、~~直感的にフォロワー数/記事数/いいね値数の**一部が多いもの**、**一部が少ない**もので下記の(6 * 3) + 1 = 19グループに分ける
※判定は+や-数が多い順に行う

グループ名|色|判定内容|タグ(TOP100内)|補足
|:-:|:-:|:-:|:---|:-:|
いいね+++|`rgba(255, 0, 0, 0.5)`|いいねの割合が一番高く、<br>他のポイントの2.5倍以上|DeepLearning<br>Firebase<br>新人プログラマ応援<br>ポエム<br>自然言語処理<br>個人開発<br>ネタ<br>設計<br>UX<br>初心者向け|記事数/フォロワー数の割にいいねが多い?
いいね++|`rgba(191, 0, 0, 0.4)`|いいねの割合が一番高く、<br>他のポイントの1.6倍以上|Vue.js<br>機械学習<br>TypeScript<br>nuxt.js<br>MachineLearning<br>数学<br>Elm<br>データ分析<br>アルゴリズム<br>AI|記事数/フォロワー数の割にいいねが多い?
いいね+|`rgba(127, 0, 0, 0.3)`|いいねの割合が一番高く、<br>他のポイントの1.1倍以上|Python<br>React<br>VSCode<br>Slack<br>Keras<br>OpenCV|記事数/フォロワー数の割にいいねが多い?
フォロワー+++|`rgba(0, 0, 255, 0.5)`|フォロワーの割合が一番高く、<br>他のポイントの2.5倍以上|Git<br>Linux<br>GitHub<br>HTML5<br>MySQL<br>Qiita<br>Vim<br>jQuery<br>Chrome<br>iPhone<br>Xcode<br>Twitter<br>CSS3<br>C<br>MacOSX<br>CentOS<br>ShellScript<br>正規表現<br>SSH<br>Apache<br>nginx<br>Scala<br>Haskell<br>Emacs<br>Objective-C<br>Zsh<br>MongoDB|記事数/記事内容共に不足している?
フォロワー++|`rgba(0, 0, 191, 0.4)`|フォロワーの割合が一番高く、<br>他のポイントの1.6倍以上|HTML<br>Java<br>CSS<br>Node.js<br>Android<br>Mac<br>Heroku<br>golang<br>Rust|記事数/記事内容共に不足している?
フォロワー+|`rgba(0, 0, 127, 0.3)`|フォロワーのポイントが一番高く、<br>他のポイントの1.1倍以上|iOS<br>C++<br>C#<br>Go<br>Elixir|記事数/記事内容共に不足している?
記事数+++|`rgba(0, 255, 0, 0.5)`|記事数の割合が一番高く、<br>他のポイントの2.5倍以上|-|フォロワーが少なく、いいねがもらいにくい?
記事数++|`rgba(0, 191, 0, 0.4)`|記事数の割合が一番高く、<br>他のポイントの1.6倍以上|Python3<br>Django<br>Windows<br>SQL<br>lambda|フォロワーが少なく、いいねがもらいにくい?
記事数+|`rgba(0, 127, 0, 0.3)`|記事数の割合が一番高く、<br>他のポイントの1.1倍以上|AWS<br>Laravel<br>IoT<br>GoogleCloudPlatform|フォロワーが少なく、いいねがもらいにくい?
いいね---|`rgba(0, 255, 255, 0.4)`|いいねの割合が一番低く、<br>他のポイントの0.4倍以下|Ubuntu|記事数、フォロワー数は比較的多いが、いいねがつきにくい?
いいね--|`rgba(0, 191, 191, 0.3)`|いいねの割合が一番低く、<br>他のポイントの0.625倍以下|Ruby<br>PHP<br>Rails<br>Azure<br>R<br>PostgreSQL|記事数、フォロワー数は比較的多いが、いいねがつきにくい?
いいね-|`rgba(0, 127, 127, 0.2)`|いいねの割合が一番低く、<br>他のポイントの0.9倍以下|Swift<br>Kotlin|記事数、フォロワー数は比較的多いが、いいねがつきにくい?
フォロワー---|`rgba(255, 255, 0, 0.4)`|フォロワーの割合が一番低く、<br>他のポイントの0.4倍以下|初心者<br>docker-compose<br>api|フォロワー数は比較的少ないが、記事は多く、いいねもついている?
フォロワー--|`rgba(191, 191, 0, 0.3)`|フォロワーの割合が一番低く、<br>他のポイントの0.625倍以下|競技プログラミング<br>pandas|フォロワー数は比較的少ないが、記事は多く、いいねもついている?
フォロワー-|`rgba(127, 127, 0, 0.2)`|フォロワーの割合が一番低く、<br>他のポイントの0.9倍以下|Unity<br>kubernetes<br>gcp<br>Bash<br>Flutter|フォロワー数は比較的少ないが、記事は多く、いいねもついている?
記事数---|`rgba(255, 0, 255, 0.4)`|記事数の割合が一番低く、<br>他のポイントの0.4倍以下|-|記事数は比較的少ないが、フォロワーは多く、いいねもついている?
記事数--|`rgba(191, 0, 191, 0.3)`|記事数の割合が一番低く、<br>他のポイントの0.625倍以下|JavaScript<br>TensorFlow|記事数は比較的少ないが、フォロワーは多く、いいねもついている?
記事数-|`rgba(127, 0, 127, 0.2)`|記事数の割合が一番低く、<br>他のポイントの0.9倍以下|-|記事数は比較的少ないが、フォロワーは多く、いいねもついている?
バランス|`rgba(0, 0, 0, 0.4)`|上記以外<br>分散が近い|Docker<br>RaspberryPi<br>GoogleAppsScript|-

# グラフ化

縦軸が「記事数」、横軸が「フォロワー数」、円の大きさを「いいね数」で表して、上記のグループ色でグラフ化しました。

<p class="codepen" data-height="1062" data-theme-id="0" data-default-tab="result" data-user="j5c8k6m8" data-slug-hash="zQjKxJ" style="height: 1062px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="qiita_tag_score_v2">
  <span>See the Pen <a href="https://codepen.io/j5c8k6m8/pen/zQjKxJ/">
  qiita_tag_score_v2</a> by j5c8k6m8 (<a href="https://codepen.io/j5c8k6m8">@j5c8k6m8</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

~~tooltipとかスケールとか頑張ればもう少し何とかなりますが、疲れたので。~~

# 考察等

- グラフで見ると、「Python」と「JavaScript」が圧倒的。JavaScriptはフォロワー数やいいね数に比べると記事が不足気味
- 記事数よりもいいね数のほうが顕著にトレンドを表しているように見える。2018/12～2019/3でいうとDeepLearning,Firebase,自然言語処理,Vue.js,機械学習,TypeScript,nuxt.js,Elmあたり
- RUby,Rails,PHPは安定し記事数やフォロワー数に対して「いいね」はつきにくい。
- AWSは記事数は多いが、いいね数は少ない
- gitを含めフォロワー数が多いが、記事数といいね数が少ない安定した領域が多い←これはPythonやJavaScriptにデータが引っ張られている要因もあるかも

# コード

<details><summary>使用した全コードはこちら</summary><div>

~~汚いので参考まで~~

``` javascript:getItems.js
const moment = require('moment')
const DATE_PIRIOD = [ '2018-12-01', '2019-03-31' ];

let request = require('request');
let fs = require("fs");

let headers = {
    'Authorization': 'Bearer 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcd' // token
};

let itesm = [];
let users = [];

function getDayItems(argMoment, cnt, callback) {
  let options = {
    url: `https://qiita.com/api/v2/items?page=${cnt}&per_page=100&query=created:<${argMoment.format('YYYY-MM-DD')}`,
    headers: headers
  }
  request(options, function(error, response, body) {
    if (error) {
        return console.error('ERROR!', error);
    } else {
        let subtractDate = moment(argMoment.format('YYYY-MM-DD') + 'T09:00:00+09:00').subtract(1, 'days');
        console.log(subtractDate.format('YYYY-MM-DD'));
        let tmp = JSON.parse(body).filter( v => subtractDate.isSameOrBefore(v.created_at));
        users = users.concat(tmp.map( v => v.user.id));
        itesm = itesm.concat(tmp.map( v => { return { id: v.id, likes_count: v.likes_count, tags: v.tags, created_at: v.created_at}; }));
        if (tmp.length === 100) {
          setTimeout( () => getDayItems(argMoment, cnt + 1, callback), 3600); // 3,600秒 / 1,000回
        } else {
          callback();
        }
    }
  });
}

function getPeriod(target_moment, end_moment) {
  if (end_moment.isSameOrBefore(target_moment)) {
    getDayItems(target_moment, 1, () => getPeriod(target_moment.subtract(1, 'days'), end_moment));
  } else {
    fs.writeFile('itesm.json', JSON.stringify(itesm) , (err, data) => {});
    fs.writeFile('users.json', JSON.stringify(users.filter((x, i, self) => self.indexOf(x) === i)), (err, data) => {});
    fs.writeFile('created_at.list', itesm.map( v => v.created_at ).join('\n') , (err, data) => {});
  
  }
}
getPeriod(moment(DATE_PIRIOD[1]).add(1, 'days'), moment(DATE_PIRIOD[0]).add(1, 'days'));
```

``` javascript:getFollowers.js
let request = require('request');
let fs = require("fs");

let headers = {
    'Authorization': 'Bearer 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcd' // token
};

let tags = [];
let followers = [];

function getFollowers(user_id) {
  return new Promise( (resolve) => {
    let options = {
      url: `https://qiita.com/api/v2/users/${user_id}/following_tags`,
      headers: headers
    }
    request(options, function(error, response, body) {
      if (error) {
          return console.error('ERROR!', error);
      } else {
          let followers = JSON.parse(body);
          fs.writeFile(`./followers/${user_id}.json`, JSON.stringify(followers) , (err, data) => {});
          setTimeout( () => resolve(followers), 3600); // 3,600 * 1000秒 / 1,000回
      }
    });
  });
}

function getFollowersByFile(path) {
  return new Promise( (resolve) => {
    fs.readFile(path, 'utf8', function (err, text) {
      let followers = JSON.parse(text);
      resolve(followers);
    });
  });
}

(async () => {
  fs.readFile('./users.json', 'utf8', async (err, text) => {
    let user = JSON.parse(text);
    for (let i = 0; i < user.length; i++) {
      let follower_tags;
      try {
        fs.statSync(`./followers/${user[i]}.json`);
        follower_tags = await getFollowersByFile(`./followers/${user[i]}.json`);
      } catch(err) {
        follower_tags = await getFollowers(user[i]);
      }
      tags.push(follower_tags);
      console.log(tags.length);
    }
    fs.writeFile('followers.json', JSON.stringify(tags) , (err, data) => {});
  });
})()

```

``` javascript:createTags.js
let fs = require("fs");
let tag_Hash = {};
let tags = [];

fs.readFile('./items.json', 'utf8', function (err, text) {
  let items = JSON.parse(text);
  items.forEach(item => {
    item.tags.forEach( tag => {
      if (tag.name) {
        if (!tag_Hash[tag.name]) {
          tag_Hash[tag.name] = { id: tag.name, items_count: 0, followers_count: 0, likes_count: 0 };
          tags.push(tag_Hash[tag.name]);
        }
        tag_Hash[tag.name].items_count += 1;
        tag_Hash[tag.name].likes_count += item.likes_count;
      }
    });
  });

  fs.readFile('./followers.json', 'utf8', function (err, text) {
    let followers = JSON.parse(text);
    followers.forEach(follower_tags => {
      if (follower_tags.type !== 'not_found') {
        follower_tags.forEach( tag => {
            if (!tag_Hash[tag.id]) {
              tag_Hash[tag.id] = { id:tag.id, items_count: 0, followers_count: 0, likes_count: 0 };
              tags.push(tag_Hash[tag.id]);
            }
            tag_Hash[tag.id].followers_count += 1;
        });
      }
    });
    fs.writeFile('tags.json', JSON.stringify(tags) , (err, data) => {});
  });
});

```

``` javascript:editJson.js
// tags.jsonにデータが配置している前提
const OUTPUT_RANKING_NUM = 100;
const WEIGHT = { item_count: 1, followers_count: 1, likes_count: 1,};

let fs = require("fs");

const set_rank = (arr, attr, sort_flg) => {
  let target = sort_flg ? arr : arr.slice();
  target.sort( (a, b) => b[attr] - a[attr] );
  let tmp_ranking = 0;
  let tmp_score = 9999999999;
  target.forEach( (v, i) => {
    if (v[attr] < tmp_score) {
      tmp_score = v[attr];
      tmp_ranking = i + 1;
    }
    v[`${attr}_rank`] = tmp_ranking;
  })
}

const get_ranked_json = (tags, num, weight) =>{
  let total_items_count = tags.reduce( (s, v) => v.items_count + s, 0)
  let total_followers_count = tags.reduce( (s, v) => v.followers_count + s, 0)
  let total_likes_count = tags.reduce( (s, v) => v.likes_count + s, 0)
  console.log(`総タグ数: ${tags.length}, 総記事数: ${total_items_count}, 総フォロワー数: ${total_followers_count}, 総いいね数: ${total_likes_count}`);
  tags = JSON.parse(JSON.stringify(tags)); // 属性を書き換えるのでオブジェクトをコピーする
 
  set_rank(tags, 'items_count');
  set_rank(tags, 'followers_count');
  set_rank(tags, 'likes_count');
  tags.forEach( t => {
    t.items_point = t.items_count * 100 / total_items_count;
    t.followers_point = t.followers_count * 100 / total_followers_count;
    t.likes_point = t.likes_count * 100 / total_likes_count;
    t.score = (t.items_point * weight.item_count + t.followers_point * weight.followers_count + t.likes_point * weight.likes_count) / (weight.item_count + weight.followers_count + weight.likes_count);
    t.score_old = (t.items_point * weight.item_count + t.followers_point * weight.followers_count) / (weight.item_count + weight.followers_count);
    if (t.items_point > t.followers_point * 2.5 && t.items_point > t.likes_point * 2.5) {
      t.type = 'ITEM+++';
      t.color = 'rgba(0, 255, 0, 0.5)';
    } else if (t.followers_point > t.items_point * 2.5 && t.followers_point > t.likes_point * 2.5) {
      t.type = 'FOLLOWERS+++';
      t.color = 'rgba(0, 0, 255, 0.5)';
    } else if (t.likes_point > t.items_point * 2.5 && t.likes_point > t.followers_point * 2.5) {
      t.type = 'LIKES+++';
      t.color = 'rgba(255, 0, 0, 0.5)';
    } else if (t.items_point * 2.5 < t.followers_point && t.items_point * 2.5 < t.likes_point) {
      t.type = 'ITEM---';
      t.color = 'rgba(255, 0, 255, 0.4)';
    } else if (t.followers_point * 2.5 < t.items_point && t.followers_point * 2.5 < t.likes_point) {
      t.type = 'FOLLOWERS---';
      t.color = 'rgba(255, 255, 0, 0.4)';
    } else if (t.likes_point * 2.5 < t.items_point && t.likes_point * 2.5 < t.followers_point) {
      t.type = 'LIKES---';
      t.color = 'rgba(0, 255, 255, 0.4)';
    } else if (t.items_point > t.followers_point * 1.6 && t.items_point > t.likes_point * 1.6) {
      t.type = 'ITEM++';
      t.color = 'rgba(0, 191, 0, 0.4)';
    } else if (t.followers_point > t.items_point * 1.6 && t.followers_point > t.likes_point * 1.6) {
      t.type = 'FOLLOWERS++';
      t.color = 'rgba(0, 0, 191, 0.4)';
    } else if (t.likes_point > t.items_point * 1.6 && t.likes_point > t.followers_point * 1.6) {
      t.type = 'LIKES++';
      t.color = 'rgba(191, 0, 0, 0.4)';
    } else if (t.items_point * 1.6 < t.followers_point && t.items_point * 1.6 < t.likes_point) {
      t.type = 'ITEM--';
      t.color = 'rgba(191, 0, 191, 0.3)';
    } else if (t.followers_point * 1.6 < t.items_point && t.followers_point * 1.6 < t.likes_point) {
      t.type = 'FOLLOWERS--';
      t.color = 'rgba(191, 191, 0, 0.3)';
    } else if (t.likes_point * 1.6 < t.items_point && t.likes_point * 1.6 < t.followers_point) {
      t.type = 'LIKES--';
      t.color = 'rgba(0, 191, 191, 0.3)';
    } else if (t.items_point > t.followers_point * 1.1 && t.items_point > t.likes_point * 1.1) {
      t.type = 'ITEM+';
      t.color = 'rgba(0, 127, 0, 0.3)';
    } else if (t.followers_point > t.items_point * 1.1 && t.followers_point > t.likes_point * 1.1) {
      t.type = 'FOLLOWERS+';
      t.color = 'rgba(0, 0, 127, 0.3)';
    } else if (t.likes_point > t.items_point * 1.1 && t.likes_point > t.followers_point * 1.1) {
      t.type = 'LIKES+';
      t.color = 'rgba(127, 0, 0, 0.3)';
    } else if (t.items_point * 1.1 < t.followers_point && t.items_point * 1.1 < t.likes_point) {
      t.type = 'ITEM-';
      t.color = 'rgba(127, 0, 127, 0.2)';
    } else if (t.followers_point * 1.1 < t.items_point && t.followers_point * 1.1 < t.likes_point) {
      t.type = 'FOLLOWERS-';
      t.color = 'rgba(127, 127, 0, 0.2)';
    } else if (t.likes_point * 1.1 < t.items_point && t.likes_point * 1.1 < t.followers_point) {
      t.type = 'LIKES-';
      t.color = 'rgba(0, 127, 127, 0.2)';
    } else {
      t.type = 'NORMAL';
      t.color = 'rgba(0, 0, 0, 0.3)';
    }
    t.diff = t.followers_point - t.items_point;
  })
  set_rank(tags, 'score_old');
  set_rank(tags, 'score', true);
  return tags.slice(0, num);
}

const to_chart_data = v => {
  return { label: v.id, data: [ { x: v.followers_count, y: v.items_count, r: 6 + (8 * v.likes_point) } ], backgroundColor: v.color }
};

fs.readFile('./tags.json', 'utf8', function (err, text) {
  let tags = JSON.parse(text);
  tags = get_ranked_json(tags, OUTPUT_RANKING_NUM, WEIGHT);

  let str = '"タグ名",評価値順位,フォロワー数順位,記事数順位,いいね数順位,評価値,フォロワー数,記事数,いいね数,タイプ\n';
  str += tags.map( v => `"${v.id}",${v.score_rank},${v.followers_count_rank},${v.items_count_rank},${v.likes_count_rank},${v.score},${v.followers_count},${v.items_count},${v.likes_count},${v.type}`).join('\n')
  fs.writeFile(`list.csv`, str , (err, data) => {});
  fs.writeFile(`chart.json`, JSON.stringify(tags.filter( v => v.score_rank <= OUTPUT_RANKING_NUM ).map(to_chart_data)) , (err, data) => {});

  // 最後ソートしてから
  tags.sort( (a, b) => b.score_old - a.score_old );
  str = '"タグ名",評価値順位,フォロワー数順位,記事数順位,評価値,フォロワー数,記事数,評価値差分,\n';
  str += tags.map( v => `"${v.id}",${v.score_old_rank},${v.followers_count_rank},${v.items_count_rank},${v.score_old},${v.followers_count},${v.items_count},${v.diff}`).join('\n')
  fs.writeFile(`list_old.csv`, str , (err, data) => {});

});
```

</div></details>


# さいごに

意外と感覚的に正しそうな値が出たので満足したが、2018/12～2019/3以外に、時系列で同様の分析をしても新たな発見があるかも。（リクエストがあれば。）

これで、関連記事に同じ観点の記事が出たら負け。