Skip to main content

instate: state and language composition estimates for Indian surnames

CI image Documentation image Models

Instate reports how processed occurrences of a surname distribute across states in the 2017 Indian electoral rolls, as calibrated 0 to 1 proportions. A lookup covers 1.9 million surnames; a calibrated character-level model extends the same quantity to surnames outside the table; and a language composition mixes the state shares with Census 2011 mother-tongue shares. The outputs describe name patterns in stated reference populations. They do not estimate an individual's residence, origin, or language.

Results follow the appeler inference contract, composition form: every row carries proportions that sum to one, explicit abstention with a machine-readable reason instead of a default distribution, and provenance columns identifying the exact artifacts used.

Installation

pip install instate

Usage

lookup_state_composition reports the electoral-roll shares for surnames in the table and abstains on the rest:

import instate

result = instate.lookup_state_composition(["dhingra", "sood", "xyz123"])
result[
    [
        "surname",
        "scored",
        "abstention_reason",
        "state_share_delhi",
        "state_share_punjab",
        "surname_record_count",
    ]
]
#   surname  scored  abstention_reason  state_share_delhi  state_share_punjab  surname_record_count
#   dhingra    True               <NA>              0.534               0.233                  7519
#      sood    True               <NA>              0.194               0.365                 29403
#    xyz123   False  out-of-dictionary               <NA>                <NA>                  <NA>

estimate_state_composition runs the temperature-scaled BiLSTM for the same quantity, including surnames the table has never seen:

result = instate.estimate_state_composition(["chintalapati"])

estimate_language_composition mixes state evidence with each state's Census 2011 mother-tongue shares. By default it uses the lookup where the surname is known and falls back to the model, recording which in a language_basis column:

result = instate.estimate_language_composition(["sood", "chintalapati"])
result[["surname", "language_basis", "language_share_punjabi", "language_share_telugu"]]

DataFrame input uses the fleet signature: data first, then the column name, with every option keyword-only.

import pandas as pd

frame = pd.DataFrame({"lastname": ["sharma", "patel"], "person_id": [1, 2]})
result = instate.lookup_state_composition(frame, "lastname")

Two reference lookups round out the API: lookup_state_official_languages maps states to their official languages, and list_supported_states returns the 34-state vocabulary.

What the outputs mean

The state shares' denominator is included, processed occurrences of the surname in the 2017 rolls, not people in the current population. The model is trained so its softmax targets exactly that distribution, and its probabilities are temperature-scaled against held-out surnames, so the lookup and the estimate are two routes to one quantity.

The language composition is defined, not observed:

p(language | surname) = sum over states of
    p(state | surname) x census mother-tongue share of the language in the state

The mother-tongue shares come from Census of India 2011 table C-16, with Telangana aggregated from its ten 2011 districts and languages below a 1% share in every state pooled into other (builder, provenance and hashes in the shipped manifest). Two caveats are part of the definition: C-16 records mother tongue, not languages spoken, and the mixing assumes language and surname are independent within a state, which understates community-specific associations.

Known data weaknesses: Telugu/Telangana and Gujarat surnames are noisier in the source romanization; trailing-vowel spelling variants (Kannada patila, Odia dasa) are merged into their canonical forms (patil, das).

Abstention

A surname the package cannot support gets abstained = True and a reason from the contract's shared vocabulary (missing-name, no-letters, unsupported-script, out-of-dictionary, insufficient-evidence), never a default distribution. Supported input is romanized ASCII a to z; the model additionally requires three supported characters.

Model and evaluation

The state model is a two-layer character-level bidirectional LSTM trained on the rebuilt 34-state data, with surnames assigned to deterministic disjoint train, validation, and test splits before training and the best validation epoch restored before saving. Training and evaluation write manifests that bind the data bytes, checkpoint bytes, seed, and split membership; untouched-test evaluation refuses checkpoints without an eligible manifest (details).

Shipped-checkpoint metrics on the untouched test split, 177,019 surnames weighted by 58.3 million records:

metric value
modal state accuracy, top 1 / top 3 0.534 / 0.770
record mass covered, top 1 / top 3 0.447 / 0.668
record-weighted log loss, calibrated 1.762
top-1 confidence minus mass covered 0.040 (0.106 before calibration)

Calibration fits one temperature on the validation split against each surname's empirical state distribution; the shipped instate_state_lstm_calibration.json records the temperature, objective, and before/after metrics.

Checkpoints and calibration download from the pinned Hugging Face repository on first use and are cached. Set INSTATE_MODEL_DIR to a directory holding the artifacts to run offline.

Data

The underlying electoral-roll data: https://doi.org/10.7910/DVN/ZXMVTJ. Census language shares rebuild from the pinned census downloads with model_training/build_state_language_shares.py.

Authors

Atul Dhingra, Gaurav Sood, and Rajashekar Chintalapati.

Contributor Code of Conduct

The project welcomes contributions from everyone! In fact, it depends on it. To maintain this welcoming atmosphere, and to collaborate in a fun and productive way, we expect contributors to the project to abide by the Contributor Code of Conduct.

License

The package is released under the MIT License.

Adjacent repositories

  • appeler/naampy — Infer Sociodemographic Characteristics from Names Using Indian Electoral Rolls
  • appeler/ethnicolr2 — Ethnicolr implementation with new models in pytorch
  • appeler/parsernaam — AI name parsing. Predict first or last name using a DL model.
  • appeler/ethnicolor — Race and Ethnicity based on name using data from census, voter reg. files, etc.
  • appeler/ethnicolr — Predict Race and Ethnicity Based on the Sequence of Characters in a Name

Download files

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

Source Distribution

instate-3.0.0.tar.gz (26.5 MB view details)

Uploaded Source

Built Distribution

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

instate-3.0.0-py3-none-any.whl (50.2 kB view details)

Uploaded Python 3

File details

Details for the file instate-3.0.0.tar.gz.

File metadata

  • Download URL: instate-3.0.0.tar.gz
  • Upload date:
  • Size: 26.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for instate-3.0.0.tar.gz
Algorithm Hash digest
SHA256 fd49bd6a414d788bd6ad1f4440a8fea26954508ef2f61b03125503b35f7605e9
MD5 43595e5273f5ce51a62a43b38e6f7ddc
BLAKE2b-256 19eed3a8fee3b4359865a70ceb27313e56a3c9eb1c6a54b6a2afcbfde5d8974d

See more details on using hashes here.

Provenance

The following attestation bundles were made for instate-3.0.0.tar.gz:

Publisher: release.yml on appeler/instate

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file instate-3.0.0-py3-none-any.whl.

File metadata

  • Download URL: instate-3.0.0-py3-none-any.whl
  • Upload date:
  • Size: 50.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for instate-3.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 36d6fa8626fd0830e0af31f230c9b9804f0dd1fdf38d5b04e4e44115e97c4290
MD5 75314274dbfebe1a1cf84a1c7fd13b20
BLAKE2b-256 b3916b44424afac413500135328270938c693de13b23907ac084bcebcf3e0681

See more details on using hashes here.

Provenance

The following attestation bundles were made for instate-3.0.0-py3-none-any.whl:

Publisher: release.yml on appeler/instate

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

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