Space-Risk-Intelligence-API / app /feature_engineering.py
Adisri99's picture
Upload 26 files
1ce499f verified
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"]
FEATURE_LABELS={"delta_mean_motion":"Mean motion difference","delta_inclination":"Inclination difference","delta_eccentricity":"Eccentricity difference","delta_raan":"RAAN difference","delta_bstar":"BSTAR difference","launch_year_gap":"Launch year gap","same_object_type":"Same object type","same_shell":"Same orbital shell","shell_density_proxy":"Shell density proxy","close_approach_proxy":"Close approach proxy","persistence_proxy":"Persistence proxy","recurrence_count":"Recurrence count","trend_delta_score":"Trend delta","score_volatility_proxy":"Score volatility","graph_degree_sum":"Graph degree sum","graph_common_neighbors":"Common neighbors","graph_jaccard":"Graph jaccard","graph_local_density":"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}