Corin1998 commited on
Commit
2fc41c7
·
verified ·
1 Parent(s): 95091a6

Update core/external_scoring.py

Browse files
Files changed (1) hide show
  1. core/external_scoring.py +16 -66
core/external_scoring.py CHANGED
@@ -10,6 +10,7 @@ __all__ = [
10
  "score_external_from_df",
11
  ]
12
 
 
13
  _TEMPLATE_ROWS: List[Tuple[str, str]] = [
14
  ("経営者能力", "予実達成率_3年平均(%)"),
15
  ("経営者能力", "監査・内部統制の重大な不備 件数(過去3年)"),
@@ -71,26 +72,22 @@ def fill_missing_with_external(df: pd.DataFrame, suggestions: Dict[str, Any] | N
71
  return df2
72
 
73
  def merge_market_into_external_df(ext_df: pd.DataFrame, market: Dict[str, Any], products: List[str]) -> pd.DataFrame:
74
- """市場推定結果と商品リストをext_dfへ反映"""
75
  df = ext_df.copy()
76
 
77
- def _set(label: str, val):
78
- m = df["入力項目"].eq(label)
79
  if m.any():
80
- df.loc[m, "値"] = val
81
- else:
82
- # 念のため行が無ければ追加
83
- cat = "成長率" if "成長" in label else "安定性"
84
- df = pd.concat([df, pd.DataFrame([[cat, label, val]], columns=df.columns)], ignore_index=True)
85
- return df
86
-
87
- # 市場成長率
88
  if market.get("市場の年成長率(%)") is not None:
89
- df = _set("市場の年成長率(%)", float(market["市場の年成長率(%)"]))
90
 
91
- # 主力商品数 / 成長中主力商品数
92
  prods = [p for p in products if str(p).strip()]
93
- df = _set("主力商品数", len(prods))
94
 
95
  growing = 0
96
  prod_growth: Dict[str, float] = market.get("製品別年成長率(%)") or {}
@@ -100,11 +97,10 @@ def merge_market_into_external_df(ext_df: pd.DataFrame, market: Dict[str, Any],
100
  growing += 1
101
  except Exception:
102
  pass
103
- df = _set("成長中主力商品数", growing)
104
-
105
  return df
106
 
107
- # ===== スコア計算(定量・ばらつき強化) =====
108
  _WEIGHTS = {
109
  ("経営者能力", "経営姿勢"): 8,
110
  ("経営者能力", "事業経験"): 5,
@@ -170,6 +166,7 @@ def _add(items, cat, name, raw, weight, reason):
170
  })
171
 
172
  def score_external_from_df(df: pd.DataFrame) -> Dict[str, Any]:
 
173
  def ref(label: str):
174
  m = df["入力項目"].eq(label)
175
  return df.loc[m, "値"].values[0] if m.any() else None
@@ -252,7 +249,6 @@ def score_external_from_df(df: pd.DataFrame) -> Dict[str, Any]:
252
  _add(items,"成長率","売上高伸長性", _ramp(s_cagr,0.08,-0.05),
253
  _WEIGHTS[("成長率","売上高伸長性")],
254
  f"CAGR売上{round((s_cagr or 0)*100,1) if s_cagr is not None else '—'}%")
255
-
256
  _add(items,"成長率","利益伸長性", _ramp(p_cagr,0.08,-0.05),
257
  _WEIGHTS[("成長率","利益伸長性")],
258
  f"CAGR営業{round((p_cagr or 0)*100,1) if p_cagr is not None else '—'}%")
@@ -282,57 +278,11 @@ def score_external_from_df(df: pd.DataFrame) -> Dict[str, Any]:
282
  _ramp(-(delay_days or 0),0,-30) )/3
283
  rs=f"遅延{int(delay_cnt or 0)}/不渡{int(boun_cnt or 0)}/平均{int(delay_days or 0)}日"
284
  else:
285
- sc=_ramp(cash_to_ms,1.0,0.2); rs=f"代理:現預金/月商≈{round(cash_to_ms,2) if cash_to_ms else '—'}"
286
  _add(items,"安定性","決済振り", sc, _WEIGHTS[("安定性","決済振り")], rs)
287
 
288
  sc_mb = 5.0
289
  sc_mb += 2.0 if mainbank else (-0.5 if mainbank is False else 0)
290
  sc_mb += 1.0 if has_line else 0
291
  sc_mb = _clamp(sc_mb,0,10)
292
- _add(items,"安定性","金融取引", sc_mb, _WEIGHTS[("安定性","金融取引")],
293
- f"メイン{'有' if mainbank else '無' if mainbank is False else '—'}/与信枠{'有' if has_line else '無' if has_line is False else '—'}")
294
-
295
- _add(items,"安定性","資産担保余力", _ramp(coll_to_ms,4.0,0.0),
296
- _WEIGHTS[("安定性","資産担保余力")], f"担保/月商≈{round(coll_to_ms,2) if coll_to_ms else '—'}")
297
-
298
- _add(items,"安定性","取引先",
299
- ( _ramp(-(top1 or 50),0,-80) +
300
- _ramp(cust_score,80,50) +
301
- _ramp(-(npl_cnt or 1),0,-3) )/3,
302
- _WEIGHTS[("安定性","取引先")],
303
- f"上位1社{top1 or '—'}%/信用{cust_score or '—'}/不良{int(npl_cnt or 0)}")
304
-
305
- _add(items,"安定性","業歴", _ramp(years,20,1),
306
- _WEIGHTS[("安定性","業歴")], f"{years or '—'}年")
307
-
308
- # 公平性
309
- sc_dis = 0.0
310
- has_sec = _to_bool(ref("有価証券報告書提出企業か(TRUE/FALSE)"))
311
- sc_dis += 10.0 if has_sec else 0.0
312
- if sc_dis == 0.0:
313
- pub_off = _to_bool(ref("決算公告や官報での公開あり(TRUE/FALSE)"))
314
- pub_web = _to_bool(ref("HP/IRサイトで財務資料公開あり(TRUE/FALSE)"))
315
- sc_dis += 7.0 if (pub_off or pub_web) else 4.0
316
- upd_on = _to_bool(ref("直近更新が定め通りか(TRUE/FALSE)"))
317
- if upd_on: sc_dis += 1.0
318
- sc_dis = _clamp(sc_dis,0,10)
319
- _add(items,"公平性・総合世評","ディスクロージャー", sc_dis,
320
- _WEIGHTS[("公平性・総合世評","ディスクロージャー")],
321
- f"{'有報' if has_sec else '公開あり' if sc_dis>=7.0 else '公開乏しい'} / 更新{'◯' if upd_on else '—'}")
322
-
323
- total = round(sum(x["score"] for x in items),1)
324
-
325
- from collections import defaultdict
326
- cat_sum, cat_w = defaultdict(float), defaultdict(float)
327
- for it in items:
328
- cat_sum[it["category"]] += it["score"]
329
- cat_w[it["category"]] += it["weight"]
330
- cat_scores = {c: round((cat_sum[c] / cat_w[c]) * 100.0 if cat_w[c] > 0 else 0.0, 1) for c in cat_sum}
331
-
332
- return {
333
- "name": "企業評価(外部・定量)",
334
- "external_total": total,
335
- "items": items,
336
- "category_scores": cat_scores,
337
- "notes": "欠損は中立+市場成長/商品構成を反映。ストレッチでばらつきを拡大。",
338
- }
 
10
  "score_external_from_df",
11
  ]
12
 
13
+ # ひな形(+市場成長率系の列を追加)
14
  _TEMPLATE_ROWS: List[Tuple[str, str]] = [
15
  ("経営者能力", "予実達成率_3年平均(%)"),
16
  ("経営者能力", "監査・内部統制の重大な不備 件数(過去3年)"),
 
72
  return df2
73
 
74
  def merge_market_into_external_df(ext_df: pd.DataFrame, market: Dict[str, Any], products: List[str]) -> pd.DataFrame:
75
+ """市場推定結果と商品リストをext_dfへ反映(必ずDataFrameを返す)"""
76
  df = ext_df.copy()
77
 
78
+ def _set(df_: pd.DataFrame, label: str, val: Any, cat_hint: str = "成長率") -> pd.DataFrame:
79
+ m = df_["入力項目"].eq(label)
80
  if m.any():
81
+ df_.loc[m, "値"] = val
82
+ return df_
83
+ # 行がない場合は追加
84
+ return pd.concat([df_, pd.DataFrame([[cat_hint, label, val]], columns=df_.columns)], ignore_index=True)
85
+
 
 
 
86
  if market.get("市場の年成長率(%)") is not None:
87
+ df = _set(df, "市場の年成長率(%)", float(market["市場の年成長率(%)"]), "成長率")
88
 
 
89
  prods = [p for p in products if str(p).strip()]
90
+ df = _set(df, "主力商品数", len(prods), "成長率")
91
 
92
  growing = 0
93
  prod_growth: Dict[str, float] = market.get("製品別年成長率(%)") or {}
 
97
  growing += 1
98
  except Exception:
99
  pass
100
+ df = _set(df, "成長中主力商品数", growing, "成長率")
 
101
  return df
102
 
103
+ # ===== スコア計算(定量化+ばらつきストレッチ) =====
104
  _WEIGHTS = {
105
  ("経営者能力", "経営姿勢"): 8,
106
  ("経営者能力", "事業経験"): 5,
 
166
  })
167
 
168
  def score_external_from_df(df: pd.DataFrame) -> Dict[str, Any]:
169
+ # 必ず dict を返す。途中で例外にならないよう to_x で吸収。
170
  def ref(label: str):
171
  m = df["入力項目"].eq(label)
172
  return df.loc[m, "値"].values[0] if m.any() else None
 
249
  _add(items,"成長率","売上高伸長性", _ramp(s_cagr,0.08,-0.05),
250
  _WEIGHTS[("成長率","売上高伸長性")],
251
  f"CAGR売上{round((s_cagr or 0)*100,1) if s_cagr is not None else '—'}%")
 
252
  _add(items,"成長率","利益伸長性", _ramp(p_cagr,0.08,-0.05),
253
  _WEIGHTS[("成長率","利益伸長性")],
254
  f"CAGR営業{round((p_cagr or 0)*100,1) if p_cagr is not None else '—'}%")
 
278
  _ramp(-(delay_days or 0),0,-30) )/3
279
  rs=f"遅延{int(delay_cnt or 0)}/不渡{int(boun_cnt or 0)}/平均{int(delay_days or 0)}日"
280
  else:
281
+ sc=_ramp(_ratio(cash, sales_m2),1.0,0.2); rs=f"代理:現預金/月商≈—"
282
  _add(items,"安定性","決済振り", sc, _WEIGHTS[("安定性","決済振り")], rs)
283
 
284
  sc_mb = 5.0
285
  sc_mb += 2.0 if mainbank else (-0.5 if mainbank is False else 0)
286
  sc_mb += 1.0 if has_line else 0
287
  sc_mb = _clamp(sc_mb,0,10)
288
+ _a_