Machine-learning engineer checking source row IDs and annotating a printed nearest-neighbor test report.

scikit-learn kneighbors: Exclude Self-Matches Without Losing Valid Rows

Wed, Oct 28, 2026

A maintenance refactor can look almost content-free:

model.kneighbors(n_neighbors=k) becomes model.kneighbors(X_train, n_neighbors=k).

The feature values have not changed. The explicit array may even be the same array used in fit, or an exact X_train.copy(). Yet the meaning of the query has changed. In scikit-learn 1.8.0, omitting X asks for neighbors of the indexed points while excluding each indexed point from its own neighborhood. Passing an explicit array asks for those rows as ordinary query points; when that query array matches the training set, the documented example includes each training point itself at distance zero.

That distinction turns a refactor into an identity-review problem. For every returned neighbor, a reviewer must ask: which fitted source record does this returned index identify, and is that record eligible under the declared policy?

Distance alone cannot answer the question. Zero distance can mean either an impermissible self-match or a perfectly legitimate different source row with identical feature coordinates. A genuinely external record can also match a fitted row at distance zero.

The laboratory below fixes that ambiguity with retained row IDs, a source-position manifest, exact one-dimensional brute-force search and an independent scalar distance-and-identity oracle. Its purpose is narrow: reproduce the semantic change, expose two plausible but wrong repairs, rebuild explicit member queries correctly even after reordering, and support an operational ACCEPT, REJECT or HOLD decision. It does not establish entity independence or an unbiased estimate of real-world model quality.

Define the row-exclusion contract before querying

Before inspecting distances, define five objects separately.

Term

Meaning in this laboratory

Fitted source population

The fixed rows passed to fit

Query population

The rows for which neighbors are requested

Row ID

A unique retained identifier such as A or B

Source position

The integer position of that ID in the fitted population

k

The required count of eligible source rows returned per query

The central policy is deliberately row-specific. For a member query, the query represents one known fitted source row. That row's own unique source ID is ineligible; every other source ID remains eligible, including a different row with the same feature value. A valid result must contain exactly k eligible IDs.

For an external query, there is no fitted source row to remove merely because feature values coincide. A zero-distance match can therefore be acceptable.

This is not group isolation. Excluding one fitted row says nothing about whether another row belongs to the same person, device, household or business entity. Refonte Learning's discussion of why group counts and row counts differ makes the corresponding distinction at evaluation-split level: row identity and group identity are different units, and satisfying one contract does not establish the other.

A source row ID is the exclusion unit

Three things that often get conflated must remain separate.

Equal feature values do not make two records the same row. Python object identity does not define the application's source-row identity. And two unique row IDs do not prove that the rows represent independent real-world entities.

In this fixture, the manifest binds source IDs, feature values and fitted ordering by construction. Thus A means a particular retained fitted row, not “whichever row has value 0.” This authored rule is what makes it possible to say that source A should be excluded when querying member A, while source B may remain eligible even if B has exactly the same coordinate.

That is an application policy layered over scikit-learn's API contract. The experiment can verify whether returned fitted positions comply with that row policy. It cannot prove that duplicate-feature records are genuinely independent observations in the underlying business process.

Read the two kneighbors query contracts

The most important branch is visible directly in the scikit-learn 1.8.0 NearestNeighbors.kneighbors contract. When X is omitted, neighbors are requested for each indexed point, and the query point is not considered its own neighbor. The returned integer indices identify points in the fitted population matrix.

So this call:

model.kneighbors(n_neighbors=1)

is not semantically interchangeable with:

model.kneighbors(X_train, n_neighbors=1)

The second expression supplies explicit query rows. The 1.8.0 User Guide demonstrates exactly this pattern with nbrs.kneighbors(X): when the query set matches the training set, the displayed result contains the point itself at distance zero.

The implementation in the 1.8.0 source reinforces the documented distinction. It sets its training-query branch from X is None; in that branch it uses the fitted data, asks for an additional candidate and later removes the indexed sample itself. Explicit X follows the ordinary query path instead.

That is why this is not “automatic self-detection based on equal arrays.” The contract branch is driven by whether the query argument is omitted. The returned indices then refer to the fitted population, not to positions within whatever query batch you supplied.

Omitted X and an explicit array have different meanings

X_train.copy() does not recover the omitted-X contract. It is still an explicit query array.

Likewise, a genuinely external query Q at exactly the same coordinate as fitted source A is not automatically an error. Under an external-query policy, Q → A:0 can be the correct nearest-neighbor result. The API reports geometric proximity; the application decides which source identities are eligible.

Tie handling needs similar discipline. The scikit-learn User Guide warns that behavior at a neighbor boundary can depend on training ordering when distances tie. Therefore an audit should not invent a universal order for equally distant eligible neighbors. It should instead test whether all strictly closer rows are present and whether any boundary row belongs to the permitted tied set.

Capture a small population with independently checkable answers

The first source population has unique one-dimensional coordinates:

Source position

Row ID

Value

0

A

0.0

1

B

2.0

2

C

5.0

3

D

9.0

For this cohort, k=1 makes the self-exclusion effect obvious. Once a member excludes itself, A's nearest eligible row is B at distance 2; C's is B at distance 3.

The second population deliberately contains a feature duplicate:

Source position

Row ID

Value

0

A

0.0

1

B

0.0

2

C

3.0

3

D

7.0

4

E

12.0

Here A and B are distinct source rows under the authored policy. With k=2, querying member A should retain B at distance 0 and C at distance 3. Removing every zero-distance neighbor would therefore be wrong.

Both estimators use dense one-dimensional float64, algorithm="brute", metric="euclidean" and n_jobs=1. The broader ecosystem context (the roles of NumPy, SciPy and scikit-learn) is covered in Refonte Learning's scientific Python library foundations; this experiment does not need a library survey.

The audit intentionally does not call euclidean_distances as its independent oracle. For one-dimensional rows it computes the scalar distance abs(query_value - source_value). Scikit-learn documents Euclidean pairwise distance computation using an efficient dot-product formulation and notes numerical precision limitations, including possible catastrophic cancellation. That is why exact scalar equality in this tiny fixture should not be generalized into a universal floating-point comparison policy.

For identities, the oracle computes all policy-eligible source rows, finds the kth distance cutoff, requires every row strictly closer than that cutoff, and permits any eligible row tied exactly at the boundary. It also checks count, ID uniqueness and each reported distance against the retained source value.

Run the complete twelve-case laboratory

The execution report records a successful baseline execution from 2026-10-28T07:17:06.618316+00:00 through 2026-10-28T07:17:06.647066+00:00, with process exit code 0 and status PASS_12_CASES. Those timestamps are provenance, not a performance benchmark.

The recorded environment is Python 3.12.14, NumPy 2.3.5, SciPy 1.17.0, scikit-learn 1.8.0, joblib 1.5.3 and threadpoolctl 3.6.0 on Linux 6.18.55-x86_64-with-glibc2.39; Python reports Clang 22.1.3. The neighbor settings are brute-force Euclidean search with n_jobs=1. That parameter does not establish that every native thread pool was constrained.

Save the following source exactly as kneighbors_identity_lab.py. The supplied baseline records SHA-256 a2d082f3ed1bc5897fdf25751c885d0254ae1c95b3071d31b2bd04c5200c94f8.

"""Owned, one-dimensional nearest-neighbor identity experiment."""
import hashlib
import json
import platform
import sys
from datetime import datetime, timezone
from pathlib import Path

import numpy as np
import scipy
import sklearn
from sklearn.model_selection import LeaveOneOut
from sklearn.neighbors import KNeighborsClassifier, NearestNeighbors

UNIQUE_IDS = ("A", "B", "C", "D")
UNIQUE_VALUES = (0.0, 2.0, 5.0, 9.0)
DUP_IDS = ("A", "B", "C", "D", "E")
DUP_VALUES = (0.0, 0.0, 3.0, 7.0, 12.0)
qualified_queries = 0


class ContractError(ValueError):
    pass


def require(condition, message):
    if not condition:
        raise AssertionError(message)


def matrix(values):
    return np.asarray(values, dtype=np.float64).reshape(-1, 1)


def fitted(values):
    return NearestNeighbors(algorithm="brute", metric="euclidean", n_jobs=1).fit(matrix(values))


def ledger(query_ids, source_ids, distances, indices):
    return [{"query_id": qid, "neighbors": [source_ids[int(i)] for i in row_i],
             "distances": [float(d) for d in row_d]}
            for qid, row_d, row_i in zip(query_ids, distances, indices, strict=True)]


def audit(rows, query_ids, query_values, source_ids, source_values, k, exclude_self):
    # Scalar one-dimensional distances and ID equality are the independent oracle.
    failures = []
    if [row["query_id"] for row in rows] != list(query_ids):
        return ["query identity/order mismatch"]
    source = dict(zip(source_ids, source_values, strict=True))
    for row, qid, value in zip(rows, query_ids, query_values, strict=True):
        ids, distances = row["neighbors"], row["distances"]
        eligible = [(abs(value - source[sid]), sid) for sid in source_ids
                    if not exclude_self or sid != qid]
        cutoff = sorted(d for d, in eligible)[k - 1]
        required = {sid for d, sid in eligible if d < cutoff}
        allowed = {sid for d, sid in eligible if d <= cutoff}
        if len(ids) != k or len(distances) != k or len(set(ids)) != len(ids):
            failures.append(qid + ": wrong neighbor count or duplicate ID")
        if not required.issubset(ids) or not set(ids).issubset(allowed):
            failures.append(qid + ": wrong eligible neighbor identities")
        for sid, distance in zip(ids, distances):
            if sid not in source or distance != abs(value - source.get(sid, value)):
                failures.append(qid + ": distance/ID disagreement")
    return failures


def memberquery(model, source_ids, source_values, query_ids, query_values, k):
    global qualified_queries
    source = dict(zip(source_ids, source_values, strict=True))
    if len(source) != len(source_ids) or len(set(query_ids)) != len(query_ids):
        raise ContractError("IDs must be unique")
    if len(query_ids) != len(query_values) or not 1 <= k < len(source_ids):
        raise ContractError("Invalid query count or k")
    for qid, value in zip(query_ids, query_values, strict=True):
        if qid not in source:
            raise ContractError("Unknown fitted-row identity")
        if not np.isfinite(value) or value != source[qid]:
            raise ContractError("Query identity/value disagrees with capture record")
    qualified_queries += 1
    distances, indices = model.kneighbors(matrix(query_values), n_neighbors=k + 1)
    rows = []
    for qid, row_d, row_i in zip(query_ids, distances, indices, strict=True):
        pairs = [(source_ids[int(i)], float(d)) for d, i in zip(row_d, row_i)
                 if source_ids[int(i)] != qid][:k]
        rows.append({"query_id": qid, "neighbors": [sid for sid, in pairs],
                     "distances": [distance for , distance in pairs]})
    require(not audit(rows, query_ids, query_values, source_ids, source_values, k, True),
            "Qualified result failed the independent oracle")
    return rows


def run(report):
    require(sklearn.__version__ == "1.8.0", "Use scikit-learn 1.8.0 for this baseline")
    cases = report["cases"]
    model = fitted(UNIQUE_VALUES)
    x = matrix(UNIQUE_VALUES)

    def record(name, rows, query_ids, query_values, source_ids, source_values, k,
               exclude_self, expected_ok, decision):
        errors = audit(rows, query_ids, query_values, source_ids, source_values, k, exclude_self)
        require((not errors) is expected_ok, name + ": unexpected audit decision")
        cases.append({"case": name, "decision": decision, "ledger": rows,
                      "audit_errors": errors})

    d, i = model.kneighbors(n_neighbors=1)
    rows = ledger(UNIQUE_IDS, UNIQUE_IDS, d, i)
    require([r["neighbors"] for r in rows] == [["B"], ["A"], ["B"], ["C"]], "N1 known answer")
    record("N1_implicit_indexed_queries", rows, UNIQUE_IDS, UNIQUE_VALUES,
           UNIQUE_IDS, UNIQUE_VALUES, 1, True, True, "ACCEPT_MEMBER_EXCLUSION")

    for name, query in [("N2_explicit_training_array", x), ("N3_explicit_copy", x.copy())]:
        d, i = model.kneighbors(query, n_neighbors=1)
        rows = ledger(UNIQUE_IDS, UNIQUE_IDS, d, i)
        require([r["neighbors"] for r in rows] == [[sid] for sid in UNIQUE_IDS], name + " self control")
        record(name, rows, UNIQUE_IDS, UNIQUE_VALUES, UNIQUE_IDS, UNIQUE_VALUES,
               1, True, False, "REJECT_SELF_MATCH_FOR_MEMBER_POLICY")

    d, i = model.kneighbors(matrix([0.0]), n_neighbors=1)
    rows = ledger(["Q"], UNIQUE_IDS, d, i)
    require(rows[0]["neighbors"] == ["A"] and rows[0]["distances"] == [0.0], "N4 zero control")
    record("N4_external_query_same_value", rows, ["Q"], [0.0], UNIQUE_IDS,
           UNIQUE_VALUES, 1, False, True, "ACCEPT_EXTERNAL_ZERO_DISTANCE")

    duplicate_model = fitted(DUP_VALUES)
    d, i = duplicate_model.kneighbors(n_neighbors=2)
    rows = ledger(DUP_IDS, DUP_IDS, d, i)
    expected = [{"B", "C"}, {"A", "C"}, {"A", "B"}, {"C", "E"}, {"C", "D"}]
    require([set(row["neighbors"]) for row in rows] == expected, "N5 known identity sets")
    record("N5_distinct_duplicate_rows", rows, DUP_IDS, DUP_VALUES, DUP_IDS,
           DUP_VALUES, 2, True, True, "ACCEPT_DISTINCT_ZERO_DISTANCE_NEIGHBOR")

    dropped = [{"query_id": row["query_id"],
                "neighbors": [sid for sid, distance in zip(row["neighbors"], row["distances"]) if distance > 0],
                "distances": [distance for distance in row["distances"] if distance > 0]}
               for row in rows]
    record("N6_drop_all_zero_distances", dropped, DUP_IDS, DUP_VALUES, DUP_IDS,
           DUP_VALUES, 2, True, False, "REJECT_DISTINCT_ROW_LOSS")

    repaired = member_query(duplicate_model, DUP_IDS, DUP_VALUES, DUP_IDS, DUP_VALUES, 2)
    record("N7_explicit_identity_filter", repaired, DUP_IDS, DUP_VALUES, DUP_IDS,
           DUP_VALUES, 2, True, True, "ACCEPT_IDENTITY_AWARE_REBUILD")

    reordered_ids = ("C", "A", "D", "B")
    reordered_values = (5.0, 0.0, 9.0, 2.0)
    d, i = model.kneighbors(matrix(reordered_values), n_neighbors=2)
    wrong = []
    for position, (qid, row_d, row_i) in enumerate(zip(reordered_ids, d, i, strict=True)):
        pairs = [(UNIQUE_IDS[int(j)], float(distance)) for distance, j in zip(row_d, row_i)
                 if int(j) != position][:1]
        wrong.append({"query_id": qid, "neighbors": [sid for sid, in pairs],
                      "distances": [distance for , distance in pairs]})
    record("N8_drop_query_position", wrong, reordered_ids, reordered_values, UNIQUE_IDS,
           UNIQUE_VALUES, 1, True, False, "REJECT_POSITION_AS_IDENTITY")

    repaired = member_query(model, UNIQUE_IDS, UNIQUE_VALUES, reordered_ids, reordered_values, 1)
    record("N9_reordered_identity_filter", repaired, reordered_ids, reordered_values, UNIQUE_IDS,
           UNIQUE_VALUES, 1, True, True, "ACCEPT_REORDERED_MEMBER_QUERIES")

    for name, ids, values, expected_message in [
        ("N10_unknown_member_id", ("Q",), (0.0,), "Unknown fitted-row identity"),
        ("N11_identity_value_mismatch", ("B",), (0.0,), "Query identity/value disagrees with capture record"),
    ]:
        before = qualified_queries
        try:
            member_query(model, UNIQUE_IDS, UNIQUE_VALUES, ids, values, 1)
        except ContractError as error:
            require(str(error) == expected_message, name + ": wrong rejection")
        else:
            raise AssertionError(name + ": expected rejection missing")
        require(qualified_queries == before, name + ": rejected input reached query")
        cases.append({"case": name, "decision": "HOLD_BEFORE_MEMBER_QUERY",
                      "reason": expected_message, "query_called": False})

    labels = np.array([0, 1, 0, 1])
    classifier = KNeighborsClassifier(n_neighbors=1, algorithm="brute", metric="euclidean", n_jobs=1).fit(x, labels)
    explicit_predictions = classifier.predict(x)
    implicit_predictions = classifier.predict(None)
    require(explicit_predictions.tolist() == [0, 1, 0, 1], "N12 explicit known answer")
    require(implicit_predictions.tolist() == [1, 0, 1, 0], "N12 implicit known answer")
    loo_predictions = []
    for train, test in LeaveOneOut().split(x):
        fold = KNeighborsClassifier(n_neighbors=1, algorithm="brute", metric="euclidean", n_jobs=1)
        fold.fit(x[train], labels[train])
        loo_predictions.append(int(fold.predict(x[test])[0]))
    require(loo_predictions == implicit_predictions.tolist(), "N12 leave-one-out control")
    require(classifier.score(x, labels) == 1.0 and classifier.score(None, labels) == 0.0,
            "N12 score observations")
    cases.append({"case": "N12_downstream_classification_control", "decision": "DO_NOT_LABEL_TRAINING_SCORE_AS_HELD_OUT",
                  "explicit_predictions": explicit_predictions.tolist(),
                  "implicit_predictions": implicit_predictions.tolist(), "loo_predictions": loo_predictions,
                  "explicit_score": 1.0, "implicit_score": 0.0})
    require(len(cases) == 12 and qualified_queries == 2, "Wrong case/query count")
    report["qualified_query_calls"] = qualified_queries
    report["status"] = "PASS_12_CASES"


if name == "__main__":
    report = {"status": "FAIL", "started_utc": datetime.now(timezone.utc).isoformat(),
              "source_sha256": hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
              "runtime": {"python": sys.version, "numpy": np.__version__, "scipy": scipy.__version__,
                          "scikit_learn": sklearn.__version__, "platform": platform.platform()},
              "baseline": {"unique_ids": UNIQUE_IDS, "unique_values": UNIQUE_VALUES,
                           "duplicate_ids": DUP_IDS, "duplicate_values": DUP_VALUES,
                           "metric": "euclidean", "algorithm": "brute", "n_jobs": 1}, "cases": []}
    try:
        run(report)
    except Exception as error:
        report["failure"] = {"type": type(error).__name__, "message": str(error)}
    report["finished_utc"] = datetime.now(timezone.utc).isoformat()
    print(json.dumps(report, indent=2, allow_nan=False))
    sys.exit(0 if report["status"] == "PASS_12_CASES" else 1)

Assuming python3.12 is a Python 3.12.14 interpreter, reproduce the pinned dependency environment and capture the evidence JSON with:

python3.12 -m venv .venv-kneighbors
.venv-kneighbors/bin/python -m pip install numpy==2.3.5 scipy==1.17.0 scikit-learn==1.8.0 joblib==1.5.3 threadpoolctl==3.6.0
.venv-kneighbors/bin/python kneighbors_identity_lab.py > neighbors-evidence.json

The script itself enforces scikit-learn 1.8.0 and records the runtime, source hash, source manifests, case ledgers and decisions. A different Python patch release or dependency combination is a new environment, even when results agree.

PASS_12_CASES does not mean that twelve neighbor outputs were accepted. It means the positive controls, intentionally wrong repairs, pre-query holds and classifier comparator all behaved according to their declared assertions. In particular, N2, N3, N6 and N8 are supposed to expose rejected results.

Reproduce the self-match introduced by an explicit training query

N1 establishes the member-query control on the unique cohort.

With omitted X and k=1, the supplied execution records:

Query member

Returned source

Distance

A

B

2

B

A

2

C

B

3

D

C

4

That is consistent with the documented omitted-query behavior: an indexed point is not considered its own neighbor.

N2 makes one syntactic change: it supplies the fitted feature matrix explicitly. All four queries now return their corresponding source row at distance zero: A→A:0, B→B:0, C→C:0, D→D:0. This is also consistent with the 1.8.0 User Guide's explicit-training-array example.

N3 then queries x.copy(). The result does not revert to N1. It reproduces the same four self-matches.

That rules out several weak review checks. Equal shape is not evidence that query semantics stayed constant. Equal feature values are not evidence that the same exclusion rule ran. A copied array is not a hidden signal for “these rows are fitted members.” And “the code still runs without exceptions” says nothing about whether the returned source records satisfy the authored member policy.

The correct question is not “did the array change?” It is “did the call move from the indexed-member contract to the explicit-query contract?”

Keep legitimate zero-distance neighbors

N4 prevents the opposite mistake: declaring every zero-distance result invalid.

The query is external ID Q with value 0.0; the fitted population still contains source A at 0.0. The observed result is Q→A:0. Because Q is not claiming to be a fitted member, there is no source ID Q to exclude. Under the declared external-query policy, that zero-distance result is accepted.

N5 makes the distinction sharper. In the duplicate-feature cohort, source rows A and B both have value 0.0, but they have separate retained row IDs. For member A, self-exclusion removes A, not every source at coordinate zero. B therefore remains the nearest eligible row at zero distance.

That policy is compatible with the broader need to define duplicates at the correct data grain: equal-looking records, repeated events and genuinely redundant duplicates are not interchangeable categories, and indiscriminate deletion can erase valid observations.

Equal coordinates do not make two source IDs the same row

The supplied N5 ledger records:

A→{B:0, C:3}
B→{A:0, C:3}
C→{A:3, B:3}
D→{C:4, E:5}
E→{D:5, C:9}

Braces matter for C. Both A and B are distance 3, so the oracle treats {A, B} as the required eligible set for k=2; it does not use an undocumented tie ordering as evidence.

For A and B, however, the zero-distance identity point is unambiguous: A→B:0 and B→A:0 are acceptable because each returned source ID differs from the queried member ID.

This does not claim that two equal-feature records should always be treated as independent. It says only that this laboratory's row-eligibility contract permits them. A production dataset needs a separately authored rule for customers, devices, sessions, repeated measurements or other dependence structures.

Show why deleting all zero distances loses valid records

N6 applies a tempting repair to the already valid N5 output: delete every pair whose distance is zero.

That operation removes B from A's result and removes A from B's result. Each query is left with only C:3.

Two invariants fail at once.

First, membership is wrong. B was an eligible source row for member A, and A was an eligible source row for member B. The post-processing rule deletes valid records because it substitutes a geometric property, distance zero, for the actual exclusion key: source-row identity.

Second, count is wrong. The declared contract requires k=2 eligible neighbors. After deletion, those two rows each have only one.

Requesting additional candidates does not rescue the rule if the subsequent filter still says “throw away all zero distances.” More candidates can compensate for a known number of exclusions only when the exclusion predicate itself is correct. Under this policy, the correct predicate is returned_source_id != queried_member_id.

This distinction is precisely why a kneighbors duplicate zero distance review needs both the distance and identity ledger. From distance alone, A→A:0, A→B:0 and external Q→A:0 look identical numerically. Their eligibility differs because the query identities and returned source identities differ.

Zero is therefore evidence about coordinates, not sufficient evidence of selfhood.

Break the assumption that query position identifies the source row

A second misleading fix works on the original training order and then fails as soon as member queries are reordered.

N8 sends the explicit member batch in this order:

C, A, D, B

with values:

5.0, 0.0, 9.0, 2.0.

The faulty repair assumes that query batch position p identifies fitted source position p, and removes any returned fitted index equal to that batch offset.

But scikit-learn's returned neighbor indices refer to the fitted population matrix. They are not indices into the query batch.

The source manifest remains:

0→A, 1→B, 2→C, 3→D.

The query batch has a different mapping:

0→C, 1→A, 2→D, 3→B.

N8's position filter is therefore comparing integers from different coordinate systems. The supplied execution shows the practical consequence: all four reordered member queries still return their own fitted source row at distance zero. The intended self-match survives.

Source positions and query positions belong to different arrays

Take query C.

Within the reordered query batch, C is at position 0.

Within the fitted source population, C is at source position 2.

If an explicit query for value 5.0 returns fitted index 2, scikit-learn is telling you that the neighbor is source ID C. Removing fitted index 0 because the query happened to occupy batch row 0 removes or ignores the wrong identity.

The safe sequence is therefore:

1.     Interpret every returned integer through the fitted-source manifest.

2.     Recover the corresponding stable source ID.

3.     Compare that ID with the member ID attached to the query row.

4.     Remove only the source row whose ID equals the queried member ID.

Reordering queries is harmless when identity metadata moves with them. It becomes dangerous when software treats transient batch offsets as though they were stable source identities.

Rebuild explicit member queries with an ID-aware filter

N7 and N9 demonstrate the accepted repair implemented by member_query.

For a validated member request, the helper knows which unique source ID the query represents. It asks the explicit kneighbors call for k+1 candidates, maps every returned fitted index through source_ids, removes only the pair whose mapped source ID equals the queried member ID, and retains the first k remaining candidates.

Why is k+1 sufficient in this laboratory? Because IDs are unique and the policy excludes at most one fitted source row: the one row carrying the queried member's own ID. There can be many equal-feature records, but they are not excluded merely for sharing a coordinate.

This is not a general bound for group exclusion, entity exclusion or any policy that can invalidate multiple source rows.

N7 applies the repair to the duplicate-feature cohort. Its eligible IDs and distances match N5: in particular, A retains B:0, and B retains A:0. The repair solves self-exclusion without converting distance zero into a deletion rule.

N9 applies the same method to the reordered member batch and records:

Query

Accepted neighbor

Distance

C

B

3

A

B

2

D

C

4

B

A

2

The result follows query identity, not query position.

The independent audit then checks more than an example-specific expected ordering. For each query it computes all eligible source IDs, requires every candidate strictly inside the kth-distance boundary, allows eligible ties at that boundary, verifies exactly k unique IDs and recomputes each reported one-dimensional distance independently.

That tie-aware comparison matters. The User Guide explicitly warns that equal-distance boundary behavior can depend on source ordering. A robust audit should therefore verify the allowed identity set and distances rather than pretending one tied sequence is universally mandated.

The key operational pattern is thus request enough candidates, map fitted indices to retained identities, exclude by identity, then audit the reconstructed result.

Hold malformed member requests before the neighbor query

Identity-aware filtering is only meaningful if the request has qualified as a member query.

The wrapper first verifies that fitted source IDs are unique and that query IDs are unique within the requested batch. It requires query ID and query value counts to match, and requires 1 <= k < len(source_ids).

For each member query, it then checks three properties before calling kneighbors: the ID must exist in the retained fitted-member manifest, the one-dimensional value must be finite, and the supplied value must equal the value retained for that ID.

Those guards are intentionally narrow. They support this fixed laboratory and its retained manifest; they are not a general validation framework.

N10 exercises the unknown-ID control. Query ID Q is presented as a member even though no fitted source row carries ID Q. The wrapper raises Unknown fitted-row identity, records HOLD_BEFORE_MEMBER_QUERY, and no qualified neighbor query is run.

N11 uses known ID B but supplies value 0.0 rather than its captured unique-cohort value 2.0. It raises Query identity/value disagrees with capture record, again before the member query is issued.

The execution report records qualified_query_calls=2. That count refers only to successful calls through the member_query wrapper: N7 and N9. It does not count all direct kneighbors calls elsewhere in the script. N10 and N11 do not increment it because they stop before querying.

Validate the retained one-dimensional manifest within its limits

Passing these checks is not proof that an arbitrary estimator and metadata file share authentic provenance.

The laboratory assumes that source_ids, source_values, their ordering and the fitted model remain bound together as constructed. The helper does not cryptographically authenticate an arbitrary estimator, detect every mutation of a source matrix, reconstruct a lost preprocessing state or validate a multidimensional feature-generation pipeline.

Likewise, exact value != source[qid] comparison is reasonable for the deliberately chosen small float64 fixture but should not be promoted to a universal numerical identity policy. Scikit-learn itself documents numerical limitations in generic pairwise Euclidean calculations.

Finally, a genuinely external Q should not be forced through this member-only contract. External queries have no fitted source member to exclude merely because a coordinate matches.

Interpret the classifier consequence without claiming model quality

N12 keeps the classifier comparison deliberately small.

A one-neighbor KNeighborsClassifier is fit on the unique cohort with labels [0, 1, 0, 1]. The supplied baseline records:

Query mode

Predictions

Score

Explicit predict(x)

[0, 1, 0, 1]

1.0

Indexed predict(None)

[1, 0, 1, 0]

0.0

Explicit LeaveOneOut refits

[1, 0, 1, 0]

Not reported

Scikit-learn 1.8.0 documents predict(None) as producing predictions for the indexed points while not considering each point its own neighbor. Its score(None, y) documentation specifically describes estimator-level leave-one-out behavior.

The explicit comparator independently refits one classifier per LeaveOneOut split. The LeaveOneOut contract uses each sample once as the singleton test set while all remaining samples form that fold's training set; its groups argument is ignored, so it should not be mistaken for group isolation.

In this constructed fixture, the explicit refits produce the same predictions as the indexed predict(None) path. That is a useful control for this estimator-level behavior, not a population-performance result.

For realistic split design, baselines, leakage controls and uncertainty, the relevant broader resource is Refonte Learning's guide to defensible machine-learning evaluation, which explicitly separates training performance from evidence on appropriately unseen data.

Estimator-level exclusion does not validate the complete pipeline

There is no learned preprocessing in N12. There is no grouped population, temporal dependence, feature-selection stage, hyperparameter search or protected final test set.

Consequently, neither 1.0 nor 0.0 should be read as an estimate of deployment accuracy. The fixture was intentionally chosen so that self-use changes the classifier outcome sharply enough to expose the query-mode consequence.

The documentation's leave-one-out equivalence applies at the estimator operation it describes. It does not, by itself, show that upstream preprocessing was fit without leakage, that repeated entities are isolated, that model-selection decisions were independent of the evaluated rows or that leave-one-out is an appropriate production validation strategy. LeaveOneOut itself can require as many splits as samples and the documentation notes that it can be costly for large datasets.

The article's central question remains narrower: which fitted source row was allowed to act as a neighbor?

Recover the result from retained source records

Once a neighbor artifact is rejected for self-use or incorrect filtering, do not patch the already truncated output and assume the missing information can be inferred.

Recovery begins from retained source evidence:

1.     Stop downstream use of the rejected neighbor result.

2.     Preserve that rejected ledger for audit rather than overwriting it.

3.     Recover the model together with the bound source-ID ordering and retained source feature values.

4.     Determine whether each intended query is a fitted member or an external record.

5.     For member queries, reconstruct the query values from the preserved source record when necessary, issue the qualified identity-aware query, and audit its IDs, count and distances.

6.     Replace downstream artifacts only after the rebuilt ledger satisfies the declared policy.

Rerunning from preserved source records is especially important after N6-style damage. If a previous stage requested too few candidates and then deleted a valid zero-distance row, an already truncated list contains no information about candidates that were never returned. You cannot reconstruct an unseen source ID merely by inspecting the survivors.

The same applies to identity/value disagreement. When an incoming member ID says B but its supplied features do not match the retained source record, the correct response is HOLD, not silently filtering whichever explicit query happened to arrive. If the intent really is “rerun fitted member B,” reconstruct the query from the retained B record and record that reconstruction as the source of the query.

A rollback is different. Restoring a previously accepted query configuration or artifact can be appropriate when its semantics still match the current policy. Rollback does not retroactively make the rejected self-matching result valid.

Recovery therefore depends on retaining source features, IDs, ordering and enough model provenance to reproduce the intended query semantics.

Decide whether to accept, reject or hold the output

A reviewer should make the eligibility decision from query mode, source mapping, count, identity and independently checked distance, rather than from a single distance-zero heuristic.

Case

Evidence

Operating decision

N1

Omitted X; each indexed member excludes itself

ACCEPT: member exclusion

N2

Explicit training array returns each source row itself

REJECT: self-match for member policy

N3

Explicit copy has the same self-matches

REJECT: copying does not restore indexed semantics

N4

External Q legitimately matches A at distance 0

ACCEPT: external zero distance

N5

Distinct A/B rows remain eligible at distance 0

ACCEPT: distinct zero-distance neighbor

N6

All zero distances removed; valid row and count lost

REJECT: distinct-row loss

N7

k+1, source-ID mapping, remove only queried ID

ACCEPT: identity-aware rebuild

N8

Query batch position confused with fitted position

REJECT: position is not identity

N9

Reordered queries filtered using retained member IDs

ACCEPT: reordered member queries

N10

Claimed member ID absent from fitted manifest

HOLD: resolve identity before querying

N11

Member ID/value disagrees with retained record

HOLD: reconcile source record before querying

N12

Training query modes produce different classifier results

Do not label training score as held-out performance

For a member result to be accepted under this laboratory's policy, the reviewer should be able to establish all of the following: the request is actually a fitted-member query; returned integer indices have been interpreted against the fitted-source manifest; the queried member's own unique source ID is absent; exactly k eligible IDs remain; distinct permitted zero-distance rows have not been discarded; and each distance agrees with the independent scalar oracle, allowing any eligible tied row at the kth-distance boundary.

Responsibility should be explicit. A data or evaluation reviewer owns the eligibility policy: what counts as “self,” and whether other source rows are permissible. The implementer owns the model/manifest binding, index-to-ID conversion and evidence capture. Neither role should infer the other's contract from numeric distances alone.

ACCEPT therefore means “this output satisfies the declared row-level contract in the recorded scope.” It does not mean the rows are independent real-world entities, the model is unbiased or the evaluation design is otherwise production-ready.

Build the review skills behind reliable neighbor workflows

The larger skill is not memorizing a special-case filter. It is learning to separate API semantics, source identity, numerical evidence and evaluation policy, then preserve enough provenance to reproduce the decision. Refonte Learning's broader guide to reproducible data-science practice places Python, numerical computing and machine-learning tools within that wider working toolkit.

For structured study, Refonte Learning's Data Science & AI program currently lists Python Data Science, statistical modelling, machine learning and predictive modelling, model optimization/problem solving, exploratory data analysis and visualization, and application to industry projects among its competencies. Its FAQ names Python, Jupyter Notebook, Pandas, NumPy, Matplotlib, scikit-learn and TensorFlow. Program Specifics states a three-month period and 12 to 14 hours per week.

Those published competencies align with the skills this review demands, but the page does not establish that this exact kneighbors identity laboratory or scikit-learn 1.8.0 baseline is part of the current syllabus. The page also contains differing prerequisite language between Program Specifics and its FAQ, so current applicants should verify the syllabus and admission terms directly.

A useful question for any current project-based curriculum is whether learners must preserve row identities, reconstruct source-position mappings and defend model outputs with reproducible evidence, rather than merely obtain a successful prediction call.