314 lines
16 KiB
Python
314 lines
16 KiB
Python
"""评价权重计算引擎。
|
||
|
||
6 轴动态权重合并 + 归一化:
|
||
1. 基金类型 × 存续期 → 基础权重模板(32 个预设)
|
||
2. 企业阶段 → 阶段系数调整(5 个预设)
|
||
3. 产业赛道 → 维度裁剪 + 专属指标注入(6 个预设)
|
||
4. 投资策略 → ±5% 微调(4 个预设)
|
||
5. 归一化 — 裁剪后剩余维度权重自动归一化到 100%
|
||
6. 修饰因子叠加 — LP 附加指标 + 地域基准校准
|
||
"""
|
||
|
||
import logging
|
||
from typing import Any
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
# --- 基础 14 维度权重(来自 health_calculator.py) ---
|
||
BASE_WEIGHTS: dict[str, float] = {
|
||
"financial": 0.15,
|
||
"operational": 0.10,
|
||
"ai_commercial": 0.10,
|
||
"ai_cost": 0.05,
|
||
"org_talent": 0.10,
|
||
"product_tech": 0.10,
|
||
"market_compete": 0.10,
|
||
"governance": 0.05,
|
||
"financing": 0.05,
|
||
"synergy": 0.05,
|
||
"ai_model_product": 0.05,
|
||
"data_compliance": 0.05,
|
||
"team_tech": 0.03,
|
||
"customer_success": 0.07,
|
||
}
|
||
|
||
# 维度 key 映射:权重 key → 评分字段 key
|
||
DIMENSION_KEY_MAP: dict[str, str] = {
|
||
"financial": "financial_score",
|
||
"operational": "operational_score",
|
||
"ai_commercial": "ai_commercial_score",
|
||
"ai_cost": "ai_cost_score",
|
||
"org_talent": "org_talent_score",
|
||
"product_tech": "product_tech_score",
|
||
"market_compete": "market_compete_score",
|
||
"governance": "governance_score",
|
||
"financing": "financing_score",
|
||
"synergy": "synergy_score",
|
||
"ai_model_product": "ai_model_product_score",
|
||
"data_compliance": "data_compliance_score",
|
||
"team_tech": "team_tech_score",
|
||
"customer_success": "customer_success_score",
|
||
}
|
||
|
||
# --- 轴 5:基金类型 × 存续期基础权重系数(32 个预设) ---
|
||
FUND_LIFECYCLE_MULTIPLIERS: dict[tuple[str, str], dict[str, float]] = {
|
||
("angel", "investment"): {"financial": 0.5, "product_tech": 1.8, "org_talent": 1.5, "market": 1.2},
|
||
("angel", "growth"): {"financial": 0.7, "product_tech": 1.5, "org_talent": 1.3, "market": 1.2},
|
||
("angel", "exit_preparation"): {"financial": 1.0, "product_tech": 1.2, "org_talent": 1.0, "financing": 1.5},
|
||
("angel", "liquidation"): {"financial": 1.5, "financing": 2.0, "product_tech": 0.8},
|
||
|
||
("early_vc", "investment"): {"financial": 0.7, "product_tech": 1.5, "market": 1.2, "customer_success": 0.8},
|
||
("early_vc", "growth"): {"financial": 0.9, "product_tech": 1.3, "market": 1.2, "customer_success": 1.0},
|
||
("early_vc", "exit_preparation"): {"financial": 1.3, "market": 1.0, "customer_success": 1.2, "financing": 1.5},
|
||
("early_vc", "liquidation"): {"financial": 1.8, "financing": 2.0, "product_tech": 0.6},
|
||
|
||
("growth_vc", "investment"): {"financial": 1.0, "market": 1.3, "customer_success": 1.2},
|
||
("growth_vc", "growth"): {"financial": 1.2, "market": 1.2, "customer_success": 1.3},
|
||
("growth_vc", "exit_preparation"): {"financial": 1.5, "market": 1.0, "customer_success": 1.2, "financing": 1.5},
|
||
("growth_vc", "liquidation"): {"financial": 2.0, "financing": 2.0, "market": 0.8},
|
||
|
||
("pe", "investment"): {"financial": 1.8, "governance": 1.5, "customer_success": 1.3, "product_tech": 0.5, "ai_commercial": 0.3, "ai_cost": 0.3, "ai_model_product": 0.3},
|
||
("pe", "growth"): {"financial": 2.0, "governance": 1.5, "customer_success": 1.3, "product_tech": 0.5, "ai_commercial": 0.3, "ai_cost": 0.3, "ai_model_product": 0.3},
|
||
("pe", "exit_preparation"): {"financial": 2.5, "governance": 1.8, "financing": 1.5, "ai_commercial": 0.3, "ai_cost": 0.3, "ai_model_product": 0.3},
|
||
("pe", "liquidation"): {"financial": 3.0, "financing": 2.0, "governance": 1.5, "ai_commercial": 0.3, "ai_cost": 0.3, "ai_model_product": 0.3},
|
||
|
||
("cvc", "investment"): {"synergy": 2.0, "market": 1.3, "product_tech": 1.2, "financial": 0.7},
|
||
("cvc", "growth"): {"synergy": 1.8, "market": 1.2, "product_tech": 1.2, "financial": 0.8},
|
||
("cvc", "exit_preparation"): {"synergy": 1.5, "market": 1.0, "financial": 1.2, "financing": 1.3},
|
||
("cvc", "liquidation"): {"financial": 1.5, "financing": 1.5, "synergy": 1.0},
|
||
|
||
("distress", "investment"): {"financial": 2.5, "governance": 1.5, "product_tech": 0.5, "market": 0.5, "ai_commercial": 0.3, "ai_cost": 0.3, "ai_model_product": 0.3},
|
||
("distress", "growth"): {"financial": 2.5, "governance": 1.5, "product_tech": 0.5, "ai_commercial": 0.3, "ai_cost": 0.3, "ai_model_product": 0.3},
|
||
("distress", "exit_preparation"): {"financial": 3.0, "governance": 1.5, "financing": 1.5, "ai_commercial": 0.3, "ai_cost": 0.3, "ai_model_product": 0.3},
|
||
("distress", "liquidation"): {"financial": 3.0, "financing": 2.0, "governance": 1.5, "ai_commercial": 0.3, "ai_cost": 0.3, "ai_model_product": 0.3},
|
||
|
||
("esg", "investment"): {"governance": 1.8, "data_compliance": 1.5, "product_tech": 1.2, "financial": 0.8},
|
||
("esg", "growth"): {"governance": 1.5, "data_compliance": 1.3, "customer_success": 1.2},
|
||
("esg", "exit_preparation"): {"governance": 1.8, "financial": 1.3, "financing": 1.3},
|
||
("esg", "liquidation"): {"financial": 1.5, "governance": 1.5, "financing": 1.5},
|
||
|
||
# FOF 不直接评价单企业,使用默认权重
|
||
("fof", "investment"): {},
|
||
("fof", "growth"): {},
|
||
("fof", "exit_preparation"): {},
|
||
("fof", "liquidation"): {},
|
||
}
|
||
|
||
# --- 轴 2:企业阶段系数(5 个预设) ---
|
||
STAGE_MULTIPLIERS: dict[str, dict[str, float]] = {
|
||
"seed": {"financial": 0.6, "product_tech": 1.8, "org_talent": 1.5, "market_compete": 0.5, "governance": 0.6, "customer_success": 0.5},
|
||
"a": {"financial": 0.8, "product_tech": 1.5, "org_talent": 1.2, "market_compete": 1.0, "governance": 0.7, "customer_success": 0.8},
|
||
"b": {"financial": 1.2, "market_compete": 1.3, "customer_success": 1.3, "product_tech": 1.0, "governance": 1.0},
|
||
"c": {"financial": 1.5, "market_compete": 1.3, "governance": 1.3, "customer_success": 1.3, "product_tech": 0.8},
|
||
"pre_ipo": {"financial": 1.5, "governance": 1.8, "customer_success": 1.3, "market_compete": 1.0, "product_tech": 0.8},
|
||
}
|
||
|
||
# --- 轴 3:产业赛道配置(6 个预设) ---
|
||
INDUSTRY_CONFIGS: dict[str, dict[str, Any]] = {
|
||
"ai": {
|
||
"enabled": list(DIMENSION_KEY_MAP.keys()),
|
||
"disabled": [],
|
||
"custom_metrics": [
|
||
{"key": "model_accuracy", "label": "模型精度", "description": "AI 模型准确率/召回率"},
|
||
{"key": "inference_cost", "label": "推理成本", "description": "单次推理成本趋势"},
|
||
{"key": "api_call_volume", "label": "API 调用量", "description": "月度 API 调用次数"},
|
||
{"key": "poc_conversion_rate", "label": "PoC 转化率", "description": "PoC 到付费转化率"},
|
||
],
|
||
},
|
||
"saas": {
|
||
"enabled": ["financial", "operational", "ai_commercial", "org_talent", "product_tech",
|
||
"market_compete", "governance", "financing", "synergy", "data_compliance",
|
||
"team_tech", "customer_success"],
|
||
"disabled": ["ai_cost", "ai_model_product"],
|
||
"custom_metrics": [
|
||
{"key": "arr_growth", "label": "ARR 增长率", "description": "年度经常性收入增长率"},
|
||
{"key": "net_revenue_retention", "label": "NRR", "description": "净收入留存率"},
|
||
{"key": "cac_payback", "label": "CAC 回收期", "description": "获客成本回收月数"},
|
||
{"key": "rule_of_40", "label": "Rule of 40", "description": "增长率 + 利润率"},
|
||
],
|
||
},
|
||
"hardware": {
|
||
"enabled": ["financial", "operational", "org_talent", "product_tech", "market_compete",
|
||
"governance", "financing", "synergy", "data_compliance",
|
||
"team_tech", "customer_success"],
|
||
"disabled": ["ai_commercial", "ai_cost", "ai_model_product"],
|
||
"custom_metrics": [
|
||
{"key": "patent_count", "label": "专利数", "description": "累计授权专利数量"},
|
||
{"key": "tape_out_progress", "label": "流片进度", "description": "芯片流片里程碑进展"},
|
||
{"key": "yield_rate", "label": "良率", "description": "产品良率"},
|
||
{"key": "rd_investment_ratio", "label": "研发投入比", "description": "研发投入占营收比例"},
|
||
],
|
||
},
|
||
"biotech": {
|
||
"enabled": ["financial", "operational", "org_talent", "product_tech", "governance",
|
||
"financing", "synergy", "data_compliance", "team_tech"],
|
||
"disabled": ["ai_commercial", "ai_cost", "ai_model_product", "market_compete", "customer_success"],
|
||
"custom_metrics": [
|
||
{"key": "clinical_stage", "label": "临床阶段", "description": "当前临床试验阶段"},
|
||
{"key": "pipeline_progress", "label": "管线进度", "description": "在研管线推进情况"},
|
||
{"key": "regulatory_milestone", "label": "审批节点", "description": "监管审批里程碑"},
|
||
{"key": "patent_landscape", "label": "专利布局", "description": "核心专利布局覆盖度"},
|
||
],
|
||
},
|
||
"consumer": {
|
||
"enabled": ["financial", "operational", "org_talent", "product_tech", "market_compete",
|
||
"governance", "financing", "synergy", "team_tech", "customer_success"],
|
||
"disabled": ["ai_commercial", "ai_cost", "ai_model_product", "data_compliance"],
|
||
"custom_metrics": [
|
||
{"key": "gmv", "label": "GMV", "description": "月度交易总额"},
|
||
{"key": "repurchase_rate", "label": "复购率", "description": "客户复购率"},
|
||
{"key": "brand_index", "label": "品牌指数", "description": "品牌知名度/美誉度"},
|
||
{"key": "channel_coverage", "label": "渠道覆盖率", "description": "销售渠道覆盖广度"},
|
||
],
|
||
},
|
||
"fintech": {
|
||
"enabled": ["financial", "operational", "ai_commercial", "org_talent", "product_tech",
|
||
"market_compete", "governance", "financing", "synergy", "ai_model_product",
|
||
"data_compliance", "team_tech", "customer_success"],
|
||
"disabled": ["ai_cost"],
|
||
"custom_metrics": [
|
||
{"key": "license_progress", "label": "牌照进度", "description": "金融牌照获取进展"},
|
||
{"key": "risk_control_score", "label": "风控指标", "description": "风控模型评分"},
|
||
{"key": "compliance_events", "label": "合规事件", "description": "合规事件数量"},
|
||
{"key": "npl_ratio", "label": "坏账率", "description": "不良贷款率"},
|
||
],
|
||
},
|
||
"manufacturing": {
|
||
"enabled": ["financial", "operational", "org_talent", "product_tech", "market_compete",
|
||
"governance", "financing", "synergy", "data_compliance",
|
||
"team_tech", "customer_success"],
|
||
"disabled": ["ai_commercial", "ai_cost", "ai_model_product"],
|
||
"custom_metrics": [
|
||
{"key": "capacity_utilization", "label": "产能利用率", "description": "实际产能/设计产能"},
|
||
{"key": "delivery_cycle", "label": "交付周期", "description": "订单交付周期天数"},
|
||
{"key": "supply_chain_stability", "label": "供应链稳定性", "description": "供应链中断风险评分"},
|
||
{"key": "rd_investment_ratio", "label": "研发投入比", "description": "研发投入占营收比例"},
|
||
],
|
||
},
|
||
}
|
||
|
||
# --- 轴 4:投资策略微调(4 个预设,±5%) ---
|
||
STRATEGY_ADJUSTMENTS: dict[str, dict[str, float]] = {
|
||
"growth": {"market_compete": 5, "product_tech": 5, "customer_success": 5, "financial": -5, "governance": -5},
|
||
"value": {"financial": 5, "governance": 5, "customer_success": 5, "market_compete": -5, "product_tech": -5},
|
||
"empowerment": {"synergy": 5, "org_talent": 5, "product_tech": 5, "financial": -5, "market_compete": -5},
|
||
"turnaround": {"financial": 5, "governance": 5, "market_compete": -5, "product_tech": -5},
|
||
}
|
||
|
||
|
||
def compute_weights(
|
||
fund_type: str,
|
||
fund_lifecycle: str,
|
||
company_stage: str,
|
||
industry: str,
|
||
strategy: str = "growth",
|
||
investor_type: str = "investor",
|
||
) -> dict[str, Any]:
|
||
"""计算 6 轴动态权重。
|
||
|
||
Args:
|
||
fund_type: 基金类型 — angel/early_vc/growth_vc/pe/cvc/fof/distress/esg
|
||
fund_lifecycle: 存续期阶段 — investment/growth/exit_preparation/liquidation
|
||
company_stage: 企业阶段 — seed/a/b/c/pre_ipo
|
||
industry: 产业赛道 — ai/saas/hardware/biotech/consumer/fintech/manufacturing
|
||
strategy: 投资策略 — growth/value/empowerment/turnaround
|
||
investor_type: 投资人类型 — gp/post_invest_lead/investor(不影响权重)
|
||
|
||
Returns:
|
||
包含 weights、enabled_dimensions、disabled_dimensions、custom_metrics 的字典
|
||
"""
|
||
# Step 1:复制基础权重
|
||
weights = dict(BASE_WEIGHTS)
|
||
|
||
# Step 2:基金类型 × 存续期系数
|
||
fund_key = (fund_type, fund_lifecycle)
|
||
fund_multipliers = FUND_LIFECYCLE_MULTIPLIERS.get(fund_key, {})
|
||
for dim, multiplier in fund_multipliers.items():
|
||
if dim in weights:
|
||
weights[dim] *= multiplier
|
||
|
||
# Step 3:企业阶段系数
|
||
stage_multipliers = STAGE_MULTIPLIERS.get(company_stage, {})
|
||
for dim, multiplier in stage_multipliers.items():
|
||
if dim in weights:
|
||
weights[dim] *= multiplier
|
||
|
||
# Step 4:产业赛道 — 维度裁剪
|
||
industry_config = INDUSTRY_CONFIGS.get(industry, INDUSTRY_CONFIGS["ai"])
|
||
enabled_dims = industry_config["enabled"]
|
||
disabled_dims = industry_config["disabled"]
|
||
|
||
# 禁用的维度权重置零
|
||
for dim in disabled_dims:
|
||
if dim in weights:
|
||
weights[dim] = 0.0
|
||
|
||
# Step 5:投资策略微调(±5%,基于百分比点)
|
||
strategy_adj = STRATEGY_ADJUSTMENTS.get(strategy, {})
|
||
for dim, adjustment in strategy_adj.items():
|
||
if dim in weights and weights[dim] > 0:
|
||
# 将百分比点转换为权重调整量
|
||
weights[dim] += adjustment / 100.0
|
||
|
||
# 确保非负
|
||
for dim in weights:
|
||
weights[dim] = max(0.0, weights[dim])
|
||
|
||
# Step 6:归一化 — 只对启用维度归一化到 1.0
|
||
enabled_weights = {dim: weights[dim] for dim in enabled_dims if dim in weights}
|
||
total = sum(enabled_weights.values())
|
||
|
||
if total > 0:
|
||
normalized = {dim: w / total for dim, w in enabled_weights.items()}
|
||
else:
|
||
# 极端情况:所有权重为零,均分
|
||
count = len(enabled_dims) if enabled_dims else 1
|
||
normalized = {dim: 1.0 / count for dim in enabled_dims}
|
||
|
||
# 转换为百分比格式(保留 4 位小数)
|
||
final_weights = {dim: round(w * 100, 2) for dim, w in normalized.items()}
|
||
|
||
logger.info(
|
||
"权重计算完成: fund_type=%s, lifecycle=%s, stage=%s, industry=%s, strategy=%s → %s",
|
||
fund_type, fund_lifecycle, company_stage, industry, strategy, final_weights,
|
||
)
|
||
|
||
return {
|
||
"weights": final_weights,
|
||
"enabled_dimensions": enabled_dims,
|
||
"disabled_dimensions": disabled_dims,
|
||
"custom_metrics": industry_config.get("custom_metrics", []),
|
||
}
|
||
|
||
|
||
def get_dimension_score_key(weight_key: str) -> str:
|
||
"""将权重 key 转换为评分字段 key。"""
|
||
return DIMENSION_KEY_MAP.get(weight_key, f"{weight_key}_score")
|
||
|
||
|
||
def calculate_weighted_score(
|
||
dimension_scores: dict[str, float],
|
||
weights: dict[str, float],
|
||
) -> float:
|
||
"""根据维度评分和权重计算加权总分。
|
||
|
||
Args:
|
||
dimension_scores: 各维度评分(0-100),key 为权重 key(如 financial)
|
||
weights: 各维度权重(百分比),key 为权重 key
|
||
|
||
Returns:
|
||
加权总分(0-100)
|
||
"""
|
||
total = 0.0
|
||
weight_sum = 0.0
|
||
|
||
for dim, weight in weights.items():
|
||
score = dimension_scores.get(dim)
|
||
if score is not None and weight > 0:
|
||
total += score * weight
|
||
weight_sum += weight
|
||
|
||
if weight_sum > 0:
|
||
return round(total / weight_sum, 1)
|
||
return 0.0
|