---
title: 'Öznitelik Üretme'
source: 'https://academia.sh/tr/kurslar/oznitelik-muhendisligi/oznitelik-uretme'
course: 'Veri Hazırlama ve Öznitelik Mühendisliği'
language: tr
updated: '2026-08-17T18:10:11+00:00'
license: 'CC BY-SA 4.0'
---

# Öznitelik Üretme

Var olan sütunlardan yeni sütun çıkarmanın ayrılmış kümede ne kattığının tek tek sayılması: oran özniteliği 0,7778 olan sınama sayısını 0,7897'ye taşırken fark ve eğitimden öğrenilmiş gösterge 0,0040 katıyor, elle konan 25 m³ eşiği 0,0159 ve iki sütunun çarpımı 0,0238 kaybettiriyor, 40 m³ eşiği ise tam sıfır katkı üretiyor. Altı sütun birikimli olarak eklendiğinde eğitim sayısı 0,8466'dan 0,8677'ye çıkarken ayrılmış küme sayısı 0,7897'de tepe yapıp 0,7698'e düşüyor; tek tek pozitif katkı veren üç sütun birlikte eklendiğinde toplam katkı 0,0000 oluyor.

Önceki altı ders var olan sütunlar üzerinde çalıştı: eksik değer dolduruldu, ölçek yalnız eğitim
kümesinden öğrenildi, kategoriler kodlandı, dengesizlik ele alındı, aykırı değerler modele göre
değerlendirildi. Hepsinde sütun kümesi aynı kaldı. Hiç **yeni sütun** üretilmedi ve hiçbir sütun
atılmadı; model her derste aynı on bir sayıya baktı.

Bu ders sütun sayısını ilk kez artırır. Sorusu şudur: var olan sütunlardan aritmetikle çıkarılan
yeni bir sayı, modele **bilgi mi** ekler yoksa yalnız **arama alanı mı** genişletir. Kursun kuralı
burada da geçerlidir — bir hazırlama adımı ayrılmış kümede ölçülen katkısı kadar vardır — ve bu
derste altı öznitelik tek tek üretilip tek tek ölçülür. Katkısı sıfır ve eksi çıkanlar da tabloya
yazılır.

- **OS1.** Küme M27/K01'in **kurgu** abone tablosudur: aynı tohum (20260218), aynı bölme
  (756 eğitim, 252 doğrulama, 252 sınama), aynı etiket. Ayrılmış küme sınama kümesidir.
- **OS2.** Model kurs boyunca **sabit** tutulur: derinlik 6 karar ağacı. Değişen tek şey sütun
  kümesidir. Taban çizgisi en sık sınıfı söylemektir ve sınama kümesinde 0,7579'dur.
- **OS3.** Karar öncesi çizgi, hazırlama adımlarının bıraktığı on bir sütunun çizgisidir:
  eğitimde 0,8466, sınamada 0,7778.
- **OS4.** Ham okumalar hâlâ elde tutulur. `ort_tuketim` ve `oynaklik` bu okumaların bir özetidir
  ve o özetleme kendisi bir öznitelik üretme kararıydı; ders bu kararı geri açar.
- **OS5.** Satır düzeyinde hesaplanan öznitelikler (oran, fark, çarpım, sabit eşik) kümeden hiçbir
  şey öğrenmez ve bölmeden bağımsızdır.
- **OS6.** Kümeden bir sayı öğrenen öznitelik — bölge ortancasının üstünde olmak — o sayıyı
  **yalnız eğitim kümesinden** okur ve üç kümeye de aynı sayıyla uygulanır.
- **OS7.** Katkı, aynı modelin ayrılmış kümedeki sayısının karar öncesi çizgiden farkıdır. 252
  satırlık kümede bir satır 0,0040'a karşılık gelir.

## Aynı Sütunlardan Altı Yeni Sayı

Kurulum M27/K01'inkiyle aynıdır ve aynı tohumla aynı kümeyi üretir. Bu kez ham okuma listesi de
saklanır, çünkü üretilecek özniteliklerden biri ona dayanır.

```python
# uretme.py — MODELDIR. M27/K01'in KURGU abone tablosu ayni tohumla yeniden uretilir;
# model derinlik 6 karar agacidir ve kurs boyunca sabit kalir.
import math

TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF
BOLGE = [("kuzey", 0.28, 21, 0.00), ("guney", 0.22, 17, -0.10),
         ("dogu", 0.18, 26, 0.30), ("bati", 0.14, 14, -0.05),
         ("merkez", 0.18, 23, 0.05)]


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


def ayrik(u, w):
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


ABONE, VERI = [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r, v = uretec(TOHUM + 7000 + k["no"]), []
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        v.append(0.0 if r() < 0.038 else math.floor(
            k["bolge"][2] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100)
        r()
    if not v:
        continue
    ort, oyn, r = sum(v) / len(v), max(v) - min(v), uretec(TOHUM + 51000 + k["no"])
    z = (0.052 * (ort - 20) + 0.85 * (min(v) == 0.0) + 0.026 * oyn
         + 0.24 * (k["hane"] >= 5) - 0.20 * (k["memnuniyet"] >= 4) + k["bolge"][3]
         + 0.9 * (k["no"] - 10001) / 1399 + (r() + r() + r() - 1.5) * 1.30)
    x = {"no": k["no"], "hane": k["hane"], "memnuniyet": k["memnuniyet"],
         "donem": len(v), "ort_tuketim": round(ort, 2), "oynaklik": round(oyn, 2),
         "sifir_okuma": int(min(v) == 0.0), "supheli": int(z > 1.35),
         "okuma": [round(q, 2) for q in v], "bolge_ad": k["bolge"][0]}
    for b in BOLGE:
        x["b_" + b[0]] = int(k["bolge"][0] == b[0])
    VERI.append(x)

TEMEL = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
         "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]


def karistir(veri, tohum):
    r, s = uretec(tohum), list(range(len(veri)))
    for i in range(len(s) - 1, 0, -1):
        j = int(r() * (i + 1))
        s[i], s[j] = s[j], s[i]
    return [veri[i] for i in s]


K = karistir(VERI, TOHUM + 90000)
EGT, DOG, SIN = K[:756], K[756:1008], K[1008:]


def gini(s):
    p = sum(x["supheli"] for x in s) / len(s) if s else 0.0
    return 2 * p * (1 - p)


def agac(s, derinlik, alanlar, enaz=2):
    p, en = sum(x["supheli"] for x in s) / len(s), None
    if derinlik and len(s) >= 2 * enaz and 0.0 < p < 1.0:
        for a in alanlar:
            d = sorted({x[a] for x in s})
            for v in (d[1:] if len(d) < 10 else
                      [d[int(i * len(d) / 10)] for i in range(1, 10)]):
                sol = [x for x in s if x[a] < v]
                sag = [x for x in s if x[a] >= v]
                if min(len(sol), len(sag)) < enaz:
                    continue
                k = gini(s) - (len(sol) * gini(sol) + len(sag) * gini(sag)) / len(s)
                if en is None or k > en[0]:
                    en = (k, a, v, sol, sag)
    if en is None or en[0] <= 1e-9:
        return {"tahmin": int(p > 0.5)}
    return {"alan": en[1], "esik": en[2],
            "sol": agac(en[3], derinlik - 1, alanlar, enaz),
            "sag": agac(en[4], derinlik - 1, alanlar, enaz)}


def tahmin(d, x):
    while "tahmin" not in d:
        d = d["sol"] if x[d["alan"]] < d["esik"] else d["sag"]
    return d["tahmin"]


def dogruluk(d, s):
    return sum(tahmin(d, x) == x["supheli"] for x in s) / len(s)


def taban(egt, s):
    c = int(sum(x["supheli"] for x in egt) * 2 > len(egt))
    return sum(x["supheli"] == c for x in s) / len(s)


def olc(alanlar, derinlik=6):
    m = agac(EGT, derinlik, alanlar)
    return dogruluk(m, EGT), dogruluk(m, SIN)
```

Üretilecek altı öznitelik beş türü temsil eder. **Oran**, iki sütunun bölümüdür: kişi başına
düşen tüketim, hanenin büyüklüğünü tüketimden ayırır. **Fark**, ham okumaların sonuncusu ile
ilki arasındaki değişimdir; `oynaklik` yalnız açıklığı taşır, yönü taşımaz. **Etkileşim
özniteliği** (interaction feature) iki sütunun çarpımıdır. **Eşik göstergesi** alan bilgisinden
gelir: tarife basamakları 25 ve 40 m³'te durur. Sonuncusu kümeden bir sayı **öğrenir** —
abonenin kendi bölgesindeki ortancanın üstünde olup olmadığı — ve o ortanca yalnız eğitim
kümesinden okunur.

```python
for x in VERI:
    o = x["okuma"]
    x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3)
    x["son_ilk_fark"] = round(o[-1] - o[0], 2)
    x["hane_memnuniyet"] = x["hane"] * x["memnuniyet"]
    x["esik_25"] = int(x["ort_tuketim"] > 25)
    x["esik_40"] = int(x["ort_tuketim"] > 40)

ORTANCA = {}
for b in BOLGE:
    v = sorted(x["ort_tuketim"] for x in EGT if x["bolge_ad"] == b[0])
    ORTANCA[b[0]] = v[len(v) // 2]
for x in VERI:
    x["bolge_ustu"] = int(x["ort_tuketim"] > ORTANCA[x["bolge_ad"]])

ONCE = olc(TEMEL)
YENI = ["kisi_basi", "son_ilk_fark", "bolge_ustu", "esik_25", "hane_memnuniyet",
        "esik_40"]
print(f"{'oznitelik':<18} {'tur':<12} {'egitimde':>9} {'ayrilmis':>9} {'katki':>8}")
print(f"{'-- yok --':<18} {'11 sutun':<12} {ONCE[0]:>9.4f} {ONCE[1]:>9.4f}")
for a, t in zip(YENI, ["oran", "fark", "ogrenilmis", "esik", "etkilesim", "esik"]):
    e, s = olc(TEMEL + [a])
    print(f"{a:<18} {t:<12} {e:>9.4f} {s:>9.4f} {s - ONCE[1]:>+8.4f}")
print(f"\ntaban cizgisi {taban(EGT, SIN):.4f}; 25 m3 ustu {sum(x['esik_25'] for x in VERI)} "
      f"satir, 40 m3 ustu {sum(x['esik_40'] for x in VERI)} satir")
```

```
oznitelik          tur           egitimde  ayrilmis    katki
-- yok --          11 sutun        0.8466    0.7778
kisi_basi          oran            0.8519    0.7897  +0.0119
son_ilk_fark       fark            0.8571    0.7817  +0.0040
bolge_ustu         ogrenilmis      0.8492    0.7817  +0.0040
esik_25            esik            0.8479    0.7619  -0.0159
hane_memnuniyet    etkilesim       0.8492    0.7540  -0.0238
esik_40            esik            0.8466    0.7778  +0.0000

taban cizgisi 0.7579; 25 m3 ustu 243 satir, 40 m3 ustu 2 satir
```

Katkı sütununda üç işaret birden var. En büyük kazanç oran özniteliğinden geliyor: 0,0119, yani
252 satırlık kümede üç abone. Bu, aritmetik olarak yeni bilgi taşımayan bir sütundur —
`ort_tuketim` ve `hane` zaten kümededir — ama ağaç bölmelerini **tek sütun üzerinde** yapar ve
iki sütunun bölümünü bir bölmeyle kuramaz. Oranın kattığı şey bilgi değil, o bilginin
**bölünebilir biçimidir**.

Fark özniteliği ile eğitimden öğrenilmiş gösterge birer satır kazandırıyor: 0,0040. Bu, tek bir
abonenin doğru sınıflanmasıdır ve rastlantıdan ayırt edilemeyecek kadar küçüktür. Böyle bir sayı
"katkı vardır" diye raporlanamaz; en fazla "ölçüldü ve sıfırdan ayrılamadı" diye raporlanır.

Bu iki sütun arasında bir tür farkı var ve kursun ikinci kuralı tam oradan geçiyor. `son_ilk_fark`
her satırda kendi içinde hesaplanır; kümedeki başka hiçbir satırı görmez, bölmeden önce de sonra
da aynı sayıyı verir. `bolge_ustu` ise bir sayıya — bölge ortancasına — dayanır ve o sayı veriden
**okunur**. Kodda bu ayrım tek satırda duruyor: ortanca sözlüğü `EGT` üzerinde kuruluyor, `VERI`
üzerinde değil. Kaynak `VERI` yapılsaydı sütunun değerleri hiç değişmezdi, sınama kümesindeki
252 satır kendi eşiklerinin belirlenmesine katkıda bulunmuş olurdu ve ölçülen katkının bir payı
öğrenmeden değil sızıntıdan gelirdi. Üretilen öznitelik de **öğrenilmiş bir nesnedir** ve
öğrendiği yeri yazmak, kattığı sayıyı yazmak kadar zorunludur. Bu ayrım beşinci derste boru
hattının kurucu ilkesi olacak.

## Sıfırın İki Ayrı Nedeni

Tablonun en öğretici satırı 40 m³ eşiğidir: katkı **tam sıfır**, eğitim sayısı bile kılpayı
değişmemiş. Nedeni son satırda görünüyor — kümede 40 m³'ün üstünde yalnız 2 satır var. Sabite
yakın bir sütun hiçbir bölmede en az iki satırlık iki yan üretemez, dolayısıyla ağaç onu hiç
seçmez. Sütun eklenmiştir, ölçülmüştür, ve modelin gördüğü ağaç birebir aynıdır.

25 m³ eşiği farklı bir sıfır türüdür ve aslında sıfır bile değil, eksidir: 0,0159 kayıp, dört
abone. Bu sütun 243 satırı ayırıyor, yani sabit değil. Ama taşıdığı bilgi `ort_tuketim`'in içinde
zaten var ve ağaç kendi eşiğini veriden **arayarak** buluyor. Elle konan eşik yeni bir şey
söylemiyor, buna karşılık her düğümde bir bölme adayı olarak yarışıyor; eğitim kümesinde biraz
daha iyi görünen bir bölme seçtirip ayrılmış kümede daha kötü bir ağaç üretiyor.

En büyük kayıp etkileşim özniteliğinden: 0,0238, altı abone. `hane` ile `memnuniyet`in çarpımı
iki sütunu tek sayıya sıkıştırıyor ve etiketle ilişkisi bu iki sütunun kendisinden zayıf. Ağaç
çarpımı seçtiğinde ayrımı daha kaba yapıyor. Alan bilgisinden gelmeyen, "olur da tutar" diye
üretilen etkileşimlerin tipik davranışı budur.

Üç ayrı sıfır-ya-altı nedeni birbirinden ayrılmalıdır: sütun **hiç bölünemiyor** (40 m³),
bilgisi **zaten var** (25 m³), ya da bilgiyi **bozarak** taşıyor (çarpım). Üçü de "katkısı yok"
diye özetlenirse tabloda kaybolan şey, hangi düzeltmenin işe yarayacağıdır.

## Katkılar Toplanmaz

Tek tek ölçülen katkılar üç pozitif değer verdi: 0,0119, 0,0040, 0,0040. Toplamları 0,0199 eder.
Sütunlar birikimli olarak eklendiğinde ne olduğuna bakmak gerekir.

```python
birikim = list(TEMEL)
print(f"{'eklenen':<18} {'sutun':>6} {'egitimde':>9} {'ayrilmis':>9} {'katki':>8}")
for a in YENI:
    birikim.append(a)
    e, s = olc(birikim)
    print(f"{a:<18} {len(birikim):>6} {e:>9.4f} {s:>9.4f} {s - ONCE[1]:>+8.4f}")
UC = ["kisi_basi", "son_ilk_fark", "bolge_ustu"]
e, s = olc(TEMEL + UC[:2])
print(f"\nyalniz iki katkili sutun {e:.4f} {s:.4f} {s - ONCE[1]:+.4f}")
e, s = olc(TEMEL + UC)
print(f"yalniz uc katkili sutun  {e:.4f} {s:.4f} {s - ONCE[1]:+.4f}")
```

```
eklenen             sutun  egitimde  ayrilmis    katki
kisi_basi              12    0.8519    0.7897  +0.0119
son_ilk_fark           13    0.8598    0.7897  +0.0119
bolge_ustu             14    0.8611    0.7778  +0.0000
esik_25                15    0.8664    0.7698  -0.0079
hane_memnuniyet        16    0.8677    0.7698  -0.0079
esik_40                17    0.8677    0.7698  -0.0079

yalniz iki katkili sutun 0.8598 0.7897 +0.0119
yalniz uc katkili sutun  0.8611 0.7778 +0.0000
```

İki sütun birbirinden bağımsız olsaydı katkıları toplanırdı. Toplanmıyor. Tek tek 0,0119 ve 0,0040
katan iki sütun birlikte 0,0119 katıyor; üçüncüsü eklendiğinde toplam katkı **0,0000**'a iniyor.
Tek tek pozitif ölçülen üç öznitelik, birlikte karar öncesi çizgiye geri dönüyor.

Nedeni ağacın açgözlü olmasıdır: her düğümde o an en iyi görünen bölmeyi seçer ve seçim
geri alınmaz. Yeni bir sütun, kök düğümde daha iyi görünen bir bölme sunup ağacın geri kalanını
tümüyle başka bir yola sokabilir. Katkı, sütunun kendi bilgisi değil, **sütunun modelin arama
yoluna yaptığı etkidir** ve bu etki toplanabilir bir büyüklük değildir.

İki sütun ayrı ayrı okunmalıdır. Eğitim sayısı boyunca tek yönde artıyor: 0,8466'dan 0,8677'ye,
altı sütunun her biri onu biraz daha yukarı çekiyor. Ayrılmış küme sayısı ise on iki sütunda tepe
yapıp düşüyor ve on yedi sütunda karar öncesi çizginin altında kalıyor. M27/K01'in ikinci dersi
bu ayrışmayı kapasiteyi artırarak üretmişti; burada model sabit, artan tek şey **sütun sayısı**.
Öznitelik eklemek de kapasite artırmaktır.

Kursun kuralı bu tabloda somutlaşıyor. Altı sütun üretildi, altısı da makul bir gerekçeyle
üretildi, ve ayrılmış kümede ölçüldüğünde geriye tek bir tanesi kaldı. Ölçülmeseydi altısı da
kümede kalırdı ve model on yedi sütunla 0,7698'de, karar öncesi çizginin 0,0080 altında
çalışırdı — üstelik eğitim sayısı 0,8677'ye çıktığı için tablo daha iyi görünürdü.

## Özet

- Oran özniteliği ayrılmış küme sayısını 0,7778'den 0,7897'ye taşıyor (0,0119, üç abone); fark
  özniteliği ve eğitimden öğrenilmiş bölge göstergesi 0,0040 katıyor, yani birer abone.
- Katkısı sıfır ve eksi çıkanlar da yazılır: 40 m³ eşiği tam 0,0000, 25 m³ eşiği 0,0159 kayıp,
  iki sütunun çarpımı 0,0238 kayıp.
- Sıfırın nedeni ayrıştırılır: sütun sabite yakın olduğu için bölünemiyor, bilgisi başka sütunda
  zaten var, ya da bilgiyi bozarak taşıyor.
- Katkılar toplanmaz: tek tek 0,0119, 0,0040 ve 0,0040 katan üç sütun birlikte 0,0000 katıyor,
  çünkü katkı sütunun bilgisi değil modelin arama yoluna etkisidir.
- Sütun sayısı 11'den 17'ye çıkarken eğitim sayısı 0,8466'dan 0,8677'ye tek yönde artıyor,
  ayrılmış küme sayısı 0,7897'de tepe yapıp 0,7698'e düşüyor; öznitelik eklemek de kapasite
  artırmaktır.

## Sonraki Adım

Bu dersin altı özniteliği sayısal sütunlardan aritmetikle çıkarıldı. Abone tablosunda ise
sayısal olmayan iki alan daha var: sözleşmenin başladığı tarih ve saha ekibinin bıraktığı kısa
not. İkisi de olduğu gibi bir modele verilemez; ikisinden de birden çok sayı çıkarılabilir. Bir
tarihten kaç sayı çıkar, kısa bir metinden kaç sayı çıkar ve bu sayıların **toplam** katkısı ne
olur — sonraki ders bunu ölçer.
