Üniversite sayfasındaki 'Örgün öğrenci' karesine '%54 kadın · %46 erkek' satırı eklendi; kaynak notu üniversite düzeyi olduğunu ve bölüm bazında veri olmadığını söyler. Filtre ya da öncelik değil, bilgi satırı. Üretim betiği E/K sütunlarını okur; kadinYuzdesi() yardımcı eklendi. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
169 lines
6.3 KiB
Python
169 lines
6.3 KiB
Python
"""YÖK İstatistik Excel'lerinden src/lib/yok-istatistik.ts sabitini üretir.
|
||
|
||
Kullanım (yılda bir, YÖK İstatistik Mart'ta yayımlayınca):
|
||
python3 scripts/yok-istatistik-uret.py 2025-2026
|
||
|
||
Girdi: data/kaynak/yok-istatistik-{ogrenci,ogretim-elemani}-sayilari-<DONEM>.xls
|
||
(istatistik.yok.gov.tr'den tarayıcıyla indirilir, API yok). Bağımlılık: xlrd.
|
||
|
||
Kurallar:
|
||
- Öğrenci = örgün öğrenci (BİRİNCİ Ö. + İKİNCİ Ö.), tüm düzeyler. UZAKTAN Ö.
|
||
ve AÇIK Ö. dışarıda: açıköğretimli üç büyük üniversitede oranı anlamsız
|
||
kılar ve kampüste okuyan öğrenciyi anlatmaz.
|
||
- Öğretim üyesi = Profesör + Doçent + Doktor Öğretim Üyesi (YÖK tanımı).
|
||
- Anahtar: /universite/[slug] sayfa slug'ı; yalnız yokatlas.db'de sayfası
|
||
olan üniversiteler yazılır, eşleşmeyenler ekrana basılır.
|
||
"""
|
||
|
||
import sqlite3
|
||
import sys
|
||
import unicodedata
|
||
import re
|
||
from pathlib import Path
|
||
|
||
import xlrd
|
||
|
||
KOK = Path(__file__).resolve().parent.parent
|
||
DONEM = sys.argv[1] if len(sys.argv) > 1 else "2025-2026"
|
||
|
||
|
||
def slugify(s: str) -> str:
|
||
# src/lib/slug.ts turkishSlugify ile aynı kural.
|
||
s = s.replace("I", "ı").replace("İ", "i").lower()
|
||
for a, b in [("ı", "i"), ("ş", "s"), ("ğ", "g"), ("ü", "u"), ("ö", "o"),
|
||
("ç", "c"), ("â", "a"), ("î", "i"), ("û", "u")]:
|
||
s = s.replace(a, b)
|
||
s = unicodedata.normalize("NFKD", s)
|
||
s = re.sub(r"[̀-ͯ]", "", s)
|
||
s = re.sub(r"[^a-z0-9]+", "-", s)
|
||
return s.strip("-")
|
||
|
||
|
||
def sayfa_slug(ad: str) -> str:
|
||
return slugify(re.sub(r"\s*\([^)]*\)\s*$", "", ad).strip())
|
||
|
||
|
||
def tamsayi(v) -> int:
|
||
return int(float(v)) if v not in ("", None) else 0
|
||
|
||
|
||
def sayfa(ad: str):
|
||
return xlrd.open_workbook(
|
||
KOK / "data" / "kaynak" / f"yok-istatistik-{ad}-sayilari-{DONEM}.xls"
|
||
).sheet_by_index(0)
|
||
|
||
|
||
# Öğrenci: sütun 1 ad, 4 öğrenim türü, 19 genel toplam (T).
|
||
# Kadın/erkek: ön lisans E/K sütun 5/6, lisans E/K sütun 8/9 — yalnız örgün
|
||
# ön lisans + lisans (tercih yapan öğrencinin gireceği düzey).
|
||
ogrenci: dict[str, int] = {}
|
||
cinsiyet: dict[str, list[int]] = {}
|
||
s = sayfa("ogrenci")
|
||
for r in range(4, s.nrows):
|
||
v = s.row_values(r)
|
||
ad, tur = str(v[1]).strip(), str(v[4]).strip()
|
||
if not ad or ad == "TOPLAM":
|
||
continue
|
||
if tur in ("BİRİNCİ Ö.", "İKİNCİ Ö."):
|
||
k = sayfa_slug(ad)
|
||
ogrenci[k] = ogrenci.get(k, 0) + tamsayi(v[19])
|
||
c = cinsiyet.setdefault(k, [0, 0])
|
||
c[0] += tamsayi(v[6]) + tamsayi(v[9]) # kadın
|
||
c[1] += tamsayi(v[5]) + tamsayi(v[8]) # erkek
|
||
|
||
# Akademisyen: T sütunları Prof 6, Doç 9, Dr. Öğr. Üyesi 12, genel toplam 21.
|
||
akademik: dict[str, tuple[int, int]] = {}
|
||
s = sayfa("ogretim-elemani")
|
||
for r in range(4, s.nrows):
|
||
v = s.row_values(r)
|
||
ad = str(v[1]).strip()
|
||
if not ad or ad == "TOPLAM":
|
||
continue
|
||
uye = tamsayi(v[6]) + tamsayi(v[9]) + tamsayi(v[12])
|
||
akademik[sayfa_slug(ad)] = (uye, tamsayi(v[21]))
|
||
|
||
db = sqlite3.connect(KOK / "data" / "yokatlas.db")
|
||
sayfalar = {sayfa_slug(a) for (a,) in db.execute("SELECT DISTINCT universite FROM programs")}
|
||
|
||
satirlar = []
|
||
for k in sorted(sayfalar):
|
||
if k not in ogrenci or k not in akademik:
|
||
continue
|
||
uye, toplam = akademik[k]
|
||
if ogrenci[k] == 0 or uye == 0:
|
||
continue
|
||
kadin, erkek = cinsiyet.get(k, (0, 0))
|
||
satirlar.append(
|
||
f' "{k}": {{ ogrenci: {ogrenci[k]}, ogretimUyesi: {uye}, akademisyen: {toplam}, '
|
||
f'kadin: {kadin}, erkek: {erkek} }},'
|
||
)
|
||
|
||
oranlar = sorted(ogrenci[k] / akademik[k][0] for k in sayfalar
|
||
if ogrenci.get(k) and akademik.get(k, (0, 0))[0])
|
||
medyan = round(oranlar[len(oranlar) // 2])
|
||
|
||
eksik = sorted(sayfalar - {l.split('"')[1] for l in satirlar})
|
||
print(f"{len(satirlar)}/{len(sayfalar)} sayfa eşleşti. Eşleşmeyen {len(eksik)}:", file=sys.stderr)
|
||
for k in eksik:
|
||
print(" -", k, file=sys.stderr)
|
||
for k in sorted(set(ogrenci) - sayfalar):
|
||
print(" Excel'de var, sayfası yok:", k, file=sys.stderr)
|
||
|
||
cikti = f'''// YÖK İstatistik {DONEM}: üniversite başına örgün öğrenci ve öğretim üyesi sayısı.
|
||
//
|
||
// ÜRETİLMİŞ DOSYA — elle düzenleme. Kaynak Excel'ler data/kaynak/ altında;
|
||
// yeniden üretmek için: python3 scripts/yok-istatistik-uret.py {DONEM}
|
||
//
|
||
// Öğrenci = örgün (birinci + ikinci öğretim), tüm düzeyler; uzaktan ve açık
|
||
// öğretim dahil değil. Öğretim üyesi = Prof. + Doç. + Dr. Öğr. Üyesi.
|
||
// Kadın/erkek = örgün ön lisans + lisans öğrencisi (E/K sütunları).
|
||
// Anahtar: /universite/[slug] sayfa slug'ı. Burada olmayan üniversitenin
|
||
// YÖK İstatistik satırı yok (KKTC/yurt dışı ya da öğrencisi/üyesi 0).
|
||
|
||
export const YOK_ISTATISTIK_DONEM = "{DONEM}";
|
||
|
||
export const YOK_ISTATISTIK_KAYNAK_URL = "https://istatistik.yok.gov.tr/";
|
||
|
||
/** Sayfası olan üniversitelerde öğretim üyesi başına öğrencinin medyanı — kıyas çizgisi. */
|
||
export const OGRENCI_BASINA_UYE_MEDYAN = {medyan};
|
||
|
||
export type UniIstatistik = {{
|
||
/** Örgün öğrenci (ön lisans + lisans + yüksek lisans + doktora) */
|
||
ogrenci: number;
|
||
/** Profesör + doçent + doktor öğretim üyesi */
|
||
ogretimUyesi: number;
|
||
/** Tüm akademik personel (öğretim görevlisi ve araştırma görevlisi dahil) */
|
||
akademisyen: number;
|
||
/** Örgün ön lisans + lisans kadın öğrenci */
|
||
kadin: number;
|
||
/** Örgün ön lisans + lisans erkek öğrenci */
|
||
erkek: number;
|
||
}};
|
||
|
||
export const YOK_ISTATISTIK: Record<string, UniIstatistik> = {{
|
||
{chr(10).join(satirlar)}
|
||
}};
|
||
|
||
/** Üniversite sayfa slug'ının YÖK İstatistik satırı; yoksa null. */
|
||
export function uniIstatistikBul(slug: string): UniIstatistik | null {{
|
||
return YOK_ISTATISTIK[slug] ?? null;
|
||
}}
|
||
|
||
/** Öğretim üyesi başına örgün öğrenci, tam sayıya yuvarlanmış. */
|
||
export function ogrenciBasinaUye(i: UniIstatistik): number {{
|
||
return Math.round(i.ogrenci / i.ogretimUyesi);
|
||
}}
|
||
|
||
/**
|
||
* Örgün ön lisans + lisans öğrencisinde kadın yüzdesi (0-100, tam sayı);
|
||
* iki sayı da sıfırsa null. Üniversite düzeyidir, bölüm düzeyinde veri yok —
|
||
* bilgi olarak gösterilir, filtre ya da öncelik yapılmaz.
|
||
*/
|
||
export function kadinYuzdesi(i: UniIstatistik): number | null {{
|
||
const toplam = i.kadin + i.erkek;
|
||
if (toplam === 0) return null;
|
||
return Math.round((i.kadin / toplam) * 100);
|
||
}}
|
||
'''
|
||
(KOK / "src" / "lib" / "yok-istatistik.ts").write_text(cikti, encoding="utf-8")
|