唯物是真 @Scaled_Wurm

プログラミング(主にPython2.7)とか機械学習とか

AtCoderの参加回数が多い人ほどレーティングが高い?

前にAtCoderのレーティングの分布について調べて記事を書きました
sucrose.hatenablog.com
Twitterで「AtCoderにたくさん参加すればレーティングが上がる」という話を見かけて気になったので、ユーザーの参加回数とレーティングの関係を雑にグラフにしたりレーティングの分布のグラフを書いたりしてみました

調べるのが簡単なAtCoderのランキングに書いてある現在のレーティングと参加回数の表のデータを使いました

AtCoderのレーティングの分布

レーティングの色分けについてはこちら↓

1回しか参加していないユーザーも数えているので灰色が全体の半分近くを占めています
f:id:sucrose:20180128234236p:plain

レーティング レーティング上位何%か
2800(赤) 1%
2400(オレンジ) 2%
2000(黄色) 5%
1600(青) 11%
1200(水色) 21%
800(緑) 35%
400(茶色) 52%
0(灰色) 100%

参加回数とレーティングの関係

見たところ10回から15回ぐらいの参加まではレーティングの平均が大きく変わっていそう
その後の参加回数が増えるごとにレーティングの平均は徐々に増えていっているように見えますが回数が増えてもばらつきは結構大きいです
f:id:sucrose:20180129010422p:plain

感想

参加回数が多いほどレーティングの平均が増えていそうな気もする
やる気の有無が参加回数とレーティングの上昇の両方に関わってくると思われるので、もっとちゃんと調べるなら個々のユーザーのレーティングの上下を追ってちゃんと調べないとダメそう

おまけ: 箱ひげ図

箱ひげ図も書いたのでついでに貼っておきます
上の平均と標準偏差の棒グラフと見比べると結構印象が変わります
f:id:sucrose:20180128235546p:plain

ソースコード

# coding: utf-8
import pyquery
import requests
import time
import scipy.stats
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.font_manager
import matplotlib.cm as cm
import tqdm
import matplotlib.pyplot as plt

rating_atcoder = []
counts = []
for i in tqdm.tqdm(xrange(1, 129)):
    table = pyquery.PyQuery(url='https://atcoder.jp/ranking?p={}'.format(i))
    for elm in table.find('tr')[1:]:
        tr = pyquery.PyQuery(elm)
        tds = tr.find('td')
        rank = int(pyquery.PyQuery(tds[0]).text())
        name = pyquery.PyQuery(tds[1]).text()
        rating = int(pyquery.PyQuery(tds[2]).text())
        count = int(pyquery.PyQuery(tds[4]).text())
        
        rating_atcoder.append(rating)
        counts.append(count)
    time.sleep(1)

df = pd.DataFrame({
    'rating_atcoder': rating_atcoder,
    'count': counts
})

prop = matplotlib.font_manager.FontProperties(fname=r'C:\Windows\Fonts\meiryo.ttc', size=12)

plt.hist(df[df['rating_atcoder'] < 400].reset_index()['rating_atcoder'], bins=range(0, 4001, 100), histtype='stepfilled', color='#808080')
plt.hist(df[(400 <= df['rating_atcoder']) & (df['rating_atcoder'] < 800)].reset_index()['rating_atcoder'], bins=range(0, 4001, 100), histtype='stepfilled', color='#804000')
plt.hist(df[(800 <= df['rating_atcoder']) & (df['rating_atcoder'] < 1200)].reset_index()['rating_atcoder'], bins=range(0, 4001, 100), histtype='stepfilled', color='#008000')
plt.hist(df[(1200 <= df['rating_atcoder']) & (df['rating_atcoder'] < 1600)].reset_index()['rating_atcoder'], bins=range(0, 4001, 100), histtype='stepfilled', color='#00C0C0')
plt.hist(df[(1600 <= df['rating_atcoder']) & (df['rating_atcoder'] < 2000)].reset_index()['rating_atcoder'], bins=range(0, 4001, 100), histtype='stepfilled', color='#0000FF')
plt.hist(df[(2000 <= df['rating_atcoder']) & (df['rating_atcoder'] < 2400)].reset_index()['rating_atcoder'], bins=range(0, 4001, 100), histtype='stepfilled', color='#C0C000')
plt.hist(df[(2400 <= df['rating_atcoder']) & (df['rating_atcoder'] < 2800)].reset_index()['rating_atcoder'], bins=range(0, 4001, 100), histtype='stepfilled', color='#FF8000')
plt.hist(df[2800 <= df['rating_atcoder']].reset_index()['rating_atcoder'], bins=range(0, 4001, 100), histtype='stepfilled', color='#FF0000')
plt.title(u'AtCoderのレーティングの分布', fontproperties=prop)
plt.xlabel(u'AtCoderのレーティング', fontproperties=prop)
plt.ylabel(u'ユーザー数', fontproperties=prop)
plt.show()

print 'rating: percentile'
for i in [0, 400, 800, 1200, 1600, 2000, 2400, 2800]:
    print '{}: {:.3}'.format(i, 100 - scipy.stats.percentileofscore(df['rating_atcoder'], i))

df = df.dropna()

# 回数ごとの分布も出す

sns.barplot(x=df['count'], y=df['rating_atcoder'], ci='sd')
plt.title(u'AtCoderの参加回数ごとのレーティングの平均と標準偏差', fontproperties=prop)
plt.xlabel(u'AtCoderの参加回数', fontproperties=prop)
plt.ylabel(u'レーティングの平均', fontproperties=prop)
plt.show()

# 箱ひげ図
sns.boxplot(x=df['count'], y=df['rating_atcoder'])
plt.title(u'AtCoderの参加回数ごとのレーティング(箱ひげ図)', fontproperties=prop)
plt.xlabel(u'AtCoderの参加回数', fontproperties=prop)
plt.ylabel(u'レーティング', fontproperties=prop)
plt.show()

print df.groupby('count').mean()['rating_atcoder']