Acest document explică, pas cu pas și fără termeni de specialitate, cum se obține
numărul pe care îl vezi când scrii zipf_frequency('cuvânt'). Cine vrea să cite tabelul
într-o lucrare găsește la final ce să scrie. Sursele sunt descrise în
sources.md.
Versiunea descrisă aici: 0.2.0.
wROdfreq răspunde la o singură întrebare: cât de des apare un cuvânt în româna de azi? Pentru fiecare cuvânt dă un număr, plus câteva semne care spun cât de sigur e acel număr.
Nu este: un lematizator (nu află singur forma de dicționar a unui cuvânt), un analizor de părți de vorbire, un corpus de text și nici o listă de „cuvinte corecte". Un cuvânt scris greșit des apare în tabel, pentru că tabelul măsoară ce se scrie, nu ce e corect.
Valoarea unui cuvânt este logaritmul în baza 10 al numărului de apariții la un miliard de cuvinte. Câteva repere:
| Zipf | Cam cât de des apare | Exemplu |
|---|---|---|
| 7 | o dată la 100 de cuvinte | de, a, în, și |
| 6 | o dată la 1.000 | unde (5,98), sunt (6,61) |
| 5 | o dată la 10.000 | casă (5,07) |
| 4 | o dată la 100.000 | cuvinte destul de rare |
| 3 | o dată la un milion | cuvinte rare |
| 1–2 | o dată la zeci/sute de milioane | nume rare, termeni tehnici |
Fiecare unitate înseamnă de zece ori mai des. Tabelul rotunjește la două zecimale; a treia ar fi doar zgomot.
Scara este aceeași ca la proiectul wordfreq, așa că numerele se pot compara.
Fiecare pas este un script separat din build/. Oricare poate fi rulat din nou oricând,
iar rezultatul este identic, bit cu bit.
Un singur program, wrodfreq/tokenizer.py, face asta pentru toate sursele. Dacă două
surse ar tăia textul diferit, rezultatele lor nu s-ar mai putea combina, și nimeni nu ar
observa. De aceea există un test care verifică ca toate sursele să dea exact aceleași
cuvinte pentru același text.
Reguli:
- Se pune totul cu litere mici. Se unifică
şșiţ(cu sedilă) înșșiț(cu virgulă). - Un cuvânt este un șir de litere românești (
a-z,ă,â,î,ș,ț), eventual cu cratimă sau apostrof în interior:cluj-napoca,mass-media. - Formele elidate se despart:
într-odevineîntrșio. - Cuvintele scurte se numără. Cele mai frecvente cuvinte românești au una sau două
litere (
a,o,de,la,cu,nu,se). Dacă le-am arunca, toate procentele ar ieși umflate. - Numerele nu se numără, nici la numărător, nici la numitor.
- Nu filtrăm cu un dicționar. Se numără orice cuvânt, ca să apară și
laptop,selfie,covid,clujean. Un filtru cu dicționarul le-ar ascunde.
Pentru fiecare sursă și fiecare cuvânt păstrăm de câte ori apare și în câte documente. Păstrăm și numărul total de cuvinte al sursei, adică numitorul. Numărătorile pe fiecare sursă rămân păstrate: tabelul final se obține din ele, nu le înlocuiește.
zipf = log10( apariții / total cuvinte din sursă × 1.000.000.000 )
O sursă contează pentru un cuvânt doar dacă îl vede de cel puțin 5 ori. Sub 5, sursa se abține: nu spune „rar", spune „nu știu". Nu raportează niciodată zero.
Motivul: zero este o afirmație („cuvântul e rar"), dar un corpus mic care nu a văzut un cuvânt, de cele mai multe ori e doar mic. Dacă am trece zerouri în medie, Wikipedia (110 milioane de cuvinte) ar trage în jos un cuvânt pe care CulturaX (23,8 miliarde) l-a măsurat bine.
Pragul se calculează din mărimea fiecărei surse, nu se fixează: 5 apariții în
110 milioane de cuvinte înseamnă altceva decât 5 în 23,8 miliarde. În construcția
curentă, pragurile sunt între −0,68 (web) și 1,77 (eu); valorile sunt în tabela sources.
Se iau doar sursele marcate „contemporan" care au văzut cuvântul de cel puțin 5 ori.
| Câte surse îl văd sigur | Ce facem |
|---|---|
| 5 sau 6 | Media tăiată: scoatem cea mai mare și cea mai mică valoare, facem media celorlalte |
| 3 sau 4 | Media simplă |
| 2 | Media simplă (încredere scăzută) |
| 1 | Valoarea acelei surse (încredere scăzută) |
| 0 | Cuvântul nu intră în tabel |
Două decizii care merită explicate:
- Nu tăiem sub 5 surse. Din 3 valori, scoțând cea mare și cea mică, rămâne una: ar însemna „alege corpusul din mijloc", ceea ce e mai prost decât media simplă.
- Nu cântărim sursele după mărime. CulturaX este de peste zece ori mai mare decât următoarea sursă. Dacă l-am cântări după mărime, tabelul ar deveni „CulturaX, cu pași în plus", iar tăierea nu ar mai avea rost.
Baza de date conține 6.064.995 de cuvinte; din pachet lipsesc 23.453 de șiruri cu trei sau mai multe cratime (vezi secțiunea 7), deci pachetul conține 6.041.542. Câte surse văd sigur cuvintele din baza de date:
| Surse sigure | Cuvinte |
|---|---|
| 6 | 62.937 |
| 5 | 93.356 |
| 4 | 154.887 |
| 3 | 222.973 |
| 2 | 669.070 |
| 1 | 4.861.772 |
Cele mai multe cuvinte (80%) sunt cuvinte rare, văzute sigur de o singură sursă, aproape întotdeauna web. Despre ele tabelul spune „există și apare cam așa de des", nu mai mult. Alte 27,4 milioane de forme au fost văzute, dar sub pragul tuturor surselor, și nu apar.
frequency_detail('birjă') întoarce nu un număr, ci patru:
zipf— valoarea combinată, descrisă mai sus.n_reliable— câte surse l-au văzut sigur (cel puțin 5 ori). Este o măsură de confirmare: un cuvânt văzut sigur de 6 surse e cu adevărat în uz; unul văzut de o singură sursă poate fi o greșeală de scriere sau un nume rar.n_attesting— câte surse l-au văzut măcar o dată. Diferența față den_reliablearată zona „există, dar e rar".spread— diferența dintre cea mai mare și cea mai mică valoare dintre surse. Unspreadmare înseamnă că sursele nu sunt de acord: cuvântul ține de un registru (iohannis: 5,37 în presă, 1,11 în subtitrări) sau se schimbă în timp.
Și by_source('birjă') arată valoarea fiecărei surse; None înseamnă „s-a abținut", nu
„zero".
În română, un cuvânt are multe forme. Verbul a înmărmuri apare în text în forme
ca înmărmurit, înmărmurește, înmărmuriți. Dacă numeri doar forma din dicționar,
verbul pare aproape dispărut: înmărmuri singur are Zipf 0,81, iar toată
familia lui 1,66.
lemma_frequency('înmărmuri') adună frecvența tuturor formelor unui cuvânt din
dicționar (o „lemă"), folosind harta formelor din DEX Online (aproximativ 318 mii
de lexeme și 2,3 milioane de forme). Tabelul de leme are 180.569 de intrări.
Trei reguli fac diferența între o hartă bună și una greșită:
- O formă ambiguă se împarte, nu se dublează. Aproximativ 12% dintre forme aparțin
mai multor leme.
veștiaparține luiveste(o știre) și luiveșcă(un obiect rar). Dacă i-am da fiecăreia toate aparițiile,veșcăar primi tot ce areveste. - Împărțirea se face după cât de frecvent este fiecare candidat. Pentru
vești,vesteeste de mii de ori mai frecventă decâtveșcă, așa că primește aproape tot. - Pentru documente se ia maximul formelor, nu suma. Un document în care apar două forme ale aceleiași leme nu se numără de două ori.
lemma_detail(cuvânt) mai dă și numărul de forme, valoarea formei din dicționar luată
singură și family_ratio: de câte ori ar fi fost mai mare totalul familiei dacă formele
ambigue nu s-ar fi împărțit. Valoarea 1 înseamnă o familie fără ambiguitate. O valoare
mare (tinereță: 128) arată că familia are forme comune cu cuvinte mult mai frecvente,
așa că trebuie citită cu grijă.
Lema se caută după forma din dicționar (înmărmuri, nu înmărmurit). Dacă
cuvântul nu e o lemă, sau dacă pachetul nu conține stratul de leme,
lemma_frequency întoarce valoarea obișnuită, zipf_frequency.
Stratul de leme este separat de numărătorile pe forme. Se poate aduna, dar nu se poate desface, așa că nu amestecăm cele două.
Licență. Harta formelor vine din datele DEX Online. Condițiile de redistribuire sunt în curs de clarificare cu DEX Online; când vor fi clare, vor fi trecute aici.
build/validate.py rulează la fiecare construcție și oprește construcția dacă ceva
nu e în regulă:
- Cuvintele-unealtă sunt sus.
de,și,la,un,cutrebuie să aibă Zipf între 6,0 și 7,5. Dacă nu, numitorul e greșit. Este cea mai importantă verificare. Acum:de7,68,și7,34,la7,23,un6,94,cu7,08. - Acord cu
wordfreq. Luăm perechile de cuvinte pe carewordfreqle vede clar diferite (cel puțin 0,3 pe scara Zipf) și verificăm că le ordonăm la fel. Cerința: cel puțin 93%. Acum: 94,8%. Valorile noastre ies în medie cu 0,20 mai mici decât cele dinwordfreq. - 59 de perechi alese de mână (de exemplu, un cuvânt comun trebuie să fie peste unul rar). Acum: toate corecte.
- Acoperirea DEX. Cel puțin 95% din lemele cu frecvență peste 0,8 trebuie să apară. Acum: 97,7%. Dacă scade, înseamnă că un filtru cu dicționar s-a strecurat înapoi.
- Raportul de dezacord (nu trece/pică): primele 100 de cuvinte după
spread, de citit cu ochii. Aici se văd nume proprii, termeni din domenii și forme fără diacritice. - Reconstruire identică. Dacă rulezi din nou pașii 2–5 pe aceleași numărători, fișierul de date iese identic, bit cu bit.
Coeficientul Spearman față de wordfreq este afișat (acum 0,851) dar nu este o
condiție: între cuvinte cu frecvențe foarte apropiate, ordinea depinde de zgomot (și
în wordfreq), nu de calitate.
Pe lângă acestea, un set de teste (230) rulează la fiecare modificare; vezi .github/.
Tabelul nu e perfect. Iată ce știm și nu am rezolvat.
- Litere neromânești. Tokenizatorul cunoaște doar literele românești, deci un cuvânt
străin cu diacritice se rupe:
Düsseldorfdevined+sseldorf. Afectează circa 0,3% dintre cuvinte, în coada rară (doar 52 de intrări trec de Zipf 3). Am măsurat și am decis să nu lărgim alfabetul acum (docs/decisions/ADR-002). - Diacritice scrise greșit. O parte mare dintre „literele străine" din
websunt de fapt română scrisă cu tastatură străină (dupã,cã). Ele apar ca fragmente. - Forme fără diacritice. Mulți scriu
saîn loc desă. Tabelul le păstrează ca forme separate, cu frecvența lor reală; nu le unificăm. - Adrese web rupte în cuvinte. Aproximativ 23 de mii de intrări sunt șiruri cu trei sau
mai multe cratime (adrese web, titluri în engleză, denumiri chimice, liste de localități).
Sunt în baza de date, dar nu sunt în pachet:
zipf_frequency('state-of-the-art')dă 0,0. Cuvintele cu una sau două cratime (cluj-napoca,play-off-ul) rămân, dar și printre ele sunt multe șiruri fără valoare, nemăsurate încă. - Engleză în text. Toate sursele conțin cuvinte englezești (
theare 5,0–6,4 în fiecare). Nu le scoatem: tabelul măsoară ce apare, nu ce e românesc. - Surse traduse.
subsșieusunt în mare parte traduceri. documentsnu înseamnă același lucru peste tot. Lasubsșieue un rând de text, lasocialun mesaj, lawikișiwebun document. Nu e o dovadă de independență; vezi sources.md.- Numerele nu se numără.
zipf_frequency('123')dă valoarea minimă, nu ce dăwordfreq. - Nu e lematizator. Stratul de leme pornește de la forma din dicționar. Nu ghicește forma unui cuvânt.
- Perioada. Sursele sunt texte din ultimele decenii. Tabelul nu spune nimic despre româna veche sau despre cum se scria acum o sută de ani.
Versiunea MAJOR.MINOR.PATCH. MINOR se schimbă când se schimbă panoul de surse.
Pachetul îți spune exact ce construcție folosești:
>>> import wrodfreq
>>> wrodfreq.build_info()
{'version': '0.2.0', 'sources': ['eu', 'news', 'social', 'subs', 'web', 'wiki'],
'built': '2026-10-05'}Într-o lucrare, scrie versiunea și lista surselor din build_info(), de exemplu:
wROdfreq 0.2.0 (construit la 5 octombrie 2026; surse: eu, news, social, subs, web, wiki), https://github.com/gov2-ro/wrodfreq
python build/ingest_<sursă>.py # câte unul pentru wiki, web, news, subs, eu, social
python build/compute_zipf.py # valoarea Zipf și pragul, pe sursă
python build/merge.py # combinarea surselor
python build/build_lemma_layer.py # stratul de leme (are nevoie de harta DEX)
python build/build_package.py # fișierele de date din pachet
python build/validate.py # verificările din secțiunea 6Colectarea surselor mari durează zile; fiecare script poate fi oprit și reluat din punctul în care a rămas.