from IPython.display import HTML
HTML('''<script>
code_show=true;
function code_toggle() {
if (code_show){
$('div.input').hide();
} else {
$('div.input').show();
}
code_show = !code_show
}
$( document ).ready(code_toggle);
</script>
<input type="button" value="Clicca per vedere/nascondere il codice Python" onclick="code_toggle()">''')
import pandas as pd
import json, hashlib
score = None
with open("highscore.json") as hs:
score = json.load(hs)
scoredf = pd.DataFrame(score['exams'])
# L'orario va corretto per il fuso orario
scoredf['server_start'] = pd.to_datetime(scoredf['exam_date'].astype('int64') + 60*60, unit='s')
scoredf['orainizio'] = pd.np.floor((scoredf['exam_date'].astype('int64') + 60*60) / (45*60)) # ore da 45', il tempo di gara
scoredf['punteggio'] = pd.to_numeric(scoredf['score'])
scoredf['anonid'] = scoredf['team_id'].str.cat(scoredf['exam_date']).map(lambda x: hashlib.md5(x).hexdigest())
scoredf['categoria'] = scoredf['category'].astype("category", categories=["Kilo","Mega","Giga","Tera","Peta"], ordered=True)
valid = scoredf[scoredf['exam_valid_score'] == 1]
valid.to_csv('anonris.csv', columns=['anonid', 'categoria', 'orainizio', 'punteggio', 'time'])
from IPython.display import display, Markdown
txt = '''<table>
<caption>Squadre partecipanti al Bebras 20156 con risultati validi,
cioè ritenuti confrontabili con gli altri perché privi di anomalie tecniche o organizzative</caption>
<thead>
<tr><th>Categoria</th>
<th>squadre</th>
<th> min </th>
<th> max </th>
<th> media </th>
<th> std.dev. </th>
<th>I quartile </th>
<th>mediana </th>
<th>III quartile</th>
</tr>
<tbody>
'''
for k in valid['categoria'].unique():
s = valid[valid['categoria'] == k]['punteggio'].describe()
txt += "<tr><th>{}</th><td>{}</td><td>{}</td><td>{}</td><td>{:.1f}</td>\
<td>{:3.1f}</td><td>{}</td><td>{}</td><td>{}</td></tr>".format(k,
int(s['count']),
int(s['min']),
int(s['max']),
float(s['mean']),
float(s['std']),
int(s['25%']),
int(s['50%']),
int(s['75%']))
txt += '<tfoot><tr><th>Totale</th><td>{}</td></tr>'.format(valid['punteggio'].count())
txt += '</table>'
display(Markdown(txt))
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('ggplot')
histograms = valid['punteggio'].hist(by=valid['categoria'], bins=30, figsize=(10,8))
for k in valid['categoria'].unique():
tot = float(valid[(valid['categoria'] == k)]['punteggio'].count())
pp = [100 * valid[(valid['categoria'] == k) & (valid['punteggio'] < i)]['punteggio'].count()/tot for i in xrange(1,61)]
txt = '''<table>
<caption>Percentili per la categoria {} (che percentuale di squadre si supera con un dato punteggio)</caption>
<thead>'''.format(k)
txt += ''.join(['<td>{}</td>'.format(i) for i in xrange(1,61)])
txt += '<tbody>'
txt += ''.join(['<td>{:.1f}</td>'.format(f) for f in pp])
txt += '</table>'
display(Markdown(txt))
rr = []
for r in valid.itertuples():
for q in r.questions:
t = q.copy()
t['anonid'] = r.anonid
rr.append(t)
quiz = pd.DataFrame(rr)
MAPBEBRAS = {
'Pennello': 'PK-03',
'RicettaSegreta': 'HU-02',
'MessaggiSegreti': 'UK-06',
'Coccinelle': 'SK-10',
'ColoraFiori': 'SK-04',
'ConiBiglietti': 'FR-02',
'PallaCastoro': 'JP-03',
'Commissioni': 'LT-03',
'Tappi': 'JP-06',
'Soccer': 'US-07b',
'Direzioni': 'IE-05',
'Robot': 'FR-04',
'Scanner': 'MY-02',
'SacchiAscensore': 'CZ-02a',
'Rafting': 'LT-02',
'Insalata': 'DE-08',
'Cannone': 'IT-06',
'Mug': 'TW-05',
'HealthCare': 'CH-03',
'Thief': 'BE-02',
'FiltroMediano': 'RU-02',
'Bolle': 'IT-03',
'Tunnel': 'CH-04a',
'Isole': 'FR-03',
'Colori': 'UK-04',
'Mapreduce': 'CA-08b',
'BandiereCompresse': 'CZ-04',
'Smartphone': 'IT-04',
'Albero': 'CA-05',
'Pozioni': 'JP-01',
'Legno': 'CA-01',
'Avventura': 'FR-07',
'Kix': 'NL-04',
'Biglie': 'IT-02b',
'Forme': 'CA-09'
}
MAPNAMES = {
'Pennello': "Il rullo dell'imbianchino",
'RicettaSegreta': 'La ricetta segreta',
'MessaggiSegreti': 'Messaggi segreti',
'Coccinelle': 'Coccinelle',
'ColoraFiori': 'Colora i fiori',
'ConiBiglietti': 'Coni e biglietti',
'PallaCastoro': 'BeaverBall',
'Commissioni': 'Commissioni',
'Tappi': 'Tappi',
'Soccer': 'Partita di calcio',
'Direzioni': 'Direzioni concorrenti',
'Robot': 'Fai uscire il robot',
'Scanner': 'Scanner per immagini',
'SacchiAscensore': "Sacchi nell'ascensore",
'Rafting': 'Rafting',
'Insalata': 'Una tartaruga sistematica',
'Cannone': 'Artiglieria programmabile',
'Mug': 'Una collezione di tazze',
'HealthCare': 'Pronto soccorso',
'Thief': 'Caccia al ladro',
'FiltroMediano': 'Filtro mediano',
'Bolle': 'Bolle',
'Tunnel': 'La galleria',
'Isole': 'Isole',
'Colori': 'Quanti colori?',
'Mapreduce': 'Fra parentesi',
'BandiereCompresse': 'Bandiere',
'Smartphone': 'In fila per tre',
'Albero': "L'albero di Natale",
'Pozioni': 'Pozioni magiche',
'Legno': 'Il legno buono',
'Avventura': 'Avventura',
'Kix': 'Codice a barre',
'Biglie': 'Biglie',
'Forme': 'Gioco di forme'
}
quiz['nome'] = quiz['code'].str.extract('\d+_.+_(.+)', expand=False)
quiz['cat'] = quiz['code'].str.extract('\d+_(.+)_.+', expand=False)
quiz['edizione'] = quiz['code'].str.extract('(\d+)_.+_.+', expand=False)
quiz['bebras'] = quiz['nome'].map(lambda x: MAPBEBRAS[x])
quiz['completo'] = quiz['score'] == quiz['score_max']
quiz['parziale'] = (quiz['score'] > 0) & (quiz['score'] != quiz['score_max'])
quiz['voto'] = quiz['score'] / quiz['score_max'].astype('float64')
quiz['minuti'] = quiz['time'].map(lambda x: x/(1000*60) if x >= 0 else pd.np.NaN)
quiz.to_csv('quiz.csv', columns=['anonid', 'cat', 'edizione', 'nome', 'bebras', 'score', 'score_max', 'time'])
vquiz = pd.merge(valid[['anonid', 'categoria', 'punteggio','orainizio','teacher_id','school_cap']], quiz, on='anonid')
plt.figure(figsize=(16,20))
def bname(n):
if n in MAPBEBRAS and n in MAPNAMES:
return '{} ({})'.format(MAPNAMES[n], MAPBEBRAS[n])
else:
return n
for j, k in enumerate(valid['categoria'].unique()):
plt.subplot(5,1, j+1)
plt.ylim(0,1)
m = vquiz[vquiz['categoria'] == k].groupby('nome',
sort=False)[['completo','voto', 'parziale', 'minuti','score_max']].mean()
m['vparziale'] = m['voto'] - m['completo']
c = plt.bar(pd.np.arange(m.index.size), m['completo'])
p = plt.bar(pd.np.arange(m.index.size), m['parziale'], bottom=m['completo'], color='lightblue')
plt.xticks(pd.np.arange(m.index.size) + 0.4, map(bname, m.index.tolist()), rotation=90)
for i, y in enumerate(m['voto'].tolist()):
plt.annotate(s='{:.0f}'.format(m['minuti'].iloc[i]), xy=(i+0.3, y+.08))
plt.annotate(s='{}'.format(m['score_max'].iloc[i]), xy=(i+0.3, .02), color='red')
plt.legend((c[0],p[0]), ('completo','parziale'))
plt.title('{}: tassi di soluzione (il numero in nero indica i minuti spesi in media sul quesito, \
il numero in rosso il punteggio massimo ottenibile)'.format(k))
plt.tight_layout()
plt.figure(figsize=(16,20))
for j, k in enumerate(valid['categoria'].unique()):
plt.subplot(5,1, j+1)
plt.ylim(0,1)
m = vquiz[vquiz['categoria'] == k].groupby('nome',
sort=False)[['completo','voto', 'parziale', 'minuti','score_max']].mean()
m['vparziale'] = m['voto'] - m['completo']
c = plt.bar(pd.np.arange(m.index.size), m['voto'], color='green')
plt.xticks(pd.np.arange(m.index.size) + 0.4, map(bname, m.index.tolist()), rotation=90)
for i, y in enumerate(m['voto'].tolist()):
plt.annotate(s='{}'.format(m['score_max'].iloc[i]), xy=(i+0.3, y+.08), color='red')
plt.title('{}: percentuale di punteggio attribuito in media (in rosso il punteggio massimo ottenibile)'.format(k))
plt.tight_layout()
members = []
for r in valid[valid['team_composition'] != False].itertuples():
k = r.categoria
for m in r.team_composition['members']:
m['categoria'] = k
members.append(m)
pupils = pd.DataFrame(members)
pupils['genere'] = pupils['sex'].map(lambda x: x if x != '-' else pd.np.NaN)
pupils['categoria'] = pupils['categoria'].astype("category", categories=["Kilo","Mega","Giga","Tera","Peta"], ordered=True)
gender = pupils[(pupils['name'] != '') | pupils['genere'].notnull()].groupby(['categoria', 'genere']).count()
txt = '''<table><caption>Studenti partecipanti al Bebras 2016 con risultati validi
(i dati dipendono dalla corretta compilazione dei profili delle squadre)</caption>
<thead>
<tr><th>Categoria</th>
<th>studenti</th>
<th>femmine</th>
<th>maschi</th>
<th>squadre con dati mancanti</th>
<th>media component per squadra</th>
</tr>
<tbody>
'''
totf = 0
totm = 0
for k in pupils['categoria'].unique():
f = gender.loc[(k,'f')]['class']
totf += f
m = gender.loc[(k,'m')]['class']
totm += m
s = valid.groupby('categoria').count().loc['Kilo']['login']
empty = len(valid[(valid['categoria'] == k) &(valid['team_composition'] == False)])
txt += '<tr><th>{}</th><td>{}</td><td>{} ({:.1f}%)</td><td>{} ({:.1f}%)</td><td>{}</td><td>{:.1f}</td></tr>'.format(
k, f+m, f, 100*float(f)/float(f+m), m, 100*float(m)/float(f+m), empty, float(m+s) / float(s - empty)
)
txt += '<tr><th>Totale:</th><td>{}</td><td>{} ({:.1f}%)</td><td>{} ({:.1f}%)</td></tr>'.format(totf+totm,
totf, 100*float(totf)/float(totf+totm),
totm, 100*float(totm)/float(totf+totm))
txt += '</table>'
display(Markdown(txt))
TAGCLOUD = 'tags.png'
import os
if not os.path.isfile(TAGCLOUD) or os.path.getmtime(TAGCLOUD) < os.path.getmtime('highscore.json'):
from pytagcloud import create_tag_image, make_tags
from pytagcloud.lang.counter import get_tag_counts
import re
notwanted = re.compile('^0\d+$|^\d\w|^the$|^and$|^classe$|^squadra$|^gruppo$|^team$|^i+$|^iv$|^\w$|^prima$|^seconda$\
|^terza$|^quarta$|^quinta$')
names = ' '.join(scoredf['team_name'].str.strip().str.lower().tolist())
names = names.encode('iso-8859-1', 'ignore')
oknames = filter(lambda w: not notwanted.match(w), names.split(' '))
counts = get_tag_counts(' '.join(oknames))
# Solo quelli con almeno 10 occorrenze
tags = make_tags(filter(lambda x: (x[1] >= 10), counts), maxsize=75)
cloud = create_tag_image(tags, "tags.png", (900, 900), fontname="Neuton")
plt.axis('off')
os = scoredf['operating_system'].value_counts().plot.pie(autopct='%.1f', radius=1.22,
explode=[.06*i*i for i in xrange(len(scoredf['operating_system'].unique()))],
figsize=(5,5), title='Sistemi operativi utilizzati')