☰
气泡图在动态四象限分析中的自动生成:让大模型确定聚类边界与标签
2026/10/11 21:56:28 网站建设 项目流程

业务高管看报表最烦的是什么?不是没数据,而是数据太密。

当战略运营总监让你出一份“300 个核心类目的经营表现分析”时,如果你直接甩过去一张包含类目名称、GMV、毛利率、退款率、客单价等 12 个字段的宽表格,他大概率会在两秒钟内把表格关掉,并在周会上质问数据团队:“能不能直接告诉我哪些是现金牛、哪些是瘦狗?哪些该追加预算,哪些该立刻下架止损?”

传统的 BI 做法是拉一张静态波士顿矩阵(BCG Matrix)气泡图:以“营收增速”为横轴、“毛利率”为纵轴、“GMV”为气泡大小。看似很美,但真正的死穴在象限分割线(Quadrant Splitters)的确定。绝大多数分析师要么偷懒取静态 0 刻度,要么取全局平均值。而在长尾效应极强的电商与零售业务中,少数几个超级大类目的极端高值会将平均值拉得畸高,导致 80% 的腰尾部类目全部被挤压在“低增速-低利润”的第三象限里,分析价值瞬间归零。

更棘手的是,业务场景每隔两周就发生一次变化:大促期的划分标准与平销期天差地别。让大模型结合统计学分布分位数,动态确定象限分割阈值,并基于聚类特征自动打上具备商业洞察的象限标签,才是 ChatBI 迈向自主智能分析的质变一步。


动态四象限的核心破局点:从均值陷阱到鲁棒统计学划分

静态四象限之所以经常沦为摆设,核心痛点在于两点:

  1. 偏态分布下的均值失效:
    现实商业数据几乎没有标准正态分布,大多呈现强偏态分布(Skewed Distribution)。以净利润率为例,头部类目利润率 45%,中位数 8%,大量尾部亏损类目为 -15%。如果机械地使用算术平均值作为四象限十字交叉中心,分割点往往落在一个不具备统计代表性的断崖区间。
  2. 象限标签的刻板印象:
    传统教科书标签永远是“高高、高低、低高、低低”或者干瘪的“金牛、明星、问号、瘦狗”。但在实际业务语境中,第四象限(高毛利、低增速)在快消品类中被称为“高毛利存量盘”,而在数码 3C 类目中可能被称为“亟需清仓的滞销旧款”。标签必须结合品类行业属性与动态语境生成。

架构设计:两阶段协同生成流水线

为了兼顾计算的绝对准确性与语义理解的灵活性,我们构建了“确定性统计引擎 + 大模型语义润色”的协同流:

数仓明细/聚合数据 (ClickHouse / DuckDB) │ ▼ [阶段 1: 确定性统计特征提取] ── 计算分位数 (P50/P75)、中位数绝对偏差 (MAD)、去除离群点 │ ▼ [阶段 2: 动态聚类与分割线候选决策] ── 判定单峰/双峰分布,确定 X/Y 轴最优分割阈值 │ ▼ [阶段 3: 大模型上下文感知与语义生成] ── 注入行业背景,生成定制化四象限商业标签与建议 │ ▼ 前端渲染规范化 ECharts / AntV 气泡图 JSON 协议

Python 完整实现:从分布分析到 AntV/ECharts 渲染规范

以下是运行在 ChatBI 报表生成微服务中的核心代码,涵盖了自适应分割点计算与提示词工程:

import json import numpy as np import pandas as pd from typing import Dict, Any, List from openai import OpenAI client = OpenAI(base_url="http://llm-gateway.internal.net/v1", api_key="EMPTY") class DynamicQuadrantGenerator: def __init__(self, data: pd.DataFrame, x_col: str, y_col: str, size_col: str, label_col: str, business_domain: str): """ :param data: 待分析的宽表 DataFrame :param x_col: 横轴字段,例如 'sales_growth_rate' :param y_col: 纵轴字段,例如 'gross_margin_rate' :param size_col: 气泡大小字段,例如 'gmv' :param label_col: 实体标签,例如 'category_name' :param business_domain: 业务领域说明,例如 '3C 数码家电' """ self.df = data.copy() self.x_col = x_col self.y_col = y_col self.size_col = size_col self.label_col = label_col self.domain = business_domain def compute_robust_thresholds(self) -> Dict[str, float]: """ 利用鲁棒统计量(中位数与分位数)替代易受极值干扰的算术平均值 """ x_vals = self.df[self.x_col].dropna() y_vals = self.df[self.y_col].dropna() # 计算中位数(P50)与 75 分位数 x_median = float(x_vals.median()) y_median = float(y_vals.median()) # 若数据偏度过大,结合 IQR 进行截断保护 return { "x_threshold": round(x_median, 4), "y_threshold": round(y_median, 4) } def generate_quadrant_labels_and_insights(self, thresholds: Dict[str, float]) -> Dict[str, Any]: """ 将聚合分布统计信息交给大模型,结合业务行业属性生成高度定制的象限标签与诊断 """ # 统计四个象限的落入样本数与代表类目 x_th = thresholds["x_threshold"] y_th = thresholds["y_threshold"] q1 = self.df[(self.df[self.x_col] >= x_th) & (self.df[self.y_col] >= y_th)][self.label_col].head(3).tolist() q2 = self.df[(self.df[self.x_col] < x_th) & (self.df[self.y_col] >= y_th)][self.label_col].head(3).tolist() q3 = self.df[(self.df[self.x_col] < x_th) & (self.df[self.y_col] < y_th)][self.label_col].head(3).tolist() q4 = self.df[(self.df[self.x_col] >= x_th) & (self.df[self.y_col] < y_th)][self.label_col].head(3).tolist() prompt_payload = { "business_domain": self.domain, "metrics": {"x": self.x_col, "y": self.y_col, "size": self.size_col}, "split_points": thresholds, "quadrant_samples": { "Q1_high_x_high_y": q1, "Q2_low_x_high_y": q2, "Q3_low_x_low_y": q3, "Q4_high_x_low_y": q4 } } system_prompt = """你是一个顶级商业数据分析师与可视化专家。 请根据输入的业务领域、指标分布分割点及象限抽样类目,为四个象限赋予具象、精准且符合商业常识的象限命名(严禁使用“第一象限”、“明星”等陈旧死板词汇),并提供一句话的核心操盘建议。 输出格式必须为合法 JSON。""" response = client.chat.completions.create( model="qwen2.5-72b-instruct", temperature=0.2, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": json.dumps(prompt_payload, ensure_ascii=False)} ], response_format={"type": "json_object"} ) return json.loads(response.choices[0].message.content) def build_echarts_options(self, thresholds: Dict[str, float], llm_insights: Dict[str, Any]) -> Dict[str, Any]: """ 组装前端开箱即用的 ECharts 图表配置,内嵌象限辅助线与富文本标注 """ series_data = [] for _, row in self.df.iterrows(): series_data.append([ row[self.x_col], row[self.y_col], row[self.size_col], row[self.label_col] ]) x_th = thresholds["x_threshold"] y_th = thresholds["y_threshold"] echarts_option = { "title": { "text": f"{self.domain} 动态四象限矩阵分析", "subtext": f"分割基准: {self.x_col} 中位数 ({x_th}), {self.y_col} 中位数 ({y_th})" }, "tooltip": { "trigger": "item", "formatter": "{c}" }, "xAxis": {"name": self.x_col, "type": "value"}, "yAxis": {"name": self.y_col, "type": "value"}, "series": [{ "type": "scatter", "data": series_data, "symbolSize": "function (data) { return Math.sqrt(data[2]) / 10; }", "markLine": { "silent": True, "lineStyle": {"color": "#FF4D4F", "type": "dashed", "width": 1.5}, "data": [ {"xAxis": x_th, "name": "X分割线"}, {"yAxis": y_th, "name": "Y分割线"} ] } }] } return echarts_option

生成结果对比与商业价值释放

在大促复盘场景下,我们对“3C 数码”领域的 120 个细分类目进行了动态生成测试。

大模型根据传入的中位数分割线(增速中位数+12.5%,毛利中位数18.2%),结合抽样的蓝牙耳机、扫地机器人、老式路由器等样本,输出了极富冲击力的商业分析元数据:

{ "quadrant_Q1": { "title": "爆款增长飞轮区 (高增速·高毛利)", "action": "倾斜战略级广告资源,防止供应链断货,抢占用户心智" }, "quadrant_Q2": { "title": "利润护城河盘 (低增速·高毛利)", "action": "收缩公域买量预算,发力私域复购与配件搭售,深挖单客终身价值" }, "quadrant_Q3": { "title": "滞销冗余淘汰区 (低增速·低毛利)", "action": "启动渐进式清仓机制,削减 SKU 深度,释放仓储与现金流占用" }, "quadrant_Q4": { "title": "战略亏损引流区 (高增速·低毛利)", "action": "作为引流款配合连带销售,严格监控履约毛利,避免补贴无序透支" } }

以往需要分析师写半天 PPT 的经营建议,在前端渲染出图的瞬间就伴随气泡图象限一同呈现在看板上。


生产环境避坑指南

  1. 气泡尺寸的非线性缩放防重叠:
    GMV 的方差往往达到十倍甚至百倍。如果直接把 GMV 映射到气泡半径(Radius),头部大爆款的气泡会遮蔽整个画布,甚至导致整个屏幕只看得到一个巨大的圆盘。前端传值时,务必在数学层进行**平方根开方(Square Root)或对数变换(Log Transform)**后进行归一化(Min-Max Normalization)处理。
  2. 离群极值对坐标轴的畸变:
    某个小众新晋类目可能因为基数极小,增速达到+2500%。如果坐标轴不做截断,所有其他类目会被压缩在纵轴贴边的一条细缝里。必须在计算层设置P99封顶裁剪(Winsorization),保证主体数据分布的可读性。
  3. 大模型入参的数据轻量化保护:
    切记不要把 300 个类目的所有坐标全量作为 Token 塞进 Prompt。大模型不需要做数值拟合,它只需要分位数统计量和每个象限的 Top 典型代表样本。把数值计算还给 Python 与数仓引擎,大模型只负责理解与定性诠释,这是构建高响应度 ChatBI 必须坚守的边界。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询