Corin1998 commited on
Commit
6116cd3
·
verified ·
1 Parent(s): fc23dfc

Update core/external_scoring.py

Browse files
Files changed (1) hide show
  1. core/external_scoring.py +25 -21
core/external_scoring.py CHANGED
@@ -2,7 +2,6 @@
2
  from __future__ import annotations
3
  from typing import Dict, Any, List, Tuple
4
  import pandas as pd
5
- import math
6
 
7
  __all__ = [
8
  "get_external_template_df",
@@ -71,7 +70,7 @@ def fill_missing_with_external(df: pd.DataFrame, suggestions: Dict[str, Any] | N
71
  df2.at[idx, "値"] = suggestions[key]
72
  return df2
73
 
74
- # ===== スコア計算(定量的・ルールベース) =====
75
  _WEIGHTS = {
76
  ("経営者能力", "経営姿勢"): 8,
77
  ("経営者能力", "事業経験"): 5,
@@ -81,7 +80,7 @@ _WEIGHTS = {
81
  ("成長率", "売上高伸長性"): 10,
82
  ("成長率", "利益伸長性"): 10,
83
  ("成長率", "商品"): 6,
84
- ("成長率", "市場成長調整"): 6, # 市場成長率を反映
85
 
86
  ("安定性", "自己資本"): 8,
87
  ("安定性", "決済振り"): 10,
@@ -95,34 +94,21 @@ _WEIGHTS = {
95
  _WEIGHT_NORM = 100.0 / float(sum(_WEIGHTS.values()))
96
 
97
  def _clamp(v, a, b): return max(a, min(b, v))
98
-
99
- def _add(items, cat, name, raw, weight, reason):
100
- raw_s = None if raw is None else round(raw, 2)
101
- w = round(weight * _WEIGHT_NORM, 2)
102
- sc = 0.0 if raw is None else round((raw / 10.0) * w, 2)
103
- items.append({
104
- "category": cat, "name": name, "raw": raw_s,
105
- "weight": w, "score": sc, "reason": reason
106
- })
107
-
108
  def _to_float(x):
109
  if x is None: return None
110
  try:
111
  return float(str(x).replace(",", "").replace("▲", "-").replace("△", "-"))
112
  except Exception:
113
  return None
114
-
115
  def _to_bool(x):
116
  if x is None: return None
117
  s = str(x).strip().lower()
118
  if s in ("true","t","1","yes","y","有","あり"): return True
119
  if s in ("false","f","0","no","n","無","なし"): return False
120
  return None
121
-
122
  def _ratio(a,b):
123
  if a is None or b is None or b == 0: return None
124
  return a/b
125
-
126
  def _ramp(x, good, bad, lo=0.0, hi=10.0, neutral=None):
127
  if x is None:
128
  return neutral if neutral is not None else (lo+hi)/2.0
@@ -135,8 +121,27 @@ def _ramp(x, good, bad, lo=0.0, hi=10.0, neutral=None):
135
  if x <= good: return hi
136
  return lo + (hi-lo) * (x-good)/(bad-good)
137
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  def score_external_from_df(df: pd.DataFrame) -> Dict[str, Any]:
139
- """入力DF(カテゴリー/入力項目/値)を定量スコア化。欠損は中立。市場成長率も反映。"""
140
  def ref(label: str):
141
  m = df["入力項目"].eq(label)
142
  return df.loc[m, "値"].values[0] if m.any() else None
@@ -225,7 +230,7 @@ def score_external_from_df(df: pd.DataFrame) -> Dict[str, Any]:
225
  _WEIGHTS[("成長率","利益伸長性")],
226
  f"CAGR営業{round((p_cagr or 0)*100,1) if p_cagr is not None else '—'}%")
227
 
228
- # 商品スコア
229
  if prod_total is None or prod_total <= 0:
230
  pr_sc = 5.0; rs = "不明→中立"
231
  else:
@@ -273,7 +278,7 @@ def score_external_from_df(df: pd.DataFrame) -> Dict[str, Any]:
273
  _add(items,"安定性","業歴", _ramp(years,20,1),
274
  _WEIGHTS[("安定性","業歴")], f"{years or '—'}年")
275
 
276
- # 公平性(←ここを二行に分割して修正)
277
  sc_dis = 0.0
278
  has_sec = _to_bool(ref("有価証券報告書提出企業か(TRUE/FALSE)"))
279
  sc_dis += 10.0 if has_sec else 0.0
@@ -290,7 +295,6 @@ def score_external_from_df(df: pd.DataFrame) -> Dict[str, Any]:
290
 
291
  total = round(sum(x["score"] for x in items),1)
292
 
293
- # レーダ用カテゴリスコア(重み付き)
294
  from collections import defaultdict
295
  cat_sum, cat_w = defaultdict(float), defaultdict(float)
296
  for it in items:
@@ -303,5 +307,5 @@ def score_external_from_df(df: pd.DataFrame) -> Dict[str, Any]:
303
  "external_total": total,
304
  "items": items,
305
  "category_scores": cat_scores,
306
- "notes": "欠損は中立。市場成長率を成長評価に加味(過熱/低迷の補正)。",
307
  }
 
2
  from __future__ import annotations
3
  from typing import Dict, Any, List, Tuple
4
  import pandas as pd
 
5
 
6
  __all__ = [
7
  "get_external_template_df",
 
70
  df2.at[idx, "値"] = suggestions[key]
71
  return df2
72
 
73
+ # ===== スコア計算(定量・ばらつき強化) =====
74
  _WEIGHTS = {
75
  ("経営者能力", "経営姿勢"): 8,
76
  ("経営者能力", "事業経験"): 5,
 
80
  ("成長率", "売上高伸長性"): 10,
81
  ("成長率", "利益伸長性"): 10,
82
  ("成長率", "商品"): 6,
83
+ ("成長率", "市場成長調整"): 6,
84
 
85
  ("安定性", "自己資本"): 8,
86
  ("安定性", "決済振り"): 10,
 
94
  _WEIGHT_NORM = 100.0 / float(sum(_WEIGHTS.values()))
95
 
96
  def _clamp(v, a, b): return max(a, min(b, v))
 
 
 
 
 
 
 
 
 
 
97
  def _to_float(x):
98
  if x is None: return None
99
  try:
100
  return float(str(x).replace(",", "").replace("▲", "-").replace("△", "-"))
101
  except Exception:
102
  return None
 
103
  def _to_bool(x):
104
  if x is None: return None
105
  s = str(x).strip().lower()
106
  if s in ("true","t","1","yes","y","有","あり"): return True
107
  if s in ("false","f","0","no","n","無","なし"): return False
108
  return None
 
109
  def _ratio(a,b):
110
  if a is None or b is None or b == 0: return None
111
  return a/b
 
112
  def _ramp(x, good, bad, lo=0.0, hi=10.0, neutral=None):
113
  if x is None:
114
  return neutral if neutral is not None else (lo+hi)/2.0
 
121
  if x <= good: return hi
122
  return lo + (hi-lo) * (x-good)/(bad-good)
123
 
124
+ def _stretch_0_10(x: float, k: float = 1.2) -> float:
125
+ """
126
+ 0-10 を保ちつつ中央付近(4-6)の密集をほぐす単調変換。
127
+ k>1で両端を強調。k≈1.2~1.4 推奨。
128
+ """
129
+ if x is None: return None
130
+ t = (x/10.0)
131
+ t = t**(1.0/k) if t >= 0.5 else (t**k)
132
+ return _clamp(t*10.0, 0.0, 10.0)
133
+
134
+ def _add(items, cat, name, raw, weight, reason):
135
+ raw2 = _stretch_0_10(raw, k=1.25) if raw is not None else None
136
+ w = round(weight * _WEIGHT_NORM, 2)
137
+ sc = 0.0 if raw2 is None else round((raw2 / 10.0) * w, 2)
138
+ items.append({
139
+ "category": cat, "name": name, "raw": None if raw is None else round(raw,2),
140
+ "raw_stretched": None if raw2 is None else round(raw2,2),
141
+ "weight": w, "score": sc, "reason": reason
142
+ })
143
+
144
  def score_external_from_df(df: pd.DataFrame) -> Dict[str, Any]:
 
145
  def ref(label: str):
146
  m = df["入力項目"].eq(label)
147
  return df.loc[m, "値"].values[0] if m.any() else None
 
230
  _WEIGHTS[("成長率","利益伸長性")],
231
  f"CAGR営業{round((p_cagr or 0)*100,1) if p_cagr is not None else '—'}%")
232
 
233
+ # 商品
234
  if prod_total is None or prod_total <= 0:
235
  pr_sc = 5.0; rs = "不明→中立"
236
  else:
 
278
  _add(items,"安定性","業歴", _ramp(years,20,1),
279
  _WEIGHTS[("安定性","業歴")], f"{years or '—'}年")
280
 
281
+ # 公平性
282
  sc_dis = 0.0
283
  has_sec = _to_bool(ref("有価証券報告書提出企業か(TRUE/FALSE)"))
284
  sc_dis += 10.0 if has_sec else 0.0
 
295
 
296
  total = round(sum(x["score"] for x in items),1)
297
 
 
298
  from collections import defaultdict
299
  cat_sum, cat_w = defaultdict(float), defaultdict(float)
300
  for it in items:
 
307
  "external_total": total,
308
  "items": items,
309
  "category_scores": cat_scores,
310
+ "notes": "欠損は中立+市場成長補正。ストレッチでばらつきを拡大。",
311
  }