diff --git a/prediction/algorithms/pair_trawl.py b/prediction/algorithms/pair_trawl.py index 683fb72..d2e21d7 100644 --- a/prediction/algorithms/pair_trawl.py +++ b/prediction/algorithms/pair_trawl.py @@ -390,7 +390,7 @@ def _trajectory_similarity( # bbox 1차 탐색 반경 (도 단위) BBOX_DEG = 0.01 # 약 1.1km — 주변 후보만 컷 SIMILARITY_PAIR = 0.70 # 유력 페어 -SIMILARITY_OBSERVE = 0.50 # 관찰 페어 +SIMILARITY_OBSERVE = 0.45 # 관찰 페어 (0.50 → 0.45 완화: pool 확대 후 recall 확보) def find_pair_candidates( diff --git a/prediction/scheduler.py b/prediction/scheduler.py index 91e39f1..abe0e49 100644 --- a/prediction/scheduler.py +++ b/prediction/scheduler.py @@ -212,15 +212,28 @@ def run_analysis_cycle(): pt_sub_registered: set[str] = set() # TODO: fishery_code=PT-S 구분 base_mmsis: set[str] = {c['mmsi'] for c in classifications} base_mmsis |= pt_registered - - # pool은 전체 24h 누적 tracks (중국 어선 중심 8k+ 선박) + # 조업 속력대(1.5~5.0kn)에서 움직이는 모든 중국 선박을 base로 확장. + # classifications 500척만으로는 bbox 기점이 부족해 실제 공조 페어를 놓침. pool_tracks = getattr(vessel_store, '_tracks', {}) or vessel_dfs + for mmsi, df in pool_tracks.items(): + if not mmsi.startswith('412'): + continue + if df is None or df.empty or 'sog' not in df.columns: + continue + try: + mean_sog = float(df['sog'].tail(12).mean()) + if 1.5 <= mean_sog <= 5.0: + base_mmsis.add(mmsi) + except Exception: + continue + pair_candidates = find_pair_candidates( base_mmsis=base_mmsis, vessel_dfs=pool_tracks, get_vessel_info=vessel_store.get_vessel_info, pt_registered=pt_registered, pt_sub_registered=pt_sub_registered, + min_common_samples=4, ) pt_det = 0; coop_det = 0 for cand in pair_candidates: