J'ai essayé de visualiser la distribution des tranches d'âge et les taux de personnes participant à AtCoder (programmation de compétition) par grattage et traitement statistique avec Python.
Tout d'abord, les groupes d'âge participant à Atcoder sont grattés et tabulés, ils sont donc indiqués ci-dessous. De plus, les personnes qui n'indiquent pas leur âge dans leur profil ne sont pas comptabilisées. Comme vous pouvez l'imaginer, il y a beaucoup de jeunes, surtout des étudiants universitaires.
Sans surprise, il semble y avoir une corrélation entre le nombre d'inscriptions au concours et le taux. En passant, selon les spécifications du système de notation d'AtCoder, si le nombre de participation est de 10 ou moins, le taux peut être nettement inférieur à la capacité réelle. Veuillez consulter la page suivante pour plus de détails. À propos de l'évaluation du concours AtCoder
J'ai essayé de visualiser le taux d'utilisateurs actifs par la valeur moyenne et l'écart type pour chaque nombre de participation au concours jusqu'à présent. La valeur moyenne est le point bleu et la valeur moyenne ± écart type est indiquée par la bande jaune. Même après avoir soustrait les spécifications du système de notation ci-dessus, il semble y avoir une corrélation positive entre le nombre de participations et le taux. Dans mon imagination, si le nombre de participation est d'environ 30 fois, il n'y a pas beaucoup de corrélation entre le nombre de participation et le taux dans la zone au-delà (il s'en tient à la limite supérieure), mais il semble que ce soit effectivement le cas. ..
À titre d'exemple, voici un histogramme du nombre et des taux de personnes qui ont participé au concours cinq fois jusqu'à présent.
La visualisation par la valeur moyenne est fortement influencée par les valeurs aberrantes telles que ceux qui ont de l'expérience en programmation compétitive (la capacité est anormalement élevée depuis le début), j'ai donc décidé de visualiser par la valeur médiane. La valeur moyenne est un point bleu et les 25% supérieurs aux 25% inférieurs sont représentés par une bande jaune. La médiane semble avoir un score global légèrement inférieur à la moyenne.
Une question s'est posée pour faire progresser la visualisation des groupes d'âge et des distributions de taux. Vous avez probablement entendu parler de la théorie de la retraite du programmeur de 35 ans, mais y a-t-il une corrélation entre l'âge et le taux d'AtCoder? Par conséquent, j'ai décidé de le visualiser. Comme mentionné ci-dessus, en raison des spécifications du système de notation d'AtCoder, si le nombre de participation est de 10 ou moins, le taux peut être nettement inférieur à la capacité réelle, de sorte que le graphique ci-dessous montre que le nombre de participation est de 10. Limité aux personnes qui ont plus d'une fois, nous avons visualisé la valeur médiane de sorte que l'influence des valeurs aberrantes soit moins susceptible de se produire. En regardant les résultats, il semble qu'il n'y ait pratiquement aucune corrélation entre l'âge et la cote. Il existe peu de données sur les personnes dans la quarantaine et les résultats varient, c'est donc juste pour référence.
Le code source est indiqué ci-dessous.
code
from urllib import request
from bs4 import BeautifulSoup
#En modifiant l'url ici, vous pouvez limiter le nombre de participation, etc.
url = "https://atcoder.jp/ranking/?f.Country=&f.UserScreenName=&f.Affiliation=&f.BirthYearLowerBound=0&f.BirthYearUpperBound=9999&f.RatingLowerBound=0&f.RatingUpperBound=9999&f.HighestRatingLowerBound=0&f.HighestRatingUpperBound=9999&f.CompetitionsLowerBound=1&f.CompetitionsUpperBound=9999&f.WinsLowerBound=0&f.WinsUpperBound=9999&page="
html = request.urlopen(url+"0")
soup = BeautifulSoup(html, "html.parser") #Extraire les informations du fichier html
ul = soup.find_all("ul") #Peut être extrait en spécifiant le nom de l'élément et l'attribut
a = []
page = 0
i = 0
for tag in ul:
i+=1
try:
string_ = tag.get("class")
if "pagination" in string_:
a = tag.find_all("a")
break
except:
pass
for tag in a:
try:
string_ = tag.get("href")
if "ranking" in string_:
page = max(page, int(tag.string))
except:
pass
organization = []
rank = []
name = []
for i in range(1,page+1): #page
html = request.urlopen(url+str(i))
soup = BeautifulSoup(html, "html.parser")
td = soup.find_all("span")
for tag in td:
try:
string_ = tag.get("class")[0]
except:
continue
try:
if string_ == "ranking-affiliation":
organization.append(str(tag.string))
except:
pass
pp = soup.find_all("a")
for tag in pp:
try:
string_ = tag.get("class")[0]
except:
continue
try:
if string_ == "username":
name.append(str(tag.string))
except:
pass
information = []
for i in range(1,page+1): #page
html = request.urlopen(url+str(i))
soup = BeautifulSoup(html, "html.parser")
tbody = soup.find_all("tbody")
for tr in tbody:
for td in tr:
temp = []
for tag in td:
try:
string_ = str(tag.string).strip()
if len(string_) > 0:
temp.append(string_)
except:
pass
if len(temp)>0:
information.append(temp[2:])
information = [[name[i],organization[i]] + (information[i]) for i in range(len(information))]
#%%
import matplotlib.pyplot as plt
year_upper = 2020
rank_dic = {i:[] for i in range(year_upper+1)}
generation = [0 for i in range(year_upper)]
for i in range(len(information)):
old = information[i][2]
try:
rank_dic[int(old)].append(int(information[i][3]))
generation[int(old)] += 1
except:
pass
for i in range(len(rank_dic)-1, -1, -1): #Supprimé lorsqu'il n'y a pas 10 personnes
if len(rank_dic[int(i)]) < 10:
del rank_dic[int(i)]
#%%
import numpy as np
from statistics import mean, median,variance,stdev
ave_rank = np.array([[i ,mean(rank_dic[i])] for i in list(rank_dic.keys())], dtype = "float32")
stdev_rank = np.array([[i ,stdev(rank_dic[i])] for i in list(rank_dic.keys())], dtype = "float32")
max_rank = np.array([[i ,max(rank_dic[i])] for i in list(rank_dic.keys())], dtype = "float32")
median_rank = np.array([[i ,median(rank_dic[i])] for i in list(rank_dic.keys())], dtype = "float32")
percent25 = np.array([[i,np.percentile(rank_dic[i], [25])] for i in list(rank_dic.keys())], dtype = "float32")
percent75 = np.array([[i,np.percentile(rank_dic[i], [75])] for i in list(rank_dic.keys())], dtype = "float32")
#Classement moyen par âge
plt.fill_between(ave_rank[:,0], ave_rank[:,1]-stdev_rank[:,1], ave_rank[:,1]+stdev_rank[:,1],facecolor='y',alpha=0.5)
plt.scatter(ave_rank[:,0], ave_rank[:,1])
plt.xlim(1970,2010)
plt.ylim(-100,2000)
plt.tick_params(labelsize=15)
plt.grid()
plt.title("ave")
plt.show()
#Classement central par âge
plt.fill_between(percent25[:,0], percent25[:,1], percent75[:,1],facecolor='y',alpha=0.5)
plt.scatter(median_rank[:,0], median_rank[:,1])
plt.xlim(1970,2010)
plt.ylim(-100,2000)
plt.tick_params(labelsize=15)
plt.grid()
plt.title("med")
plt.show()
#Répartition des groupes d'âge participants
plt.plot([1996,1996],[-200,5000],zorder=1,linestyle="dashed",color="red")
plt.plot([2001,2001],[-200,5000],zorder=1,linestyle="dashed",color="red")
plt.fill_between([1996,2001], [-200,-200],[5000,5000],facecolor='red',alpha=0.5)
plt.scatter(range(len(generation)), generation,s=80,c="white",zorder=2,edgecolors="black",linewidths=2)
plt.xlim(1960,2010)
plt.ylim(-100,4500)
plt.tick_params(labelsize=15)
plt.grid()
plt.title("population")
plt.show()
#%%
compe_count = [[] for i in range(201)]
for i in range(len(information)):
compe_count[int(information[i][5])].append(int(information[i][3]))
ave_rank_count = np.array([[i,mean(X)] if len(X)>5 else [i,None] for i,X in enumerate(compe_count)], dtype = "float32")[1:]
stdev_rank_count = np.array([[i,stdev(X)] if len(X)>5 else [i,None] for i,X in enumerate(compe_count)], dtype = "float32")[1:]
max_rank_count = np.array([[i,max(X)] if len(X)>5 else [i,None] for i,X in enumerate(compe_count)], dtype = "float32")[1:]
min_rank_count = np.array([[i,min(X)] if len(X)>5 else [i,None] for i,X in enumerate(compe_count)], dtype = "float32")[1:]
med_rank_count = np.array([[i,median(X)] if len(X)>5 else [i,None] for i,X in enumerate(compe_count)], dtype = "float32")[1:]
percent25_count = np.array([[i,np.percentile(X, [25])] if len(X)>5 else [i,None] for i,X in enumerate(compe_count)], dtype = "float32")[1:]
percent75_count = np.array([[i,np.percentile(X, [75])] if len(X)>5 else [i,None] for i,X in enumerate(compe_count)], dtype = "float32")[1:]
#Vérifiez l'histogramme
for i, X in enumerate(compe_count[1:20]):
plt.hist(X, bins=40)
plt.title(i)
plt.show()
#Nombre de participation et score moyen
plt.fill_between(ave_rank_count[:,0],ave_rank_count[:,1]-stdev_rank_count[:,1],ave_rank_count[:,1]+stdev_rank_count[:,1],facecolor='y',alpha=0.5)
plt.scatter(ave_rank_count[:,0], ave_rank_count[:,1],zorder=2)
plt.tick_params(labelsize=15)
plt.grid()
plt.ylim(-100,2500)
#plt.title("ave_count")
plt.show()
#Compte de participation et score central
plt.fill_between(percent25_count[:,0], percent25_count[:,1], percent75_count[:,1],facecolor='y',alpha=0.5)
plt.scatter(med_rank_count[:,0], med_rank_count[:,1])
plt.tick_params(labelsize=15)
plt.ylim(-100,2500)
plt.grid()
#plt.title("med_count")
plt.show()
J'ai beaucoup parlé de l'article suivant. J'ai essayé d'obtenir la distribution des taux d'AtCoder par le Web scraping de Python J'ai examiné la répartition des notes d'AtCoder
Recommended Posts