用Python评估足球夏窗引援性价比:一个完整案例
评估引援性价比的核心是:用合理的成本买到符合球队需要的产出,下面用一个可运行的Python案例,从数据建模到可视化完整走一遍。

评估框架设计
性价比 = 产出 / 成本,但需要拆解:
| 维度 | 指标 | 说明 |
|---|---|---|
| 成本 | 转会费、年薪、签字费、经纪人佣金 | 折算为"年均总成本" |
| 产出 | 进球、助攻、关键传球、抢断、拦截、出场时间 | 需按位置加权 |
| 风险 | 伤病史、年龄、联赛适应度 | 折价因子 |
| 适配 | 与球队战术、位置缺口匹配度 | 需求系数 |
核心公式:
性价比得分 = (产出评分 × 适配系数 × 健康系数) / 年均成本
数据准备(示例数据)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 模拟某队夏窗5名引援的数据
data = {
'player': ['A前锋', 'B中场', 'C后卫', 'D边锋', 'E门将'],
'position': ['FW', 'MF', 'DF', 'FW', 'GK'],
'transfer_fee': [50, 30, 25, 15, 8], # 百万欧元
'annual_wage': [10, 8, 6, 4, 3], # 百万欧元/年
'contract_years': [5, 4, 4, 3, 3],
'age': [24, 26, 23, 22, 28],
'goals': [18, 6, 1, 10, 0],
'assists': [5, 9, 2, 7, 0],
'key_passes': [40, 65, 15, 55, 2],
'tackles': [10, 45, 70, 20, 3],
'interceptions': [5, 30, 55, 10, 2],
'minutes': [2800, 2600, 2900, 2200, 2700],
'injury_days_last3y': [30, 15, 60, 10, 5],
'appearances': [32, 30, 33, 26, 30]
}
df = pd.DataFrame(data)
成本模型:年均总成本
def annual_cost(row):
# 转会费按合同年限摊销 + 年薪 + 10%隐性成本(佣金/签字费)
amortization = row['transfer_fee'] / row['contract_years']
hidden = row['transfer_fee'] * 0.1 / row['contract_years']
return amortization + row['annual_wage'] + hidden
df['annual_cost'] = df.apply(annual_cost, axis=1)
# 单位:百万欧元/年
关键点:转会费必须摊销,否则5000万签5年和5000万签2年的性价比会被误判。
产出评分:按位置加权
不同位置贡献方式不同,不能简单相加。
# 位置权重(可根据球队战术调整)
weights = {
'FW': {'goals': 3.0, 'assists': 2.0, 'key_passes': 0.5,
'tackles': 0.1, 'interceptions': 0.1},
'MF': {'goals': 1.5, 'assists': 2.5, 'key_passes': 1.0,
'tackles': 1.0, 'interceptions': 1.0},
'DF': {'goals': 0.5, 'assists': 0.5, 'key_passes': 0.3,
'tackles': 2.0, 'interceptions': 2.0},
'GK': {'goals': 0, 'assists': 0.2, 'key_passes': 0,
'tackles': 0.5, 'interceptions': 0.5},
}
def raw_output(row):
w = weights[row['position']]
# 按90分钟标准化,避免出场少的被低估
per90 = row['minutes'] / 90
score = sum(row[k] * w[k] for k in w) / per90 * 90
return score
df['raw_output'] = df.apply(raw_output, axis=1)
# 归一化到0-100
df['output_score'] = (df['raw_output'] / df['raw_output'].max()) * 100
风险与适配系数
# 1. 健康系数:过去3年伤病天数越多,折价越大
df['health_factor'] = np.clip(1 - df['injury_days_last3y'] / 180, 0.5, 1.0)
# 2. 年龄系数:24-27岁为巅峰,过小或过大折价
def age_factor(age):
if 24 <= age <= 27: return 1.0
elif age < 24: return 0.9 # 潜力未兑现风险
else: return max(0.7, 1 - (age - 27) * 0.05)
df['age_factor'] = df['age'].apply(age_factor)
# 3. 适配系数:假设球队急需前锋和中场(位置缺口)
team_needs = {'FW': 1.2, 'MF': 1.1, 'DF': 0.9, 'GK': 0.8}
df['fit_factor'] = df['position'].map(team_needs)
综合性价比得分
df['value_score'] = (
df['output_score']
* df['health_factor']
* df['age_factor']
* df['fit_factor']
/ df['annual_cost']
)
# 归一化展示
df['value_score_norm'] = (df['value_score'] / df['value_score'].max() * 100).round(1)
df['value_score_norm'] = df['value_score_norm'].round(1)
print(df[['player', 'annual_cost', 'output_score',
'health_factor', 'fit_factor', 'value_score_norm']]
.sort_values('value_score_norm', ascending=False))
可视化:性价比四象限图
用"成本 vs 产出"做散点,气泡大小=性价比,快速识别"高性价比"和"溢价"。
plt.figure(figsize=(10, 7))
scatter = plt.scatter(
df['annual_cost'], df['output_score'],
s=df['value_score_norm'] * 15,
c=df['value_score_norm'], cmap='RdYlGn',
alpha=0.8, edgecolors='black'
)
for _, row in df.iterrows():
plt.annotate(row['player'], (row['annual_cost'], row['output_score']),
xytext=(5, 5), textcoords='offset points')
# 分界线取中位数
plt.axvline(df['annual_cost'].median(), color='gray', ls='--', alpha=0.5)
plt.axhline(df['output_score'].median(), color='gray', ls='--', alpha=0.5)
plt.xlabel('年均总成本 (百万欧元/年)')
plt.ylabel('产出评分 (0-100)')'夏窗引援性价比四象限图')
plt.colorbar(scatter, label='性价比得分')
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()
四象限解读:
- 左上(低成本高产):宝藏引援 ✅
- 右上(高成本高产):合理但需兑现 ⚠️
- 左下(低成本低产):轮换/储备 🔵
- 右下(高成本低产):溢价风险 ❌
进阶建议(真实场景)
- 数据源:FBref、Transfermarkt、Opta、StatsBomb(xG/xA比进球助攻更抗噪)。
- 位置标准化:用百分位排名(同位置球员比较),避免不同位置直接比。
- 联赛难度调整:从荷甲/葡超到五大联赛的产出通常打7-8折,可加
league_factor。 - 时间衰减:近1个赛季权重大于3年前的赛季。
- 敏感性分析:权重是主观的,建议跑蒙特卡洛或网格,看排名是否稳定。
- 避免幸存者偏差:要把"没踢出来的引援"也纳入历史回测,校准权重。
一句话总结:性价比不是"便宜",而是(位置加权产出 × 健康 × 年龄 × 战术适配)/ 摊销后年成本,再配合四象限图做决策沟通,这个框架最大的价值不是给出一个绝对分数,而是让不同引援方案可以用同一把尺子比较。