Statistiche sulla partecipazione al Bebras italiano 2020/21

In [1]:
from IPython.display import HTML, Markdown

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()">''')
Out[1]:
In [2]:
import warnings
#warnings.filterwarnings('once')
warnings.filterwarnings('ignore')
In [3]:
%matplotlib inline
import pandas as pd
import urllib.request
from IPython.display import display, Markdown
import matplotlib.pyplot as plt

pd.options.display.max_rows = None
plt.style.use('ggplot')
In [4]:
miur = pd.read_csv('bebras_school_list.zip', low_memory=False)

def norm_region(r):
    """Normalize the name of a region. It also corrects wrong names."""
    r = r.strip().upper()
    if r == 'FVG' or r.startswith('FRIULI'):
        return 'FRIULI-VENEZIA GIULIA'
    if r.startswith('EMILIA'):
        return 'EMILIA-ROMAGNA'
    if r.startswith('TRENTINO') or r.startswith('ALTO ADIGE'):
        return 'TRENTINO-ALTO ADIGE'
    if r.startswith('LOMB'):
        return 'LOMBARDIA'
    if r.startswith('VALLE') or 'AOSTA' in r:
        return "VALLE D'AOSTA"
    if r == 'G6GG6Y' or r == 'ITALIA':
        return None
    if r == 'ALBANIA' or r == 'BAVIERA' or r == 'SIERRA' or r == 'DDDD' or r == 'FRANCE' or r == 'SVIZZERA':
        return 'ESTERO'
    else:
        return r

def infer_school_type(k):
    knorm = k['school_kind'].strip().upper()
    cnorm = k['school_code'].strip().upper()
    if cnorm and miur[miur['i_code'] == cnorm]['i_type'].count() > 0:
        knorm = str(miur[miur['i_code'] == cnorm]['i_type'].iloc[0])
    if 'PRIMARIA' in knorm or 'INFANZIA' in knorm or 'ELEMENTARE' in knorm:
        return 'E'
    if 'PRIMO GRADO' in knorm or ('MEDIA' in knorm and (not 'SUP' in knorm))\
    or '1°' in knorm or ' I GRADO' in knorm or knorm == 'IC':
        return 'M'
    if 'COMPRENSIVO' in knorm:
        return 'EM'
    if 'SECONDO GRADO' in knorm or '2°' in knorm  or 'II GRADO' in knorm \
    or 'LICEO' in knorm or 'ITI' in knorm or 'PROF' in knorm or 'IST TEC' in knorm \
    or 'TECNICO' in knorm or 'MAGISTRALE' in knorm or 'SUPERIORE' in knorm:
        return 'S'
    if knorm == 'STATALE' or 'C.D.38':
        return 'EMS'
    else:
        return knorm
   

Insegnanti, stima delle squadre e alunni

In [5]:
YEAR=2020

with open('secret.key') as k:
    key = k.readline().strip()

r = urllib.request.urlopen(("https://bebras.it/api?key={}&view=teachers_edition"+
                           "&edition=bebras_{}&subscription=1").format(key, YEAR))

with open("teachers.json", "w") as tw:
     tw.writelines(r.read().decode('utf-8'))        

teachers = pd.DataFrame(pd.read_json("teachers.json", convert_axes=True))

teachers.index = range(len(teachers))
teachers['confirm_time'] = pd.to_datetime(teachers['confirm_time'], unit='s')
teachers['enter_time'] = pd.to_datetime(teachers['enter_time'], unit='s')

teachers['school_code'] = teachers['school_code'].str.strip().str.upper()
teachers['school_type'] = teachers[['school_kind','school_code']].apply(infer_school_type, axis=1)
filled = len(teachers)
expected = teachers.sum()
regteams = expected['teams_active']

today = pd.datetime.today()
if today > pd.datetime(YEAR,11,8):
    today = pd.datetime(YEAR,11,8)
s = """*{}:* **{:d}** insegnanti hanno confermato la partecipazione; 
ci sono **{:d}** squadre già registrate (~*{:d}* alunni).
"""
display(Markdown(s.format(str(today)[:19], 
                          filled, regteams, regteams)))

if today <= pd.datetime(YEAR,11,8):
    isotoday = today.isoformat()[:10]
    with open("stats-" + isotoday + ".txt", "w") as stat:
        stat.write("{:d} {:d} {:d}\n".format(filled, regteams, regteams))

2020-11-08 00:00:00: 546 insegnanti hanno confermato la partecipazione; ci sono 27181 squadre già registrate (~27181 alunni).

In [6]:
oldteachers = {}
for y in [2015, 2016, 2017, "bebras_2018", "bebras_2019"]:
    r = urllib.request.urlopen(("https://bebras.it/api?key={}&view=teachers_edition"+
                                "&edition={}").format(key, y))
    with open("teachers{}.json".format(y), "w") as tw:
        tw.writelines(r.read().decode('utf-8'))

    oldteachers[y] = pd.DataFrame(pd.read_json("teachers{}.json".format(y), convert_axes=True))[3:]
    #oldtteachers[y]['school_type'] = oldteachers[['school_kind','school_code']].apply(infer_school_type, axis=1)
In [7]:
intersect = {}
for y in [2015, 2016, 2017, "bebras_2018", "bebras_2019"]:
    intersect[y] = pd.merge(teachers, oldteachers[y], on='id', how='inner')
    intersect[y]['deltateams'] = intersect[y]['teams_active_x'] - intersect[y]['teams_active_y']
    returning = intersect[y]['id'].count()
    base = len(oldteachers[y][oldteachers[y]['teams_active'] > 0])
    s = """*{:d}* insegnanti hanno già partecipato all'edizione {} (**{:.0f}%** dei partecipanti di quell'edizione), 
il numero di squadre è aumentato in media di {:.1f} (deviazione standard {:.0f}).
"""
    display(Markdown(s.format(returning, str(y)[-4:], 
                              100*float(returning)/float(base),
                              intersect[y]['deltateams'].mean(), intersect[y]['deltateams'].std() 
                             )))

50 insegnanti hanno già partecipato all'edizione 2015 (21% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di 42.8 (deviazione standard 60).

101 insegnanti hanno già partecipato all'edizione 2016 (14% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di 44.0 (deviazione standard 63).

188 insegnanti hanno già partecipato all'edizione 2017 (18% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di 43.0 (deviazione standard 60).

264 insegnanti hanno già partecipato all'edizione 2018 (23% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di 41.3 (deviazione standard 78).

324 insegnanti hanno già partecipato all'edizione 2019 (36% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di 36.9 (deviazione standard 72).

In [8]:
trintersec = pd.merge(intersect["bebras_2018"], oldteachers[2017], on='id', how='inner') 
print("Hanno partecipato nel 2017, 2018 e 2019: {}".format(len(trintersec)))
print("Hanno partecipato nel 2016, 2018 e 2019: {}".format(
      len(pd.merge(intersect["bebras_2018"], oldteachers[2016], on='id', how='inner'))))
print("Hanno partecipato nel 2016, 2017 e 2019: {}".format(
      len(pd.merge(intersect[2017], oldteachers[2016], on='id', how='inner'))))
print("Hanno partecipato nel 2016, 2017, 2018 e 2019: {}".format(
      len(pd.merge(trintersec, oldteachers["bebras_2018"], on='id', how='inner'))))
Hanno partecipato nel 2017, 2018 e 2019: 178
Hanno partecipato nel 2016, 2018 e 2019: 92
Hanno partecipato nel 2016, 2017 e 2019: 93
Hanno partecipato nel 2016, 2017, 2018 e 2019: 178
In [9]:
institutes = teachers[(teachers['school_code'].str.strip() != "") 
                      & (teachers['subscription'] > 0) 
                      & (teachers['confirm_time'] > pd.datetime(2019,9,1))].groupby('school_code')['id'].count()

print("Totale istituti con codice meccanografico: {}; numero medio insegnanti per codice: {:.2f}".format(len(institutes), institutes.mean()))
Totale istituti con codice meccanografico: 265; numero medio insegnanti per codice: 1.58
In [10]:
import os
data = []
for path, dirs, files in os.walk("."):
    for f in files:
        if path == '.' and f.startswith("stats-"):
            d = [int(x) for x in f.split('.')[0].split('-')[1:4]]
            with open(f,"r") as df:
                nn = [int(x) for x in df.readline().strip().split(" ")]
                dd = pd.datetime(YEAR, 11, 11) - pd.datetime.fromtimestamp(os.stat(f).st_mtime)
                data.append((dd, nn))
data = pd.DataFrame.from_dict(dict(data), orient="index", 
                               columns=["insegnanti","squadre","alunni"]).sort_index(ascending=False)
data['giorni'] = (data.index * -1).astype('timedelta64[D]')
In [11]:
olddata = []
for path, dirs, files in os.walk("old"):
    for f in files:
        if f.startswith("stats-"):
            d = [int(x) for x in f.split('.')[0].split('-')[1:4]]
            with open(path + "/" + f,"r") as df:
                nn = [int(x) for x in df.readline().strip().split(" ")]
                olddata.append((pd.datetime(YEAR-1,11,12) - pd.datetime(*d), nn))
olddata = pd.DataFrame.from_dict(dict(olddata), orient="index", 
                                  columns=["insegnanti","squadre","alunni"]).sort_index(ascending=False)
olddata['giorni'] = (olddata.index * -1).astype('timedelta64[D]')
In [12]:
fig, ax = plt.subplots(1,2)
fig.set_size_inches(11,5)

for i, t in enumerate(['squadre', 'insegnanti']):
    ax[i].plot([-d.days for d in data.index], list(data[t]), label=t + ' ' + str(YEAR))
    ax[i].plot([-d.days for d in olddata.index], list(olddata[t]), '--', label=t + ' ' + str(YEAR-1) )
    ax[i].legend()
    ax[i].set_xlim([-50,0])
    delta = (data[t].max()-olddata[t].max())/olddata[t].max()
    ax[i].text(-.9*data[t].count(), .9*data[t].max(), '{:+.1f}%'.format(delta*100), color='tomato')

plt.show()
In [13]:
r = urllib.request.urlopen(("https://bebras.it/api?key={}&view=teams"+
                           "&edition=bebras_{}").format(key, YEAR))
with open("teams.json", "w") as tw:
     tw.writelines(r.read().decode('utf-8'))        
In [14]:
import json

with open("teams.json") as t:
    teams = pd.DataFrame(json.load(t)['teams'])

oldteams = pd.DataFrame({'class':['kilo','mega','giga','tera','peta'],f'teams_{YEAR-1}':[3044,5728,2709,2072,1481]})
oldteams.index = oldteams['class']
del oldteams['class']
    
tdata = teams.groupby('class').count()['login'].copy()

for i in oldteams.index:
    oldteams.loc[i]['teams_' + str(YEAR)] = 1

tdata = pd.concat([tdata, oldteams],axis=1)


tdata['Incremento %'] = 100*(tdata['login']-tdata[f'teams_{YEAR-1}'])/tdata[f'teams_{YEAR-1}']
display(tdata)
print("In totale {} squadre iscritte ({:+.2f}% rispetto alle squadre partecipanti nel {})".format(
    tdata['login'].sum(), 
    100*(tdata['login'].sum()-tdata[f'teams_{YEAR-1}'].sum())/tdata[f'teams_{YEAR-1}'].sum(), YEAR-1))
print("In totale {} squadre iscritte ({:+.2f}% rispetto alle squadre iscritte nel {})".format(
    tdata['login'].sum(), 
    100*(tdata['login'].sum()-olddata['squadre'].max())/olddata['squadre'].max(), YEAR-1))
print(f"Nell'edizione {YEAR-1} le squadre avevano 4 componenti, nel {YEAR} soltanto 1.")
login teams_2019 Incremento %
giga 5130 2709 89.368771
kilo 4825 3044 58.508541
mega 9824 5728 71.508380
peta 3183 1481 114.922350
tera 4220 2072 103.667954
In totale 27182 squadre iscritte (+80.80% rispetto alle squadre partecipanti nel 2019)
In totale 27182 squadre iscritte (+54.48% rispetto alle squadre iscritte nel 2019)
Nell'edizione 2019 le squadre avevano 4 componenti, nel 2020 soltanto 1.

La popolazione studentesca nazionale

Dati ISTAT della popolazione studentesca scuola primaria e secondaria nel 2014 (fonte: http://dati.istat.it)

In [15]:
istat = pd.DataFrame.from_dict(
    dict([
    ("PIEMONTE",              (191399, 117997, 168439)),
    ("VALLE D'AOSTA",         (  5981,   3691,   5309)),
    ("LIGURIA",               ( 61566,  39213,  60184)),
    ("LOMBARDIA",             (468662, 283007, 381619)),
    ("TRENTINO-ALTO ADIGE",   ( 27028,  16890,  21836)),
    ("VENETO",                (232694, 142401, 204262)),
    ("FRIULI-VENEZIA GIULIA", ( 51830,  32143,  46949)),
    ("EMILIA-ROMAGNA",        (198417, 118460, 176968)),
    ("TOSCANA",               (161001,  98203, 152886)),
    ("UMBRIA",                ( 39181,  23488,  36946)),
    ("MARCHE",                ( 67996,  42095,  70602)),
    ("LAZIO",                 (268133, 161573, 249145)),
    ("ABRUZZO",               ( 57146,  35828,  58578)),
    ("MOLISE",                ( 12595,   8354,  14990)),
    ("CAMPANIA",              (317346, 204223, 326644)),
    ("PUGLIA",                (198662, 130675, 213545)),
    ("BASILICATA",            (25237,  17097,   30214)),
    ("CALABRIA",              (93277,  59624,  101208)),
    ("SICILIA",               (254023, 164520, 252730)),
    ("SARDEGNA",              (67379,  44105,   74003)),
    ("ESTERO",       (pd.np.NaN, pd.np.NaN, pd.np.NaN))
    ]),
    orient = "index",
    columns = ('Primaria','Secondaria I grado','Secondaria II grado'))
istat['totale'] = istat['Primaria'] + istat['Secondaria I grado'] + istat['Secondaria II grado']
with pd.option_context('display.float_format', '{:.0f}'.format):
    display(istat)
Primaria Secondaria I grado Secondaria II grado totale
PIEMONTE 191399 117997 168439 477835
VALLE D'AOSTA 5981 3691 5309 14981
LIGURIA 61566 39213 60184 160963
LOMBARDIA 468662 283007 381619 1133288
TRENTINO-ALTO ADIGE 27028 16890 21836 65754
VENETO 232694 142401 204262 579357
FRIULI-VENEZIA GIULIA 51830 32143 46949 130922
EMILIA-ROMAGNA 198417 118460 176968 493845
TOSCANA 161001 98203 152886 412090
UMBRIA 39181 23488 36946 99615
MARCHE 67996 42095 70602 180693
LAZIO 268133 161573 249145 678851
ABRUZZO 57146 35828 58578 151552
MOLISE 12595 8354 14990 35939
CAMPANIA 317346 204223 326644 848213
PUGLIA 198662 130675 213545 542882
BASILICATA 25237 17097 30214 72548
CALABRIA 93277 59624 101208 254109
SICILIA 254023 164520 252730 671273
SARDEGNA 67379 44105 74003 185487
ESTERO nan nan nan nan

Analisi delle gare

In [16]:
CATS = ('kilo', 'mega', 'giga', 'tera', 'peta')
snames = {'E': 'Primaria', 'M': 'Secondaria I grado', 'S': 'Secondaria II grado'}
In [17]:
for i, k in enumerate(CATS):
    if not os.path.exists("overview-{}.json".format(k)):
        r = urllib.request.urlopen("https://bebras.it/api?key={}&view=exams&test={}&examdata=0&edition=bebras_{}&events=0".format(key,92+i, YEAR))
        with open("overview-{}.json".format(k), "w") as tw:
            tw.writelines(r.read().decode('utf-8'))
In [18]:
import json

overview = []
for k in CATS:
    with open("overview-{}.json".format(k), "r") as t:
        j = json.load(t)
        overview += j['exams']
In [19]:
dfov = pd.DataFrame(overview)
gare = pd.DataFrame()
gare['categoria'] = dfov['category'].str.lower().astype(pd.api.types.CategoricalDtype(categories = CATS, ordered=True))
gare['insegnante'] = dfov['teacher_id'].astype('int64')
gare['login'] = dfov['login']
gare['status'] = dfov['exam_valid_score']
gare['risultato'] = dfov['score']
gare['data'] = pd.to_datetime(dfov['time'])
gare['studenti'] = dfov['team_composition'].map(lambda tt: 0 if type(tt) != type({}) else len([s for s in tt['members'] if s['name'] != '' ]))
In [20]:
fid = teachers.set_index('id')
fid['regione'] = fid['school_region'].map(norm_region)
gare = gare.join(fid[['regione']],on='insegnante')
In [21]:
done = gare[gare['status'] == 1]

Insegnanti partecipanti

In [22]:
len(done.groupby(['insegnante']))
Out[22]:
447

Insegnanti per regione che hanno partecipato

In [23]:
display(done.groupby(['regione'])['insegnante'].nunique())
regione
ABRUZZO                    5
BASILICATA                 5
CALABRIA                   4
CAMPANIA                  19
EMILIA-ROMAGNA            27
FRIULI-VENEZIA GIULIA     19
LAZIO                     44
LIGURIA                   12
LOMBARDIA                128
MARCHE                     6
MOLISE                     5
PIEMONTE                  25
PUGLIA                    16
SARDEGNA                   4
SICILIA                    9
TOSCANA                   17
TRENTINO-ALTO ADIGE        9
UMBRIA                     3
VALLE D'AOSTA             29
VENETO                    61
Name: insegnante, dtype: int64

Insegnanti per categoria

In [24]:
display(done.groupby(['categoria'])['insegnante'].nunique())
categoria
kilo    121
mega    214
giga    164
tera     81
peta     79
Name: insegnante, dtype: int64

Squadre per categoria

In [25]:
with pd.option_context('display.float_format', '{:.0f}'.format):
    display(done.groupby(['regione', 'categoria'])['login'].count())
regione                categoria
ABRUZZO                kilo           95
                       mega           43
                       giga           17
                       tera            0
                       peta            0
BASILICATA             kilo            0
                       mega          103
                       giga           60
                       tera           44
                       peta            0
CALABRIA               kilo            6
                       mega           20
                       giga           12
                       tera           46
                       peta            0
CAMPANIA               kilo          149
                       mega          478
                       giga          214
                       tera          129
                       peta           55
EMILIA-ROMAGNA         kilo          202
                       mega          339
                       giga          206
                       tera          488
                       peta          150
FRIULI-VENEZIA GIULIA  kilo           40
                       mega           45
                       giga           64
                       tera          424
                       peta          166
LAZIO                  kilo          541
                       mega          238
                       giga          138
                       tera          307
                       peta          428
LIGURIA                kilo           28
                       mega           44
                       giga           29
                       tera          149
                       peta          213
LOMBARDIA              kilo         1007
                       mega         1661
                       giga          779
                       tera          676
                       peta          367
MARCHE                 kilo            0
                       mega           28
                       giga           15
                       tera          100
                       peta          268
MOLISE                 kilo            0
                       mega           65
                       giga           18
                       tera            0
                       peta           19
PIEMONTE               kilo           47
                       mega          271
                       giga          112
                       tera          203
                       peta          273
PUGLIA                 kilo          341
                       mega          286
                       giga          145
                       tera           35
                       peta           28
SARDEGNA               kilo           12
                       mega          136
                       giga           49
                       tera            0
                       peta            8
SICILIA                kilo            0
                       mega           92
                       giga           34
                       tera            9
                       peta            9
TOSCANA                kilo           75
                       mega          222
                       giga          127
                       tera            0
                       peta            3
TRENTINO-ALTO ADIGE    kilo           13
                       mega          315
                       giga          165
                       tera            0
                       peta            0
UMBRIA                 kilo            1
                       mega           47
                       giga           18
                       tera          167
                       peta            0
VALLE D'AOSTA          kilo           78
                       mega          838
                       giga          513
                       tera            0
                       peta            0
VENETO                 kilo          485
                       mega         1302
                       giga          606
                       tera          548
                       peta          376
Name: login, dtype: int64

Studenti per categoria

In [26]:
with pd.option_context('display.float_format', '{:.0f}'.format):
    display(done.groupby(['regione', 'categoria'])['studenti'].sum())
regione                categoria
ABRUZZO                kilo          93
                       mega           2
                       giga           0
                       tera         nan
                       peta         nan
BASILICATA             kilo         nan
                       mega          34
                       giga           1
                       tera          44
                       peta         nan
CALABRIA               kilo           6
                       mega          20
                       giga          12
                       tera          46
                       peta         nan
CAMPANIA               kilo         139
                       mega         270
                       giga          92
                       tera          77
                       peta          36
EMILIA-ROMAGNA         kilo         115
                       mega          91
                       giga          25
                       tera         184
                       peta          20
FRIULI-VENEZIA GIULIA  kilo           0
                       mega          34
                       giga          53
                       tera         393
                       peta         136
LAZIO                  kilo         228
                       mega         103
                       giga          82
                       tera         286
                       peta         304
LIGURIA                kilo           6
                       mega          15
                       giga          18
                       tera           0
                       peta          35
LOMBARDIA              kilo         580
                       mega        1053
                       giga         529
                       tera         387
                       peta         182
MARCHE                 kilo         nan
                       mega           0
                       giga           0
                       tera          50
                       peta         236
MOLISE                 kilo         nan
                       mega          39
                       giga          18
                       tera         nan
                       peta           0
PIEMONTE               kilo          39
                       mega         198
                       giga          40
                       tera         137
                       peta         205
PUGLIA                 kilo         182
                       mega          99
                       giga          36
                       tera          34
                       peta          28
SARDEGNA               kilo           0
                       mega           0
                       giga           0
                       tera         nan
                       peta           7
SICILIA                kilo         nan
                       mega          86
                       giga          31
                       tera           9
                       peta           9
TOSCANA                kilo          58
                       mega         133
                       giga         123
                       tera         nan
                       peta           3
TRENTINO-ALTO ADIGE    kilo           0
                       mega           0
                       giga           0
                       tera         nan
                       peta         nan
UMBRIA                 kilo           1
                       mega          47
                       giga          18
                       tera         167
                       peta         nan
VALLE D'AOSTA          kilo          77
                       mega         552
                       giga         356
                       tera         nan
                       peta         nan
VENETO                 kilo         252
                       mega         639
                       giga         350
                       tera         319
                       peta         267
Name: studenti, dtype: float64
In [27]:
! pip install mapclassify
Requirement already satisfied: mapclassify in /opt/conda/lib/python3.8/site-packages (2.4.0)
Requirement already satisfied: scikit-learn in /opt/conda/lib/python3.8/site-packages (from mapclassify) (0.23.2)
Requirement already satisfied: numpy>=1.3 in /opt/conda/lib/python3.8/site-packages (from mapclassify) (1.19.2)
Requirement already satisfied: scipy>=1.0 in /opt/conda/lib/python3.8/site-packages (from mapclassify) (1.5.2)
Requirement already satisfied: networkx in /opt/conda/lib/python3.8/site-packages (from mapclassify) (2.5)
Requirement already satisfied: pandas>=1.0 in /opt/conda/lib/python3.8/site-packages (from mapclassify) (1.1.3)
Requirement already satisfied: joblib>=0.11 in /opt/conda/lib/python3.8/site-packages (from scikit-learn->mapclassify) (0.17.0)
Requirement already satisfied: threadpoolctl>=2.0.0 in /opt/conda/lib/python3.8/site-packages (from scikit-learn->mapclassify) (2.1.0)
Requirement already satisfied: decorator>=4.3.0 in /opt/conda/lib/python3.8/site-packages (from networkx->mapclassify) (4.4.2)
Requirement already satisfied: pytz>=2017.2 in /opt/conda/lib/python3.8/site-packages (from pandas>=1.0->mapclassify) (2020.1)
Requirement already satisfied: python-dateutil>=2.7.3 in /opt/conda/lib/python3.8/site-packages (from pandas>=1.0->mapclassify) (2.8.1)
Requirement already satisfied: six>=1.5 in /opt/conda/lib/python3.8/site-packages (from python-dateutil>=2.7.3->pandas>=1.0->mapclassify) (1.15.0)

Cartografia ISTAT 2011 (fonte: http://www.istat.it/it/archivio/24613), convertita con il comando:

ogr2ogr -f GeoJSON -s_srs reg2011_g.prj -t_srs EPSG:4326 it.json reg2011_g.shp

(fonte: https://gist.github.com/riccardoscalco/6029355)

In [28]:
import geopandas as gpd
%matplotlib inline

it = gpd.read_file("it.json")

TYPES = ['totale'] + list(snames.values())

dreg = done.groupby(['regione']).count()
dregk = done.groupby(['regione','categoria']).count()

sreg = done.groupby(['regione']).sum()
sregk = done.groupby(['regione','categoria']).sum()


def get_data_with_default(geo, i, t, ddata, sdata, jj, labeld='login', labels='studenti'):
    try:
        geo.loc[i, 'squadre' + ' ' + t] = 0
        for j in jj:
            geo.loc[i, 'squadre' + ' ' + t] += ddata.loc[j, labeld] if ddata.loc[j, labeld] > 0 else 0 
    except:
        geo.loc[i, 'squadre' + ' ' + t] += 0
    try:
        geo.loc[i, 'studenti' + ' ' + t] = 0
        for j in jj:
            geo.loc[i, 'studenti' + ' ' + t] += sdata.loc[j, labels] if sdata.loc[j, labels] > 0 else 0
    except:
        geo.loc[i, 'studenti' + ' ' + t] += 0

        
for i, r in it.iterrows():
    for cname in istat.index:
        if r['NOME_REG'][0:5] == cname[0:5]:
            it.loc[i, 'NOME_REG'] = cname
            get_data_with_default(it, i, TYPES[0], dreg, sreg, [cname])
            get_data_with_default(it, i, TYPES[1], dregk, sregk, [(cname, 'kilo')])
            get_data_with_default(it, i, TYPES[2], dregk, sregk, [(cname, 'mega'), (cname, 'giga')])
            get_data_with_default(it, i, TYPES[3], dregk, sregk, [(cname, 'tera'), (cname, 'peta')])
                
            it.loc[i, 'popolazione ' + TYPES[0]] = istat.loc[cname, 'totale']
            it.loc[i, 'popolazione ' + TYPES[1]] = istat.loc[cname, snames['E']]
            it.loc[i, 'popolazione ' + TYPES[2]] = istat.loc[cname, snames['M']]
            it.loc[i, 'popolazione ' + TYPES[3]] = istat.loc[cname, snames['S']]
            break

for t in TYPES:
    it['copertura ' + t] = 1000 * it['studenti ' + t] / it['popolazione ' + t]

fig, ax = plt.subplots(2,2)
fig.set_size_inches(15,11)
for i, t in enumerate(TYPES):
    r = i // 2
    c = i % 2
    ax[r][c].set_aspect("equal")
    ax[r][c].set_axis_off()
    ax[r][c].set_title("Studenti ogni mille ({})".format(t))
    it.plot(ax=ax[r][c], column='copertura ' + t, cmap='YlOrRd', scheme='quantiles', legend=True)
    
fig.savefig('italia.png')    
plt.show()    

Il Bebras nel mondo (dati 2019)

In [29]:
w = gpd.read_file("world.json")
w = w.set_index("name")

with open("wbebras.json", "r") as t:
    wbebras = pd.DataFrame(pd.read_json(t, convert_axes=True, orient='index'))

wbebras['copertura'] = 1000 * wbebras["bebras"] / wbebras["oecd"]    
    

for i in wbebras.index:
    try:
        w.loc[i, "bebras"] = wbebras.loc[i, "bebras"]
        w.loc[i, "oecd"]   = wbebras.loc[i, "oecd"]
        w.loc[i, "copertura"]   = wbebras.loc[i, "copertura"]
    except:
        print(i)

plt.figure(figsize=(20,20))
ax = plt.subplot(212)
ax.set_aspect("equal")
ax.set_axis_off()
ax.set_title("Partecipanti ogni 1000 studenti (dati OECD 2018)")       
w.dropna().plot(ax=ax,column='copertura', cmap='Blues', scheme='quantiles', legend=True)


ax = plt.subplot(211)
ax.set_aspect("equal")
ax.set_axis_off()
ax.set_title("Partecipanti Bebras 2019")       
p = w.dropna(subset=["bebras"]).plot(ax=ax,column='bebras', cmap='YlOrRd', scheme='quantiles', legend=True)
plt.show()

Numeri assoluti

In [30]:
display(wbebras.sort_values("bebras",ascending=False)[["bebras","oecd","copertura"]])
bebras oecd copertura
France 702060 10412016.0 67.427864
Germany 401737 9935909.0 40.432838
United Kingdom 260971 11066193.0 23.582726
India 178239 NaN NaN
Belarus 176492 NaN NaN
Taiwan 143076 NaN NaN
Ukraine 110978 NaN NaN
Turkey 109563 16384160.0 6.687130
Czech Republic 90976 1370636.0 66.375026
Slovakia 89768 671408.0 133.701118
United States of America 56534 49829312.0 1.134553
Republic of Serbia 53099 NaN NaN
Australia 46738 4627837.0 10.099319
Italy 46052 7501201.0 6.139284
South Korea 44332 5613337.0 7.897620
Lithuania 43490 349619.0 124.392553
Austria 37621 1026408.0 36.653066
Slovenia 28803 276126.0 104.311075
Hungary 27702 1182406.0 23.428501
Netherlands 25482 2807504.0 9.076390
Switzerland 25345 1123542.0 22.558124
North Macedonia 25166 NaN NaN
Croatia 24819 NaN NaN
Greece 21717 1311383.0 16.560379
Poland 20622 4669836.0 4.416001
Latvia 19550 239000.0 81.799163
Canada 19546 5061204.0 3.861927
Romania 15695 NaN NaN
Vietnam 15130 NaN NaN
China 13475 NaN NaN
Russia 11937 16217168.0 0.736072
Bosnia and Herzegovina 9765 NaN NaN
Pakistan 9240 NaN NaN
Ireland 6882 1056064.0 6.516651
Indonesia 6773 NaN NaN
Kazakhstan 6698 NaN NaN
Saudi Arabia 6008 NaN NaN
Finland 5395 915321.0 5.894107
Portugal 5137 1388754.0 3.698999
Belgium 4050 2000570.0 2.024423
Thailand 3964 NaN NaN
Sweden 3609 1828036.0 1.974250
Estonia 3475 172124.0 20.188934
Japan 3420 13500120.0 0.253331
Uzbekistan 3347 NaN NaN
Iran 2768 NaN NaN
Iceland 2451 67592.0 36.261688
Egypt 2410 NaN NaN
New Zealand 2312 878178.0 2.632724
Algeria 894 NaN NaN
Spain 694 6414465.0 0.108193
Cyprus 521 NaN NaN
Bulgaria 502 NaN NaN
Singapore 187 NaN NaN
In [31]:
print("In totale nel mondo {} partecipanti".format(wbebras['bebras'].sum()))
In totale nel mondo 2977217 partecipanti
In [ ]: