如何让seaborn.kdeplot对负值/零值具备鲁棒性?
问题描述
我有两个存储在原生Python列表中的浮点型变量:
x = [2.232, 2.331, 2.112...] y = [-3.431, 2.213, -1.232...]
注意其中存在负值,调用kde时出现以下错误:
ZeroDivisionError: 0.0 cannot be raised to a negative power.
由于场景对绘图精度要求不高,我尝试给x和y的所有元素临时添加一个小值:
x = [] for i in range(len(raw_data)): x.append(float(raw_data[i][1])+.000000001)
但错误仍然存在,甚至尝试添加更大的值(0.1)也没用。
核心问题
有没有更可靠的方法确保kde调用对非零值具备鲁棒性?手动调整数据无效说明可能还有其他问题。
调用代码
seaborn.kdeplot(x,y)
错误详情
~\Anaconda3\lib\site-packages\statsmodels\nonparametric\bandwidths.py in bw_scott(x, kernel) 53 A = _select_sigma(x) 54 n = len(x) ---> 55 return 1.059 * A * n ** (-0.2) 56 57 def bw_silverman(x, kernel=None):
解决思路与方案
从错误栈来看,问题出在statsmodels的带宽计算函数bw_scott里,n ** (-0.2)报错,说明要么数据长度为0,要么数据的离散程度估计量为0,具体解决方法如下:
检查数据有效性
先确认x和y的长度是否一致且不为空,打印len(x)和len(y)即可。如果其中一个列表为空,或者两者长度不匹配,直接修正数据来源。排查数据方差
如果某一列数据所有值完全相同(比如所有x值都是同一个数),会导致_select_sigma(x)返回0,触发计算错误。可以用以下代码检查方差:import numpy as np print(np.var(x), np.var(y))若方差为0,给该列添加极小的随机噪声(比固定加值更可靠):
x = np.array(x) + np.random.normal(0, 1e-8, size=len(x)) y = np.array(y) + np.random.normal(0, 1e-8, size=len(y))手动指定带宽
绕开自动带宽计算逻辑,直接给kdeplot指定带宽参数:import seaborn as sns # 通过bw_adjust调整平滑程度,数值越大越平滑 sns.kdeplot(x=x, y=y, bw_adjust=0.5) # 或者直接指定固定带宽值 sns.kdeplot(x=x, y=y, bw_method=0.3)数据平移(可选)
若担心负值影响(实际KDE本身支持负值),可以对数据进行平移,确保所有值为正且分布趋势不变:min_x = min(x) min_y = min(y) x_shifted = [val - min_x + 1e-6 for val in x] y_shifted = [val - min_y + 1e-6 for val in y] sns.kdeplot(x_shifted, y_shifted)
内容的提问来源于stack exchange,提问作者Arash Howaida
相关产品推荐
相关产品推荐

