momente şi schiţe de informatică

Un calcul de medii, intermediat de Python

Creat: 2012/dec       Comentarii

Python | situații școlare

Să zicem că într-un text avem câte o secvenţă de medii - în ordinea obiectelor din catalogul şcolar - pentru fiecare elev:

Popa Dan 7.67 8.67 9 10 9.5 10 10 10 8.67 7.67 8.67 9 10 9 10 10
Albu Diana Ioana 8 9 10 6.67 10 10 10 10 7.67 8.67 9 10 6.67 10 10 10
...

Ar fi de calculat mediile generale pe orizontale (pentru fiecare elev) şi pe verticale (pentru fiecare obiect); "salvăm" interesul pentru acest calcul (altfel, banal) invocând faptul că rezultatele trebuie deservite de un site constituit cu Python.

În Python putem folosi funcţia sum(listă_de_numere[, start]), obţinând media astfel:

vb@vb:~$ python
>>> l_nr = [7.67, 8.67, 9, 10, 9.5]
>>> sum(l_nr) / len(l_nr)
8.968

Textul de forma redată mai sus trebuie prelucrat pentru a obţine listele de numere; folosim modulul Python re pentru a extrage subşirurile corespunzătoare mediilor şi funcţia float pentru a transforma aceste subşiruri în numere - ca în exemplul următor:

>>> import re
>>> text = "Popa Dan 7.67 8.67 9 10 9.5"
>>> l_nr = [float(sbs) for sbs in re.findall(r"(\d+\.*\d*)", text)]
>>> print l_nr
[7.67, 8.67, 9.0, 10.0, 9.5]

Şablonul "(\d+\.*\d*)" furnizat metodei re.findall() extrage din text secvenţele nevide de cifre ("\d+": cel puţin un "digit"), precum şi pe acelea care încep cu cifre şi sunt eventual urmate de punct zecimal ("\.") şi alte cifre ("*": zero sau mai multe apariţii ale caracterului precedent).

În prealabil, textul va trebui împărţit pe rânduri; folosim în acest scop metoda split(separator), cu separator='\n' (caracterul "end-line"):

>>> text = """Popa Dan 7.67 8.67 9 10 9.5
... Albu Diana Ioana 8 9 10 6.67 10
... """
>>> text.split('\n')
['Popa Dan 7.67 8.67 9 10 9.5', 'Albu Diana Ioana 8 9 10 6.67 10', '']

""" delimitează un şir care este preluat ca atare (fără vreo interpretare). La sfârşitul listei rezultate avem şi un şir vid, pentru că marcatorul final """ nu urmează imediat după încheierea ultimului rând, ci după "Enter"; putem elimina ultimul element din listă folosind text.split('\n')[:-1].

Cu aceste precizări, putem constitui următorul program:

# -*- coding: utf-8 -*-
import re

medii_elevi = """Popa Dan 7.67 8.67 9 10 9.5 10 10 10 8.67 7.67 8.67 9 10 9 10 10
Albu Diana Ioana 8 9 10 6.67 10 10 10 10 7.67 8.67 9 10 6.67 10 10 10
Popa Dan 7.67 8.67 9 10 9.5 10 10 10 8.67 7.67 8.67 9 10 9 10 10
Albu Diana Ioana 8 9 10 6.67 10 10 10 10 7.67 8.67 9 10 6.67 10 10 10
""" # COPY-PASTE de 10 ori, pentru a testa pe un tabel mai mare de date

def medii_generale(text_medii):
    _medii = text_medii.split('\n')[:-1]
    list_medii = [[float(sbs) 
                   for sbs in re.findall(r"(\d+\.*\d*)", _med)] 
                  for _med in _medii]
    n = len(_medii) # nr. elevi
    k = len(list_medii[0]) # nr. obiecte
    mg_elev = [round(sum(_m)/k, 3) for _m in list_medii]
    mg_obiect = [round(sum([_m[i] for _m in list_medii])/n, 3) 
                 for i in range(k)]
    return mg_elev, mg_obiect
    
print medii_generale(medii_elevi)

Obţinem lista mediilor generale ale elevilor şi lista mediilor generale pe obiecte:

vb@vb:~ python medii-test.py 
([9.241, 9.105, 9.241, 9.105], 
[7.835, 8.835, 9.5, 8.335, 9.75, 10.0, 10.0, 10.0, 8.17, 8.17, 8.835, 9.5, 8.335, 9.5, 10.0, 10.0])

O funcţie ca aceea pusă la punct prin programul de mai sus, ne-a servit într-o aplicaţie de reflectare dinamică a situaţiei şcolare pe clasele de elevi: la cerere, pe baza notelor curent înregistrate la diversele obiecte pentru elevii respectivi - se calculează mediile (pe obiect, elev, arii curriculare, clasă) şi se ambalează în răspuns statisticile rezultate în acel moment (proiect-site-şcoală).

Sensul expunerii "dinamice" a situaţiilor şcolare (şi nu doar în momentul încheierii unui ciclu şcolar) este inspirat din sportul de performanţă: rezultatele curente ale potenţialilor competitori influenţează pozitiv efortul propriu de perfecţionare. Analog, putând observa în orice moment rezultatele proprii, comparativ cu rezultatele celorlalţi şi cu mediile clasei - ar fi de sperat că elevul se va motiva suplimentar pentru îmbunătăţirea continuă a pregătirii proprii…

Tocmai caracterul dinamic sugerat mai sus, face preferabilă constituirea şi păstrarea în baza de date a unor texte de medii precum cel exemplificat la început, faţă de o modelare (obişnuită) de genul: (id_elev, id_obiect, medie_1, medie_2) - caz în care pentru fiecare elev (şi la oricare cerere) ar trebui accesate şi updatate în baza de date un număr mare de înregistrări.

Termenul "oricare" suportă aici o anumită relativizare: contul de "diriginte" al clasei decide momentele (de exemplu, la sfârşitul unei luni) în care se calculează şi se înscriu în baza de date "textele de medii" curente; conturile de "elev" doar vor accesa rezultatele deja înscrise. Desigur, după încheierea semestrului curent, "textele de medii" rămân definitiv în baza de date, urmând să fie completate (iarăşi, în "orice" moment) cu datele proprii viitorului ciclu şcolar.

Media Dinamică

Articolul 50

Drumuri

ŞahStartTemp

25
32
17
4
19
34
14
3
26
33
16
5
31
24
15
18
35
20
2
13
27
6
9
23
30
11
8
21
28
12
22
29
10
7

Ambiţiile Cavalerului

Localităţi

Judeţ:

Constituirea unei baze de date colectând cu Python de pe web

Bliţuri

Load another random Bliţ

//slightchess

Decoraţiuni hiperbolice

SALARII 2017

//bacMath
variante BAC matematică

Bacalaureat 2015 -
de la forma microsoftizată, la R

modelare ŞAH, I-XX
construcţia unui PGN-browser()

Linux şi aplicaţii Web
în 24 de ore

Orar şcolar - exemplu
după un orar generat de "aSc Orare"

Orar Adjust
ajustează orarul şcolar