Space-Risk-Intelligence-API / app /feature_engineering.py
Adisri99's picture
Upload 24 files
9e6ee24 verified
raw
history blame
3.37 kB
from app.utils import safe_float, safe_int
FEATURE_COLUMNS = [
"delta_mean_motion","delta_inclination","delta_eccentricity","delta_raan","delta_bstar",
"launch_year_gap","same_object_type","same_shell","shell_density_proxy","close_approach_proxy",
"persistence_proxy","recurrence_count","trend_delta_score","score_volatility_proxy",
"graph_degree_sum","graph_common_neighbors","graph_jaccard","graph_local_density",
]
def normalize_object(raw):
name = raw.get("OBJECT_NAME") or raw.get("object_name") or "UNKNOWN"
norad = raw.get("NORAD_CAT_ID") or raw.get("norad_cat_id")
intl = raw.get("OBJECT_ID") or raw.get("object_id") or ""
launch_year = int(intl[:4]) if len(intl) >= 4 and intl[:4].isdigit() else None
return {
"object_id": str(norad or name),
"norad_cat_id": safe_int(norad, 0) or None,
"object_name": name,
"object_type": raw.get("OBJECT_TYPE") or raw.get("object_type"),
"mean_motion": safe_float(raw.get("MEAN_MOTION") or raw.get("mean_motion")),
"inclination": safe_float(raw.get("INCLINATION") or raw.get("inclination")),
"eccentricity": safe_float(raw.get("ECCENTRICITY") or raw.get("eccentricity")),
"raan": safe_float(raw.get("RA_OF_ASC_NODE") or raw.get("raan")),
"bstar": safe_float(raw.get("BSTAR") or raw.get("bstar")),
"launch_year": launch_year,
}
def orbital_shell_key(obj):
mm = safe_float(obj.get("mean_motion"))
inc = safe_float(obj.get("inclination"))
ecc = safe_float(obj.get("eccentricity"))
return f"mm:{int(mm)}|inc:{int(inc//5)*5}|ecc:{int(ecc*1000)//10}"
def base_pair_features(a, b):
mm1, mm2 = safe_float(a.get("mean_motion")), safe_float(b.get("mean_motion"))
inc1, inc2 = safe_float(a.get("inclination")), safe_float(b.get("inclination"))
ecc1, ecc2 = safe_float(a.get("eccentricity")), safe_float(b.get("eccentricity"))
raan1, raan2 = safe_float(a.get("raan")), safe_float(b.get("raan"))
b1, b2 = safe_float(a.get("bstar")), safe_float(b.get("bstar"))
ly1, ly2 = safe_int(a.get("launch_year")), safe_int(b.get("launch_year"))
same_type = 1 if (a.get("object_type") or "") == (b.get("object_type") or "") else 0
same_shell = 1 if orbital_shell_key(a) == orbital_shell_key(b) else 0
delta_mm = abs(mm1 - mm2)
delta_inc = abs(inc1 - inc2)
delta_ecc = abs(ecc1 - ecc2)
delta_raan = abs(raan1 - raan2)
delta_bstar = abs(b1 - b2)
launch_gap = abs(ly1 - ly2) if ly1 and ly2 else 25
shell_density_proxy = max(0.0, 10.0 - delta_mm) + max(0.0, 8.0 - delta_inc / 2.0)
close_approach_proxy = 1.0 / (1.0 + delta_mm + delta_inc / 10.0 + delta_ecc * 50.0 + delta_raan / 60.0)
persistence_proxy = 1.0 if same_shell else 0.25
return {
"delta_mean_motion": delta_mm,
"delta_inclination": delta_inc,
"delta_eccentricity": delta_ecc,
"delta_raan": delta_raan,
"delta_bstar": delta_bstar,
"launch_year_gap": float(launch_gap),
"same_object_type": float(same_type),
"same_shell": float(same_shell),
"shell_density_proxy": float(shell_density_proxy),
"close_approach_proxy": float(close_approach_proxy),
"persistence_proxy": float(persistence_proxy),
}
def combine_features(a, b, trend, graph):
return {**base_pair_features(a, b), **trend, **graph}