Community연구 & 데이터 분석github.com

dq-parser — atomizace dat

SQL 데이터베이스의 데이터 품질을 감사하고 정리하는 10가지 Claude Code 스킬: 프로파일링, 품질 지표, 감사 보고서, 표준화, 대치, 중복 제거, 결함 방지.

dq-parser — atomizace dat란 무엇인가요?

이 스킬은 Claude Code를 사용하여 모든 SQL 데이터베이스에서 데이터 품질을 감사하고 정리하는 10가지 스킬 모음입니다. 데이터 프로파일링, 품질 지표 계산, 감사 보고서 생성, 표준화, 대치, 중복 제거, 결함 방지 등의 기능을 제공합니다. SQL 데이터베이스에서 직접 실행되며, MySQL, PostgreSQL, Oracle, SQL Server, Snowflake, BigQuery 등 다양한 플랫폼을 지원합니다. 각 스킬은 명확한 파이프라인을 따라 순차적으로 실행되어 데이터 품질을 체계적으로 개선합니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add koprjaa/dq-skills

Installed? Explore more 연구 & 데이터 분석 skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서


name: dq-parser description: Parsing a atomizace dat — rozbití složených hodnot do dedikovaných sloupců (číslo popisné a orientační z ulice, obec vs. městská část, jméno a prostřední jméno, titul od jména), oprava prokládaných mezer a kódovacích chyb, extrakce vzorů regexem. První krok remediace, po auditu, před dq-standardizator. Použij, když jsou "čísla domů slitá v ulici", "složené hodnoty v jednom poli", "porušená atomicita", "je potřeba rozparsovat adresu nebo jméno". Keywords: parsing, atomizace, atomicita, rozdělení adresy, číslo popisné, regexp_substr, split, extrakce.

Parser — atomizace

První krok remediace. Nic nestandardizuj, dokud to není atomické. Standardizace pole ADDR_STREET obsahujícího „Na Budíně 854" nedá nic — registr adres zná ulici a číslo zvlášť.

Pipeline: audit → dq-parser → dq-standardizator → dq-adresar → dq-imputator → dq-deduplikator.

Pravidla

  • Originál se nemaže. Parsovaný výstup jde do nových sloupců (_STD, _NUM1, _NUM2). Original je evidence pro before/after a záchranná síť, když parser šlápne vedle.
  • Deterministicky, ne heuristikou. Parser, který v 3 % případů uhodne špatně, vyrobí tichá poškození. Když si pravidlem nejsi jistý, nech NULL a spočítej, kolik jich zbylo. Platí pro strukturované pole se známým vzorem — adresa, jméno, datum. U volného textu, kde vzor neexistuje, je statistické rozpoznávání entit (NER, spaCy) legitimní nástroj, ale jeho výstup je odhad: patří k němu skóre jistoty a příznak, a do produkčního sloupce nejde bez revize.
  • Změř míru rozparsování — kolik řádků se povedlo rozložit. To je metrika do zprávy.
  • Parsuj před čímkoli dalším: standardizace, imputace i deduplikace stojí na atomických polích.

Adresa

Nejčastější defekt: dedikované sloupce pro čísla domů jsou 100 % prázdné a číslo je slité do názvu ulice. Ve zdroji vypadá jako Na Budíně 854, Nádražní 1211/25a, Bezručova 12/3.

Rozklad na tři složky — název ulice, číslo popisné, číslo orientační (s případným písmenem):

-- MySQL 8: REGEXP_SUBSTR / REGEXP_REPLACE
UPDATE PARTY_ADDRESS SET
  ADDR_NUM1_STD   = REGEXP_SUBSTR(ADDR_STREET, '[0-9]+(?=(/[0-9]+[a-zA-Z]?)?[[:space:]]*$)'),
  ADDR_NUM2_STD   = REGEXP_SUBSTR(ADDR_STREET, '(?<=/)[0-9]+[a-zA-Z]?[[:space:]]*$'),
  ADDR_STREET_STD = TRIM(REGEXP_REPLACE(ADDR_STREET, '[0-9]+(/[0-9]+[a-zA-Z]?)?[[:space:]]*$', ''));

Python ekvivalent, když jde o pandas pipeline:

num  = raw.str.extract(r'(\d+)(?:/\d+\w?)?\s*$', expand=False)      # číslo popisné
street = raw.str.replace(r'\d+(/\d+\w?)?\s*$', '', regex=True).str.strip()

Pozor na pořadí čísel: v ČR se zapisuje popisné/orientační, ale konvence není vždy dodržená. Když parser najde jen jedno číslo, ulož ho jako popisné a orientační nech NULL — nehádej.

Složená hodnota v poli obce

Praha 5 - Smíchov, České Budějovice - České Budějovice 5 — operátor napsal do jednoho pole celou adresní hierarchii (obec + městská část + číslo obvodu). Znemožňuje párování na registr.

-- první segment před pomlčkou = obec, zbytek = městská část
SELECT ADDR_CITY,
  TRIM(SUBSTRING_INDEX(ADDR_CITY, '-', 1))                      obec,
  NULLIF(TRIM(SUBSTRING(ADDR_CITY, LOCATE('-',ADDR_CITY)+1)),'') mcast
FROM PARTY_ADDRESS WHERE ADDR_CITY LIKE '%-%';

Detekce kandidátů, než začneš parsovat:

SELECT ADDR_CITY, COUNT(*) cnt FROM PARTY_ADDRESS
WHERE ADDR_CITY REGEXP '[0-9]' OR ADDR_CITY LIKE '%-%' OR LENGTH(ADDR_CITY) > 50
GROUP BY 1 ORDER BY cnt DESC LIMIT 20;

Pozor: pomlčka v názvu obce je někdy legitimní (Frýdek-Místek, Brandýs nad Labem-Stará Boleslav). Proto se rozklad ověřuje proti registru obcí, ne slepě — a když po rozkladu obec v registru není, vrať původní hodnotu.

P.O. Box a jiné mimo-rozsahové formy

P.O. Box, poštovní přihrádka, „na doručovací adrese firmy" — formálně platné adresy, které registr budov nezná. Neparsuj je násilím, označ je vlastním příznakem a vyřaď z metriky match rate (jinak vykážeš jako chybu něco, co chyba není).

Jméno

Prokládané mezery

D A V I D, Ž A N N A — každé písmeno oddělené mezerou. Slepit lze deterministicky, když jsou všechny tokeny jednopísmenné, nebo když je jednopísmenných většina (zbytek je typicky pomlčka nebo iniciála):

toks = s.split()
if len(toks) > 1 and all(len(t) == 1 for t in toks):
    s = "".join(toks)
elif len(toks) > 1 and sum(len(t) == 1 for t in toks) >= max(2, len(toks) - 1):
    s = "".join(toks)

Nikdy neslepuj tokeny obecně — Anna Marie je dvě jména, ne AnnaMarie.

Vícesložkové jméno

Křestní + prostřední jméno v jednom poli. Rozděl podle mezery a druhý token ulož zvlášť; jednopísmenné tokeny (iniciály) zahazuj, jinak vyrobíš nesmyslné prostřední jméno:

UPDATE PART_PARTY
SET PARTY_FNAME_STD = <proper>(SUBSTRING_INDEX(PARTY_FNAME,' ',1)),
    PARTY_MNAME_STD = NULLIF(<proper>(SUBSTRING_INDEX(SUBSTRING_INDEX(PARTY_FNAME,' ',2),' ',-1)),
                             <proper>(SUBSTRING_INDEX(PARTY_FNAME,' ',1)))
WHERE PARTY_TYPE='P' AND LENGTH(SUBSTRING_INDEX(PARTY_FNAME,' ',2)) > 1;

Titul zapsaný v poli jména

Ing. Jan Novák v PARTY_NAME. Detekuj podle shody prvního tokenu se slovníkem titulů, ne podle tečky — J. Novák je iniciála, ne titul.

Slovníkem je číselník titulů (REF_*_TITBEF pro tituly před jménem, TITAFT za ním) a shodu dělej fuzzy, protože v datech vedle sebe stojí MuDr, MUDr. i Mudr. Parser titul jen oddělí; převod na kanonický tvar je práce pro dq-standardizator.

Kódovací chyby

Dvě různé věci, dvě různá řešení:

ChybaPříkladŘešení
systematická záměna znakuĄUDOVÍT (má být ĽUDOVÍT)deterministický replace, pokud je vzor jednoznačný — např. Ą na začátku slova je vždy chybný přepis, protože v polštině tam nikdy nestojí
ztracené písmenoBE0ŠOVÁ (má být BENEŠOVÁ)neopravuj v parseru. Označ příznakem _CORRUPT a nech obnovu na dq-standardizator (registr jmen) nebo dq-deduplikator (čistý dvojník v klastru)
s = re.sub(r"(^|(?<=\s))Ą", "Ľ", s)          # jednoznačné, deterministické
corrupt = bool(re.search(r"[0-9]", s))       # číslice ve jménu = poškozeno, řeší se jinde

Rozdělení je záměrné: parser dělá jen to, co je jisté. Rekonstrukce chybějícího písmene je odhad a patří tam, kde je proti čemu ho ověřit.

Datum uložené jako text

Než parsuješ, ověř formát a den/měsíc:

SELECT SUBSTRING(<col>,1,2) prvni, SUBSTRING(<col>,4,2) druhy, COUNT(*)
FROM <t> GROUP BY 1,2 ORDER BY 3 DESC LIMIT 20;

Když první pozice nikdy nepřekročí 12 a druhá ano, je pořadí MM.DD; když obojí přesahuje 12, je formát smíšený a je nutné rozhodnout per řádek podle druhého zdroje. Slepý STR_TO_DATE tichý swap nezachytí a rozseje ho po celé tabulce.

Výstup parseru

  • Nové _STD sloupce s atomickými hodnotami, originály nedotčené.
  • Míra rozparsování na každou složku (% řádků s neprázdným výsledkem).
  • Chybová tabulka řádků, které parser nerozložil, s důvodem u každého — auditní stopa o tom, proč záznam neprošel. Vstup pro ruční review nebo pro rozhodnutí „tohle je mimo rozsah".

관련 스킬