Odhad pohlaví z celého jména
Při práci s daty reálných lidí můžeme narazit na problém určení jejich pohlaví. Pokud chceme použít například personalizované oslovení „vážená paní / vážený pane“, musíme mít informace o pohlaví uložené v záznamech, nebo se je můžeme pokusit určit. V článku si ukážeme takový algoritmus na určování pohlaví.
Problém
Problému odhadu pohlaví na základě jména se věnuje mnoho webových stránek a několik specializovaných nástrojů, ale většinou vrací jenom výsledky bez popisu algoritmu, výsledků testů na reálných datech a dalších podrobností. Tento článek popisuje algoritmus, vysvětluje ho, uvádí výsledky i porovnání se specializovaným nástrojem na velkém objemu reálných dat.
Uvažujme situaci, že na základě textového řetězce potřebujeme odhadnout hodnotu pro daný parametr ze 2 možností. Bez újmy na obecnosti odhadujme pohlaví na základě celého jména, přičemž pod celým jménem budeme chápat zejména křestní jméno a příjmení, ale celé jméno může obsahovat i další atributy jako například titul nebo občanství.
Algoritmus
Základní princip je zřejmý a jednoduchý. Zjistíme, zda se dané jméno nachází v seznamu typicky mužských nebo typicky ženských jmen, a pokud je výsledek jednoznačný, uděláme odhad. V češtině, ale i v jiných slovanských jazycích, je možné odhadnout pohlaví i na základě přechýleného příjmení, naproti tomu v některých jazycích je struktura celého jména odlišná a nemůže se na něj dívat jako na jednoduchou kombinaci jednoslovného křestního jména a jednoslovného příjmení. Strukturu jmen a přechylování v algoritmu ale nevyužívám.
Dále předpokládejme, že celé jméno se skládá ze slov a současně platí:
- Je silná závislost mezi slovy celého jména a pohlavím
- Máme k dispozici velké množství dat, kde je vyplněné celé jméno a pohlaví – z této množiny vytvoříme slovník
- Množina dat, pro kterou chceme odhadovat pohlaví na základě celého jména má stejné rozdělení slov a pohlaví jako množina, z které jsme vytvořili slovník (není dobré odhadovat pro česká jména pohlaví na základě vietnamského slovníku)
K takové situaci běžně dochází v prostředí, kde je manuálně pořizováno velké množství dat (například v bankách, pojišťovnách) a do některých aplikací není možné údaj o pohlaví zadat, případně někteří pracovníci údaj o pohlaví zadávají a jiní nikoliv. Tahle situace je známá mnohým uživatelům datových skladů, proto jsem v článku použil jako jazyk PL/SQL.
Za uvedených předpokladů je možné použít níže popsaný algoritmus.
Nejprve vytvoříme slovník. Všechna celá jména standardizujeme použitím Oracle funkcí upper (velká písmena), trim (ořezání mezer), translate (nahrazení tečky a čárky mezerou), convert (zrušení diakritiky) a regexp_replace (nahrazení násobných mezer 1 mezerou)[1]. Mezery chápeme jako oddělovače jednotlivých slov standardizovaného celého jména.
Ze standardizovaných slov z celých ženských jmen vytvoříme slovník pro ženy a jednotlivým standardizovaným slovům přiřadíme skóre pomocí Oracle funkce percent_rank [3]. Analogickým způsobem vytvoříme slovník pro muže.
Pro lepší pochopení se podívejte do přílohy chicago_marathon.xls.
Slovník pro jména a příjmení na základě pohlaví včetně četnosti pro ČR je volně dostupný na stránkách MV ČR (v algoritmu jsem tento slovník nevyužil) [2].
Pro odhadnutí pohlaví na základě celého jména propojíme toto jméno s ženským a mužským slovníkem a pro oba slovníky zjistíme celkové souhrnné skóre. Pokud je absolutní rozdíl mezi souhrnným skóre pro mužský a ženský slovník větší jako epsilon (kde epsilon je 0 nebo malé kladné číslo), tak uděláme odhad na základě většího skóre.
Tento algoritmus nebere do úvahy význam dat, pořadí slov v celém jméně, kombinace s jinými entitami, kvalitu zdroje, znalosti z jiných oblastí a podobně. Proto výsledky nebudou tak dobré jako při správné analýze na základě významu dat.
Na druhé straně jsme často v situaci, že nemáme dostatečné informace o významu dat, jsme v prostředí, které neznáme a nemáme pro něj vhodnou customizaci běžných nástrojů, nemáme kvalitní slovníky a podobně. V tomto případě nám algoritmus vrátí relativně dobré výsledky bez velké námahy a hlavně respektuje rozdělení dat na vašem zdroji.
Výsledky a porovnání se specializovaným nástrojem
Algoritmus jsem otestoval na reálných datech. Pro první test jsem vybral výsledky z maratonu v Chicagu v roce 2011 (jsou dostupné na oficiálních stránkách maratonu), kde jsem vzal do úvahy celé jméno, které obsahovalo i občanství [5]. 37 547 jmen jsem rozdělil na 2 disjunktní skupiny, přičemž první skupina obsahovala 80 % běžců a sloužila k vytvoření slovníku, zbylých 20 % tvořilo druhou skupinu, kterou jsem použil ke kontrole výsledků algoritmů.
Algoritmus správně určil pohlaví 6 543 ze 7 157 běžců (pro epsilon rovné nule).
Za správný odhad považuji případ, že správně odhadnu pohlaví. Za špatný odhad považuji případ, že odhadnu opačné pohlaví. Pro zbytek do 100% algoritmus neudělal odhad.
|
|
Algoritmus |
|||
|
epsilon = 0 |
epsilon = 0.2 |
|||
|
Správný odhad |
Špatný odhad |
Správný odhad |
Špatný odhad |
|
|
Pohlaví |
91,421% |
6,371% |
72,684% |
2,124% |
Pro tento test je v příloze k dispozici úplný zdrojový kód a přehledné výsledky.
Druhý test probíhal na reálných českých datech, kde jsem na základě celého jména odhadoval pohlaví (pouze pro fyzické osoby) a pak i typ osoby (fyzická nebo právnická osoba). Celkový počet záznamů byl výrazně vyšší než u maratonu a mohutnost každé skupiny byla minimálně v desítkách tisíc. Výsledky algoritmu jsem porovnal s výsledky, které vrátil SAS Dataflux customizovaný pro Českou republiku. Algoritmus i SAS Dataflux běžely nad stejnou množinou dat. Pro detailnější přehled jsem změřil výsledky jak pro české občany (firmy), tak i pro cizince.
|
Reálná data |
Algoritmus |
Dataflux |
||||
|
epsilon = 0 |
epsilon = 0.2 |
|||||
|
Správný odhad |
Špatný odhad |
Správný odhad |
Špatný odhad |
Správný odhad |
Špatný odhad |
|
|
Pohlaví – Celkově |
98,278% |
0,236% |
95,055% |
0,117% |
94,050% |
0,210% |
|
Pohlaví – Češi |
99,597% |
0,052% |
97,095% |
0,026% |
99,007% |
0,057% |
|
Pohlaví – Cizinci |
88,993% |
1,531% |
80,695% |
0,754% |
59,156% |
1,292% |
|
Typ osoby – Celkově |
98,676% |
0,400% |
88,232% |
0,211% |
98,749% |
0,890% |
|
Typ osoby – Češi |
99,397% |
0,233% |
89,392% |
0,121% |
98,881% |
0,842% |
|
Typ osoby – Cizinci |
91,611% |
2,037% |
76,869% |
1,091% |
97,450% |
1,363% |
Vidíme, že algoritmus i Dataflux fungují výborně pro odhad pohlaví českých občanů, u cizinců je algoritmus výrazně lepší než česká verze Datafluxu.
Pokud se podíváme na odhad typu osoby, tady vidíme, že pro české občany/firmy funguje Dataflux i algoritmus s nulovým epsilon výborně. SAS Dataflux je lepší v odhadech cizích občanů/firem. Lepší výsledky algoritmu pro česká data se dá vysvětlit výrazně vyšším počtem záznamů než u cizinců, co se projevilo i v kvalitě slovníku a lepším skórováním jednotlivých standardizovaných slov.
Taky vidíme (jak jsme mohli předpokládat), že pro větší epsilon je algoritmus konzervativnější. Tj. vrací menší počet špatných, ale i správných odhadů.
Existuje více metod, jak algoritmus vylepšit. Například ignorovat ve slovníku slova s malým skóre, určit vhodné epsilon na základě počtu záznamů ve slovníku a počtu slov v celém jméně, uvažovat bayesovský pohled pro případ s velmi výrazným rozdílem mezi počtem mužů a žen v testované skupině, uvažovat více než 2 možné výsledky a podobně. Nicméně všechny tyto kroky výrazně snižují největší výhodu algoritmu – jeho jednoduchost.
Implementace v PL/SQL
Pro jednoduchost a přehlednost ukážu jenom základní principy, neuvažuji výjimky a ani speciální případy. Úplný zdrojový kód pro maraton je v příloze.
Mějme tabulky TABLE_OF_WOMEN_FULL_NAMES a TABLE_OF_MEN_FULL_NAMES s jedním varchar2 sloupcem.
Spustíme create_dictionary(‚TABLE_OF_WOMEN_FULL_NAMES‘, ‘DICTIONARY_WOMEN’) a create_dictionary(‚TABLE_OF_MEN_FULL_NAMES‘,‘DICTIONARY_MEN’), kde
CREATE OR REPLACE Procedure
create_dictionary(table_name_in In user_tables.table_name%Type,
table_name_out In varchar2)
Is
Type tabtype Is Table Of
Varchar(2000);
input_table tabtype;
words Varchar(2000);
count_of_words Number;
Begin
--create table for dictionary
Execute Immediate 'create table '|| table_name_out ||' (word VARCHAR2(200))';
Execute Immediate 'select * from ' || table_name_in
Bulk Collect
Into input_table;
For i In input_table.first ..
input_table.last
Loop --(1)
--space, comma and dot are separated symbols for
--words we replace them with space by using translate
--multiple space we replace with single space by
--using regexp_replace
--standartization of word by using upper and
--convert oracle functions
words := upper(convert(Trim(regexp_replace(translate(input_table(i),',.',' '),'( ){2,}',' ')),'US7ASCII')) || ' ';
If words = ' '
Then
count_of_words := 0;
Else
count_of_words := length(words) - length(Replace(words, ' '));
End If;
For j In 1 .. count_of_words
Loop --(2)
--inserted j-th standarted word from full name to
dictionary
If j = 1
Then
Execute Immediate 'insert into ' || table_name_out || ' values ('''||substr(words,1,instr(words, ' ', 1,
1) - 1) ||''')';
Else
Execute Immediate 'insert into ' || table_name_out || ' values (''' ||
substr(words,instr(words, ' ', 1,
j - 1) + 1,
instr(words, ' ', 1, j) - instr(words, ' ', 1, j - 1) - 1) || ''')';
End If;
End Loop; --(2)
Commit;
End Loop; --(1)
End;
Pro hodnoty z dictionary_men přiřadíme skóre pomocí percent_rank. Používám dvakrát union all, abych dal všem slovům pozitivní skóre.
select word, PERCENT_RANK () OVER (order by count(*)) score from (select word from DICTIONARY_MEN union all select word from DICTIONARY_MEN union all select null from dual) group by word
Pro odhad pohlaví použijeme následující select:
select t1.full_name,
case when
t1.men_score-t2.women_score>&epsilon then 'male'
when t2.women_score-t1.men_score>&epsilon then 'female'
else 'no result' end result
from
--full_name_without_gender
--is table with full names we need to estimate gender
--men and
--woman are tables with words from dictionaries and score
(select t.full_name ,sum(nvl(men.score,0)) men_score
from full_name_without_gender t
left join (select word, PERCENT_RANK () OVER (order by count(*)) score
from (select word from DICTIONARY_MEN union all select word from DICTIONARY_MEN union all select null from dual)
group by word)
men
on ' '||upper(convert(translate(full_name,',.-',' '),'US7ASCII'))||' ' like '% '||men.word||' %'
group by
t.full_name) t1
join
(select t.full_name ,sum(nvl(women.score,0)) women_score
from full_name_without_gender t
left join (select word, PERCENT_RANK () OVER (order by count(*)) score
from (select word from DICTIONARY_WOMEN union all select word from DICTIONARY_WOMEN union all select null from dual)
group by word)
women
on ' '||upper(convert(translate(full_name,',.-',' '),'US7ASCII'))||' ' like '% '||women.word||' %'
group by
t.full_name) t2
on t1.full_name=t2.full_name
Tento select s joinem přes like je velmi pomalý, zvlášť pro velký objem dat. Na datech z chicagského maratonu běží několik minut. Pro zrychlení je možné jednotlivá jména nejprve rozdělit a pak spustit upravený select nebo použít jiný způsob na optimalizaci selectu.
Přílohy:
chicago_marathon.xls
inserting script.sql
chicago.sql
Zdroje:
[1] Oracle Database SQL Reference 10G Release 1 (10.1), Chapter SQL Functions
http://docs.oracle.com/cd/B14117_01/server.101/b10759/functions001.htm#i88893
[2] Četnost jmena a příjmení
http://www.mvcr.cz/clanek/cetnost-jmen-a-prijmeni-722752.aspx?q=Y2hudW09MQ%3d%3d
[3] Oracle Database Data Warehousing Guide 10g Release 2 (10.2), Chapter 21 – SQL for Analysis and Reporting
http://docs.oracle.com/cd/B19306_01/server.102/b14223/analysis.htm
[4] Dataflux Technology Overview Course Notes
[5] Bank of America Chicago marathon 2011 results
http://results.public.chicagomarathon.com/2011/
[6] Estimate gender from full name with Oracle – anglická verze
http://brejcak.blogspot.com/2011/10/estimate-gender-from-full-name-with.html
Školení Google Analytics pro pokročilé

- Jak využít nové funkce Google Analytics
- Vyhodnocování kampaní díky používání Multichannel funnels
- Kde návštěvníci vašeho webu utíkají z objednávacího procesu.
- Nebudete opakovat časté chyby při vyhodnocování dat o návštěvnosti.
Detailní informace o školení Google Analytics pro pokročilé »
Přehled názorů
Tento text je již více než dva měsíce starý. Chcete-li na něj reagovat v diskusi, pravděpodobně vám již nikdo neodpoví. Pro řešení aktuálních problémů doporučujeme využít naše diskusní fórum.