Skip to main content

๐ŸŸ markrel - Markov chain model for document relevance prediction

Project description

๐ŸŸ markrel

Markov Chain Document Relevance โ€” School your documents with Markov chains!

Python 3.8+ License: MIT Tests

๐ŸŸ What is markrel? A fast, interpretable Python library that uses Markov chains to predict document relevance. Like a school of mackerel navigating the seas, markrel traces probabilistic paths through similarity space to find the most relevant documents.

    ๐ŸŸ๐ŸŸ๐ŸŸ
   ๐ŸŸ๐ŸŸ๐ŸŸ๐ŸŸ
  ๐ŸŸ๐ŸŸ๐ŸŸ๐ŸŸ๐ŸŸ   โ† Your documents
   ๐ŸŸ๐ŸŸ๐ŸŸ๐ŸŸ      swimming through
    ๐ŸŸ๐ŸŸ๐ŸŸ       relevance space!

๐Ÿ“– Table of Contents


๐ŸŒŠ Overview

markrel predicts whether a document is relevant to a query using Markov chains and similarity metrics. It's designed for:

  • ๐Ÿ” Semantic search re-ranking โ€” Filter top-k results with learned relevance
  • ๐Ÿ“ง Document classification โ€” Sort documents by relevance to topics
  • ๐Ÿค– Response selection โ€” Pick best answers from candidate pool
  • โšก High-throughput filtering โ€” Process 50K+ documents/second

Key Features

Feature Description
๐ŸŸ 8 Similarity Metrics Cosine, Euclidean, Jaccard, Overlap, Dice, Manhattan, Chebyshev, Dot Product
๐Ÿง  Markov Chain Learning Learns P(relevance) from your data, not generic rules
๐ŸŽฏ 3 Optimization Modes Tune for F1, Recall, or Precision based on your needs
โšก Fast Inference 50K+ samples/second after training
๐Ÿ”ง Embedding Agnostic Works with BERT, OpenAI, sentence-transformers, or TF-IDF
๐Ÿ“Š Interpretable See exactly why a document was flagged as relevant

โšก Quick Start (3 Minutes)

1. Install

pip install markrel

2. Train & Predict

from markrel import MarkovRelevanceModel

# Your data: queries, documents, and relevance labels
queries = ["machine learning tutorial", "baking recipes", "neural networks"]
documents = ["intro to ML", "best chocolate cake", "deep learning guide"]
labels = [1, 0, 1]  # 1 = relevant, 0 = not relevant

# Create and train (using optimal config from benchmarks)
model = MarkovRelevanceModel(
    metrics=["euclidean"],      # Best single metric
    n_bins=35,                  # Optimized for F1
    bin_strategy="uniform"
)
model.fit(queries, documents, labels)

# Predict relevance
probs = model.predict_proba(
    ["deep learning", "pasta recipes"],
    ["neural networks", "italian cooking"]
)
print(probs)  # [0.82, 0.15]

3. Use with Modern Embeddings

from sentence_transformers import SentenceTransformer

# Load BGE-M3 (best model per benchmarks)
encoder = SentenceTransformer('BAAI/bge-m3')

# Encode your texts
query_emb = encoder.encode(["what is ML?"])
doc_emb = encoder.encode(["machine learning is..."])

# Train with embeddings (disable TF-IDF)
model = MarkovRelevanceModel(
    metrics=["euclidean"],
    use_text_vectorizer=False  # Use your embeddings
)
model.fit(query_emb, doc_emb, [1])

That's it! ๐ŸŽ‰ You now have a relevance model trained on your data.


๐Ÿ“š Tutorial: Complete Walkthrough

Step 1: Prepare Your Data

Markrel needs (query, document, label) triples:

# Example: Question-Answer Relevance Dataset
queries = [
    "What is machine learning?",
    "How does photosynthesis work?",
    "Best pizza recipe?",
    "Explain neural networks",
    "Types of pasta?",
]

documents = [
    "Machine learning is a subset of AI...",
    "Photosynthesis converts sunlight into energy...",
    "Authentic Neapolitan pizza requires...",
    "Neural networks are computing systems...",
    "Popular pasta types include spaghetti...",
]

# Labels: 1 = relevant, 0 = not relevant
labels = [1, 1, 0, 1, 0]

Step 2: Choose Your Configuration

Based on our benchmarks, here are recommended configs:

# Option A: Balanced (Best F1)
model = MarkovRelevanceModel(
    metrics=["euclidean"],
    n_bins=35,
    bin_strategy="uniform"
)

# Option B: Catch Everything (Best Recall)
model = MarkovRelevanceModel(
    metrics=["euclidean"],
    n_bins=7,
    bin_strategy="uniform"
)

# Option C: Strict Filtering (Best Precision)
model = MarkovRelevanceModel(
    metrics=["cosine", "euclidean"],
    n_bins=24,
    bin_strategy="uniform"
)

Step 3: Train the Model

# Train on your data
model.fit(queries, documents, labels)

# Inspect what the model learned
print(model.summary())

Step 4: Make Predictions

# Get probability scores
probabilities = model.predict_proba(
    new_queries,
    new_documents
)

# Apply threshold (default 0.5, or optimized threshold from benchmarks)
threshold = 0.251  # F1-optimized threshold
predictions = probabilities >= threshold

# Or use built-in prediction with custom threshold
predictions = model.predict(
    new_queries,
    new_documents,
    threshold=0.251
)

Step 5: Advanced Usage with Embeddings

For best results, use modern embeddings:

from sentence_transformers import SentenceTransformer
import numpy as np

# Load encoder (BGE-M3 recommended)
encoder = SentenceTransformer('BAAI/bge-m3')

# Large-scale training
train_queries = encoder.encode(train_query_texts)
train_docs = encoder.encode(train_doc_texts)
test_queries = encoder.encode(test_query_texts)
test_docs = encoder.encode(test_doc_texts)

# Train markrel
model = MarkovRelevanceModel(
    metrics=["euclidean"],
    n_bins=35,
    use_text_vectorizer=False  # Important!
)
model.fit(train_queries, train_docs, train_labels)

# Batch prediction (fast!)
probs = model.predict_proba(test_queries, test_docs)

Complete Example: Email Classifier

from markrel import MarkovRelevanceModel
from sentence_transformers import SentenceTransformer

# Load data
emails = ["Urgent: Project deadline moved up", "Weekly team newsletter", "Invoice #1234 payment required"]
queries = ["urgent project emails", "team updates", "billing notifications"]
labels = [1, 0, 1]  # Which emails are relevant to which query

# Encode with BGE-M3
encoder = SentenceTransformer('BAAI/bge-m3')
email_emb = encoder.encode(emails)
query_emb = encoder.encode(queries)

# Train relevance classifier
model = MarkovRelevanceModel(
    metrics=["euclidean"],
    n_bins=35,
    use_text_vectorizer=False
)
model.fit(query_emb, email_emb, labels)

# Classify new emails
new_emails = encoder.encode([
    "RE: Project timeline discussion",
    "Your Amazon order has shipped",
    "URGENT: Server outage in production"
])
search_query = encoder.encode(["urgent project emails"])

relevance_scores = model.predict_proba(search_query, new_emails)
print(f"Email relevance scores: {relevance_scores}")
# Output: [0.78, 0.12, 0.91]

๐ŸŽฏ Why markrel?

The Problem

Traditional document relevance uses:

  • Fixed thresholds: "Cosine > 0.7 = relevant" (ignores domain-specific patterns)
  • Linear scoring: Assumes similarity linearly predicts relevance
  • Black-box models: Can't explain why a document was selected

The Solution

Markrel uses Markov chains to learn non-linear relevance patterns:

Similarity Score โ†’ Bin Mapping โ†’ P(Relevance)

   0.95 โ”€โ”€โ†’ Bin 9 โ”€โ”€โ†’ P(rel)=0.92  โœ“ Highly relevant
   0.75 โ”€โ”€โ†’ Bin 7 โ”€โ”€โ†’ P(rel)=0.68  โš  Maybe relevant
   0.45 โ”€โ”€โ†’ Bin 4 โ”€โ”€โ†’ P(rel)=0.23  โœ— Probably not
   0.15 โ”€โ”€โ†’ Bin 1 โ”€โ”€โ†’ P(rel)=0.05  โœ— Not relevant

Each bin learns its own probability from your training data, capturing domain-specific patterns.


๐Ÿ“Š Benchmarks

WikiQA Question-Answer Relevance

Results on 6,165 test samples (4.8% positive class):

Optimization F1 Recall Precision Config Use Case
Balanced 0.370 0.362 0.379 35 bins, euclidean General purpose
Recall 0.091 1.000 0.048 7 bins, euclidean Catch all relevant
Precision 0.007 0.003 1.000 24 bins, cos+euc Strict filtering

Embedding Model Comparison

Model F1 AUC Speed
BGE-M3 โญ 0.343 0.815 51K/s
RoBERTa-large 0.323 0.828 54K/s
MiniLM-L6 0.322 0.799 61K/s

Winner: BGE-M3 for accuracy, MiniLM for speed.


๐Ÿ”ง Installation

From PyPI (when published)

pip install markrel

From Source

git clone https://github.com/yourusername/markrel.git
cd markrel
pip install -e .

Development Install

pip install -e ".[dev]"
pytest tests/ -v

Dependencies

numpy >= 1.20.0
scikit-learn >= 1.0.0

Optional for embeddings:

sentence-transformers >= 2.0.0

๐ŸŽจ How It Works

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    ๐ŸŸ markrel Pipeline                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

  ๐Ÿ“ฅ INPUT                              ๐Ÿ”ง PROCESSING
  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                              โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚  Query   โ”‚โ”€โ”€โ”                     โ”‚  Embed with โ”‚
  โ”‚  "What   โ”‚  โ”‚                     โ”‚  BGE-M3     โ”‚
  โ”‚  is ML?" โ”‚  โ”‚                     โ”‚  (1024-dim) โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚                     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                โ”‚                           โ”‚
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚                           โ–ผ
  โ”‚ Document โ”‚โ”€โ”€โ”˜                     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚ "Machine โ”‚                        โ”‚ Similarity  โ”‚
  โ”‚ learning โ”‚                        โ”‚ Computation โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                             โ”‚
                                             โ–ผ
                                       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                                       โ”‚ ๐Ÿ“Š Markov   โ”‚
                                       โ”‚   Chain     โ”‚
                                       โ”‚             โ”‚
                                       โ”‚ Bin 0: 5%   โ”‚
                                       โ”‚ Bin 4: 23%  โ”‚
                                       โ”‚ Bin 7: 68%  โ”‚
                                       โ”‚ Bin 9: 92%  โ”‚
                                       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                             โ”‚
                                             โ–ผ
                                       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                                       โ”‚ P(Relevant) โ”‚
                                       โ”‚    0.75     โ”‚
                                       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                             โ”‚
                                             โ–ผ
                                       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                                       โ”‚  โœ… Relevantโ”‚
                                       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

  ๐Ÿ“ค OUTPUT: Probability + Prediction

The Markov Chain

Unlike fixed thresholds, markrel learns a probability for each similarity bin:

Similarity:     0.0 โ”€โ”€โ†’ 0.2 โ”€โ”€โ†’ 0.4 โ”€โ”€โ†’ 0.6 โ”€โ”€โ†’ 0.8 โ”€โ”€โ†’ 1.0
                 โ”‚       โ”‚       โ”‚       โ”‚       โ”‚       โ”‚
                 โ–ผ       โ–ผ       โ–ผ       โ–ผ       โ–ผ       โ–ผ
Bin:          [Bin0]  [Bin1]  [Bin2]  [Bin3]  [Bin4]  [Bin5]
                 โ”‚       โ”‚       โ”‚       โ”‚       โ”‚       โ”‚
P(Relevant):    0.05    0.12    0.35    0.68    0.89    0.95
                 โ”‚       โ”‚       โ”‚       โ”‚       โ”‚       โ”‚
               ๐Ÿšซ      โš ๏ธ      โš ๏ธ      โœ“       โœ“       โœ“
            Not Rel.    Maybe       Likely       Highly
                        Relevant    Relevant     Relevant

โœ… Advantages & Use Cases

โœ… Advantages

Feature Benefit
๐ŸŽฏ Domain Adaptable Learns from YOUR data, not generic assumptions
๐Ÿ“ˆ Non-linear Captures complex similarityโ†’relevance patterns
๐Ÿ”ง Tunable Optimize for F1, Recall, or Precision
โšก Fast 50K+ samples/second after training
๐Ÿ” Interpretable See P(relevance) per bin; debug predictions
๐Ÿงฉ Embedding Agnostic Use BERT, OpenAI, or TF-IDF
๐Ÿ“ฆ Lightweight No GPU required; pure NumPy

โœ… Best Use Cases

Use Case Why markrel Works
๐Ÿ” Semantic Search Re-ranking Fast second-stage filtering of retrieved docs
๐Ÿ“ง Email Classification Learn relevance patterns from your mail
๐Ÿ“„ Document Similarity Semantic matching beyond keywords
๐Ÿค– Chatbot Responses Select best response from candidates
โšก Real-time Filtering High-throughput with low latency

โŒ Limitations

Limitation Solution
Requires labeled data Use transfer learning or synthetic labels
Class imbalance Use Recall-optimized config for rare positives
No native ranking Pair with BM25 for initial retrieval
Single-pair only Use cross-encoders for document sets

๐Ÿ“– API Reference

MarkovRelevanceModel

from markrel import MarkovRelevanceModel

model = MarkovRelevanceModel(
    metrics=["euclidean"],      # Similarity metrics to use
    n_bins=35,                  # Number of bins (10-50)
    bin_strategy="uniform",     # "uniform" or "quantile"
    smoothing=1.0,              # Laplace smoothing
    combine_rule="bayesian",    # "bayesian" or "mean"
    use_text_vectorizer=True    # Auto-vectorize text
)

Methods:

  • fit(queries, documents, labels) โ€” Train the model
  • predict_proba(queries, documents) โ€” Get relevance probabilities [0-1]
  • predict(queries, documents, threshold=0.5) โ€” Binary predictions {0, 1}
  • summary() โ€” Model statistics
  • get_metric_probabilities(metric) โ€” Bin probabilities

๐Ÿ“„ License

MIT License โ€” See LICENSE for details.


๐ŸŸ About the Name

Markrel = Markov Chain + Relevance

Like a school of mackerel swimming through the ocean, markrel navigates the sea of documents, tracing probabilistic paths to find the most relevant matches. Each fish (document) follows the currents (similarity scores) toward their destination (relevance). ๐ŸŸ๐ŸŸ๐ŸŸ


Ready to school your documents? Get started with Quick Start โ†’

     ๐ŸŸ
   ๐ŸŸ๐ŸŸ๐ŸŸ
 ๐ŸŸ๐ŸŸ๐ŸŸ๐ŸŸ๐ŸŸ
   ๐ŸŸ๐ŸŸ๐ŸŸ
     ๐ŸŸ

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

markrel-0.1.0.tar.gz (1.8 MB view details)

Uploaded Source

Built Distribution

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

markrel-0.1.0-py3-none-any.whl (35.2 kB view details)

Uploaded Python 3

File details

Details for the file markrel-0.1.0.tar.gz.

File metadata

  • Download URL: markrel-0.1.0.tar.gz
  • Upload date:
  • Size: 1.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for markrel-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c5601b392d2ae35bb502c1c156020b19a91f91be329b94fca6116b9f4dcc4e05
MD5 86e7889f53151f0da72f84146837b924
BLAKE2b-256 7af72d067520e914877fe31d1f23f8e83244cadd79c9560e69b2453be9b70260

See more details on using hashes here.

Provenance

The following attestation bundles were made for markrel-0.1.0.tar.gz:

Publisher: release.yml on petabyte/markrel

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

File details

Details for the file markrel-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: markrel-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 35.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for markrel-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 dc757fe2147431326927fbe3ad8fad44e662954e6f229f4789c1f775ee701396
MD5 fdb567a8e41702af03358848f7c6e21e
BLAKE2b-256 f30bea5262f785cf778b420dc1f55809f138dccae263f04013c709c2aaa7dcad

See more details on using hashes here.

Provenance

The following attestation bundles were made for markrel-0.1.0-py3-none-any.whl:

Publisher: release.yml on petabyte/markrel

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 Pingdom Monitoring Sentry Error logging StatusPage Status page