Skip to main content

IXPLORE

Bounded Ideal Point Estimation with Grid-Based Uncertainty Quantification: A Python package for embedding users and questionnaire items in a shared 2D latent space.

IXPLORE overview

Overview

IXPLORE is a Python package that jointly embeds users and questionnaire items in a shared 2D latent space. It is designed for user-item reaction matrices commonly found in political questionnaires, where each row represents a user and each column represents an item (question). Responses can be binary (agree/disagree) or Likert-scale values, which are automatically normalized to the [0, 1] range.

The core idea is simple: a user's position in 2D space should predict their responses to all items. Each item defines a logistic regression decision boundary in this space, separating regions of agreement from disagreement. The model iteratively refines both the user positions and the item boundaries until they are mutually consistent.

IXPLORE produces:

  • User embeddings (N x 2): a 2D coordinate for each user representing their latent preferences
  • Item parameters (K x 3): logistic regression coefficients (beta1, beta2, intercept) defining each item's decision boundary
  • Posterior distributions: full probability distributions over the 2D space quantifying uncertainty about each user's position

This enables interpretable visualization of preference landscapes, principled uncertainty quantification, and missing value imputation grounded in the learned geometry.

For the design rationale behind these choices, see docs/motivation.md. For a feature-by-feature walkthrough and the full API reference, see docs/documentation.md. For the full paper, see the technical report on ArXiv.

Features

  • User Embedding: Compute posterior distributions for users based on their reactions
  • Item Models: Define decision boundaries for each question with logistic regression models
  • Iterative Refinement: Jointly optimize user embeddings and item models through iterative updates
  • Flexible Initialization: Initialize embeddings via PCA, random values, or load pretrained embeddings
  • Missing Data Handling: Robust to missing values in the user-item reaction matrix
  • Answer Imputation: Predict answers based on positions in latent space
  • New User Embedding: Embed new users in the latent space with uncertainty quantification
  • Visualization Tools: Built-in plotting functions for embeddings, posteriors, and item decision boundaries

Installation

pip install ixplore

Or install from source:

git clone https://github.com/fsvbach/ixplore.git
cd ixplore
pip install -e .

Quick Start

import pandas as pd
from ixplore import IXPLORE

# Load reaction data (users × items matrix, values in {0, 1} or Likert-scale)
reactions = pd.read_csv('../data/likert_reactions.csv', index_col=0)

# Initialize and fit the model
model = IXPLORE(reactions, pca_initialization=True)

# Refine with a few iterations of joint optimization
model.iterate(n_iterations=1)

# Get user embeddings and item parameters
embedding  = model.get_embedding()    # User positions (N × 2) with columns ['x', 'y']
parameters = model.get_parameters()   # Item parameters (K × 3): ['beta1', 'beta2', 'alpha']

# Embed a new user based on their answers
new_user_answers = pd.Series({'Q1': 0.8, 'Q2': 0.2, 'Q3': 0.6}, name='new_user')
position = model.embed(new_user_answers)

# Impute all answers for a user
predicted = model.impute_answers(new_user_answers)

Custom Configuration

import numpy as np

model = IXPLORE(
    reactions,
    prior_variance=1.0,                         # Prior regularization
    sampling_resolution=200,                    # Grid resolution for posteriors
    limits=(-1, 1),                             # Bounds for both axes (square space)
    pca_initialization=True,                    # Initialize with PCA
    random_state=17                             # For reproducibility
)

Loading Pretrained Models

# Load pretrained embedding and model parameters
pretrained_embedding = pd.read_csv('../data/pretrained_embedding_likert.csv', index_col=0)
pretrained_models = pd.read_csv('../data/pretrained_models_likert.csv', index_col=0)

model = IXPLORE(
    reactions,
    pretrained_embedding=pretrained_embedding,
    pretrained_models=pretrained_models
)

Visualization

from ixplore.visualization import plot_overview

# Load user metadata (e.g., colors for plotting)
users = pd.read_csv('../data/synthetic_users.csv', index_col=0)

# Plot user embeddings
_ = plot_overview(model, question='Q12', user='159', colors=users.color)

For the full constructor parameters and method reference, see docs/documentation.md.

Notebooks

Runnable examples live in notebooks/:

  • demo.ipynb — end-to-end workflow: load data, fit, visualize, embed new users, impute answers.
  • data.ipynb — generate the synthetic users, binary/Likert/categorical reactions used by the other notebooks.
  • prior.ipynb — sweep prior_variance via apply_prior and see how the prior shapes the embedding.
  • weights.ipynb — per-(user, item) weights and the scale_weights flag for sparse responses.
  • features.ipynb — non-linear decision boundaries via the kernel argument (interaction, quadratic, RFF) on categorical data.
  • distortion.ipynb — quantify latent-space distortion with ixplore.metrics.compute_distortion.
  • timing.ipynb — runtime breakdown and scaling in n_users, n_items, and sampling_resolution.

Dependencies

  • numpy
  • pandas
  • scipy
  • matplotlib

License

This project is licensed under the MIT License - see the LICENSE file for details.

Citation

If you use IXPLORE in your research, please cite:

@software{bachmann_ixplore_2026,
  author       = {Bachmann, Fynn},
  title        = {IXPLORE: Bounded Ideal Point Estimation with Grid-Based Uncertainty Quantification},
  year         = {2026},
  publisher    = {ArXiv Preprint},
  url          = {http://arxiv.org/abs/2609.06018}
}

Or in text format:

Bachmann, F. (2026). IXPLORE: Bounded Ideal Point Estimation with Grid-Based Uncertainty Quantification. ArXiv Preprint. http://arxiv.org/abs/2609.06018

Metadata

Release files for ixplore 1.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ixplore 1.2.1
File Size Uploaded Provenance Actions
ixplore-1.2.1.tar.gz 23.0 kB Without provenance Details for ixplore-1.2.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ixplore 1.2.1
File Interpreter ABI Platform Actions
ixplore-1.2.1-py3-none-any.whl Python 3 none any Details for ixplore-1.2.1-py3-none-any.whl

Total release size: 44.2 kB

Release files / ixplore-1.2.1.tar.gz

Download URL ixplore-1.2.1.tar.gz
Size 23.0 kB
Tags Source
SHA-256 checksum
How to use checksums
c3b6f64734daa3e5fe710f9984e4753bb32eedc4ff62fd4c14586d11e2e6f44b
BLAKE2b-256 checksum
How to use checksums
ddc259569a9405004158a8c0d6b12a6dfba74d66f64fd6760249c816bf6a6f4f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.0

Release files / ixplore-1.2.1-py3-none-any.whl

Download URL ixplore-1.2.1-py3-none-any.whl
Size 21.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
151de9bad9c744ff5687395ab6781bc322420f68464de6d66e2d305e6eecc249
BLAKE2b-256 checksum
How to use checksums
92b8ed2543c81f14dd75ac5b7ceaf7a64ff0ede11c7347f600bf317d0dff5069
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.0

Security for ixplore 1.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page