{
  "markdown": "> **Moved.** This repo has moved into the [`benzsevern/goldenmatch`](https://github.com/benzsevern/goldenmatch) monorepo at `packages/python/infermap (and packages/typescript/infermap)/`. This repo is archived; new development happens in the monorepo.\n\n<!-- mcp-name: io.github.benzsevern/infermap -->\n<h1 align=\"center\">infermap</h1>\n\n<p align=\"center\"><strong>Inference-driven schema mapping engine.</strong><br>\nMap messy source columns to a known target schema — accurately, explainably, with zero config.<br>\nBuilt by <a href=\"https://bensevern.dev\">Ben Severn</a>.</p>\n\n<p align=\"center\">\n  <a href=\"https://pypi.org/project/infermap/\"><img src=\"https://img.shields.io/pypi/v/infermap?color=d4a017&label=PyPI\" alt=\"PyPI\"></a>\n  <a href=\"https://www.npmjs.com/package/infermap\"><img src=\"https://img.shields.io/npm/v/infermap?color=cb3837&label=npm\" alt=\"npm\"></a>\n  <a href=\"https://pypi.org/project/infermap/\"><img src=\"https://img.shields.io/pypi/dm/infermap?color=d4a017&label=PyPI%20downloads\" alt=\"PyPI downloads\"></a>\n  <a href=\"https://www.npmjs.com/package/infermap\"><img src=\"https://img.shields.io/npm/dw/infermap?color=cb3837&label=npm%20downloads\" alt=\"npm downloads\"></a>\n  <a href=\"https://github.com/benzsevern/infermap/actions/workflows/test.yml\"><img src=\"https://github.com/benzsevern/infermap/actions/workflows/test.yml/badge.svg?branch=main\" alt=\"CI\"></a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://python.org\"><img src=\"https://img.shields.io/badge/python-3.11%2B-blue?logo=python&logoColor=white\" alt=\"Python 3.11+\"></a>\n  <a href=\"https://nodejs.org\"><img src=\"https://img.shields.io/badge/node-20%2B-339933?logo=node.js&logoColor=white\" alt=\"Node 20+\"></a>\n  <a href=\"https://www.typescriptlang.org/\"><img src=\"https://img.shields.io/badge/typescript-strict-3178c6?logo=typescript&logoColor=white\" alt=\"TypeScript\"></a>\n  <a href=\"https://nextjs.org/docs/app/api-reference/edge\"><img src=\"https://img.shields.io/badge/edge%20runtime-compatible-000000?logo=vercel&logoColor=white\" alt=\"Edge runtime\"></a>\n  <a href=\"https://github.com/benzsevern/infermap/wiki/Python-vs-TypeScript\"><img src=\"https://img.shields.io/badge/parity-Python%20%E2%86%94%20TypeScript-d4a017\" alt=\"Parity\"></a>\n  <a href=\"LICENSE\"><img src=\"https://img.shields.io/github/license/benzsevern/infermap?color=green\" alt=\"License: MIT\"></a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://github.com/benzsevern/infermap/wiki\">📖 Wiki</a> ·\n  <a href=\"https://benzsevern.github.io/infermap/\">🌐 Docs</a> ·\n  <a href=\"examples/\">🧪 Examples</a> ·\n  <a href=\"https://github.com/benzsevern/infermap/discussions\">💬 Discussions</a> ·\n  <a href=\"https://github.com/benzsevern/infermap/issues\">🐛 Issues</a>\n</p>\n\n---\n\n`infermap` is a schema-mapping engine. Give it any two field collections (CSVs, DataFrames, database tables, in-memory records) and it figures out which source field corresponds to which target field, with confidence scores and human-readable reasoning. Available as a **Python package on PyPI** and a **TypeScript package on npm**, with mapping decisions verified bit-for-bit by a shared golden-test parity suite.\n\n## Table of contents\n\n- [Install](#install)\n- [Quick start](#quick-start)\n- [How it works](#how-it-works)\n- [Features](#features)\n- [Which package should I use?](#which-package-should-i-use)\n- [Custom scorers](#custom-scorers)\n- [CLI examples](#cli-examples)\n- [Config reference](#config-reference)\n- [Documentation](#documentation)\n- [License](#license)\n\n## Install\n\n### Python\n\n```bash\npip install infermap\n```\n\nOptional database extras:\n\n```bash\npip install infermap[postgres]   # psycopg2-binary\npip install infermap[mysql]      # mysql-connector-python\npip install infermap[duckdb]     # duckdb\npip install infermap[all]        # all extras\n```\n\n### TypeScript / Next.js\n\n```bash\nnpm install infermap\n```\n\nZero runtime dependencies in the core entrypoint. Compatible with Next.js Server Components, Route Handlers, Server Actions, and the Edge Runtime out of the box. See the [package README](./packages/infermap-js/README.md) for the full reference.\n\n## Quick start\n\n### Python\n\n```python\nimport infermap\n\n# Map a CRM export CSV to a canonical customer schema\nresult = infermap.map(\"crm_export.csv\", \"canonical_customers.csv\")\n\nfor m in result.mappings:\n    print(f\"{m.source} -> {m.target}  ({m.confidence:.0%})\")\n# fname -> first_name  (97%)\n# lname -> last_name   (95%)\n# email_addr -> email  (91%)\n\n# Apply mappings to rename DataFrame columns\nimport polars as pl\ndf = pl.read_csv(\"crm_export.csv\")\nrenamed = result.apply(df)\n\n# Save mappings to a reusable config file\nresult.to_config(\"my_mapping.yaml\")\n\n# Reload later — no re-inference needed\nsaved = infermap.from_config(\"my_mapping.yaml\")\n```\n\n### TypeScript\n\n```ts\nimport { map } from \"infermap\";\n\nconst crm = [\n  { fname: \"John\", lname: \"Doe\", email_addr: \"j@d.co\" },\n  { fname: \"Jane\", lname: \"Smith\", email_addr: \"j@s.co\" },\n];\n\nconst canonical = [\n  { first_name: \"\", last_name: \"\", email: \"\" },\n];\n\nconst result = map({ records: crm }, { records: canonical });\n\nfor (const m of result.mappings) {\n  console.log(`${m.source} → ${m.target}  (${m.confidence.toFixed(2)})`);\n}\n// fname       → first_name  (0.44)\n// lname       → last_name   (0.48)\n// email_addr  → email       (0.69)\n```\n\nFor Next.js, drop it directly into a Route Handler — works on Edge Runtime with zero config:\n\n```ts\n// app/api/infer/route.ts\nimport { map } from \"infermap\";\nexport const runtime = \"edge\";\n\nexport async function POST(req: Request) {\n  const { sourceCsv, targetCsv } = await req.json();\n  const result = map({ csvText: sourceCsv }, { csvText: targetCsv });\n  return Response.json(result);\n}\n```\n\n## How it works\n\nEach field pair runs through a pipeline of **7 scorers**. Each scorer returns a score in `[0.0, 1.0]` or abstains (`None`/`null`). The engine combines scores via weighted average (requiring at least 2 contributors), then uses the **Hungarian algorithm** for optimal one-to-one assignment.\n\n| Scorer | Weight | What it detects |\n|---|---|---|\n| **ExactScorer** | 1.0 | Case-insensitive exact name match |\n| **AliasScorer** | 0.95 | Known field aliases (`fname` ↔ `first_name`, `tel` ↔ `phone`) + domain dictionaries |\n| **InitialismScorer** | 0.75 | Abbreviation-style names (`assay_id` ↔ `ASSI`, `confidence_score` ↔ `CONSC`) |\n| **PatternTypeScorer** | 0.7 | Semantic type from sample values — email, date_iso, phone, uuid, url, zip, currency |\n| **ProfileScorer** | 0.5 | Statistical profile similarity — dtype, null rate, unique rate, length, cardinality |\n| **FuzzyNameScorer** | 0.4 | Jaro-Winkler similarity on normalized field names (with common-prefix canonicalization) |\n| **LLMScorer** | 0.8 | Pluggable LLM-backed scorer (stubbed by default) |\n\nThe engine also applies **common-prefix canonicalization** — automatically stripping schema-wide prefixes like `prospect_` so that `City` vs `prospect_City` is compared as `City` vs `City`. And **optional confidence calibration** transforms raw scores into calibrated probabilities post-assignment (ECE from 0.46 to 0.005 on real-world data).\n\n[Read the full architecture →](https://github.com/benzsevern/infermap/wiki/Architecture)\n\n## Features\n\n| | Python | TypeScript |\n|---|---|---|\n| 7 built-in scorers | ✅ | ✅ |\n| Hungarian assignment | ✅ (scipy) | ✅ (vendored) |\n| Custom scorers | `@infermap.scorer` | `defineScorer()` |\n| Domain dictionaries | ✅ (YAML) | ✅ (inlined) |\n| Confidence calibration | ✅ (Identity/Isotonic/Platt) | ✅ |\n| Score matrix inspection | ✅ | ✅ |\n| In-memory data | Polars, Pandas, `list[dict]` | `Array<Record>` |\n| File providers | CSV, Parquet, XLSX | CSV, JSON |\n| Schema definition files | YAML + JSON | JSON |\n| Database providers | SQLite, Postgres, DuckDB | SQLite, Postgres, DuckDB |\n| Engine config | YAML | JSON |\n| Saved mapping format | YAML | JSON |\n| CLI | ✅ (Typer) | ✅ (`node:util`) |\n| Apply to DataFrame | ✅ | ❌ (CSV rewrite via CLI) |\n| Edge-runtime compatible | ❌ | ✅ |\n| Zero runtime deps | n/a | ✅ |\n| Accuracy benchmark | ✅ (162 cases, F1 0.84) | ✅ (parity within 0.0005) |\n\n[Full feature parity matrix →](https://github.com/benzsevern/infermap/wiki/Python-vs-TypeScript)\n\n## Which package should I use?\n\n| If you are… | Use |\n|---|---|\n| Building a Python data pipeline or notebook | **Python** |\n| Building a Next.js app, Node service, or browser tool | **TypeScript** |\n| Running mapping in a serverless edge function | **TypeScript** (zero Node built-ins) |\n| Doing ad-hoc CSV exploration on the command line | **Python CLI** has more features; **TS CLI** is leaner |\n| Both — Python backend + Next.js admin UI | **Both** — outputs are interoperable via the JSON config format |\n\n## What's new in v0.3\n\n**+18.3pp F1 on real-world data** from four compounding improvements:\n\n```\nv0.2 baseline    F1 0.657\n+ min_conf 0.2   F1 0.765  (+10.8pp — empirically tuned threshold)\n+ prefix-strip   F1 0.821  (+5.6pp  — City vs prospect_City now works)\n+ InitialismScorer F1 0.840 (+1.9pp  — ASSI, CONSC, RELATIT now work)\n```\n\nNew features:\n- **Domain dictionaries** — `MapEngine(domains=[\"healthcare\"])` loads curated aliases for your domain. Ships: `generic` (default), `healthcare`, `finance`, `ecommerce`. See [`examples/09_domain_dictionaries.py`](./examples/09_domain_dictionaries.py).\n- **Confidence calibration** — `MapEngine(calibrator=cal)` transforms raw scores into calibrated probabilities. Ships: `IsotonicCalibrator`, `PlattCalibrator`. Valentine ECE: 0.46 → 0.005. See [`examples/10_calibration.py`](./examples/10_calibration.py).\n- **InitialismScorer** — matches abbreviation-style column names (`assay_id ↔ ASSI`). ChEMBL F1: 0.524 → 0.819.\n- **Common-prefix canonicalization** — automatically strips `prospect_`, `assays_`, etc. before fuzzy matching.\n- **Valentine corpus** — 82 real-world schema-matching cases from the Valentine benchmark for accuracy testing.\n- **Full TypeScript parity** — all new features ported. 186 TS tests. Benchmark F1 within 0.0005 of Python.\n\n## Custom scorers\n\n### Python\n\n```python\nimport infermap\nfrom infermap.types import FieldInfo, ScorerResult\n\n@infermap.scorer(\"prefix_scorer\", weight=0.8)\ndef prefix_scorer(source: FieldInfo, target: FieldInfo) -> ScorerResult | None:\n    if source.name[:3].lower() != target.name[:3].lower():\n        return None\n    return ScorerResult(score=0.85, reasoning=f\"Shared prefix '{source.name[:3]}'\")\n\nfrom infermap.engine import MapEngine\nfrom infermap.scorers import default_scorers\n\nengine = MapEngine(scorers=[*default_scorers(), prefix_scorer])\n```\n\n### TypeScript\n\n```ts\nimport { MapEngine, defaultScorers, defineScorer, makeScorerResult } from \"infermap\";\n\nconst prefixScorer = defineScorer(\n  \"prefix_scorer\",\n  (source, target) => {\n    if (source.name.slice(0, 3).toLowerCase() !== target.name.slice(0, 3).toLowerCase()) {\n      return null;\n    }\n    return makeScorerResult(0.85, `Shared prefix '${source.name.slice(0, 3)}'`);\n  },\n  0.8 // weight\n);\n\nconst engine = new MapEngine({\n  scorers: [...defaultScorers(), prefixScorer],\n});\n```\n\n## CLI examples\n\nThe CLI works the same way in both packages:\n\n```bash\n# Map two files and print a report\ninfermap map crm_export.csv canonical_customers.csv\n\n# Map and save the config (Python: --save, TS: -o)\ninfermap map crm_export.csv canonical_customers.csv -o mapping.json\n\n# Apply a saved mapping to rename columns\ninfermap apply crm_export.csv --config mapping.json --output renamed.csv\n\n# Inspect the schema of a file or DB table\ninfermap inspect crm_export.csv\ninfermap inspect \"sqlite:///mydb.db\" --table customers\n\n# Validate a saved config against a source\ninfermap validate crm_export.csv --config mapping.json --required email,id --strict\n```\n\n## Config reference\n\nBoth packages accept an engine config (scorer weight overrides + alias extensions). Python uses YAML, TypeScript uses JSON; the **shape is identical**.\n\n```yaml\n# Python: infermap.yaml\ndomains:\n  - healthcare\n  - finance\nscorers:\n  LLMScorer:\n    enabled: false\n  FuzzyNameScorer:\n    weight: 0.3\naliases:\n  order_id:\n    - order_num\n    - ord_no\n```\n\n```json\n// TypeScript: infermap.config.json\n{\n  \"scorers\": {\n    \"LLMScorer\":       { \"enabled\": false },\n    \"FuzzyNameScorer\": { \"weight\": 0.3 }\n  },\n  \"aliases\": {\n    \"order_id\": [\"order_num\", \"ord_no\"]\n  }\n}\n```\n\nSee [`infermap.yaml.example`](./infermap.yaml.example) for a full annotated reference.\n\n## Documentation\n\n- 📖 **[Wiki](https://github.com/benzsevern/infermap/wiki)** — full reference for both languages\n  - [Getting Started](https://github.com/benzsevern/infermap/wiki/Getting-Started)\n  - [Python API](https://github.com/benzsevern/infermap/wiki/Python-API)\n  - [TypeScript API](https://github.com/benzsevern/infermap/wiki/TypeScript-API)\n  - [Python vs TypeScript](https://github.com/benzsevern/infermap/wiki/Python-vs-TypeScript) — migration guide\n  - [Scorers](https://github.com/benzsevern/infermap/wiki/Scorers)\n  - [Architecture](https://github.com/benzsevern/infermap/wiki/Architecture)\n  - [FAQ](https://github.com/benzsevern/infermap/wiki/FAQ)\n- 🌐 **[Documentation site](https://benzsevern.github.io/infermap/)**\n- 🧪 **Examples**\n  - [Python examples](./examples/) — 10 numbered scripts covering basic mapping, databases, custom scorers, config, domain dictionaries, calibration, and score-matrix introspection\n  - [TypeScript examples](./examples/typescript/) — basic mapping, Next.js Edge Runtime, custom scorer, databases, domain dictionaries, save/reuse\n- 📓 **[Open in Colab](https://colab.research.google.com/github/benzsevern/infermap/blob/main/scripts/infermap_demo.ipynb)** — Python notebook\n- 💬 **[GitHub Discussions](https://github.com/benzsevern/infermap/discussions)**\n- 🐛 **[Issue tracker](https://github.com/benzsevern/infermap/issues)**\n\n## Author\n\n[Ben Severn](https://bensevern.dev)\n\n## License\n\n[MIT](LICENSE)\n",
  "bytes": 13828,
  "sha": "a6b3a3e2e17032b46045108f5e536efb3c44e8f72b4131090e2c716586fb6703",
  "repo_slug": "benseverndev-oss/infermap",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_benseverndev_oss_infermap_78471132/readme"
}