如何用Python绘制不平衡数据两变量散点图?解决x与y长度不匹配报错
问题1:如何使用Python绘制不平衡数据集中两个变量之间的散点图?
不平衡数据集说白了就是某一类样本数量远多于其他类,直接画散点图的话,少数类很容易被多数类的点完全掩盖。给你几个实用的解决思路:
用颜色+大小突出少数类
如果你的数据带类别标签,给不同类别分配不同颜色,甚至给少数类用更醒目的颜色和更大的点。举个例子:import matplotlib.pyplot as plt import numpy as np # 构造不平衡数据:多数类(类别0)1000个样本,少数类(类别1)50个样本 np.random.seed(42) x_major = np.random.normal(loc=5, scale=1, size=1000) y_major = np.random.normal(loc=5, scale=1, size=1000) x_minor = np.random.normal(loc=8, scale=1, size=50) y_minor = np.random.normal(loc=8, scale=1, size=50) plt.scatter(x_major, y_major, label='多数类', alpha=0.5, s=20) plt.scatter(x_minor, y_minor, label='少数类', color='#ff4444', s=40) plt.legend() plt.xlabel('变量X') plt.ylabel('变量Y') plt.title('不平衡数据集散点图') plt.show()给多数类加透明度避免点堆在一起,少数类用大红圆点,一眼就能识别出来。
对多数类做下采样
如果数据量太大,直接从多数类里随机抽取和少数类数量相当的样本,让两类数据平衡后再绘图:from sklearn.utils import resample import pandas as pd # 把数据转成DataFrame方便处理 df_major = pd.DataFrame({'x': x_major, 'y': y_major, 'label': 0}) df_minor = pd.DataFrame({'x': x_minor, 'y': y_minor, 'label': 1}) # 下采样多数类,数量和少数类一致 df_major_downsampled = resample(df_major, n_samples=len(df_minor), random_state=42) df_balanced = pd.concat([df_major_downsampled, df_minor]) # 绘制平衡后的散点图 plt.scatter(df_balanced[df_balanced['label']==0]['x'], df_balanced[df_balanced['label']==0]['y'], label='多数类(下采样)') plt.scatter(df_balanced[df_balanced['label']==1]['x'], df_balanced[df_balanced['label']==1]['y'], color='#ff4444', label='少数类') plt.legend() plt.show()用Seaborn的分类图
Seaborn的stripplot或者swarmplot天生适合处理这类不平衡数据,能自动避免点过度重叠:import seaborn as sns df_all = pd.concat([df_major, df_minor]) sns.stripplot(x='label', y='x', data=df_all, jitter=True, alpha=0.6) plt.title('不平衡数据的X变量分布') plt.show()
问题2:解决
ValueError: x and y must be the same size的绘图问题 这个报错原因很直白:plt.scatter()要求x和y的长度必须完全一致,因为每个x值都得对应一个y值才能确定散点的位置。你的代码里x有6个元素,y只有3个,自然没法配对。具体怎么解决,得看你想实现的效果:
如果是数据输入错误:补全y的长度
如果你本来就想让每个x都对应一个y,那把y补到和x一样长就行:import matplotlib.pyplot as plt x = [1,2,3,4,4,5] y = [1,2,3,4,5,6] # 现在长度和x一致 plt.scatter(x,y) plt.show()如果想让每个y对应多个x值
比如y的第一个值对应x的前两个元素,第二个值对应中间两个,第三个对应最后两个,那就把y扩展成和x长度一致的数组:x = [1,2,3,4,4,5] y = [1,1,2,2,3,3] # 每个y值重复对应x的元素 plt.scatter(x,y) plt.show()如果想绘制分组散点(每个y对应一组x)
可以用循环分别绘制每组:x_groups = [[1,2], [3,4], [4,5]] # 把x分成和y长度对应的三组 y = [1,2,3] for x_group, y_val in zip(x_groups, y): plt.scatter(x_group, [y_val]*len(x_group), label=f'y={y_val}') plt.legend() plt.xlabel('X变量') plt.ylabel('Y变量') plt.show()如果想展示x在不同y类别下的分布
这种情况用箱线图或者小提琴图更合适,不需要x和y长度一致:import seaborn as sns # 把y扩展成和x长度一致,对应每个x所属的类别 y_expanded = [1,1,2,2,3,3] sns.boxplot(x=y_expanded, y=x) plt.title('X变量在不同Y类别下的分布') plt.show()
内容的提问来源于stack exchange,提问作者Shubham S. Naik
相关产品推荐
相关产品推荐

