Skip to content

reach.overlap

Rank and analyze lexical overlap between skill descriptions using BM25.

Rank and analyze lexical overlap between skill descriptions using BM25.

Competition

Bases: BaseModel

Summarize lexical competition against a target skill across the corpus.

Source code in src/reach/overlap.py
class Competition(BaseModel):
    """Summarize lexical competition against a target skill across the corpus."""

    model_config = ConfigDict(frozen=True)

    rivals: tuple[Rival, ...] = ()
    self_score: float
    skill: str

    _ranked: tuple[Rival, ...] = PrivateAttr()

    @override
    def model_post_init(self, _context: object) -> None:
        """Cache pre-sorted rivals after initialization."""
        object.__setattr__(
            self,
            "_ranked",
            tuple(sorted(self.rivals, key=lambda r: (-r.score, r.name))),
        )

    @property
    def ranked_rivals(self) -> tuple[Rival, ...]:
        """Return rivals sorted by descending score, then ascending name."""
        return self._ranked

    @property
    def outranked_by(self) -> int:
        """Count the number of rivals with a score strictly higher than self_score."""
        return sum(1 for rival in self.rivals if rival.score > self.self_score)

    @property
    def nearest_rival(self) -> Rival | None:
        """Return the top-scoring rival, or None if no rivals exist."""
        return self._ranked[0] if self._ranked else None

    @property
    def scoring_rival(self) -> Rival | None:
        """Return the top rival only if it has a non-zero overlap score."""
        nearest = self.nearest_rival
        return nearest if nearest is not None and nearest.score > 0 else None

    @property
    def rival_ratio(self) -> float:
        """Calculate the nearest rival's score relative to the target's self score."""
        nearest = self.nearest_rival
        if nearest is None:
            return 0.0
        if self.self_score > 0:
            return nearest.score / self.self_score
        return math.inf if nearest.score > 0 else 0.0

    @property
    def standings(self) -> tuple[Standing, ...]:
        """Return full competition standings including target skill placement."""
        seats = list(self.ranked_rivals)
        placed: list[tuple[str, float, bool]] = [(r.name, r.score, False) for r in seats]
        placed.insert(self.outranked_by, (self.skill, self.self_score, True))
        return tuple(
            Standing(rank=i, name=name, score=score, is_target=is_target)
            for i, (name, score, is_target) in enumerate(placed, start=1)
        )

nearest_rival property

nearest_rival: Rival | None

Return the top-scoring rival, or None if no rivals exist.

outranked_by property

outranked_by: int

Count the number of rivals with a score strictly higher than self_score.

ranked_rivals property

ranked_rivals: tuple[Rival, ...]

Return rivals sorted by descending score, then ascending name.

rival_ratio property

rival_ratio: float

Calculate the nearest rival's score relative to the target's self score.

scoring_rival property

scoring_rival: Rival | None

Return the top rival only if it has a non-zero overlap score.

standings property

standings: tuple[Standing, ...]

Return full competition standings including target skill placement.

model_post_init

model_post_init(_context: object) -> None

Cache pre-sorted rivals after initialization.

Source code in src/reach/overlap.py
@override
def model_post_init(self, _context: object) -> None:
    """Cache pre-sorted rivals after initialization."""
    object.__setattr__(
        self,
        "_ranked",
        tuple(sorted(self.rivals, key=lambda r: (-r.score, r.name))),
    )

CorpusOverlap

Bases: BaseModel

Hold competition rankings for all skills across the corpus.

Source code in src/reach/overlap.py
class CorpusOverlap(BaseModel):
    """Hold competition rankings for all skills across the corpus."""

    model_config = ConfigDict(frozen=True)

    competitions: tuple[Competition, ...] = ()

    def find(self, skill: str) -> Competition:
        """Retrieve the Competition model for a named skill."""
        for competition in self.competitions:
            if competition.skill == skill:
                return competition
        msg = f"no skill named {skill!r} in this corpus"
        raise ValueError(msg)

find

find(skill: str) -> Competition

Retrieve the Competition model for a named skill.

Source code in src/reach/overlap.py
def find(self, skill: str) -> Competition:
    """Retrieve the Competition model for a named skill."""
    for competition in self.competitions:
        if competition.skill == skill:
            return competition
    msg = f"no skill named {skill!r} in this corpus"
    raise ValueError(msg)

Rival

Bases: BaseModel

Represent a competitor skill and its lexical overlap score.

Source code in src/reach/overlap.py
class Rival(BaseModel):
    """Represent a competitor skill and its lexical overlap score."""

    model_config = ConfigDict(frozen=True)

    name: str
    score: float

Standing

Bases: BaseModel

Represent a skill's ranked standing in a competition field.

Source code in src/reach/overlap.py
class Standing(BaseModel):
    """Represent a skill's ranked standing in a competition field."""

    model_config = ConfigDict(frozen=True)

    is_target: bool
    name: str
    rank: int
    score: float

compete

compete(
    skill: Skill,
    corpus: Sequence[Skill],
    scorer: Bm25Scorer,
) -> Competition

Score a target skill against itself and all other corpus skills.

Source code in src/reach/overlap.py
def compete(skill: Skill, corpus: Sequence[Skill], scorer: Bm25Scorer) -> Competition:
    """Score a target skill against itself and all other corpus skills."""
    query = tokenize(skill_text(skill))
    return Competition(
        skill=skill.name,
        self_score=scorer.score(query, skill.name),
        rivals=tuple(
            Rival(name=c.name, score=scorer.score(query, c.name))
            for c in corpus
            if c.name != skill.name
        ),
    )

rank_corpus

rank_corpus(skills: Sequence[Skill]) -> CorpusOverlap

Compute and rank lexical overlap competition across a corpus of skills.

Source code in src/reach/overlap.py
def rank_corpus(skills: Sequence[Skill]) -> CorpusOverlap:
    """Compute and rank lexical overlap competition across a corpus of skills."""
    scorer = Bm25Scorer.from_skills(skills)
    competitions = [compete(skill, skills, scorer) for skill in skills]
    ordered = sorted(competitions, key=lambda c: (-c.rival_ratio, c.skill))
    return CorpusOverlap(competitions=tuple(ordered))