Skip to main content

Production-Grade Explainable Name Analysis: nationality, ethnicity, gender, religion prediction with morphology detection, Shannon entropy ambiguity scoring, confidence breakdown - 238 countries, 6 religions, 5.9M+ names, 100% offline!

Project description

EthniData

State-of-the-art name analysis engine — predict nationality, ethnicity, gender, language, religion, and region from first/last names. 5.9M+ records, 238 countries, explainable AI, morphology detection, and synthetic data generation.

PyPI version CI Python 3.10+ License: MIT

Installation

pip install ethnidata

Quick Start

from ethnidata import EthniData

ed = EthniData()

# Predict nationality from first name
result = ed.predict_nationality("Ahmet")
print(result["nationality"])     # Turkey
print(result["confidence"])      # 0.87
print(result["region"])          # Middle East

# With full explainability
result = ed.predict_nationality("Yılmaz", name_type="last", explain=True)
print(result["ambiguity_score"])        # 0.21 (low = confident)
print(result["confidence_level"])       # High
print(result["morphology_signal"])      # {'primary_pattern': 'maz_suffix', ...}
print(result["explanation"]["why"])     # 'Suffix -maz is strongly Turkish/Azerbaijani'

Features at a Glance

Feature Description
Nationality 238 countries — predict country of origin from name
Gender Male/female/neutral with probability score
Religion 6 major world religions (see breakdown below)
Ethnicity Fine-grained ethnic group prediction
Region 5 continental regions
Language 72 languages associated with name origin
Explainability Human-readable reasons for every prediction
Morphology 9 cultural pattern detectors (Gaelic, Slavic, Arabic, etc.)
Ambiguity Score Shannon entropy — 0 = certain, 1 = maximally ambiguous
Synthetic Data Privacy-safe name generation for testing/research

Database Coverage

Religion Records Coverage
Christianity 3.9M+ 65.2%
Buddhism 1.3M+ 22.1%
Islam 504K+ 8.5%
Judaism 121K+ 2.0%
Hinduism 90K+ 1.5%
Sikhism 24K+ 0.4%

Total: 5.9M+ records · 238 countries · 72 languages


Nationality Prediction

from ethnidata import EthniData

ed = EthniData()

# First name
r = ed.predict_nationality("Hiroshi")
print(r["nationality"])    # Japan
print(r["confidence"])     # 0.91
print(r["alternatives"])   # [{'nationality': 'China', 'prob': 0.06}, ...]

# Last name
r = ed.predict_nationality("Okonkwo", name_type="last")
print(r["nationality"])    # Nigeria
print(r["region"])         # Africa

# With explanation
r = ed.predict_nationality("O'Brien", name_type="last", explain=True)
print(r["explanation"]["why"])  # "O' prefix is a strong Gaelic/Irish marker"
print(r["morphology_signal"])   # {'primary_pattern': "o'", 'pattern_type': 'gaelic'}

Full Name Analysis

from ethnidata import EthniData

ed = EthniData()

# Analyze first + last name together
result = ed.predict_full_name("Mehmet", "Yılmaz")
print(result["nationality"])   # Turkey
print(result["confidence"])    # 0.95
print(result["gender"])        # Male
print(result["religion"])      # Islam
print(result["language"])      # Turkish

# With explainability
result = ed.predict_full_name("John", "Smith", explain=True)
print(result["explanation"]["first_name_signal"])  # 'English/Christian'
print(result["explanation"]["last_name_signal"])   # 'Anglo-Saxon occupational'
print(result["ambiguity_score"])   # 0.15 (highly confident)

Gender Prediction

from ethnidata import EthniData

ed = EthniData()

for name in ["Maria", "Carlos", "Alex", "Kim"]:
    r = ed.predict_nationality(name)
    print(f"{name:10s} → gender: {r.get('gender', 'N/A'):8s}  confidence: {r.get('gender_confidence', 0):.2f}")
# Maria      → gender: Female    confidence: 0.97
# Carlos     → gender: Male      confidence: 0.94
# Alex       → gender: Neutral   confidence: 0.52
# Kim        → gender: Neutral   confidence: 0.61

Religion Prediction

from ethnidata import EthniData

ed = EthniData()

names = [
    ("Fatima", "Al-Rashid"),
    ("Arjun", "Sharma"),
    ("David", "Cohen"),
    ("Harpreet", "Singh"),
]

for first, last in names:
    r = ed.predict_full_name(first, last)
    print(f"{first} {last}: {r['religion']} ({r['nationality']})")
# Fatima Al-Rashid: Islam (Saudi Arabia)
# Arjun Sharma: Hinduism (India)
# David Cohen: Judaism (Israel)
# Harpreet Singh: Sikhism (India)

Morphology Detection

from ethnidata.morphology import MorphologyEngine, NameFeatureExtractor

# Detect cultural pattern from name morphology alone
signal = MorphologyEngine.get_morphological_signal("O'Connor", "last")
print(signal)
# {'primary_pattern': "o'", 'pattern_type': 'gaelic', 'cultural_group': 'Irish', 'confidence': 0.88}

signal = MorphologyEngine.get_morphological_signal("Kowalski", "last")
print(signal)
# {'primary_pattern': 'ski_suffix', 'pattern_type': 'slavic', 'cultural_group': 'Polish', ...}

# Extract morphological features for analysis
features = NameFeatureExtractor.extract("Nakamura", "last")
print(features["suffix"])           # 'mura'
print(features["length"])           # 8
print(features["phonetic_family"])  # 'japanese'

Ambiguity Scoring

from ethnidata import EthniData

ed = EthniData()

# Shannon entropy: 0.0 = certain, 1.0 = maximally ambiguous
names = ["Yılmaz", "Kim", "Alex", "Mohammed"]
for name in names:
    r = ed.predict_nationality(name, explain=True)
    print(f"{name:12s}  ambiguity={r['ambiguity_score']:.2f}  level={r['confidence_level']}")
# Yılmaz       ambiguity=0.11  level=High
# Kim          ambiguity=0.74  level=Low
# Alex         ambiguity=0.68  level=Low
# Mohammed     ambiguity=0.22  level=High

Synthetic Data Generation

from ethnidata import EthniData, SyntheticDataEngine, SyntheticConfig

ed = EthniData()

# Generate privacy-safe synthetic name dataset for Turkish names
engine = SyntheticDataEngine(ed.freq_provider)
config = SyntheticConfig(size=1000, country="TUR", include_gender=True)
records = engine.generate(config)

print(f"Generated {len(records)} synthetic records")
for r in records[:3]:
    print(f"  {r.first_name} {r.last_name} ({r.gender}) — {r.nationality}")
# Mehmet Yılmaz (Male) — Turkey
# Fatma Demir (Female) — Turkey
# Ali Kaya (Male) — Turkey

# Generate multi-country dataset
config_multi = SyntheticConfig(
    size=5000,
    countries=["USA", "DEU", "JPN", "BRA"],
    balanced=True,
)
dataset = engine.generate(config_multi)

Explainability Engine

from ethnidata import ExplainabilityEngine, EthniData

ed = EthniData()

result = ed.predict_full_name("Giuseppe", "Rossi", explain=True)

print(result["explanation"]["why"])
# 'Giuseppe is a classic Italian form of Joseph; Rossi (pl. of rosso) is the most common Italian surname'

print(result["explanation"]["confidence_breakdown"])
# {'database_frequency': 0.91, 'morphology_match': 0.88, 'phonetic_score': 0.85}

print(result["explanation"]["similar_names"])
# ['Gioseppe', 'Beppe', 'Peppe'] — Italian variants

Batch Processing

import pandas as pd
from ethnidata import EthniData

ed = EthniData()

df = pd.DataFrame({
    "first_name": ["Ahmet", "Maria", "Hiroshi", "John"],
    "last_name":  ["Yılmaz", "Garcia", "Tanaka", "Smith"],
})

results = []
for _, row in df.iterrows():
    r = ed.predict_full_name(row["first_name"], row["last_name"])
    results.append({
        "nationality": r["nationality"],
        "religion":    r.get("religion", "Unknown"),
        "confidence":  r["confidence"],
    })

df = df.join(pd.DataFrame(results))
print(df[["first_name", "last_name", "nationality", "religion", "confidence"]])

Ethical Use

EthniData is designed for:

  • Research and analytics: population studies, historical data analysis
  • Data quality: enriching and validating name-country datasets
  • Privacy testing: generating synthetic test data instead of using real PII
  • Academic use: reproducible, transparent, citable

Not intended for individual profiling, discrimination, or surveillance. All predictions are probabilistic — treat with appropriate uncertainty.


License

MIT — Teyfik Öz

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ethnidata-4.5.0.tar.gz (16.6 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ethnidata-4.5.0-py3-none-any.whl (16.7 MB view details)

Uploaded Python 3

File details

Details for the file ethnidata-4.5.0.tar.gz.

File metadata

  • Download URL: ethnidata-4.5.0.tar.gz
  • Upload date:
  • Size: 16.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for ethnidata-4.5.0.tar.gz
Algorithm Hash digest
SHA256 58d2994163348da88046b9bb5d1b858b880f3588cacc7031fb29d5923e4e9972
MD5 774de32486b27a7204910b2105406896
BLAKE2b-256 f4bb4cc959cf87d97c9e2eea71a4a0163f39a90f2af61ff510839bc6de26de48

See more details on using hashes here.

File details

Details for the file ethnidata-4.5.0-py3-none-any.whl.

File metadata

  • Download URL: ethnidata-4.5.0-py3-none-any.whl
  • Upload date:
  • Size: 16.7 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for ethnidata-4.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ebd479a121d5c97c2d1e7aff85d6a03f70ab455434bb3f6e085d12923ad82e61
MD5 92e87f2ee0a162754412164e091bf48f
BLAKE2b-256 52afa3b8ce0c1af2885ea22e8c3c602cde986c2e9abcd984e191a3eced00ff89

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page