当前位置: 首页 > news >正文

蜂群图核心特点

蜂群图最巧妙的地方在于它的布局算法。

当多个数据点具有相似数值时,它们不会简单地重叠在一起,而是像有“排斥力”一样,在垂直方向(或水平方向)上轻微偏移,形成一个类似蜂群的分布。

比如,下面是同一组数据散点图蜂群图中展示的效果。

从中可以看出蜂群图的核心特点有:

  1. 绝不重叠: 它通过算法检测数据点的重叠情况,一旦发现两个点数值相近,就会自动把它们向水平方向推开。
  2. 保留分布形态: 散开后的形状,天然形成了一种类似“小提琴”或“山峰”的轮廓,直观地展示了数据的密度。
  3. 参数调整: 我们可以调整点的大小(marker size)和排列的紧密程度。点越大,视觉冲击力越强,但需要的水平空间也越多。

2. 蜂群图 vs. 条形图:从摘要到细节

条形图就像是一份数据摘要报告,它告诉我们每个类别的平均值或总计值,但隐藏了数据内部的分布细节。

蜂群图则像是一次数据点的全员大会,每个数据点都有发言的机会。

下面针对同一组数据,我们分别绘制了条形图箱线图蜂群图,一起来感受一下它们之间不同的展示效果。

<span style="color:#000000"><span style="background-color:#ffffff"><code class="language-python"><span style="color:#008000"># 生成示例数据</span> np.random.seed(<span style="color:#880000">123</span>) categories = [<span style="color:#a31515">"产品A"</span>, <span style="color:#a31515">"产品B"</span>, <span style="color:#a31515">"产品C"</span>, <span style="color:#a31515">"产品D"</span>] data_comparison = [] <span style="color:#0000ff">for</span> category <span style="color:#0000ff">in</span> categories: n_points = <span style="color:#880000">40</span> <span style="color:#0000ff">if</span> category == <span style="color:#a31515">"产品A"</span>: values = np.random.normal(<span style="color:#880000">75</span>, <span style="color:#880000">8</span>, n_points) <span style="color:#0000ff">elif</span> category == <span style="color:#a31515">"产品B"</span>: values = np.random.normal(<span style="color:#880000">82</span>, <span style="color:#880000">12</span>, n_points) <span style="color:#0000ff">elif</span> category == <span style="color:#a31515">"产品C"</span>: values = np.random.normal(<span style="color:#880000">65</span>, <span style="color:#880000">5</span>, n_points) <span style="color:#0000ff">else</span>: <span style="color:#008000"># 产品D</span> <span style="color:#008000"># 创建一个双峰分布</span> values1 = np.random.normal(<span style="color:#880000">55</span>, <span style="color:#880000">6</span>, n_points // <span style="color:#880000">2</span>) values2 = np.random.normal(<span style="color:#880000">85</span>, <span style="color:#880000">7</span>, n_points // <span style="color:#880000">2</span>) values = np.concatenate([values1, values2]) <span style="color:#0000ff">for</span> value <span style="color:#0000ff">in</span> values: data_comparison.append({<span style="color:#a31515">"产品"</span>: category, <span style="color:#a31515">"用户评分"</span>: value}) <span style="color:#008000"># 1. 条形图(平均值)</span> means = [] <span style="color:#0000ff">for</span> category <span style="color:#0000ff">in</span> categories: cat_data = [d[<span style="color:#a31515">"用户评分"</span>] <span style="color:#0000ff">for</span> d <span style="color:#0000ff">in</span> data_comparison <span style="color:#0000ff">if</span> d[<span style="color:#a31515">"产品"</span>] == category] means.append(np.mean(cat_data)) bars = axes[<span style="color:#880000">0</span>].bar( categories, means, color=[<span style="color:#a31515">"#1f77b4"</span>, <span style="color:#a31515">"#ff7f0e"</span>, <span style="color:#a31515">"#2ca02c"</span>, <span style="color:#a31515">"#d62728"</span>] ) <span style="color:#008000"># 在条形上标注平均值</span> <span style="color:#008000"># 省略...</span> <span style="color:#008000"># 2. 箱线图</span> box_data = [] <span style="color:#0000ff">for</span> category <span style="color:#0000ff">in</span> categories: cat_data = [d[<span style="color:#a31515">"用户评分"</span>] <span style="color:#0000ff">for</span> d <span style="color:#0000ff">in</span> data_comparison <span style="color:#0000ff">if</span> d[<span style="color:#a31515">"产品"</span>] == category] box_data.append(cat_data) boxplot = axes[<span style="color:#880000">1</span>].boxplot( box_data, tick_labels=categories, patch_artist=<span style="color:#a31515">True</span>, boxprops=<span style="color:#0000ff">dict</span>(facecolor=<span style="color:#a31515">"lightblue"</span>) ) <span style="color:#008000"># 省略...</span> <span style="color:#008000"># 3. 蜂群图</span> data_df = pd.DataFrame(data_comparison) sns.swarmplot( x=<span style="color:#a31515">"产品"</span>, y=<span style="color:#a31515">"用户评分"</span>, hue=<span style="color:#a31515">"产品"</span>, data=data_df, ax=axes[<span style="color:#880000">2</span>], size=<span style="color:#880000">5</span>, palette=<span style="color:#a31515">"Set2"</span>, edgecolor=<span style="color:#a31515">"black"</span>, linewidth=<span style="color:#880000">0.5</span>, ) <span style="color:#008000"># 省略...</span> plt.tight_layout() plt.show() </code></span></span>

绘制蜂群图可以用seaborn这个库中的swarmplot函数。

从上面的对比可以看出:

  • 条形图告诉我们产品D的平均分约为70分
  • 箱线图提示产品D的数据分布范围很广
  • 但只有蜂群图清晰地揭示了产品D实际上有两个明显的用户群体:一个低评分群体和一个高评分群体

3. 蜂群图 vs. 散点图:从混乱到有序

传统散点图在处理分类数据时,常常导致数据点大量重叠,形成"黑团",我们无法看清数据点的真实分布。

蜂群图通过智能布局算法解决了这个问题。

下面构造一个不同密度的数据,看看蜂群图和散点图的展示效果。

<span style="color:#000000"><span style="background-color:#ffffff"><code class="language-python"><span style="color:#008000"># 比较散点图与蜂群图的视觉效果</span> fig, axes = plt.subplots(<span style="color:#880000">1</span>, <span style="color:#880000">2</span>, figsize=(<span style="color:#880000">14</span>, <span style="color:#880000">6</span>)) <span style="color:#008000"># 生成具有不同密度的数据</span> np.random.seed(<span style="color:#880000">42</span>) density_data = [] categories = [<span style="color:#a31515">"低密度"</span>, <span style="color:#a31515">"中等密度"</span>, <span style="color:#a31515">"高密度"</span>] <span style="color:#0000ff">for</span> i, category <span style="color:#0000ff">in</span> <span style="color:#0000ff">enumerate</span>(categories): n_points = <span style="color:#880000">20</span> + i * <span style="color:#880000">30</span> <span style="color:#008000"># 不同密度</span> <span style="color:#0000ff">if</span> category == <span style="color:#a31515">"低密度"</span>: values = np.random.normal(<span style="color:#880000">50</span>, <span style="color:#880000">15</span>, n_points) <span style="color:#0000ff">elif</span> category == <span style="color:#a31515">"中等密度"</span>: values = np.random.normal(<span style="color:#880000">50</span>, <span style="color:#880000">8</span>, n_points) <span style="color:#0000ff">else</span>: <span style="color:#008000"># 高密度</span> values = np.random.normal(<span style="color:#880000">50</span>, <span style="color:#880000">4</span>, n_points) <span style="color:#0000ff">for</span> value <span style="color:#0000ff">in</span> values: density_data.append({<span style="color:#a31515">"类别"</span>: category, <span style="color:#a31515">"数值"</span>: value}) <span style="color:#008000"># 左侧:传统散点图</span> <span style="color:#0000ff">for</span> i, category <span style="color:#0000ff">in</span> <span style="color:#0000ff">enumerate</span>(categories): cat_data = [d[<span style="color:#a31515">"数值"</span>] <span style="color:#0000ff">for</span> d <span style="color:#0000ff">in</span> density_data <span style="color:#0000ff">if</span> d[<span style="color:#a31515">"类别"</span>] == category] x_positions = np.full(<span style="color:#0000ff">len</span>(cat_data), i) axes[<span style="color:#880000">0</span>].scatter(x_positions, cat_data, alpha=<span style="color:#880000">0.6</span>, s=<span style="color:#880000">60</span>, label=category) <span style="color:#008000">#省略...</span> <span style="color:#008000"># 右侧:蜂群图</span> density_data_df = pd.DataFrame(density_data) sns.swarmplot( x=<span style="color:#a31515">"类别"</span>, y=<span style="color:#a31515">"数值"</span>, hue=<span style="color:#a31515">"类别"</span>, data=density_data_df, ax=axes[<span style="color:#880000">1</span>], size=<span style="color:#880000">6</span>, palette=<span style="color:#a31515">"coolwarm"</span>, edgecolor=<span style="color:#a31515">"black"</span>, linewidth=<span style="color:#880000">0.5</span>, ) <span style="color:#008000">#省略...</span> plt.tight_layout() plt.show() </code></span></span>

蜂群图解决了“重叠(Overplotting)”的问题。在数据量适中(几百到几千个点)时,它是展示分布密度的最佳选择。

4. 蜂群图的适用场景

蜂群图并不是为了取代条形图散点图,它有自己的适用场景和局限性。

适合使用蜂群图的场景:

  • 样本量适中(通常少于几百个点)时,展示完整数据分布
  • 需要同时看到整体趋势和个体数据点
  • 数据有多个分类变量,需要比较不同类别分布
  • 希望发现异常值或特殊模式(如双峰分布)

蜂群图局限性主要有:

  1. 大数据集可能导致图表过于拥挤
  2. 对于非常大规模数据,箱线图或小提琴图可能更合适
  3. 精确的数值比较不如条形图直观
http://www.jsqmd.com/news/1101430/

相关文章:

  • 用Python玩转量子退火:手把手教你实现subQUBO算法解决TSP问题
  • 速率管理化技术中的速率计划速率实施速率验证
  • OriginOS 6状态栏交互与视觉自定义技术解析:Android 15适配指南
  • 矿山安全监测数据采集物联网方案
  • 手把手教你用Matlab和Argo数据复现海平面变化研究(附完整代码与避坑指南)
  • 手把手教你用杰理AC695x的I2C驱动ACM8625S数字功放(附完整代码)
  • WaveTools鸣潮工具箱终极指南:3步快速安装,解锁帧率优化与抽卡分析
  • Minecraft服务器包生成技术指南:ServerPackCreator架构解析与性能优化
  • 快手Agent开发一面:什么是 A2A 协议?它和 MCP 协议的区别是什么?
  • 目标检测多尺度特征融合:原理、演进与YOLO实战指南
  • 告别DHT11!用ESP32-S3和AHT20搭建高精度温湿度监测站(附完整代码与避坑指南)
  • 当 Agent 有了情绪和身体:我用魔珐星云做了一个会共情的具身 Agent
  • VMware OVF导出效率提升300%的黄金配置(附实测对比数据与vSphere 8.0兼容性验证)
  • 如何写出对单元测试“友好”的代码?
  • 别再手动插图片了!用EasyExcel 3.0.5 + POI 3.17,一键生成带产品图的Excel报告
  • 数据库安全管理策略
  • 一高科技集团AI+教育战略的核心理念与落地路径
  • EDA 签核高峰总是撞车,企业该怎么安排许可证时段
  • Rust Trait 对象的动态派发机制
  • 5分钟掌握ServerPackCreator:Minecraft服务器包自动化生成终极指南
  • Illustrator对象排序终极指南:用Harmonizer脚本告别手动排列噩梦
  • “监、管、控”一体化网管运维方案
  • 告别模拟器:5步在Windows电脑上直接运行安卓应用
  • 别怕传递函数!用MATLAB和Mathcad手把手教你搞定开关电源环路分析
  • Platinum-MD:让复古MiniDisc在数字时代重获新生的音乐时光机
  • 保姆级教程:用Python搞定PTA L3-035完美树(树形DP+贪心优化)
  • AI代码审查工具到底值不值得上?一线团队3个月实测数据揭示真实ROI与隐性成本
  • 别再只画折线图了!用C++实现时间延迟嵌入,从单列数据里挖出隐藏的动力学
  • AI 电动香薰机智能功率 MOSFET 完整选型方案
  • 2026中小商家必备AI工具:别再只用它聊天,这才是自动化获客的实战指南!