Excel QC & Reporting System: Veri Tutarlılığı ve Kalite Kontrolü
Excel veri kalite kontrolü: kural motoru, mutabakat ve istisna paneliyle raporlama hatalarını yakalayan sistemi Python örnekleriyle anlatıyorum.
Girne Amerikan Üniversitesi'nde finans raporlama süreçleri üzerinde çalıştığım dönemde, aylık raporların onlarca Excel dosyasından beslendiği bir düzenle karşı karşıyaydım: farklı birimlerden gelen mizanlar, elle güncellenen tahsilat listeleri, birbirine formüllerle bağlı özet sayfalar. Böyle bir düzende Excel veri kalite kontrolü lüks değil, zorunluluktur; çünkü tek bir bozuk hücre, zincirin sonundaki yönetim raporuna kadar sessizce taşınır. Sorunu asıl can sıkıcı yapan da bu sessizliktir: Excel hatalı veriyi çoğu zaman şikâyet etmeden hesaplar ve rapor dışarıdan "bitmiş" görünür.
O dönemde kurduğum çözüm, sonradan Excel QC Dashboard diye adlandırdığım bir kalite kontrol katmanıydı: veri sayfaları üzerinde çalışan kural kontrolleri, sayfalar ve sistemler arası mutabakat karşılaştırmaları, koşullu biçimlendirmeyle beslenen bir istisna paneli. Amaç hatayı otomatik düzeltmek değil, raporu terk etmeden önce görünür kılmaktı. Bu yaklaşım oturduktan sonra yayımlanan raporlara sızan hata sayısı gözle görülür biçimde azaldı — çünkü hatalar artık son okuyucuya değil, kontrol paneline takılıyordu.
Bu yazıda aynı yaklaşımı, bugün kurar olsam kullanacağım araçlarla — Python, pandas ve openpyxl ile — anlatacağım. Örnekler çalışır durumda; kendi raporlama düzeninize uyarlayabilirsiniz.
Excel Hatalarının Anatomisi
Kontrol katmanı kurmadan önce neyi yakalamaya çalıştığınızı bilmeniz gerekir. Finansal raporlama dosyalarında tekrar tekrar karşılaştığım hata sınıfları şunlar:
- Eksik hücreler: zorunlu bir alan — hesap kodu, tarih, birim — boş bırakılmış; toplamlar tutuyor ama kırılımlar bozuk.
- Elle ezilen formüller: birisi formül hücresine sabit değer yazmış; dosya o ay doğru, sonraki ay sessizce yanlış.
- Kopyala-yapıştır kaymaları: bir blok bir satır kaymış; tutarlar yanlış hesap kodlarının karşısında duruyor.
- Mükerrer kayıtlar: aynı işlem iki ayrı listede ya da aynı listede iki kez; toplamlar şişkin.
- Biçim karmaşası: metin olarak saklanan sayılar, iki farklı tarih biçimi, binlik ayracı yüzünden bozulan değerler.
- Yapı artıkları: filtre açıkken yapıştırılan bloklar, gizli satırlara denk gelen değerler, birleştirilmiş hücrelerin bozduğu sıralama ve toplama davranışı.
Bu sınıfların ortak özelliği şu: hiçbiri Excel'in kendi hata göstergeleriyle yakalanmaz. #DEĞER! gibi görünür hatalar zaten kimseyi yanıltmaz; asıl tehlike, hesaplanabilen ama yanlış olan değerlerdir. Bu yüzden kalite kontrolü "hata var mı" sorusundan çok "veri, beklediğim kurallara uyuyor mu" sorusuna cevap vermelidir.
Python ile Kural Motoru
QC katmanının çekirdeği basit bir kural motorudur: her kural, veri çerçevesi üzerinde bir maske üretir ve maskeye takılan satırlar bulgu listesine yazılır. Kuralların tek yerde toplanması kritik — kontrol mantığı çalışma kitabındaki formüllerin içine dağılırsa bir süre sonra kimse neyin kontrol edildiğini bilemez.
import pandas as pd
def kural_motoru(df: pd.DataFrame) -> pd.DataFrame:
# Bulgu listesi: her kural ihlali icin bir satir
bulgular = []
def kaydet(maske, kural, aciklama):
for satir in df.index[maske]:
bulgular.append({'excel_satir': satir + 2, # baslik satiri + 1
'kural': kural, 'aciklama': aciklama})
# 1. Zorunlu alanlarda eksik hucre
for kolon in ['hesap_kodu', 'tarih', 'tutar', 'birim']:
kaydet(df[kolon].isna(), 'eksik-alan', kolon + ' alani bos')
# 2. Hesap kodu bicimi: 3 haneli ana hesap, nokta, 2 haneli alt hesap
desen = r'^\d{3}\.\d{2}$'
kaydet(~df['hesap_kodu'].astype(str).str.match(desen, na=False),
'gecersiz-kod', 'hesap kodu 999.99 desenine uymuyor')
# 3. Mukerrer kayit: ayni hesap, tarih ve tutar
kaydet(df.duplicated(subset=['hesap_kodu', 'tarih', 'tutar'], keep=False),
'mukerrer-kayit', 'ayni kayit birden fazla kez girilmis')
# 4. Aykiri tutar: IQR yontemiyle olagan araligin disi
q1, q3 = df['tutar'].quantile([0.25, 0.75])
esik = 3 * (q3 - q1)
kaydet((df['tutar'] < q1 - esik) | (df['tutar'] > q3 + esik),
'aykiri-tutar', 'tutar olagan araligin belirgin disinda')
return pd.DataFrame(bulgular)
df = pd.read_excel('aylik_mizan.xlsx')
rapor = kural_motoru(df)
print(rapor['kural'].value_counts())
Hesap kodu kontrolündeki desen yaklaşımı küçük görünür ama en çok hatayı yakalayan kurallardan biridir; serbest metin alanlarından yapılandırılmış bilgi ayıklamak gerektiğinde aynı tekniğin daha gelişmiş hallerini regex ile desen tabanlı veri ayıklama yazısında anlattım. Aykırı değer kuralında eşiği bilinçli olarak geniş tuttum: kalite kontrolünde yanlış alarm, gerçek hatanın gözden kaçmasından daha ucuzdur; ama her ay yüzlerce sahte uyarı üreten bir panel de kısa sürede ciddiye alınmaz olur. Eşik, panelin güvenilirliği ile duyarlılığı arasındaki dengeyi kuran ayar vidasıdır.
Bu eşiği masa başında değil, geçmiş verinin üzerinde ayarladım. Motorun ilk sürümünü kapanmış birkaç dönemin dosyaları üzerinde çalıştırıp bulguları veriyi bilen kişilerle birlikte taradık: hangi uyarılar gerçek hataya işaret ediyor, hangileri işin doğal istisnası? Kayıt dönemlerindeki toplu tahsilatlar gibi mevsimsel hareketler ilk turda aykırı değer olarak işaretleniyordu; bu tür bilinen istisnaları kural motoruna açık birer muafiyet kaydı olarak tanıttık — sessizce eşik gevşetmek yerine, "bu desen bu dönemde normaldir" bilgisini kodda görünür bıraktık. Birkaç kalibrasyon turundan sonra panelde kalan uyarıların büyük çoğunluğu gerçekten bakılmayı hak eden satırlardı. Bu turları atlarsanız iki kötü sonuçtan birine varırsınız: ya panel gürültüden okunmaz olur ve ekip onu görmezden gelmeyi öğrenir, ya da eşikler şikâyet geldikçe gevşetile gevşetile motor hiçbir şey yakalamaz hale gelir. İkisi de kontrolün kendisinden daha tehlikelidir, çünkü ortada "kontrol var" hissi bırakırlar.
Mutabakat Kontrolleri ve İstisna Paneli
Satır bazlı kurallar tek dosyanın içine bakar; ikinci katman, dosyalar ve sistemler arası mutabakattır. Finans raporlamasında en çok işe yarayan kontroller şunlardı: özet sayfadaki toplamların detay sayfalardan yeniden hesaplanıp karşılaştırılması, muhasebe sisteminden alınan dökümle Excel tarafındaki listelerin kesiştirilmesi ve dönem başı bakiye artı hareketler eşittir dönem sonu bakiye denkleminin her hesap için doğrulanması. İki kaynağı kesiştirirken kayıtlar nadiren birebir aynı anahtarla gelir; ad ve açıklama alanlarındaki farklılıklar yüzünden eşleştirmeyi çoğu zaman fuzzy matching ile kayıt eşleştirme teknikleriyle desteklemek gerekir.
Bulguların yaşadığı yer istisna panelidir: kural motorunun ve mutabakat kontrollerinin çıktısını tek bir Excel sayfasında toplayan, önem derecesine göre renklendirilmiş, filtrelenebilir bir rapor. Paneli openpyxl ile üretmek hem biçimlendirmeyi hem de dosyanın her ay aynı düzende çıkmasını garanti eder:
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill
from openpyxl.formatting.rule import CellIsRule
AGIR_KURALLAR = {'mukerrer-kayit', 'gecersiz-kod'}
def istisna_paneli(bulgular, dosya='istisna_paneli.xlsx'):
wb = Workbook()
ws = wb.active
ws.title = 'Istisnalar'
ws.append(['Kaynak Satir', 'Kural', 'Aciklama', 'Onem'])
for hucre in ws[1]:
hucre.font = Font(bold=True)
for _, b in bulgular.iterrows():
onem = 'AGIR' if b['kural'] in AGIR_KURALLAR else 'UYARI'
ws.append([b['excel_satir'], b['kural'], b['aciklama'], onem])
# AGIR bulgulari kosullu bicimlendirmeyle kirmiziya boya
kirmizi = PatternFill(start_color='FFC7CE', end_color='FFC7CE',
fill_type='solid')
son_satir = ws.max_row
ws.conditional_formatting.add(
'D2:D' + str(son_satir),
CellIsRule(operator='equal', formula=['"AGIR"'], fill=kirmizi))
ws.auto_filter.ref = 'A1:D' + str(son_satir)
ws.freeze_panes = 'A2'
wb.save(dosya)
istisna_paneli(rapor)
Panelin işe yaraması biçimlendirmeden çok üç ilkeye bağlı:
- Hata düzeltilmez, işaretlenir: QC katmanı kaynak veriye asla yazmaz; düzeltme kararı veriyi tanıyan kişide kalır.
- Her bulgu adreslidir: istisna satırı, kaynaktaki Excel satır numarasını taşır; "bir yerlerde hata var" uyarısı kimseyi harekete geçirmez.
- Sıfır istisna hedeftir: rapor, panel boşalmadan yayımlanmaz; kalıcı olarak görmezden gelinen bir kural ya düzeltilir ya kaldırılır.
- Panel kendini de raporlar: koşu tarihi, kontrol edilen dosyanın adı ve uygulanan kural sayısı panelin başında yazar; hangi sürümle üretildiği belli olmayan bir kontrol raporu güven vermez.
Panelin insan tarafındaki akışı da en az kuralların kendisi kadar önemliydi. Her rapor döneminde paneli önce veri girişini yapan kişi görür; kendi başına düzeltebileceği bulguları — eksik hücre, biçim hatası, mükerrer satır — doğrudan kaynak dosyada düzeltir. Düzeltme hiçbir zaman panelin üzerinde yapılmaz: panel salt okunur bir aynadır, kaynak düzeldiğinde bulgu bir sonraki QC koşusunda kendiliğinden düşer. Karar gerektiren bulgular — aykırı tutar, mutabakat farkı — ilgili birim sorumlusuna gider ve kısa bir açıklamayla kapatılır. Bakış sırası da bilinçliydi: önce ağır bulgular, sonra uyarılar; önce mutabakat farkları, sonra satır bazlı kurallar. Böylece herkes panelde neye, hangi öncelikle bakacağını bilir ve "kontrol edildi" cümlesi kişiden kişiye değişen bir beyan olmaktan çıkıp tekrarlanabilir bir sürece dönüşür.
Denetim İzi ve Veri Bütünlüğü Sorumluluğu
Finansal veriyle çalışırken kalite kontrolün bir de etik ve kurumsal boyutu var. Yönetime ya da denetçiye giden bir rapor üzerinde otomasyon çalıştırıyorsanız, "hangi veriye, ne zaman, hangi kurallar uygulandı" sorusunun cevabı her an verilebilir olmalı. Benim uyguladığım asgari düzen üç parçadan oluşuyordu: her QC koşusu tarih damgalı bir kayıt satırı bırakır, kontrol edilen dosyanın bir kopyası değiştirilmeden arşivlenir ve kural setindeki her değişiklik kısa bir sürüm notuyla saklanır. Bu, denetim izi gereksiniminin ötesinde bir dürüstlük meselesidir: otomasyon hata örtme aracına dönüşmemeli, hatanın ne zaman görülüp nasıl ele alındığını şeffaflaştırmalıdır. Aynı nedenle skriptin veriyi sessizce düzeltmesine hiçbir zaman izin vermedim; sessiz düzeltme bugün pratik görünse de raporun güvenilirliğini uzun vadede sıfırlar.
Bu düzenin beklemediğim bir yan faydası da oldu: tartışmalar kısaldı. Bir rakam sorgulandığında "o gün dosyanın hangi hali kullanıldı, hangi kural neyi işaretlemişti, kim nasıl kapatmıştı" soruları dakikalar içinde cevaplanabiliyordu; hafızaya ya da e-posta arkeolojisine gerek kalmıyordu. Deneyimim şu ki denetim izi çoğu zaman denetçi için değil, kendi geçmiş kararlarınızı sakin bir şekilde savunabilmeniz için tutulur. Bir de sorumluluk sınırını netleştirir: QC katmanı verinin doğruluğunu garanti etmez, verinin tanımlı kurallardan geçtiğini garanti eder. Bu ayrımı raporu okuyanlara da açıkça söylemek gerekir; aksi halde panelin varlığı, kuralların kapsamadığı hatalar için de sahte bir güvence duygusu yaratır.
Sonuç
Dürüst olmak gerekirse Excel'in sınırlarını da söylemek lazım. Satır sayısı yüz binlere yaklaştığında, aynı dosyada aynı anda birden fazla kişinin çalışması gerektiğinde ya da aynı verinin farklı kopyaları birimler arasında dolaşmaya başladığında, QC katmanı semptomu yönetir ama hastalığı iyileştirmez. Benim çizdiğim pratik sınır şu: veri girişi ve son kullanıcıya sunum Excel'de kalabilir; doğrulama, birleştirme ve hesaplama pandas tarafına, kalıcı kayıt ise tek bir veri tabanına taşınmalıdır. İyi haber, kural motoru bu geçişte köprü görevi görür — kontrolleri zaten koda taşıdığınız için veri kaynağı değiştiğinde kuralların taşınması günler değil saatler alır; Excel'e gömülü formül kontrolleriyle böyle bir geçiş neredeyse sıfırdan yazım demektir.
Excel merkezli bir raporlama düzenini bir gecede veri tabanına taşıyamazsınız; ama üzerine bir kalite kontrol katmanı koymak birkaç günlük iştir ve deneyimime göre karşılığını hemen verir. Formül basit: hata sınıflarını adlandırın, kuralları tek bir motorda toplayın, kaynaklar arası mutabakatı otomatikleştirin, bulguları adresli bir istisna panelinde görünür kılın ve her koşunun izini tutun. GAÜ'deki finans raporlama döneminde bu yaklaşım, hataları raporun okuyucusundan önce panele düşürerek hem süreci sakinleştirdi hem de dosyalara duyulan güveni yeniden kurdu.
Benzer bir kalite kontrol katmanını kendi raporlama süreciniz için kurmayı düşünüyorsanız, veri otomasyonu çalışmalarıma ana sayfadan göz atabilir, projenizi konuşmak için sitedeki iletişim (/#contact) bölümünden bana ulaşabilirsiniz.