Přejít k navigační liště

Zdroják » Různé » Odhad pohlaví z celého jména

Odhad pohlaví z celého jména

Články Různé

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_marat­hon.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.

Chicago marathon

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_FUL­L_NAMES a TABLE_OF_MEN_FUL­L_NAMES s jedním varchar2 sloupcem.

Spustíme create_dictio­nary(‚TABLE_OF_WO­MEN_FULL_NAMES‘, ‘DICTIONARY_WO­MEN’) a create_dictio­nary(‚TABLE_OF_MEN_FUL­L_NAMES‘,‘DIC­TIONARY_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_marat­hon.xls
inserting script.sql
chicago.sql

Zdroje: 

[1] Oracle Database SQL Reference 10G Release 1 (10.1), Chapter SQL Functions
http://docs.o­racle.com/cd/B141­17_01/server.101/b10759/­functions001.htm#i88893
[2] Četnost jmena a příjmení
http://www.mvcr­.cz/clanek/cet­nost-jmen-a-prijmeni-722752.aspx?q=Y2hud­W09MQ%3d%3d
[3] Oracle Database Data Warehousing Guide 10g Release 2 (10.2), Chapter 21 – SQL for Analysis and Reporting
http://docs.o­racle.com/cd/B193­06_01/server.102/b14223/­analysis.htm
[4] Dataflux Technology Overview Course Notes
[5] Bank of America Chicago marathon 2011 results
http://results­.public.chica­gomarathon.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

Komentáře

Subscribe
Upozornit na
guest
25 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
100% Lenin

A ne jen kýč pro rychlokvašky a také programátory. Aneb, vzpomínáte na brilantní článek o pojídačích sušenek?

Díky :-)

Ivan Nový

Jo, ale ten je nejmíň 40 let starý :-)))

100% Lenin

Což neubírá jeho nadčasovosti.
Dodnes se vždy ptám sám sebe, jestli jsem někde neudělal chybu a jestli ten co to jednou po mně bude louskat (bude-li to potřeba) tomu bude rozumět.

Někdy je lepší vyžadovat více od sebe samého než-li od ostatních. Inu, sušenky se samy neupečou. Ačkoliv to mnohým dnes připadá jako samozřejmost.

Nebo snad ne?

balki

Houby, tu je dostupny aj zdrojak. Toto zvladne kazda lama.
Naviac, PL/SQL je ako ten hnusny Pascal.

nuny

??? k čemu toto ???, není lepší a přesnější (100%) male/female ~ boolean v tabulce se jménem ?

Petr

Já jsem se napřed naučil číst a teprve potom psát. Ty jsi na to evidentně šel obráceně :)

Gorila

Ano je jednodušší mít male/female v tabulce. Ale tohle je ukázka jak zjistit pohlaví osoby dle jména když pohlaví není uvedeno. A když se to nezdaří, objeví se „no results“. Otázka jak často se tohle objeví (lepší varianta) nebo jak často bude odpověd nesprávná (mnohem horší varianta).
Tracy Pearson… M nebo F?
Saša Jirků… M nebo F?
Marti Pavlů… M nebo F?

Karol

Ty nedostaneš právě výsledek u 27 procent položek noresult. Ty podle článku dostaneš 27 procent položek neurčil jsem, nu ale nemáš zaručeno v tom zbytku 73 procent jistotu určení Male/Female. Ty dostaneš pouze jistotu, že by jsi měl statisticky dostat správnou odpověď na 73 procent. A tímto projitím jsi tuto nejistotu snižil, ale nevyloučil chybu. Což podle mě program musí pokud se tváří, že to dělá.

Takže pokud tam nedáš položku male/female, je toto vhodné jenom např. policejní složky, spamery nebo obchodní přehledku. Jinak je toto pro praktické využití zbytečnost.

j

Prakticky se to vyuziva pri rozesilani spamu ;D, jednoduse mate desitky tisic adres (at uz realnych nebo mailovych) a protoze si marketaci vymejslej, ze kazdyho treba oslovit, tak se resi, kdo je chlap/zenska, paac tyhle informace se pri ziskavani tech dat vetsinou nikam nezapisujou ….

Karel

Přesně jak píšete, u slovanských jmen to bylo v příjmení, což některé „moderní“ ženy nechtějí, i na západě se začala dávat jména mužská ženám a naopak.

Takže když už to někdo dá do databáze ví jestli je to muž žena a prostě dá o „byte“ více do DBF a nemusí se vymýšlet takovéto šílenosti co žerou výkon a stojí čas programátora co se musí zaplatit.

Tedy pokud toto neřešíte v Rigest Digest nebo jak se jmenuje ta firma či podobných firmách nebo spam firma…

pek

Díky za něj. Přidám ještě odkazy na:

https://metacpan.org/module/Text::GenderFromName
https://github.com/petewarden/genderfromname

Michal Illich

Je to hezké, ale myslím, že vyšší přesnosti by se dosáhlo, kdyby se ze slovníku neořezávala diakritika + vyřešil by se jako speciální případ, když je jméno zadané bez diakritiky.

X125

Ale asi se někdo chce bavit – OK, nic proti tomu nemám.

Jen dva příklady. Třeba v USA je Dana mužské i ženské jméno, zatímco např. v Portugalsku je Maria taktéž mužské a i ženské jméno (asi i ve španělsky mluvících zemích.

http://en.wikipedia.org/wiki/Unisex_name

vembloud

1) Nebylo by lepší pro výpočet skóre místo percent_rank použít relativní četnosti? Tedy nahradit:
PERCENT_RANK () OVER (order by count(*))
za:
count(*) / sum(count(*)) over ().

Navíc by potom odpadla potřeba kejklí s UNION ALL.

2) Vzhledem k tomu, že se skóre porovnává s epsilon, nebylo by vhodnější AVG() místo SUM()? Takto jsou zvýhodňována delší jména.

JS

Jelikoz autor o sobe pise, ze se zabyva datovou kvalitou, rekl bych, ze hlavni vyuziti je kontrola databazi a hledani podezrelych zaznamu. Ti co se tu ptaji, k cemu je to dobre zrejme predpokladaji, ze pocitace jsou neomylne a v databazich nejsou chyby.

Jerry12

Pocitace jsou dost neomylna zarizeni, horsi je to s kvalitou periferie mezi zidli a klavesnici :-).

Ondra

Pro nějakou kontrolu kvality dat (tedy v tom smyslu, zda odpovídají realitě) je toto prakticky bezcenné, protože fakticky ani lidský operátor nebo administrátor nemůže nikdy s jistotou podle jména říct, zda pohlaví uvedené v databázi odpovídá realitě. V případě českých jmen a příjmení je samozřejmě výrazně jednodušší to odhadnout, ale je to stále jen odhad.
Nicméně v obecnějším smyslu jde skutečně o nástroj pro zvýšení kvality dat – jejich obohacení o informaci, která v nich dříve explicitně nebyla k dispozici. Tato informace samozřejmě není kvalitní ve smyslu „ověřená“, nicméně i tak může mít slušnou hodnotu, pokud se vhodně využije. Podle mé zkušenosti se údaj o pohlaví zjištěný takovým způsobem užívá velmi často jednak pro PR a marketing, jednak (už méně často) pro diskriminaci podle pohlaví. V těchto případech obvykle až tak moc nezáleží na tom, jestli se v nějakém tom procentu trefíme vedle.

Ladislav Thon

Hmm, zajímavý problém. Jak by asi obstálo počítání četnosti trigramů? Asi si to zkusím večer…

Clock

Jsem napsal algoritmus ktery z data a pocasi odhadne s 50% uspesnosti zda v ten den budu mit rande nebo ne

Z rande ktere jsem mel bylo 50% predpovezeno
A 50% prorokovanych rande se skutecne vyplnilo

Pocasi je teplota, tlak, osvetleni a relativni vlhkost.

JS

Jak velka byla testovaci mnozina?

Clock

Please try again later. A prispevek v prdeli.

Petr

Pokud by byl podobný, jako ten váš předchozí, tak možná pánbůh zaplať za to… Víc takových dobře načasovaných server errorů. A možná bych i odstranil tu výzvu try again latter.

Trident

Tak a ted mi reknete. Jak resite zmenu pohlavi? A neni to vubec specialni pripad jak by se mohlo zdat. Nicmene pro pany programatory to zatim v informacnich systemech byl vzdy orisek, protoze vetsinou apriori predpokladali ze ke zmene u dane polozky nedojde. Vetsinou to resil manualni UPDATE. Jak resite rozpoznani pohlavi kdyz si transexual zvoli pohlavne neutralni jmeno? To ze spousta IS vubec nepredoklada zmenu rodneho cisla ci primo identifikuje pohlavi podle nej je uz vec poddruzna.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.