Metadata-Version: 2.4
Name: preclink
Version: 0.1.0
Summary: High-precision record linkage library with multi-pass support
Project-URL: Homepage, https://github.com/finite-sample/preclink
Project-URL: Documentation, https://preclink.readthedocs.io
Project-URL: Repository, https://github.com/finite-sample/preclink
Project-URL: Issues, https://github.com/finite-sample/preclink/issues
Author-email: Gaurav Sood <gsood07@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: data-matching,deduplication,entity-resolution,fuzzy-matching,record-linkage
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: numpy>=1.26.0
Requires-Dist: pandas>=2.0.0
Requires-Dist: rapidfuzz>=3.0.0
Requires-Dist: scipy>=1.11.0
Provides-Extra: dev
Requires-Dist: mypy>=1.8.0; extra == 'dev'
Requires-Dist: pandas-stubs>=2.0.0; extra == 'dev'
Requires-Dist: pydoclint>=0.4.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.3.0; extra == 'dev'
Requires-Dist: vulture>=2.10; extra == 'dev'
Provides-Extra: docs
Requires-Dist: furo>=2024.1.0; extra == 'docs'
Requires-Dist: sphinx-autodoc-typehints>=2.0.0; extra == 'docs'
Requires-Dist: sphinx>=7.0.0; extra == 'docs'
Description-Content-Type: text/markdown

# preclink

[![PyPI version](https://badge.fury.io/py/preclink.svg)](https://badge.fury.io/py/preclink)
[![CI](https://github.com/finite-sample/preclink/actions/workflows/ci.yml/badge.svg)](https://github.com/finite-sample/preclink/actions/workflows/ci.yml)
[![Documentation](https://readthedocs.org/projects/preclink/badge/?version=latest)](https://preclink.readthedocs.io)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)

High-precision record linkage library implementing a 7-step pipeline with multi-pass support.

## Installation

```bash
pip install preclink
```

## Quick Start

```python
import pandas as pd
from preclink import Pipeline, StringComparison, ExactComparison

df_left = pd.DataFrame({
    "id": [1, 2, 3],
    "first_name": ["John", "Jane", "Bob"],
    "last_name": ["Smith", "Doe", "Johnson"],
    "state": ["CA", "NY", "CA"],
})

df_right = pd.DataFrame({
    "id": [101, 102, 103],
    "first_name": ["Jon", "Jane", "Robert"],
    "last_name": ["Smith", "Doe", "Johnson"],
    "state": ["CA", "NY", "CA"],
})

result = (
    Pipeline()
    .preprocess(normalize_unicode=True, lowercase=True)
    .block(on="state")
    .score(comparisons=[
        StringComparison("first_name", algorithm="jaro_winkler"),
        StringComparison("last_name", algorithm="jaro_winkler"),
    ])
    .filter(min_score=0.7)
    .decide(method="hungarian")
    .build()
    .link(df_left, df_right)
)

print(result.matches)
```

## The 7-Step Pipeline

1. **Preprocess**: Normalize text (unicode, case, whitespace)
2. **Deduplicate**: Remove within-table duplicates
3. **Block**: Reduce comparison space using blocking keys
4. **Score**: Compute pairwise similarity scores
5. **Filter**: Remove low-confidence pairs
6. **Decide**: Apply matching algorithm (Hungarian, Greedy, Row-Sequential)
7. **Inspect**: Generate diagnostics and reports

## Multi-Pass Matching

For complex datasets, use multi-pass matching with progressively relaxed thresholds:

```python
from preclink import MultiPassOrchestrator, StringComparison

orchestrator = MultiPassOrchestrator()
result = orchestrator.run(
    df_left,
    df_right,
    passes=[
        {"min_score": 0.95, "method": "hungarian"},
        {"min_score": 0.85, "method": "hungarian"},
        {"min_score": 0.70, "method": "greedy"},
    ],
    comparisons=[
        StringComparison("first_name"),
        StringComparison("last_name"),
    ],
)
```

## Decision Rules

- **Hungarian**: Optimal assignment maximizing total score (recommended for precision)
- **Greedy**: Best-global-pair first, fast and precision-optimized
- **Row-Sequential**: Process left records in order (baseline)

## Features

- Type-safe with full mypy strict mode support
- Extensible via protocols (custom comparisons, blockers, decision rules)
- Native pandas DataFrames throughout
- Crosswalk support for blocking key normalization
- Margin-based filtering for ambiguity removal

## Documentation

Full documentation at [preclink.readthedocs.io](https://preclink.readthedocs.io)

## License

MIT License
