如何用Seaborn distplot可视化高标准差数据的双侧尾部细节?
绘制高标准差双侧长尾数据分布的优化方案
问题背景
我有一个float类型的pd.Series,数据统计特征如下:
>>> pd.Series(foo).describe() count 3.351198e+07 mean -2.337614e+02 std 4.788547e+04 min -9.999999e+06 25% 0.000000e+00 50% 0.000000e+00 75% 0.000000e+00 max 7.499913e+07 >>> pd.Series(foo).std() 47885.47066964969
数据高度集中在0值附近,但双侧存在明显长尾与异常值。当前使用sns.distplot(新版本seaborn建议用sns.histplot)结合对数刻度的方式仅对绝对值有效,无法细致观察双侧尾部的差异。
当前代码:
bins = [0, 10, 100, 1000, 10000, 100000, 100000, 100000000] bins = [-i for i in bins[:1:-1] ] + bins g = sns.distplot(foo.values,bins=bins,kde=False) g.set_xscale('log')
优化方案
1. 拆分正负数据分别绘制对数直方图
将数据拆分为正值、负值(排除0),分左右子图绘制,直接对比双侧尾部的分布细节:
import seaborn as sns import matplotlib.pyplot as plt import pandas as pd # 拆分数据 positive_vals = foo[foo > 0] negative_abs = foo[foo < 0].abs() # 取绝对值适配对数刻度 # 创建子图 fig, (ax_neg, ax_pos) = plt.subplots(1, 2, figsize=(12, 5)) # 绘制负向尾部(绝对值) sns.histplot(negative_abs, bins=[10**i for i in range(0, 8)], kde=False, ax=ax_neg) ax_neg.set_xscale('log') ax_neg.set_title('负向尾部(绝对值)') ax_neg.set_xlabel('数值绝对值') ax_neg.set_ylabel('频数') # 绘制正向尾部 sns.histplot(positive_vals, bins=[10**i for i in range(0, 8)], kde=False, ax=ax_pos) ax_pos.set_xscale('log') ax_pos.set_title('正向尾部') ax_pos.set_xlabel('数值') plt.tight_layout() plt.show()
2. 使用对称对数刻度(symlog)
matplotlib的symlog刻度可直接处理正负值,压缩0附近的刻度密度,放大尾部细节:
import seaborn as sns import matplotlib.pyplot as plt # 自定义对称区间bins bins = [-1e7, -1e6, -1e5, -1e4, -1e3, -1e2, -10, 0, 10, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7] g = sns.histplot(foo, bins=bins, kde=False) # linthresh设置0附近线性刻度的范围,超出部分用对数刻度 g.set_xscale('symlog', linthresh=10) g.set_title('对称对数刻度下的全数据分布') plt.show()
这种方式保留了数值的正负方向,同时让尾部的细节清晰可见,0附近用线性刻度展示集中分布。
3. 分面网格精细化展示
通过分面网格分别展示0附近、负尾部、正尾部的分布,按需设置刻度:
import seaborn as sns import matplotlib.pyplot as plt import pandas as pd # 给数据打分组标签 df = pd.DataFrame({'value': foo}) df['group'] = pd.cut(df['value'], bins=[-1e8, -10, 0, 10, 1e8], labels=['负尾部', '0附近负值', '0附近正值', '正尾部']) # 绘制分面直方图 g = sns.FacetGrid(df, col='group', col_wrap=2, sharex=False, sharey=False) g.map(sns.histplot, 'value', kde=False) # 为尾部子图设置对数刻度 for ax, group_name in zip(g.axes, g.col_names): if group_name in ['负尾部', '正尾部']: ax.set_xscale('symlog' if group_name == '负尾部' else 'log') ax.set_title(group_name) plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者euh
相关产品推荐
相关产品推荐

