はじめに
2017年もあっという間に終わりが近づいてきました。
昨年もこの時期に
なんて記事を書いていたのですが、個人的に面白かったので今年も似たようなことを色々やってみます。
なお、この記事で用いている各種データは 2017年12月12日あたり のデータであり、リアルタイムなものでないことにご留意ください。
やること
昨年は Qiita User Ranking というサイトでContributionの上位を確認することができたのですが、2017年3月頃から更新が止まってしまいましたので、今回は自前でデータを集めました。
- ユーザ別Contributionランキング
- ユーザ別記事数ランキング
- ユーザ別フォロワーランキング
- 記事別いいねランキング
- その他分析いろいろ
それでは、いってみます。
前準備
分析をするにあたり、当然データを集めなければなりません。
まとまっているものではないため、シェル芸を駆使してちまちま集めました。
ちょうど Software Design(2018年1月号) の特集「使えるシェルスクリプトの書き方」の5章で「シェルスクリプトでWebスクレイピング」がありましたが、やっているイメージは同じです。
特集でも同様に触れていますが、一気に集めるとQiita側に迷惑がかかるので適宜sleepさせつつ5日間くらいかけてゆるーっと集めています。
興味本位であっても複数人がやるとさらに負荷がかかってしまうので、一旦現時点でスクリプトの公開は控えておきます。
収集のしやすさと分析することを念頭に、ユーザごとに情報が1行にまとまるようにしつつ、
[ユーザ名],[記事数],[コントリビューション数],[フォロワー数],[ストック数1位記事:いいね数],[ストック数2位記事:いいね数],...,[ストック数5位記事:いいね数]
を集めています。内容的には ユーザページ で取れるものですね。
例えば以下のような感じになります。
$ grep t_nakayama0714 qiita_data.csv
t_nakayama0714,33,6721,167,[エンジニアなら知っておきたい、絵で見てわかるセキュア通信の基本](https://qiita.com/t_nakayama0714/items/83ac0b12ced9e7083927):2585,[不思議の国のSE用語](https://qiita.com/t_nakayama0714/items/478a8ed3a9ae143ad854):1507,[Ansibleをはじめる人に。](https://qiita.com/t_nakayama0714/items/fe55ee56d6446f67113c):606,[NoSQLについて 勉強する。](https://qiita.com/t_nakayama0714/items/0ff7644666f0122cfba1):448,[無料で整える趣味チームの開発環境](https://qiita.com/t_nakayama0714/items/c0eb5e298524c127bccd):294
総量はどれくらいになったかというと、
$ wc -l qiita_data.csv
200902 qiita_data.csv
ということで、現在Qiitaユーザは登録数ベースで 20万 を超えているようです...!
ユーザ別分析
まずはユーザ別に分析をしてみます。
ユーザ別Contributionランキング
昨年もやったようなものです。
ユーザごとのランキングの他、記事数や平均いいね数、Contributionに占めるいいね1位記事の割合を出してみたいと思います。
今回は元データがまとまっているので去年ほどここでは苦労しません。
$ cat qiita_data.csv | sort -k 3nr,3 -t , | awk -F"," 'BEGIN{OFS="|"}{TOP=substr($5,index($5,"):")+2) ; TOP_ITEM=substr($5,0,index($5,"):")) ; print "|"NR"|@"$1,$3,$2,$3/$2,TOP,TOP/$3*100"%",TOP_ITEM"|"}' | head -n 10
2017年12月12日付近のTOP100は以下のようになりました。
せっかく昨年のデータがあるので、そことの差分も出してみました。つい最近1位の座が @jnchito さんに渡っていますね...!
ランク | 前年比 | ユーザ名 | 総Contribution | 前年比 | 記事数 | 平均いいね | Top数 | Top占有率 | Top記事 |
---|---|---|---|---|---|---|---|---|---|
1 | +1 | @jnchito | 33833 | +6880 | 179 | 189.011 | 2704 | 7.9922% | モデルやメソッドに名前を付けるときは英語の品詞に気をつけよう |
2 | -1 | @hirokidaichi | 33183 | +2193 | 33 | 1005.55 | 5041 | 15.1915% | ペアプログラミングして気がついた新人プログラマの成長を阻害 する悪習 |
3 | +1 | @icoxfog417 | 27896 | +8969 | 147 | 189.769 | 2891 | 10.3635% | Pythonを書き始める前に見るべきTips |
4 | -1 | @suin | 22531 | +2411 | 697 | 32.3257 | 4328 | 19.2091% | 【まとめ】これ知らないプログラマって損してんなって思う汎用的なツール 100超 |
5 | 0 | @shu223 | 19843 | +2752 | 176 | 112.744 | 1361 | 6.8588% | ディープラーニングの有名ライブラリ5種を最短距離で試す半日コース(TensorFlow, Chainer, Caffe, DeepDream, 画風変換) |
6 | 0 | @KeithYokoma | 18243 | +1506 | 142 | 128.472 | 4707 | 25.8017% | うまくメソッド名を付けるための参考情報 |
7 | +3 | @mizchi | 17591 | +2490 | 201 | 87.5174 | 1881 | 10.693% | 春からはじめるモダンJavaScript / ES2015 |
8 | -1 | @yuku_t | 17160 | +1026 | 195 | 88 | 1465 | 8.5373% | 中規模Web開発のためのMVC分割とレイヤアーキテクチャ |
9 | +4 | @mpyw | 17052 | +3092 | 257 | 66.3502 | 2055 | 12.0514% | PHPでデータベースに接続するときのまとめ |
10 | -2 | @kenju | 16864 | +1421 | 120 | 140.533 | 2381 | 14.1188% | 中上級者になるためのJavaScript【知識編】 |
11 | +1 | @opengl-8080 | 16789 | +2628 | 238 | 70.542 | 1228 | 7.31431% | AngularJS使い方メモ |
12 | -1 | @awakia | 15827 | +1185 | 152 | 104.125 | 1598 | 10.0967% | 開発フロー研修 @ Wantedly |
13 | +1 | @mono0926 | 14837 | +1548 | 94 | 157.84 | 1372 | 9.24715% | ローディング時のズルい進捗表示 |
14 | +3 | @b4b4r07 | 13127 | +1475 | 57 | 230.298 | 1575 | 11.9982% | さいつよのターミナル環境を構築しよう |
15 | 0 | @muran001 | 13078 | +766 | 34 | 384.647 | 4542 | 34.7301% | Gitでやらかした時に使える19個の奥義 |
16 | +4 | @cognitom | 13045 | +1556 | 95 | 137.316 | 1841 | 14.1127% | そろそろ真面目に、HTMLで帳票を描く話をしようか |
17 | -1 | @haminiku | 13013 | +869 | 71 | 183.282 | 2951 | 22.6773% | 2016年 独りで新規WEBサービスを開発・運用した際の知見 |
18 | +1 | @edo_m18 | 12634 | +1084 | 372 | 33.9624 | 1145 | 9.06285% | WebのUIテスト自動化 - Seleniumを使ってみる |
19 | +12 | @koher | 12002 | +3462 | 63 | 190.508 | 1422 | 11.848% | null安全でない言語は、もはやレガシー言語だ |
20 | -2 | @appwatcher | 11830 | +247 | 60 | 197.167 | 2070 | 17.4979% | iOSでこんなアプリ,こんな機能を作りたかったらこれを見ろ!作り たいアプリに対応するクラス、フレームワーク、ライブラリのまとめ! |
21 | +1 | @kazunori279 | 11636 | +1374 | 41 | 283.805 | 1312 | 11.2754% | Cloud Vision APIの凄さを伝えるべくRasPi botとビデオを作った話 |
22 | -1 | @susieyy | 11544 | +697 | 50 | 230.88 | 1941 | 16.8139% | Swiftで作られたイケてるUIライブラリたち |
23 | +2 | @zaru | 11498 | +2105 | 109 | 105.486 | 1598 | 13.8981% | Webフロントエンド表示速度、最速化手法まとめ |
24 | -1 | @yimajo | 11055 | +808 | 143 | 77.3077 | 737 | 6.66667% | iOS実機のSSL通信をプロキシによって傍受したり改ざんする方法 |
25 | +12 | @kawasima | 10196 | +2489 | 78 | 130.718 | 1026 | 10.0628% | GitHub English Challenge Cheat Sheet |
26 | +9 | @hshimo | 10021 | +1946 | 307 | 32.6417 | 2578 | 25.726% | プログラマが独立・起業する時によくするミスと対策 まとめ |
27 | +6 | @kenmatsu4 | 9990 | +1475 | 65 | 153.692 | 1653 | 16.5465% | 【機械学習】ディープラーニング フレームワークChainerを試しながら解説し てみる。 |
28 | 0 | @ynakayama | 9889 | +952 | 189 | 52.3228 | 713 | 7.21003% | scikit-learn から学ぶ機械学習の手法の概要 |
29 | -5 | @hkusu | 9771 | +528 | 208 | 46.976 | 964 | 9.86593% | [WEB開発] 私的な最近のおすすめサービス/ツール 14選 ~2014年版~ |
30 | +4 | @takeharu | 9697 | +1395 | 18 | 538.722 | 1481 | 15.2728% | JavaScriptの「this」は「4種類」?? |
31 | -5 | @uasi | 9671 | +671 | 117 | 82.6581 | 2102 | 21.7351% | 英語のコメントや issue で頻出する略語の意味 (FYI, AFAIK, ...) |
32 | -5 | @kidach1 | 9602 | +612 | 84 | 114.31 | 1314 | 13.6846% | Nginx導入時やること |
33 | -3 | @joker1007 | 9539 | +773 | 105 | 90.8476 | 1089 | 11.4163% | てめえらのRailsはオブジェクト指向じゃねえ!まずはCallbackクラ ス、Validatorクラスを活用しろ! |
34 | -2 | @tukiyo3 | 9301 | +774 | 1555 | 5.98135 | 432 | 4.64466% | たくさんあるオープンソースライセンスのそれぞれの特徴のまとめ |
35 | +1 | @tadsan | 9191 | +1396 | 167 | 55.0359 | 1965 | 21.3796% | ライセンスの選択を恐れる必要はありません |
36 | +2 | @usagimaru | 8581 | +1003 | 173 | 49.6012 | 1036 | 12.0732% | iOS ヒューマンインターフェースの原則 |
37 | +2 | @kawaz | 8243 | +680 | 146 | 56.4589 | 2032 | 24.6512% | 最強のSSH踏み台設定 |
38 | +4 | @okappy | 8098 | +880 | 28 | 289.214 | 5637 | 69.6098% | 非デザイナーエンジニアが一人でWebサービスを作るときに便利なツール32選 |
39 | +17 | @tonkotsuboy_com | 8027 | +2239 | 113 | 71.0354 | 895 | 11.1499% | 2016年新機能! GitHubのmasterブランチをWebページとして公開する手順 |
40 | +3 | @gaogao_9 | 7985 | +901 | 13 | 614.231 | 4169 | 52.2104% | 旧石器時代のJavaScriptを書いてる各位に告ぐ、現代的なJavaScript超入門 Section1 ~すぐにでも現代っぽく出来るワンポイントまとめ~ |
41 | +3 | @zembutsu | 7923 | +1053 | 87 | 91.069 | 1299 | 16.3953% | Docker 入門ハンズオン資料 |
42 | +9 | @Quramy | 7772 | +1421 | 85 | 91.4353 | 1978 | 25.4503% | Electronでアプリケーションを作ってみよう |
43 | -3 | @sion_cojp | 7730 | +387 | 41 | 188.537 | 3568 | 46.1578% | インフラエンジニアとしてよく使うコマンド集 |
44 | +3 | @vvakame | 7634 | +986 | 48 | 159.042 | 1296 | 16.9767% | Gradle入門 |
45 | -4 | @syui | 7535 | +217 | 212 | 35.5425 | 1364 | 18.1022% | MacBookAirで使っている便利ツール |
46 | 新 | @rana_kualu | 7484 | 新 | 192 | 38.9792 | 1880 | 25.1203% | 2017年のフロントエンドエンジニアならこの程度は知ってて当然だよ な? |
47 | -1 | @Qiita | 7385 | +642 | 4 | 1846.25 | 5937 | 80.3927% | Markdown記法 チートシート |
48 | +17 | @y_hokkey | 7290 | +2282 | 60 | 121.5 | 1584 | 21.7284% | Dockerで即実行できる、社内・自宅向けオープンソースWebアプリ |
49 | +49 | @Hironsan | 7286 | +3278 | 46 | 158.391 | 996 | 13.6701% | 機械学習を使って作る対話システム |
50 | -1 | @tbpgr | 7240 | +854 | 728 | 9.94505 | 937 | 12.942% | Markdown記法 サンプル集 |
51 | -6 | @kaiinui | 7191 | +382 | 47 | 153 | 2466 | 34.2929% | 最近の行儀のよい JavaScript の書き方 |
52 | -4 | @Jxck_ | 6992 | +412 | 62 | 112.774 | 1137 | 16.2614% | DELETE_FLAG を付ける前に確認したいこと。 |
53 | +5 | @tatesuke | 6873 | +1602 | 40 | 171.825 | 2179 | 31.7038% | You Don't Need jQuery |
54 | -2 | @yuya_presto | 6811 | +487 | 38 | 179.237 | 783 | 11.4961% | Gitコンフリクト解消ガイド(git mergetoolの使い方) |
55 | 新 | @t_nakayama0714 | 6721 | 新 | 33 | 203.667 | 2585 | 38.4615% | エンジニアなら知っておきたい、絵で見てわかるセキュア通信の基本 |
56 | +4 | @tag1216 | 6711 | +1441 | 90 | 74.5667 | 2781 | 41.4394% | インフラエンジニアじゃなくても押さえておきたいSSHの基礎知識 |
57 | -2 | @n0bisuke | 6583 | +781 | 266 | 24.7481 | 710 | 10.7854% | 3行のソースコードを入れるだけで機械学習できると噂のindicoをNode.jsで使って機械学習入門してみる |
58 | -5 | @gogotanaka | 6571 | +442 | 57 | 115.281 | 3368 | 51.2555% | ネイティブと働いて分かった英語コミットメッセージの頻出動詞10つ |
59 | -9 | @armorik83 | 6527 | +161 | 110 | 59.3364 | 1340 | 20.5301% | AngularJSモダンプラクティス |
60 | +2 | @amay077 | 6452 | +1365 | 254 | 25.4016 | 464 | 7.19157% | Xamarin(ザマリン) とはなんぞや |
61 | +6 | @shibukawa | 6259 | +1332 | 100 | 62.59 | 871 | 13.916% | オブジェクト指向と20年戦ってわかったこと |
62 | -3 | @jacksuzuki | 6118 | +850 | 5 | 1223.6 | 6106 | 99.8039% | ロシアの天才ハッカーによる【新人エンジニアサバイバルガイド】 |
63 | -9 | @yaotti | 6110 | +215 | 151 | 40.4636 | 1268 | 20.7529% | gitでありがちな問題の解決方法まとめ |
64 | +20 | @howdy39 | 5979 | +1603 | 43 | 139.047 | 1238 | 20.7058% | フロントエンドにテストを導入 |
65 | +14 | @kazukichi | 5939 | +1455 | 34 | 174.676 | 2284 | 38.4577% | エンジニアで稼ぐために大切な19のコト |
66 | -9 | @r7kamura | 5859 | +278 | 56 | 104.625 | 690 | 11.7768% | RailsでAPIをつくるときのエラー処理 |
67 | +1 | @magicant | 5708 | +837 | 36 | 158.556 | 2128 | 37.281% | クラスの命名のアンチパターン |
68 | -4 | @daxanya1 | 5618 | +576 | 30 | 187.267 | 4514 | 80.3489% | 数学を避けてきた社会人プログラマが機械学習の勉強を始める際の最短経路 |
69 | -3 | @koba04 | 5516 | +546 | 38 | 145.158 | 770 | 13.9594% | 私のJavaScript情報の集め方 |
70 | +4 | @mochizukikotaro | 5454 | +873 | 240 | 22.725 | 1044 | 19.1419% | 初心者がAWSでミスって不正利用されて$6,000請求、泣きそうになったお話。 |
71 | +1 | @nekoneko-wanwan | 5452 | +768 | 56 | 97.3571 | 1477 | 27.091% | はじめてajaxを使うときに知りたかったこと |
72 | -11 | @voluntas | 5451 | +351 | 107 | 50.9439 | 1053 | 19.3176% | docker コマンド チートシート |
73 | -4 | @koogawa | 5447 | +589 | 63 | 86.4603 | 1217 | 22.3426% | iPhoneアプリ申請やAppleの審査に関するメモ |
74 | +6 | @disc99 | 5416 | +945 | 24 | 225.667 | 1939 | 35.8013% | Javaを使うなら知っておきたい技術、フレームワーク、ライブラリ、ツールまとめ |
75 | -4 | @hidekuro | 5402 | +671 | 81 | 66.6914 | 2158 | 39.9482% | VagrantとDockerについて名前しか知らなかったので試した |
76 | -13 | @hnakamur | 5368 | +315 | 187 | 28.7059 | 530 | 9.87332% | ちょっとしたHTMLはGitHub Gistに置いてbl.ocks.orgで表示するのが お手軽です |
77 | +13 | @tenntenn | 5353 | +1123 | 71 | 75.3944 | 1968 | 36.7644% | Go言語の初心者が見ると幸せになれる場所 #golang |
78 | +9 | @hik0107 | 5322 | +1017 | 22 | 241.909 | 859 | 16.1405% | Pythonでデータ分析するのに必要なツールのまとめ |
79 | +7 | @ukiuni@github | 5267 | +981 | 60 | 87.7833 | 1969 | 37.3837% | JavaScriptを読んでて「なにこれ!?」と思うけれど調べられな い記法8選。 |
80 | -5 | @chuck0523 | 5178 | +611 | 44 | 117.682 | 1540 | 29.7412% | フロントエンドエンジニアが暇なときにやると良いかもしれないこと |
81 | +7 | @pugiemonn | 5144 | +910 | 265 | 19.4113 | 937 | 18.2154% | こんなHTMLとCSSのコーディング規約で書きたい |
82 | 新 | @shizuma | 5126 | 新 | 102 | 50.2549 | 657 | 12.817% | ターミナル 作業効率化 tips集 |
83 | 新 | @colorrabbit | 5064 | 新 | 253 | 20.0158 | 624 | 12.3223% | 覚えておきたい Vim コマンド 備忘録 |
84 | 新 | @TakahikoKawasaki | 4974 | 新 | 20 | 248.7 | 1287 | 25.8745% | 一番分かりやすい OAuth の説明 |
85 | 新 | @inuscript | 4971 | 新 | 111 | 44.7838 | 419 | 8.42889% | 【古い記事】Babelにおける import / export |
86 | -13 | @okmttdhr | 4971 | +307 | 70 | 71.0143 | 1932 | 38.8654% | ここ数年前から2015/5までのモダンフロントエンドを総まとめしてみ た |
87 | +2 | @ryounagaoka | 4959 | +729 | 47 | 105.511 | 1968 | 39.6854% | もう逃げない。HTMLのviewportをちゃんと理解する |
88 | -18 | @puriketu99 | 4928 | +137 | 183 | 26.929 | 875 | 17.7557% | 機械学習クソ素人の俺がプロダクトをリリースするまでの2ヶ月で覚 えたこと |
89 | -6 | @Hiraku | 4872 | +502 | 125 | 38.976 | 1240 | 25.4516% | WebAPIリクエスト仕様書としてcurlコマンドのご提案 |
90 | -5 | @mima_ita | 4822 | +483 | 99 | 48.7071 | 610 | 12.6504% | あなたのおっしゃるレビューってどのことかしら? |
91 | -13 | @kuni-nakaji | 4821 | +337 | 17 | 283.588 | 2278 | 47.2516% | httpsだからというだけで安全?調べたら怖くなってきたSSLの話! ? |
92 | +5 | @k0kubun | 4816 | +801 | 59 | 81.6271 | 1035 | 21.4909% | ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い |
93 | 新 | @nonbiri15 | 4812 | 新 | 233 | 20.6524 | 980 | 20.3658% | 優秀な技術者を追い出してしまう方法 |
94 | 新 | @zaburo | 4737 | 新 | 221 | 21.4344 | 375 | 7.9164% | gitでシンプルなデプロイ環境を作る |
95 | 新 | @shuntaro_tamura | 4717 | 新 | 63 | 74.873 | 654 | 13.8647% | フロントエンド、サーバサイド、インフラの具体例 |
96 | -19 | @m-yamashita | 4703 | +195 | 13 | 361.769 | 3491 | 74.2292% | 初心者向け、「上手い」シェルスクリプトの書き方メモ |
97 | -16 | @hachi8833 | 4688 | +251 | 45 | 104.178 | 2704 | 57.6792% | Vim幼稚園からVim小学校へ |
98 | 新 | @takahirom | 4622 | 新 | 72 | 64.1944 | 383 | 8.28646% | AndroidStudioのPostfix Completionで爆速コーディング |
99 | -6 | @konifar | 4564 | +511 | 98 | 46.5714 | 255 | 5.5872% | Android Studioのgradleビルドを高速化する |
100 | 新 | @hashrock | 4557 | 新 | 26 | 175.269 | 1040 | 22.822% | 脱Bootstrapガイド ~フルスクラッチCSS~ |
僕も 55位 にランクイン。やったッ...!やったッ...!
TOP100順位の上下
昨年データと比較した、順位の上下についてみてみます。
上昇 | 下降 | 維持 | 新規 |
---|---|---|---|
43 | 42 | 4 | 11 |
全体の1割が入れ替わり、それ以外の9割は概ね上がったり下がったりが拮抗しているようです。
また、100位以内で最も上昇幅が大きかったのが @Hironsan でした。
2017年のContributionは+3278ですが、新規記事の中では最もいいねの多い 自然言語処理における前処理の種類とその威力 ですが、集計時点で839いいねであるので、増分の約1/4程度です。
そのため、増加分の多くは既存の記事で伸ばしたことになりますが、 機械学習系の記事 を多く書かれているようなので、このあたりが今年大きく伸びたものと思われます。トレンドを感じますね。
Contributionの分布
Qiitaアカウントがトータル20万ある中で、全体はどのようなContribution分布をしているのでしょうか。
シェル芸を駆使して値の範囲ごとに数を出してみます。sedオタクみたいになってしまいました。
$ cat qiita_data.csv | cut -d , -f 3 | sed -e 's/^$/=/' -e 's/^0$/_/' -e 's/[0-9]/*/g' | sort | uniq -c | sed -e 's/ \*/ 1/g' -e 's/\*/0/g' -e 's/=/none/' -e 's/_/0/' | sed -E 's/([0-9]+) (1[0]*)/\1 \2-/g' | awk '{OFS="\t"}{print $2,$1}'
none 2247
0 169576
1- 10701
10- 11985
100- 5516
1000- 851
10000- 26
noneとなっているのはデータが取れなかったアカウントです。いわゆる凍結アカウントですね。
次にこのデータをもとにグラフを作ります。シェル芸人はExcelなどに頼らず gnuplot を使います。
$ sudo apt-get install gnuplot
楽チンです。
グラフの描画をスクリプトで多少指定しつつ、先ほどの結果を投入した contribution_stat.dat
を食わせます。
$ cat contribution_stat.plt
# png形式で出力
set terminal pngcairo
# 出力パス&ファイル名を指定
set output "contribution_graph.png"
# インプットのデリミタを指定(デフォルトはスペース)
set datafile separator "\t"
# 境界線のスタイルを指定
set style fill solid border lc rgb "#00FA9A"
# ラベルとフォントを指定
set xlabel 'Contributions'
set ylabel 'Users'
set font "DejaVuSansMono,14"
# 指定ファイルのデータを元にグラフをプロット
plot "contribution_stat.dat" using 0:2:xtic(1) with boxes lw 2 lc rgb "#00FA9A" notitle
$ gnuplot -c contribution_stat.plt
できました。
ううむ...。
なにはともあれ具体的な数値にすると以下となります。
Contribution数 | ユーザ数 | 比率 |
---|---|---|
なし | 2247 | 1.11846% |
0 | 169576 | 84.4073% |
1- | 10701 | 5.32648% |
10- | 11985 | 5.9656% |
100- | 5516 | 2.74562% |
1000- | 851 | 0.42359% |
10000- | 26 | 0.0129416% |
このように、全体の1%が凍結アカウント、 84%がContribution数0 のようでした。
なのでQiitaのContributionが1以上ある人は「 俺、Qiitaの上位15%なんだよね...(遠い目) 」って言う権利があります!
ちなみに凍結アカウントを除いた全アカウントにおいては、
有効アカウント数 | 総Contribution | 平均Contribution |
---|---|---|
198,655 | 4,560,820 | 22.9585 |
であり、さらにContribution数が1以上のアカウントをアクティブアカウントとして区別すると、
アクティブアカウント数 | 総Contribution | 平均Contribution |
---|---|---|
29,079 | 4,560,820 | 156.8424 |
という結果となります。
ユーザ別記事数ランキング
ここからはおまけです。20位くらいまで出してみましょう。
$ cat qiita_data.csv | sort -k 2nr,2 -t , | awk -F"," 'BEGIN{OFS="|"}{TOP_ITEM=substr($5,0,index($5,"):")) ; print "|"NR,"@"$1,$2,$3,TOP_ITEM"|"}' | head -n 20
|ランク|ユーザ名|記事数|Contribution数|Top記事|
|:---:|:---:|:---:|:---:|:---:|:---:|
|1|@7of9|5035|3906|Qiita > 「いいね」機能についての要望|
|2|@tukiyo3|1555|9301|たくさんあるオープンソースライセンスのそれぞれの特徴のまとめ|
|3|@tbpgr|728|7240|Markdown記法 サンプル集|
|4|@suin|697|22531|【まとめ】これ知らないプログラマって損してんなって思う汎用的なツール 100超|
|5|@ohisama@github|508|399|ウィルスと闘ってみた。|
|6|@chen7897499|457|64|rails devise|
|7|@tcsh|383|1231|[JAWS-UG CLI] ハンズオン一覧|
|8|@snaka|375|3096|rails console の tips |
|9|@edo_m18|372|12634|WebのUIテスト自動化 - Seleniumを使ってみる|
|10|@hshimo|307|10021|プログラマが独立・起業する時によくするミスと対策 まとめ|
|11|@ironsand|292|2357|git push -u
オプションの意味|
|12|@masato|273|2455|React入門 - Part2: Browserify/Reactify/Gulpを使う|
|13|@cielavenir|272|591|El Capitan移行メモ|
|14|@n0bisuke|266|6583|3行のソースコードを入れるだけで機械学習できると噂のindicoをNode.jsで使って機械学習入門してみ る|
|15|@pugiemonn|265|5144|こんなHTMLとCSSのコーディング規約で書きたい|
|16|@jkr_2255|263|2921|セッション管理の要注意点|
|17|@Nabetani|263|953|C++ の、スマートだと思う人がいるかもしれないコードの書き方12選のつもりが6個ぐらいで断念|
|18|@ngyuki|258|4003|AngularJS でログインのフローを作る|
|19|@YumaInaura|258|1004|拝啓 本当は Qiita を書きたいのに、まだ迷っているあなたへ。|
|20|@mpyw|257|17052|PHPでデータベースに接続するときのまとめ|
なんか、すごいですね。
@7of9 さんが異次元すぎる。およそ上位10人を足しても1人分な感じ。
ユーザ別フォロワー数ランキング
さっきのシェル芸で指定していたカラムを1種類ずらすだけ。
$ cat qiita_data.csv | sort -k 4nr,4 -t , | awk -F"," 'BEGIN{OFS="|"}{TOP_ITEM=substr($5,0,index($5,"):")) ; print "|"NR,"@"$1,$4,$3,TOP_ITEM"|"}' | head -n 20
|ランク|ユーザ名|フォロワー数|Contribution数|Top記事|
|:---:|:---:|:---:|:---:|:---:|:---:|
|1|@hirokidaichi|2148|33183|ペアプログラミングして気がついた新人プログラマの成長を阻害する悪習|
|2|@jnchito|1973|33833|モデルやメソッドに名前を付けるときは英語の品詞に気をつけよう|
|3|@taguchi|1885|0||
|4|@dankogai|1828|2891|Swiftで面倒なJSONの取り扱いをさらに10倍便利にするclass JSON |
|5|@mizchi|1777|17591|春からはじめるモダンJavaScript / ES2015|
|6|@yukihiro_matz|1604|104|24時間一人mrubyハッカソン|
|7|@supermomonga|1594|812|PHPとしても実行できるRubyの書きかた|
|8|@icoxfog417|1434|27896|Pythonを書き始める前に見るべきTips|
|9|@mpyw|1362|17052|PHPでデータベースに接続するときのまとめ|
|10|@shu223|1322|19843|ディープラーニングの有名ライブラリ5種を最短距離で試す半日コース(TensorFlow, Chainer, Caffe, DeepDream, 画風変換)|
|11|@kenmatsu4|1133|9990|【機械学習】ディープラーニング フレームワークChainerを試しながら解説してみる。|
|12|@hyuki|1109|157|Vimで、文字列を別のところに「持って行って置換する」効率的な方法は?|
|13|@mattn|1109|2318|本物の golang を... 本物の Gopher を、お見せしますよ。|
|14|@naoya@github|1090|3127|React Native ファーストインプレッション|
|15|@kensuu|1033|0||
|16|@joker1007|1013|9539|てめえらのRailsはオブジェクト指向じゃねえ!まずはCallbackクラス、Validatorクラスを活用しろ !|
|17|@masuidrive|985|3230|OSXでDockerを超高速化するdinghy|
|18|@kazunori279|981|11636|Cloud Vision APIの凄さを伝えるべくRasPi botとビデオを作った話|
|19|@vvakame|945|7634|Gradle入門|
|20|@Qiita|929|7385|Markdown記法 チートシート|
概ねContributionの数に連動するフォロワー数になるのかなと思っていたらずいぶん違いますね。
普通にミスったかと思いましたが、 Contributionが0でもフォロワー1000以上の人がいる なんて想像もしませんでした。すごい。
ちょっと面白かったので、 Contribution数とフォロワー数で可視化 してみます。
$ cat qiita_data.csv | sort -k 4nr,4 -t , | cut -d , -f 3,4 | head -n 100 | tr "," "\t"
33183 2148
33833 1973
0 1885
2891 1828
17591 1777
104 1604
812 1594
27896 1434
17052 1362
19843 1322
(略)
フォロワー数上位100アカウントをこういう形式で follower_stat.dat
に取って、
$ cat follower_stat.plt
# png形式で出力
set terminal pngcairo
# 出力パス&ファイル名を指定
set output "/follower_stat.png"
# インプットのデリミタを指定(デフォルトはスペース)
set datafile separator "\t"
# ラベルとフォントを指定
set xlabel 'Contributions'
set ylabel 'Followers'
set font "DejaVuSansMono,14"
# 指定データに対する近似直線を計算
fit a*x+b "follower_stat.dat" via a,b
# 指定データを用いてグラフ(データ点と近似直線)をプロット
plot "follower_stat.dat" ps 1 pt 7 lc rgb "#00FA9A" notitle, a*x+b lw 2 lc rgb "#6495ED" title sprintf("%0.2fx+%0.2f",a,b)
$ gnuplot -c follower_stat.plt
として完成です。地味に近似曲線を入れています。
上位100アカウントで取っているため左下が空いていますが、大局的な見え方は上位100アカウントで十分そうでした。
(これ以上増やしても左下に点が集まるばかりで散らばりの印象はほぼ変わりません)
グラフ上にも書いてありますが、上位100アカウントに対する近似直線は 0.02x + 517.68 となるようです。gnuplotの万能さがやばい。
近似直線と比べてみると、上側で突出している特異な点がよりわかりやすくなりますね。
散らばりのイメージ自体は上の通りですが、近似直線の切片が大きく出ているように、やはり下位を評価対象から外すのはよくありません。
改めてContribution数が1以上のアクティブアカウントにおけるグラフを生成してみましょう。
やはり左下に点が集中します。
が、近似直線のもっともらしさは上がったのではないでしょうか。
僕自身は現在 6767 Contributionに対して、フォロワー数が171ですので、近似直線の下側に位置するようです。
近似直線の真上にくる場合、フォロワー数およそ342となるContributionですので、ちょうど半分くらいのフォロワーしかいない計算です。
近似直線を境として、その上下でどういう性質に差があるのかは考えてみたいですね。
記事別分析
それでは最後に記事別にみてみましょう。
総記事数
Qiitaユーザ20万に対して記事は一体どれくらいあるのでしょうか。
1人で1000記事書いている人もいるくらいですからもしかすると...。
$ cat qiita_data.csv | awk -F"," 'BEGIN{SUM=0}{SUM+=$2}END{print SUM}'
260428
おやおやといった感じですね。1アカウントあたり 1.29 です。
しかしこちらも0記事のアカウントが多くあると推測されるため、分布をみてみましょう。
gnuplotのスクリプトはContribution分布のときとほぼ変わらないので折りたたんでおきます。
item_stat.plt
# png形式で出力
set terminal pngcairo
# 出力パス&ファイル名を指定
set output "item_stat.png"
# インプットのデリミタを指定(デフォルトはスペース)
set datafile separator "\t"
# 境界線のスタイルを指定
set style fill solid border lc rgb "#00FA9A"
# ラベルとフォントを指定
set xlabel 'Items'
set ylabel 'Users'
set font "DejaVuSansMono,14"
# 指定ファイルのデータを元にグラフをプロット
plot "item_stat.dat" using 0:2:xtic(1) with boxes lw 2 lc rgb "#00FA9A" notitle
記事数 | ユーザ数 | 比率 |
---|---|---|
なし | 2247 | 1.11846% |
0 | 168427 | 83.8354% |
1- | 23553 | 11.7236% |
10- | 6496 | 3.23342% |
100- | 177 | 0.0881027% |
1000- | 2 | 0.00099551% |
こちらもContribution同様、約85%の方が記事数0のようです。
1つ以上記事を書いている人(30,228)に絞れば、 平均記事数8.6155 となりました。
記事別いいねランキング
意外となかった記事のランキング。
でも確かに上位のものは大体見たことありますね。
自分の記事の中でも 不思議の国のSE用語 が一番好きなんですけどあと一息で入りませんでしたね。惜しい。
ちなみにこの上位100位のうち、複数記事がランクインされたのが以下の方々です。うーん、レジェンド。
ランクイン数 | ユーザ名 |
---|---|
5 | @hirokidaichi |
4 | @jnchito |
3 | @icoxfog417 |
2 | @suin |
2 | @muran001 |
2 | @mizchi |
2 | @kenju |
記事別分析の問題点
さて、出しておいてなんですが、上記の記事別分析には問題があります。
今回のデータ集めでは、ユーザ名をベースにユーザトップから各種情報を抜き出し、ついでにユーザごとのTOP5記事の情報を取得しています。
記事に関してはさすがに全データを集めるのが大変(だしサーバ負荷も相当)なので、ランキングを出せればいいやということでTOP5情報しか持たずに上記のランキングを生成しています。
が、複数記事ランキングで1つだけ気になる点があり、 @hirokidaichi さんがTOP100に5つランクインしています。
これはもしやと思い、 ユーザトップ から記事一覧を眺めていると、やはりTOP5以外でも全体のTOP100に入る記事があるではありませんか。。。
それもそのはず、個人TOP5の第5位にあたる 不安とストレスから解放される見積りとスケジュール方法 ですら、収集当時で 2411いいね となっており、これは全体でも37位にあたります。余裕のTOP100。
なので改めて、TOP100におけるボーダーが 1584いいね であることを念頭におけば、
- 40位: 2314いいね - 新人プログラマに知ってもらいたいメソッドを読みやすく維持するいくつかの原則
- 50位: 2157いいね - 新人プログラマに正月休み中を使って読んでみてほしい技術書をセレクトしてみた。
- 98位: 1608いいね - 新入社員が来てメンターになれって言われたけど、どうすればいいのかという対話テクニック
が更に入ることになり、 TOP100へのランクイン数は8 となります。恐ろしい。
今回のスポンサーたち
今回いろんな分析をするにあたり、実はそんなに多くのシェル芸パターンを使っているわけではありません。
ハタから見ると長いだけなので、今回使ったもののエッセンスだけをいくつか抜粋したいと思います。
ソート
今回はランキング、それもいくつかの切り口でのランキングですから、ソートは非常に活躍しました。
今回はCSVデータを降順ソートする事がほとんどでしたので、例えば第3カラムをソートする場合だとイディオム的には
$ (なにかのデータ) | sort -t , -k 3nr,3
みたいなものが基本の形になります。
-k
ではソート列の情報を表し、 nr
が 数字(numeric)の降順(reverse)ソート
の表現にあたります。
なんで3が2回も出て来るのって疑問はありますが、実用上はそんなに気にしなくてもよいでしょう...。2回です。2回。
気になる人は man sort
を読んでみてください。 要は「ごっちゃになるからちゃんと指定しろ」ってことです。
抽出
CSVから特定カラムの情報を抽出したいときもあるでしょう。
第3カラムを抽出する場合には以下のようになります。
$ (なにかのデータ) | cut -d , -k 3
こちらはデリミタ指定が -d
オプションになっているので非常に素直ですね。
カウント
分布などを調べる場合には値ごとのカウントが必要になります。
カウントする値が流れてくるケースでは、
$ (なにかのデータ) | sort | uniq -c
というようになります。
sort
を挟んで整列させないとカウントがおかしくなるので基本的にはこういうコマンドだと思うのがよいでしょう。
計算
平均や合計など、各行の値を横断して計算したいときもあるでしょう。
そうした場合にはそろそろ awk
が使えます。
$ (なにかのデータ) | awk -F"," 'BEGIN{SUM=0}{SUM+=$1}END{print "SUM: "SUM", AVERAGE: "SUM/NR}'
awkの場合はデリミタ指定が -F
です。
awkの中は言語のようになっているので、結構色んなことができます。ワンライナーでしか使わないことのほうが多いと思いますが、スクリプトファイルに外出すると途端に夢が広がるかもしれません。
ENDブロックで使っている NR
は、参照先の行数を表す特殊変数ですが、ENDブロックの時点では最終行に達していますから、ここのNRはインプットの行数を表すものになります。そのため、 SUM/NR
が平均として機能するわけですね。
また他にも、ソート済みストリームを整列したりするときにNRを一緒に出しておくと、それが順位の代わりになったりもして便利です。
整形/整列
色々なデータをパイプで受け取れる各種コマンドでしたが、アウトプットもコマンドによって様々です。
記事にするにあたり、当然表にして出したいのですが、Markdownの表におけるデリミタは |
であることと列の順序もいじりたかったりするため、ここを工夫しなければなりません。
そういうときにもawkが活躍してくれます。
$ (なにかのデータ) | awk -F"," 'BEGIN{OFS="|"}{print "|"$2,$1"|"}'
awkで複数フィールドを出力する際はデフォルトでスペースが用いられますが、 OFS
変数に好きなものを入れてやるとその区切りで出力してくれます。
行頭と行末には入れてくれないので自分で足しているのが少しかっこ悪く思いますが、まぁこれくらいならいいでしょう。
あとはカラムの順序を入れ替えるのも簡単でいいですね。ありがとう、awk。
おわりに
今回もデータを 取得する部分、分析する部分、可視化する部分 それぞれでシェルが大活躍してくれました。
2017年何をしたってわけでもないですが、人よりはシェルに親しんでいることもあり、昨年よりはかなりスムーズにシェルを叩いていけたような気がしました。
とはいえ、データをCSV(カンマ区切り)で集めておきながら、データ中に一部カンマが入っていたりして、分析時にかっこわるいことをしたりと苦労しました。
また来年も同じようなことをするとなれば、もう少し華麗にできるよう、データ収集から気を使っておきたいなと思いました。
あと、自分のモチベーションでgnuplotを使ったのは割と今回がはじめてに近かったのですが、これはすばらしいですね。
グラフ系って結構微調整が面倒だったりするんですが、スクリプトファイルにして直して再実行がたいへん楽。
シェルで分析してCSVにしつつ、 Excelでぽちぽちグラフに起こすなんていう不毛なこと をしていた自分を恥じたい気分です。
それではみなさま良いお年を。