#显卡横评 #ECharts #Python #数据可视化

背景

51972 发布了 RTX 5080(31 款)和 RTX 5070Ti(33 款)的大规模横评,覆盖跑分、散热、噪音、超频、体积等维度。原始数据以截图和 Excel 形式存在,不同用户关注点差异很大——性能党和静音党对同一款显卡的评价可能完全相反。

目标是把这批数据整理成一个纯静态网页工具:用户拖动权重滑块,实时看到符合自己优先级的排名,同时能在散点图上直观感受各维度的分布。


一、数据整理

数据源结构

RTX 5070Ti 数据已有完整 Excel(11 个 Sheet);RTX 5080 数据只有截图,需手工录入。两份 Excel 的 Sheet 名称如下:

GPU Sheet
5080 基础信息 · BIOS功耗设定 · SpeedWay压力测试性能 · SpeedWay散热排行 · 噪音表现排行 · 超频性能排行 · 垂直吊装散热排行
5070Ti 以上全部 + 静音BIOS测试 · SFF规格散热排行 · 统一散热-大/小尺寸风扇

所有 Sheet 第 1 行为标题、第 2 行为列头,数据从第 3 行开始。

数据质量问题

整理过程中遇到三处需要处理的问题:

① 5070Ti 噪音 Sheet 有重复行

技嘉 GAMING OC 魔鹰和影驰 HOF OC LAB Deluxe X 各出现两次(来自不同测试批次),取两次均值作为最终值。

1
2
3
4
5
6
for mdl in ['技嘉 RTX 5070Ti GAMING OC 魔鹰', '影驰 RTX 5070Ti HOF OC LAB Deluxe X']:
mask = noise['品牌型号'] == mdl
if mask.sum() == 2:
noise.loc[noise.index[mask][0], '噪音值dB(A)'] = \
round(noise.loc[mask, '噪音值dB(A)'].mean(), 2)
noise = noise.drop(noise.index[mask][1]).reset_index(drop=True)

② 5070Ti 跨 Sheet 型号名称不一致

基础信息 里写的是 微星 RTX5070Ti VANGUARD SOC 神龙(无空格),其他 Sheet 写的是 RTX 5070Ti(有空格)。用正则标准化后再做 join:

1
2
3
4
def norm_name(s):
s = re.sub(r'RTX\s*5070\s*Ti', 'RTX5070Ti', str(s))
s = re.sub(r'\s+16G\b', '', s)
return re.sub(r'\s+', ' ', s).strip()

③ 5080 索泰两款样品无实际采购价

用京东 MSRP 代入,同时在评分时添加价格异常检测(见第三节)。


二、Python 数据提取脚本

脚本 scripts/extract_data.py 读取两份 Excel,输出为浏览器可直接加载的 JS 文件:

1
2
3
4
5
装机评测/
├── scripts/extract_data.py
├── data/
│ ├── rtx5080.js # const RTX5080_DATA = { series, models: [...] }
│ └── rtx5070ti.js # const RTX5070TI_DATA = { ... }

每个型号包含的字段:

字段组 字段
性能 score, power, freq
超频 oc_score, oc_uplift, oc_power, oc_freq, oc_temp
散热(平放) core_temp, vram_temp, fan_pct
噪音 noise_db, noise_level
价格 price, msrp
尺寸 length, width, thickness, volume
垂直安装 vert_score, vert_temp, vert_pass
5070Ti 专项 silent_score, silent_noise, weight

派生字段在提取时计算:

  • volume = 长 × 宽 × 厚 / 1000(cm³)

  • oc_uplift = (超频后跑分 − 默认跑分) / 默认跑分 × 100%

最终匹配率:5080 全部 31/31;5070Ti 跑分/价格/尺寸 33/33,噪音 31/33(2 款无数据)。


三、评分算法

六个评分维度

按普通用户关注度排序:

维度 字段 方向 默认权重
性价比 跑分 / (价格/千元) 越高越好 8
性能 SpeedWay 跑分 越高越好 8
散热 平放核心温度 °C 越低越好 6
静音 噪音 dB(A) 越低越好 4
体积 长×宽×厚 cm³ 越小越好 3
OC潜力 超频提升率 % 越高越好 1

归一化:IQR Winsorization

直接 min-max 归一化会被极端值压缩。采用 Tukey IQR 截断:先计算 Q1/Q3 ± 1.5×IQR 的上下围栏,超出围栏的值被截至围栏边界,再做 min-max。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function normalizeArr(values, invert) {
const valid = [...values].filter(v => v != null).sort((a, b) => a - b);
const q1 = valid[Math.floor((valid.length - 1) * 0.25)];
const q3 = valid[Math.ceil ((valid.length - 1) * 0.75)];
const iqr = q3 - q1;
const flo = iqr > 0 ? q1 - 1.5 * iqr : -Infinity;
const fhi = iqr > 0 ? q3 + 1.5 * iqr : Infinity;
const lo = Math.max(flo, valid[0]);
const hi = Math.min(fhi, valid[valid.length - 1]);
return values.map(v => {
if (v == null) return 50;
const norm = (Math.max(flo, Math.min(fhi, v)) - lo) / (hi - lo) * 100;
return invert ? 100 - norm : norm;
});
}

价格异常检测

万丽 RTX 5080 星际 OC 初始采购价录入为 ¥4800(MSRP ¥9999),导致性价比维度严重失真,排名虚高。

处理逻辑:若实际价格 < MSRP × 65%(折扣超过 35%),以 MSRP × 65% 作为性价比计算用价,并在 UI 中标注 ⚠。后来数据更新为 ¥9500,该问题自然消除。

这个过程的启发:在做多维归一化时,单一异常值的影响远超直觉——IQR 截断能限制其在自身维度内的得分上限,但价格派生字段的极端值仍会在截断范围内占满 100 分。领域知识(“35% 折扣是正常市场行为的上限”)比纯统计方法更有效。


四、前端实现

整体架构

纯静态,无需服务器,file:// 本地可用,可直接挂静态托管:

1
2
3
4
5
6
7
8
index.html
css/style.css
js/
├── core.js # 归一化 + 评分算法(无 DOM 依赖,可独立测试)
└── app.js # UI 管理:滑块、表格、图表、交互联动
data/
├── rtx5080.js
└── rtx5070ti.js

data/ 下的 JS 文件用 const VAR = {...} 的形式定义全局变量,避免 file:// 协议下 fetch() 的 CORS 限制。

权重滑块

6 个滑块,范围 0–10,右侧实时显示归一化后的百分比占比。拖动任一滑块触发 computeScores() 重新排序并刷新表格和图表。

1
2
3
4
5
// 权重百分比显示
function pct(w) {
const t = DIMS.reduce((s, d) => s + state.weights[d.key], 0);
return t > 0 ? Math.round(w / t * 100) : 0;
}

ECharts 散点图

提供 7 种图表组合,两个图表区可独立切换:

  • 性能 / 噪音(Y 轴倒序,上方 = 更静)

  • 价格 / 性能

  • 性能 / 温度(Y 轴倒序)

  • 体积 / 性能

  • 噪音 / 温度

  • OC 潜力

  • 功耗效率

坐标轴范围基于实际数据 ± 10% 边距,不从零开始,数据点居中显示。

点大小使用二次曲线映射综合得分,放大高分与低分的视觉差异:

1
2
// 范围 4–30px;composite=50 时约 10.5px,composite=90 时约 25px
const size = 4 + Math.pow(composite / 100, 2) * 26;

表格与图表双向联动

  • 鼠标悬停表格行 → 对应散点放大 1.5× + 白色描边,其余点透明度降至 15%

  • 点击表格行 → 钉住高亮,移开鼠标不消失;再次点击取消

  • 鼠标悬停散点 → 对应表格行高亮

1
2
3
4
5
6
7
8
9
10
// 表格行 → 图表
tr.addEventListener('mouseenter', () => {
highlightRow(m.name);
highlightModel(m.name); // dispatchAction highlight 到所有 chart slot
});

// 图表 → 表格(仅注册一次,在 instance 首次创建时)
slot.instance.on('mouseover', params => {
if (params.data?._model) highlightRow(params.data._model.name);
});

图表区高度可调

表格与图表区之间有一个拖动分隔条,范围 140–600px,支持用户自定义两者的屏幕占比。拖动时所有 ECharts 实例调用 resize()


五、排名结果(默认权重)

以 性价比(8) · 性能(8) · 散热(6) · 静音(4) · 体积(3) · OC(1) 为默认权重,全 64 款综合排名前五:

# 型号 综合分 跑分 噪音 温度 价格
1 万丽 RTX 5080 星云 66.2 9153 31.0 dB 65°C ¥8,100
2 影驰 RTX 5080 金属大师白金版 OC 63.4 9141 31.3 dB 68°C ¥9,100
3 万丽 RTX 5080 星舰 OC 63.2 9232 30.6 dB 63°C ¥9,500
4 七彩虹 RTX 5080 Neptune OC 水神 62.4 9202 34.1 dB 54°C ¥11,000
5 万丽 RTX 5080 雪狐 OC 61.8 9120 29.8 dB 66°C ¥8,300

将性价比权重调为 0、性能权重拉满,七彩虹水神(全场最低温 54°C)和 ROG ASTRAL(最高跑分 9400)会进入前三。这正是工具的设计意图:同一批数据,不同偏好的用户得到不同答案。


六、后续计划

  • 补充机箱数据(已预留 Tab 占位),根据显卡长度/厚度/功耗自动匹配可用机箱,同时展示支持的电源规格(ATX/SFX)、散热规格(水冷排尺寸)和 IO 规格

  • 增加更多 GPU 系列(RTX 5070 / 5090 等)

→ 打开可交互可视化工具(RTX 5080 / 5070Ti 横评)