#!/usr/bin/env python3 """turk.kim özgün analizleri: sitenin kendi verisinden kendi hesapları. Çalıştırma: python3 -I calisma/3e/analiz_uret.py Girdi: site/veri/antik_bireyler.json (AADR v66.p1'den üretilmiş birey kayıtları) site/veri/atlas_olaylar.json (dönem sınırları; kaynaklı tarihler buradan gelir) Çıktı: site/veri/analizler.json Üç analiz: 1) ph1795 — J-PH1795 ve üst dallarını taşıyan antik bireylerin zaman-mekân dağılımı. Soru: bu dal Osmanlı hanedanına ya da Anadolu'ya özgü mü? 2) mogolistan — Moğolistan'ın baba hattı profilinin dönemden döneme değişimi. Soru: yayınların bildirdiği değişim, derlemenin kendisinden yeniden üretilebilir mi? 3) anadolu — Anadolu'da 11. yüzyıl sonrası yayımlanmış antik birey var mı, ne gösteriyor? Soru: Türk dönemi Anadolu'su antik DNA ile ne kadar görünür? İlke: hiçbir sayı elle yazılmaz. Dönem sınırları atlas veri dosyasındaki kaynaklı tarihlerden alınır; sınırı veriden gelmeyen tek şey, bir dönemin "öncesi/sonrası" diye bölünmesidir ve o da aşağıda açıkça tanımlıdır. Kalite bayrağı taşıyan bireyler (AADR'nin kendi uyarısı) ayrıca sayılır ve dışlanmaz — sayıları raporlanır. """ import collections, json, os, re KOK = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) VERI = os.path.join(KOK, "site", "veri") HEDEF = os.path.join(VERI, "analizler.json") BIREY = json.load(open(os.path.join(VERI, "antik_bireyler.json"), encoding="utf-8")) OLAY = json.load(open(os.path.join(VERI, "atlas_olaylar.json"), encoding="utf-8")) KAYIT = BIREY["kayitlar"] BOLGE = BIREY["bolgeler"] # J-PH1795 ve YFull ağacındaki alt dalları. ISOGG ön eki (J2a2a1a1a) tek başına yetmez: # o ön ek, PH1795'in KARDEŞ dallarını (J-Y25795, J-BY40968, J-P279 …) da kapsar. Dal adları # calisma/3e/ph1795_dallar.py ile YFull'dan çıkarılır. PH_ONEK = "J2a2a1a1a" # yalnız kardeş dalları göstermek için kullanılır PH_DALLAR = json.load(open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "veri", "ph1795_dallar.json"), encoding="utf-8")) # Ülke adlarının Türkçe karşılıkları ortak dosyadan gelir (calisma/3f/ulkeler_uret.py); # aynı eşleme gezginde ve atlasta da kullanılır. ULKE_TR = json.load(open(os.path.join(VERI, "ulkeler.json"), encoding="utf-8"))["tr"] def temiz(y): return (y or "").rstrip("~") # Paragruplar (birden çok harfle yazılan düğümler) kısaltılmaz: "CT" → "CT", "C2" → "C2". PARAGRUP = ("A0-T", "A1b", "BT", "CT", "CF", "DE", "GHIJK", "HIJK", "IJK", "IJ", "K2", "NO", "LT") def kok(y): """ISOGG adından ana dalı çıkarır: J2a2a1a1a → J2, R1a1a1b2 → R1, CT → CT.""" y = temiz(y) for p in PARAGRUP: if y == p or y.startswith(p + "~"): return p m = re.match(r"^([A-T])(\d+)?", y) if not m: return None return m.group(1) + (m.group(2)[0] if m.group(2) else "") def olay(kimlik): for o in OLAY["kayitlar"]: if o["id"] == kimlik: return o raise KeyError(kimlik) def birey_ozet(x): return { "id": x["i"], "yil": x["yil"], "tarih_turu": x["t"], "tam_tarih": x.get("td"), "ulke": ULKE_TR.get(x.get("u"), x.get("u")), "ulke_ozgun": x.get("u"), "bolge": BOLGE[x["b"]], "la": x["la"], "lo": x["lo"], "grup": x.get("g"), "y": temiz(x.get("y")), "y_ad": x.get("ym"), "mt": x.get("m"), "yayin": x.get("p"), "snp": x.get("n"), "kalite": x.get("q"), } def analiz_ph1795(): dallar = set(PH_DALLAR["dallar"]) onek = [x for x in KAYIT if temiz(x.get("y")).startswith(PH_ONEK)] tasiyan = sorted([x for x in onek if (x.get("ym") or "") in dallar], key=lambda x: x["yil"]) kardes = sorted([x for x in onek if (x.get("ym") or "") not in dallar], key=lambda x: x["yil"]) ulke = collections.Counter(ULKE_TR.get(x.get("u"), x.get("u")) or "—" for x in tasiyan) adlar = collections.Counter(x.get("ym") or "—" for x in tasiyan) ph = [x for x in tasiyan if (x.get("ym") or "") == "J-PH1795"] belirsiz = [x for x in tasiyan if (x.get("y") or "").endswith("~")] return { "baslik": "J-PH1795 dalını taşıyan antik bireyler", "soru": "Osmanlı hanedanı için önerilen baba hattı, antik bireylerde nerede ve ne zaman görülüyor?", "yontem": (f"Önce AADR v66.p1'de ISOGG çağrısı {PH_ONEK} ile başlayan bütün bireyler alındı. " "Bu ön ek J-PH1795'in kardeş dallarını da kapsadığı için ikinci bir süzgeç " f"uygulandı: bireyin dal adı, YFull'un J-PH1795 alt ağacındaki " f"{len(dallar)} addan biri olmalı ({PH_DALLAR['_kaynak']['veri']}). Dal adları " "olduğu gibi aktarıldı; yeniden çağrı yapılmadı."), "n": len(tasiyan), "n_ph1795": len(ph), "n_belirsiz": len(belirsiz), "n_kardes": len(kardes), "dal_sayisi": len(dallar), "yfull_surum": PH_DALLAR["_kaynak"]["veri"], "ulkeler": dict(ulke.most_common()), "dal_adlari": dict(adlar.most_common()), "en_eski": tasiyan[0]["yil"] if tasiyan else None, "en_yeni": tasiyan[-1]["yil"] if tasiyan else None, "bireyler": [birey_ozet(x) for x in tasiyan], "kardes_bireyler": [birey_ozet(x) for x in kardes], } def analiz_mogolistan(): # Dönem sınırları atlas veri dosyasındaki kaynaklı tarihlerden gelir. sinir = [ ("Tunç Çağı", olay("Afanasyevo")["bas"], olay("SlabGrave")["bas"]), ("Taş Sandık ve erken göçebeler", olay("SlabGrave")["bas"], olay("xiongnu-kurulus")["bas"]), ("Xiongnu dönemi", olay("xiongnu-kurulus")["bas"], olay("xianbei")["bas"]), ("Xianbei ve Rouran", olay("xianbei")["bas"], olay("gokturk-1")["bas"]), ("Göktürk dönemi", olay("gokturk-1")["bas"], olay("uygur-kaganligi")["bas"]), ("Uygur ve Kırgız dönemi", olay("uygur-kaganligi")["bas"], olay("mogol-istilasi")["bas"]), ("Moğol dönemi ve sonrası", olay("mogol-istilasi")["bas"], olay("kazak-hanligi")["son"]), ] mogolistan = [x for x in KAYIT if (x.get("u") or "") == "Mongolia"] kapsam = (sinir[0][1], sinir[-1][2]) disarida = [x for x in mogolistan if not (kapsam[0] <= x["yil"] < kapsam[1])] donemler = [] for ad, bas, son in sinir: grup = [x for x in mogolistan if bas <= x["yil"] < son] y_olan = [x for x in grup if temiz(x.get("y"))] say = collections.Counter(kok(x.get("y")) for x in y_olan) donemler.append({ "ad": ad, "bas": bas, "son": son, "n": len(grup), "n_y": len(y_olan), "hatlar": dict(say.most_common()), "kaliteli_olmayan": sum(1 for x in grup if x.get("q")), }) return { "kapsam": list(kapsam), "n_donemli": sum(d["n"] for d in donemler), "n_disarida": len(disarida), "baslik": "Moğolistan'da baba hatlarının dönemden döneme değişimi", "soru": ("Yayınların bildirdiği değişim — Türk döneminde Q'nun gerilemesi, Moğol döneminde " "C2'nin yükselişi — AADR derlemesinden bağımsız olarak yeniden üretilebilir mi?"), "yontem": ("Yalnız bugünkü Moğolistan sınırları içinden gelen bireyler alındı (AADR'nin ülke " "sütunu). Dönem sınırları elle seçilmedi: sitenin atlas veri dosyasındaki kaynaklı " "tarihlerden türetildi. Her birey, ISOGG çağrısının ana dalına (ilk harf ve " "basamak: C2, R1, Q1 gibi) indirgendi; alt dal ayrımı yapılmadı."), "n": len(mogolistan), "donemler": donemler, } def analiz_anadolu(): tr = [x for x in KAYIT if (x.get("u") or "") == "Turkey"] en_eski = min(x["yil"] for x in tr) if tr else 0 sinir = [ ("Malazgirt öncesi (bütün dönemler)", en_eski, olay("malazgirt")["bas"]), ("Malazgirt sonrası", olay("malazgirt")["bas"], max(x["yil"] for x in tr) + 1), ] donemler = [] for ad, bas, son in sinir: grup = [x for x in tr if bas <= x["yil"] < son] y_olan = [x for x in grup if temiz(x.get("y"))] say = collections.Counter(kok(x.get("y")) for x in y_olan) donemler.append({ "ad": ad, "bas": bas, "son": son, "n": len(grup), "n_y": len(y_olan), "hatlar": dict(say.most_common()), "gruplar": dict(collections.Counter(x.get("g") or "—" for x in grup).most_common()), }) # Orta Asya ile ilişkilendirilen ana dallar, Malazgirt sonrası Anadolu'da var mı? sonrasi = [x for x in tr if x["yil"] >= olay("malazgirt")["bas"]] dogu = [x for x in sonrasi if temiz(x.get("y")) and kok(x.get("y")) in ("C2", "Q1", "N1")] return { "baslik": "Anadolu'da 11. yüzyıl sonrası: antik DNA ne gösteriyor?", "soru": ("Anadolu'ya Türk göçünün antik DNA'daki izi nedir? Malazgirt sonrası Anadolu'dan " "kaç birey yayımlandı ve bunlar ne söylüyor?"), "yontem": ("AADR'nin ülke sütunu 'Turkey' olan bütün bireyler, Malazgirt yılına (atlas veri " "dosyasından) göre ikiye ayrıldı. Doğu Avrasya ile ilişkilendirilen ana dallar " "(C2, Q1, N1) ayrıca sayıldı. Bu bir karışım analizi değildir: yalnız baba " "hattının ana dalına bakar."), "n": len(tr), "donemler": donemler, "dogu_dal": [birey_ozet(x) for x in dogu], "sonrasi_bireyler": [birey_ozet(x) for x in sorted(sonrasi, key=lambda x: x["yil"])], } def main(): cikti = { "_kaynak": { "veri": BIREY["_kaynak"]["veri"], "dosya": BIREY["_kaynak"]["dosya"], "atif": BIREY["_kaynak"]["atif"], "uretim": "calisma/3e/analiz_uret.py", "tarih": "22 Ekim 2026", "donem_kaynagi": "site/veri/atlas_olaylar.json (tarihleri kaynaklı)", "uyari": ("Bu sayfalardaki bütün sayılar yayımlanmış bireylerin sayımıdır, nüfus " "oranı değildir. Antik örneklem kazı ve dizileme kararlarıyla oluşur; " "bir dönemin az sayıda bireyle temsil edilmesi o dönemde az insan " "yaşadığını göstermez."), }, "ph1795": analiz_ph1795(), "mogolistan": analiz_mogolistan(), "anadolu": analiz_anadolu(), } with open(HEDEF, "w", encoding="utf-8") as fh: json.dump(cikti, fh, ensure_ascii=False, indent=1) print(f"3 analiz → {HEDEF}") print(f" J-PH1795 dalı: {cikti['ph1795']['n']} birey " f"({cikti['ph1795']['n_ph1795']}'i doğrudan J-PH1795 çağrısı)") print(f" Moğolistan: {cikti['mogolistan']['n']} birey, {len(cikti['mogolistan']['donemler'])} dönem") for d in cikti["mogolistan"]["donemler"]: print(f" {d['ad']:32s} n={d['n']:>4} Y={d['n_y']:>3} " + " · ".join(f"{h} {n}" for h, n in list(d["hatlar"].items())[:5])) a = cikti["anadolu"] print(f" Anadolu: {a['n']} birey; Malazgirt sonrası {a['donemler'][1]['n']} birey, " f"{a['donemler'][1]['n_y']}'inde Y; doğu dalı (C2/Q1/N1) {len(a['dogu_dal'])}") if __name__ == "__main__": main()