Statistiche sulla partecipazione al Bebras italiano 2025/26

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') or 'ROMAGNA' in r:
        return 'EMILIA-ROMAGNA'
    if r.startswith('TRENTINO') or r.startswith('ALTO ADIGE') or r == 'P.A.T.' or 'TRENTO' in r:
        return 'TRENTINO ALTO ADIGE / SÜDTIROL'
    if r.startswith('LO'):
        return 'LOMBARDIA'
    if r.endswith('MONTE'):
        return 'PIEMONTE'
    if r.startswith('VALLE') or 'AOSTA' in r:
        return "VALLE D'AOSTA / VALLÉE D'AOSTE"
    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' or r == 'CROAZIA' or r == 'ILFOV' \
       or 'ISTRIA' in r or 'SHUBRA' in r:
        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]:
from datetime import date
In [6]:
YEAR=2025
LAST_DAY=date(YEAR,11,9)

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)
regteams = teachers['teams_active'].sum()

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

if today <= LAST_DAY:
    isotoday = today.isoformat()[:10]
    with open("stats-" + isotoday + ".txt", "w") as stat:
        stat.write(f"{filled:d} {regteams:d} {3*regteams:d}\n")

2025-11-09: 1336 insegnanti hanno confermato la partecipazione; ci sono 31581 squadre già registrate (~94743 alunni).

In [7]:
oldeditions = (2015, 2016, 2017, "bebras_2018", "bebras_2019", "bebras_2020", "bebras_2021", "bebras_2022", "bebras_2023", "bebras_2024")
In [8]:
oldteachers = {}
for y in oldeditions:
    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 [9]:
intersect = {}
for y in oldeditions:
    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() 
                             )))

41 insegnanti hanno già partecipato all'edizione 2015 (17% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di 8.7 (deviazione standard 28).

87 insegnanti hanno già partecipato all'edizione 2016 (12% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di 16.3 (deviazione standard 38).

145 insegnanti hanno già partecipato all'edizione 2017 (14% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di 18.1 (deviazione standard 46).

214 insegnanti hanno già partecipato all'edizione 2018 (19% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di 15.9 (deviazione standard 41).

255 insegnanti hanno già partecipato all'edizione 2019 (28% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di 12.4 (deviazione standard 37).

249 insegnanti hanno già partecipato all'edizione 2020 (50% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di -25.9 (deviazione standard 77).

371 insegnanti hanno già partecipato all'edizione 2021 (47% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di -16.7 (deviazione standard 58).

456 insegnanti hanno già partecipato all'edizione 2022 (47% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di -3.5 (deviazione standard 39).

606 insegnanti hanno già partecipato all'edizione 2023 (51% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di 0.8 (deviazione standard 28).

790 insegnanti hanno già partecipato all'edizione 2024 (66% dei partecipanti di quell'edizione), il numero di squadre è aumentato in media di 1.4 (deviazione standard 23).

In [10]:
all_intersect = pd.merge(teachers['id'], oldteachers[oldeditions[0]]['id'], on='id', how='inner')

for e in oldeditions[1:]:
    all_intersect = pd.merge(all_intersect['id'], oldteachers[e]['id'], on='id', how='inner')

    
print(f"Hanno partecipato a tutte le {len(oldeditions) + 1} edizioni: {len(all_intersect)} insegnanti.")

all_editions = pd.merge(teachers, all_intersect, on='id', how='inner')
#display(all_editions[['firstname', 'name', 'school_name', 'school_city', 'school_kind']])
Hanno partecipato a tutte le 11 edizioni: 21 insegnanti.
In [11]:
institutes = teachers[(teachers['school_code'].str.strip() != "") 
                      & (teachers['subscription'] > 0) 
                      & (teachers['confirm_time'].dt.date > date(YEAR,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: 511; numero medio insegnanti per codice: 2.11
In [12]:
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 = LAST_DAY - date.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).days
In [13]:
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((date(YEAR-1,11,10) - date(*d), nn))
olddata = pd.DataFrame.from_dict(dict(olddata), orient="index", 
                                  columns=["insegnanti","squadre","alunni"]).sort_index(ascending=False)
olddata['giorni'] = (olddata.index * -1).days
In [14]:
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,7])
    delta = (data[t].max()-olddata[t].max())/olddata[t].max()
    _ = ax[i].text(-.9*data[t].count(), .75*data[t].max(), '{:+.1f}%'.format(delta*100), color='red' if delta < 0 else 'green')
No description has been provided for this image
In [15]:
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 [16]:
import json
In [17]:
CATS = ('kilo','mega','giga','tera','peta')
CATEGORIES = tuple(f'{c}' for c in CATS)
In [18]:
with open("teams.json") as t:
    teams = pd.DataFrame(json.load(t)['teams'])

oldteams = pd.DataFrame({'class': CATS,f'teams_{YEAR-1}':[3463, 10697, 5016, 2654, 1883]})
oldteams.index = oldteams['class']
del oldteams['class']
teams['macro'] = teams['class'].str.slice(0,4)
tdata = teams.groupby('macro').count()['login'].copy()
In [19]:
tdata = pd.concat([tdata, oldteams],axis=1)
tdata = tdata.reindex(index = CATEGORIES)
In [20]:
tdata['Incremento potenziale %'] = 100*(tdata['login']-tdata[f'teams_{YEAR-1}'])/tdata[f'teams_{YEAR-1}']
display(tdata)

print(f"""In totale {tdata['login'].sum()} squadre iscritte 
({100*(tdata['login'].sum()-olddata['squadre'].max())/olddata['squadre'].max():+.2f}% rispetto alle squadre iscritte nel {YEAR-1})
({100*(tdata['login'].sum()-oldteams['teams_2024'].sum())/oldteams['teams_2024'].sum():+.2f}% rispetto alle squadre partecipanti nel {YEAR-1})
""")

students = teams.groupby('class').count().apply(lambda x: 3*x, axis=1)['login']

print('\nIl numero di partecipanti previsto per categoria:')
display(students)
print(f"Il numero totale di partecipanti previsto è {students.sum()}.")
login teams_2024 Incremento potenziale %
kilo 4597 3463 32.746174
mega 14218 10697 32.915771
giga 6993 5016 39.413876
tera 3273 2654 23.323286
peta 2527 1883 34.200743
In totale 31608 squadre iscritte 
(+9.71% rispetto alle squadre iscritte nel 2024)
(+33.29% rispetto alle squadre partecipanti nel 2024)


Il numero di partecipanti previsto per categoria:
class
giga    20979
kilo    13791
mega    42654
peta     7581
tera     9819
Name: login, dtype: int64
Il numero totale di partecipanti previsto è 94824.

La popolazione studentesca nazionale

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

In [21]:
istat = pd.read_csv('studenti_italia.csv', 
                usecols=['Territorio', 
                         'Ordine scolastico', 
                         'Value'])
In [22]:
istat = istat.rename(columns={'Territorio':'regione'})
In [23]:
istat['regione'] = istat['regione'].str.upper()
tot_istat = istat.groupby('regione')['Value'].sum()
reg_istat = istat.groupby(['regione', 'Ordine scolastico'])['Value'].sum()
In [24]:
all_istat = reg_istat.unstack()
all_istat['totale'] = tot_istat

all_istat
Out[24]:
Ordine scolastico primaria secondaria I grado secondaria II grado totale
regione
ABRUZZO 53145 34299 56435 143879
BASILICATA 20922 14333 28202 63457
CALABRIA 80867 52845 95931 229643
CAMPANIA 270047 181821 330549 782417
EMILIA-ROMAGNA 193247 125634 198096 516977
FRIULI-VENEZIA GIULIA 48202 31888 49939 130029
ITALIA 2588383 1706482 2730359 7025224
LAZIO 253371 164187 258650 676208
LIGURIA 56301 38096 62401 156798
LOMBARDIA 448350 293318 409987 1151655
MARCHE 63478 41880 71735 177093
MOLISE 10919 7111 13158 31188
PIEMONTE 177669 117200 177897 472766
PUGLIA 171014 114102 200441 485557
SARDEGNA 60420 40327 71806 172553
SICILIA 219759 145681 239790 605230
TOSCANA 151736 100906 166834 419476
TRENTINO ALTO ADIGE / SÜDTIROL 54030 33924 42514 130468
UMBRIA 36097 23874 38850 98821
VALLE D'AOSTA / VALLÉE D'AOSTE 5445 3633 5566 14644
VENETO 213364 141423 211578 566365

Analisi delle gare

In [25]:
snames = {'E': 'primaria', 'M': 'secondaria I grado', 'S': 'secondaria II grado'}
In [26]:
FIRST=121 # da aggiornare per l'anno corrente

for i, k in enumerate(CATS):
    if not os.path.exists(f"overview-{k}.json"):
        r = urllib.request.urlopen(f"https://bebras.it/api?key={key}&view=exams&test={FIRST+i}&examdata=0&edition=bebras_{YEAR}&events=0")
        with open(f"overview-{k}.json", "w") as tw:
            tw.writelines(r.read().decode('utf-8'))
In [27]:
import json

overview = []
for k in CATEGORIES:
    with open(f"overview-{k}.json", "r") as t:
        j = json.load(t)
        overview += j['exams']
In [28]:
dfov = pd.DataFrame(overview)
In [29]:
gare = pd.DataFrame()
gare['categoria'] = dfov['category'].str.lower().astype(pd.api.types.CategoricalDtype(categories = CATEGORIES, 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 [30]:
fid = teachers.set_index('id')
fid['regione'] = fid['school_region'].map(norm_region)
gare = gare.join(fid[['regione']],on='insegnante')
In [31]:
done = gare[gare['status'] == 1]
In [32]:
f'In tutto, completate {len(done)} gare (~{len(done)*3} studenti)'
Out[32]:
'In tutto, completate 23723 gare (~71169 studenti)'

Insegnanti partecipanti

In [33]:
len(done.groupby(['insegnante']))
Out[33]:
1141

Insegnanti per regione che hanno partecipato

In [34]:
display(done.groupby(['regione'])['insegnante'].nunique())
regione
ABRUZZO                             1
BASILICATA                         11
CALABRIA                            4
CAMPANIA                           71
EMILIA-ROMAGNA                     41
ESTERO                              4
FRIULI-VENEZIA GIULIA              18
LAZIO                              33
LIGURIA                            14
LOMBARDIA                         205
MARCHE                             18
MOLISE                             11
PIEMONTE                           53
PUGLIA                             38
SARDEGNA                           15
SICILIA                            11
TOSCANA                            40
TRENTINO ALTO ADIGE / SÜDTIROL     26
UMBRIA                              9
VALLE D'AOSTA / VALLÉE D'AOSTE     35
VENETO                            104
Name: insegnante, dtype: int64

Insegnanti per categoria

In [35]:
display(done.groupby(['categoria'], observed=True)['insegnante'].nunique())
categoria
kilo    301
mega    645
giga    445
tera    148
peta    109
Name: insegnante, dtype: int64

Squadre per categoria

In [36]:
with pd.option_context('display.float_format', '{:.0f}'.format):
    display(done.groupby(['regione', 'categoria'], observed=True)['login'].count())
regione                         categoria
ABRUZZO                         kilo           14
                                mega           20
                                giga            5
BASILICATA                      kilo           85
                                mega          204
                                giga          109
CALABRIA                        kilo            1
                                tera           11
                                peta           11
CAMPANIA                        kilo          160
                                mega          735
                                giga          331
                                tera          192
                                peta          156
EMILIA-ROMAGNA                  kilo           84
                                mega          440
                                giga          204
                                tera          177
                                peta           77
ESTERO                          kilo            8
                                mega            2
                                giga            1
                                tera           15
                                peta           62
FRIULI-VENEZIA GIULIA           kilo           60
                                mega           50
                                giga           21
                                tera          238
                                peta          107
LAZIO                           kilo          160
                                mega          193
                                giga          138
                                tera           40
                                peta          142
LIGURIA                         kilo           48
                                mega          128
                                giga           59
                                peta           71
LOMBARDIA                       kilo          495
                                mega         2390
                                giga         1143
                                tera          581
                                peta          251
MARCHE                          kilo            7
                                mega          316
                                giga           93
                                tera           47
                                peta          125
MOLISE                          kilo            2
                                mega          122
                                giga           56
PIEMONTE                        kilo           80
                                mega          743
                                giga          332
                                tera          188
                                peta          111
PUGLIA                          kilo          207
                                mega          531
                                giga          273
                                tera           61
                                peta           32
SARDEGNA                        kilo           21
                                mega          125
                                giga           64
                                tera           28
                                peta           58
SICILIA                         kilo           22
                                mega           52
                                giga           42
                                tera            8
                                peta           13
TOSCANA                         kilo          121
                                mega          375
                                giga          183
                                tera           39
TRENTINO ALTO ADIGE / SÜDTIROL  kilo           83
                                mega          455
                                giga          192
                                tera           34
                                peta           29
UMBRIA                          kilo            1
                                mega          219
                                giga          121
                                tera           39
VALLE D'AOSTA / VALLÉE D'AOSTE  kilo           98
                                mega          391
                                giga          250
VENETO                          kilo          414
                                mega         1093
                                giga          515
                                tera          193
                                peta          291
Name: login, dtype: int64

Studenti per categoria

In [37]:
with pd.option_context('display.float_format', '{:.0f}'.format):
    display(done.groupby(['regione', 'categoria'], observed=True)['studenti'].sum())
regione                         categoria
ABRUZZO                         kilo            0
                                mega            0
                                giga            0
BASILICATA                      kilo          111
                                mega          425
                                giga          222
CALABRIA                        kilo            3
                                tera           33
                                peta           29
CAMPANIA                        kilo          337
                                mega         1616
                                giga          726
                                tera          331
                                peta          180
EMILIA-ROMAGNA                  kilo          149
                                mega          887
                                giga          400
                                tera          343
                                peta          188
ESTERO                          kilo           20
                                mega            5
                                giga            2
                                tera           38
                                peta          186
FRIULI-VENEZIA GIULIA           kilo          153
                                mega           58
                                giga           14
                                tera          498
                                peta          194
LAZIO                           kilo          269
                                mega          442
                                giga          240
                                tera          104
                                peta          353
LIGURIA                         kilo           34
                                mega          221
                                giga          120
                                peta           88
LOMBARDIA                       kilo         1021
                                mega         4911
                                giga         2421
                                tera          736
                                peta          526
MARCHE                          kilo           16
                                mega          820
                                giga          258
                                tera          135
                                peta          340
MOLISE                          kilo            0
                                mega          290
                                giga          124
PIEMONTE                        kilo           76
                                mega         1126
                                giga          505
                                tera          387
                                peta          115
PUGLIA                          kilo          594
                                mega         1093
                                giga          684
                                tera          169
                                peta           90
SARDEGNA                        kilo            0
                                mega          329
                                giga          185
                                tera           45
                                peta           85
SICILIA                         kilo            0
                                mega           94
                                giga           91
                                tera           23
                                peta           39
TOSCANA                         kilo          309
                                mega          873
                                giga          512
                                tera          103
TRENTINO ALTO ADIGE / SÜDTIROL  kilo          195
                                mega          481
                                giga          196
                                tera           93
                                peta           85
UMBRIA                          kilo            0
                                mega           85
                                giga           84
                                tera           82
VALLE D'AOSTA / VALLÉE D'AOSTE  kilo          178
                                mega          775
                                giga          513
VENETO                          kilo          935
                                mega         2356
                                giga         1053
                                tera          446
                                peta          539
Name: studenti, dtype: int64

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 [38]:
import geopandas as gpd
%matplotlib inline

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

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

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

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


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 all_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]] = all_istat.loc[cname, 'totale']
            it.loc[i, 'popolazione ' + TYPES[1]] = all_istat.loc[cname, snames['E']]
            it.loc[i, 'popolazione ' + TYPES[2]] = all_istat.loc[cname, snames['M']]
            it.loc[i, 'popolazione ' + TYPES[3]] = all_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')    
fig
/home/monga/.local/share/virtualenvs/statistiche-1Or8MH4V/lib/python3.13/site-packages/pyogrio/__init__.py:7: DeprecationWarning: The 'shapely.geos' module is deprecated, and will be removed in a future version. All attributes of 'shapely.geos' are available directly from the top-level 'shapely' namespace (since shapely 2.0.0).
  import shapely.geos  # noqa: F401
Out[38]:
No description has been provided for this image
No description has been provided for this image

Il Bebras nel mondo (dati 2024)

Dati UNESCO 2022 da: http://data.uis.unesco.org

In [39]:
unesco = pd.read_csv('unesco.csv')

unesco_tot = unesco.groupby('Country').sum()['Value']

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['unesco'] = float('nan')

for c in wbebras.index:
    if c in unesco_tot:
        wbebras.at[c, 'unesco'] = float(unesco_tot[c])

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

for i in wbebras.index:
    try:
        w.loc[i, "bebras"] = wbebras.loc[i, "bebras"]
        w.loc[i, "unesco"]   = wbebras.loc[i, "unesco"]
        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(f"Partecipanti ogni 1000 studenti (dati UNESCO {unesco['TIME'][0]})")       
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 2024")       
p = w.dropna(subset=["bebras"]).plot(ax=ax,column='bebras', cmap='YlOrRd', scheme='quantiles', legend=True)
plt.show()
No description has been provided for this image

Numeri assoluti

In [40]:
display(wbebras.sort_values("bebras",ascending=False)[["bebras","unesco","copertura"]])
bebras unesco copertura
France 648250 2.091625e+07 30.992652
Germany 542997 1.981358e+07 27.405299
United Kingdom of Great Britain and Northern Ireland 467072 2.233629e+07 20.910899
Czechia 270173 2.918822e+06 92.562342
India 269931 5.408922e+08 0.499048
Taiwan 163699 NaN NaN
China 145176 4.035212e+08 0.359773
Portugal 136232 2.654846e+06 51.314464
Slovakia 129088 1.381396e+06 93.447498
Uruguay 91244 1.294786e+06 70.470333
Italy 70296 1.453918e+07 4.834935
Republic of Korea 67474 1.061291e+07 6.357731
Viet Nam 66792 3.763225e+07 1.774861
Ukraine 66664 1.695406e+06 39.320375
Lithuania 61818 7.031040e+05 87.921559
Indonesia 59739 1.118278e+08 0.534205
Austria 55933 2.084666e+06 26.830680
Croatia 51220 9.516840e+05 53.820386
Hungary 49767 2.362620e+06 21.064327
Saudi Arabia 47591 1.342873e+07 3.543970
Latvia 39557 4.844920e+05 81.646343
Canada 35172 1.020958e+07 3.445001
Mexico 30947 5.322944e+07 0.581389
Switzerland 30850 2.310532e+06 13.351903
United States of America 26491 9.743885e+07 0.271873
Slovenia 25233 5.759160e+05 43.813681
Brazil 25200 7.481081e+07 0.336850
Greece 25010 2.558984e+06 9.773410
Uzbekistan 22019 1.297386e+07 1.697182
South Africa 20023 2.602258e+07 0.769447
Azerbaijan 17564 3.338378e+06 5.261238
North Macedonia 17292 5.182160e+05 33.368325
Netherlands 16653 5.513390e+06 3.020465
Romania 15564 4.625432e+06 3.364875
Argentina 15361 1.932641e+07 0.794819
Poland 14990 9.516956e+06 1.575083
Thailand 13069 1.910819e+07 0.683948
Ireland 12395 2.010996e+06 6.163612
Australia 11844 9.605306e+06 1.233068
Algeria 10888 2.110341e+07 0.515936
Colombia 9149 1.797992e+07 0.508845
Peru 6842 1.363291e+07 0.501874
Japan 5995 2.594533e+07 0.231063
Finland 5612 1.800826e+06 3.116348
Belgium 5519 3.936128e+06 1.402139
Malaysia 5130 1.131612e+07 0.453336
Philippines 5048 5.060718e+07 0.099749
Spain 4760 1.301531e+07 0.365723
Montenegro 4337 1.889980e+05 22.947333
Estonia 4080 3.669347e+05 11.119146
New Zealand 3743 1.815482e+06 2.061711
Syrian Arab Republic 3670 6.983128e+06 0.525552
Iceland 3200 1.387640e+05 23.060736
Türkiye 2500 3.454113e+07 0.072377
Malta 2435 1.168678e+05 20.835508
Jamaica 2432 7.952320e+05 3.058227
Senegal 2400 7.214878e+06 0.332646
Iran 2375 NaN NaN
Armenia 2165 8.563780e+05 2.528089
Kosovo 1764 NaN NaN
Cyprus 1703 2.310780e+05 7.369806
Dominican Republic 1305 4.052346e+06 0.322036
Puerto Rico 1261 NaN NaN
Bosnia and Herzegovina 1238 7.461180e+05 1.659255
Palestine 1028 2.716820e+06 0.378384
Paraguay 762 2.623744e+06 0.290425
Singapore 692 8.046200e+05 0.860033
Cuba 595 2.979674e+06 0.199686
Bulgaria 592 1.434128e+06 0.412794
Denmark 523 1.944004e+06 0.269032
Afghanistan 460 NaN NaN
Pakistan 394 7.944248e+07 0.004960
Costa Rica 272 1.966272e+06 0.138333
Namibia 56 1.095422e+06 0.051122
Myanmar 0 NaN NaN
Kazakhstan 0 7.624312e+06 0.000000
Israel 0 3.839150e+06 0.000000
Sweden 0 3.773755e+06 0.000000
In [41]:
print("In totale nel mondo {} partecipanti".format(wbebras['bebras'].sum()))
In totale nel mondo 3981315 partecipanti
In [ ]: