Spaces:
Sleeping
Sleeping
File size: 5,287 Bytes
1aebf33 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | """Graduated title-fit scoring.
Combines:
- exact role-group match on current and historical titles
- embedding cosine of current title to the centroid of target titles
- promotion velocity / role progression features
"""
from __future__ import annotations
import re
from typing import List
import numpy as np
import pandas as pd
from .. import config
def _normalise(title: str) -> str:
t = (title or "").lower()
t = re.sub(r"[^a-z0-9+\-# ]+", " ", t)
t = re.sub(r"\s+", " ", t).strip()
return t
def _title_group(title_norm: str) -> str | None:
best = None
for group, members in config.TITLE_ROLE_GROUPS.items():
for m in members:
if m in title_norm:
if best is None or config.TITLE_GROUP_WEIGHT[group] > config.TITLE_GROUP_WEIGHT[best]:
best = group
return best
def title_fit_features(df: pd.DataFrame) -> pd.DataFrame:
"""Return a DataFrame of per-candidate title features."""
current = df["current_title"].fillna("").tolist()
histories = df["career_titles"].tolist()
# Pre-compute best historical group across all rows
current_groups = [_title_group(_normalise(t)) for t in current]
history_groups: List[List[str]] = []
history_max_weight: List[float] = []
for hist in histories:
if hist is None:
hist = []
if hasattr(hist, "tolist"):
hist = hist.tolist()
gs = [_title_group(_normalise(t)) for t in (hist or [])]
gs = [g for g in gs if g is not None]
history_groups.append(gs)
if gs:
history_max_weight.append(max(config.TITLE_GROUP_WEIGHT[g] for g in gs))
else:
history_max_weight.append(0.0)
# Per-row title features
current_weight = [config.TITLE_GROUP_WEIGHT.get(g, 0.05) for g in current_groups]
is_target = [1.0 if (g in {"applied_ml", "retrieval_ranking", "nlp_llm"}) else 0.0 for g in current_groups]
is_services_or_noneng = [1.0 if g in {"non_target"} else 0.0 for g in current_groups]
is_data_platform = [1.0 if g in {"data_platform"} else 0.0 for g in current_groups]
is_data_science = [1.0 if g in {"data_science"} else 0.0 for g in current_groups]
is_generic_swe = [1.0 if g in {"generic_swe"} else 0.0 for g in current_groups]
# Promotion velocity: number of distinct titles / yoe (low if many short stints)
n_titles = []
for h in histories:
if h is None:
n_titles.append(0)
elif hasattr(h, "tolist"):
n_titles.append(len(h.tolist()))
else:
n_titles.append(len(h))
avg_tenure_months = []
for ch in df["career"].tolist():
if ch is None:
avg_tenure_months.append(0.0)
continue
if hasattr(ch, "tolist"):
ch = ch.tolist()
if not ch:
avg_tenure_months.append(0.0)
continue
durs = [int(c.get("duration_months") or 0) for c in (ch or [])]
durs = [d for d in durs if d > 0]
if durs:
avg_tenure_months.append(sum(durs) / len(durs))
else:
avg_tenure_months.append(0.0)
out = pd.DataFrame({
"title_weight": current_weight,
"title_history_max_weight": history_max_weight,
"is_target_title": is_target,
"is_noneng_title": is_services_or_noneng,
"is_data_platform": is_data_platform,
"is_data_science": is_data_science,
"is_generic_swe": is_generic_swe,
"n_career_titles": n_titles,
"avg_tenure_months": avg_tenure_months,
# blended title fit (current 70%, history 30%)
"title_fit_blend": [
0.7 * w + 0.3 * hw for w, hw in zip(current_weight, history_max_weight)
],
})
return out
# ---------------------------------------------------------------------------
# Company tier (0-3)
# ---------------------------------------------------------------------------
def _company_tier(name: str) -> int:
"""Map company name to tier. 3=FAANG+top-AI, 2=strong product, 1=other, 0=unknown."""
name = (name or "").strip()
if not name:
return 0
nl = name.lower()
for tier in (3, 2):
for c in config.COMPANY_TIER.get(tier, set()):
if c.lower() in nl or nl in c.lower():
return tier
# IT services
for svc in config.IT_SERVICES_PURE_PLAY:
if svc.lower() in nl:
return 0
return 1 # unknown product/startup
def company_tier_features(df: pd.DataFrame) -> pd.DataFrame:
"""Company tier features: current tier, max tier across career, top-tier flags."""
def _tier_from_list(lst):
if lst is None:
return []
if hasattr(lst, "tolist"):
lst = lst.tolist()
return [_company_tier(c) for c in (lst or [])]
current_tier = [_company_tier(c) for c in df["current_company"].fillna("").tolist()]
max_tiers = [max(_tier_from_list(lst)) for lst in df["career_companies"].tolist()]
return pd.DataFrame({
"company_tier_current": current_tier,
"company_tier_max": max_tiers,
"is_top_tier_company": [1 if t >= 3 else 0 for t in max_tiers],
"is_product_company_v2": [1 if t >= 1 else 0 for t in max_tiers],
})
|