如何用点而非条形绘制频率图?已有分箱与频率值
分箱频率点图绘制方案
需求说明
需要绘制分箱频率点图,已提前计算好分箱区间(low_bin、high_bin)和对应频率(frequency),样本数据如下:
import pandas as pd df_fd = pd.DataFrame({ 'low_bin': [13.142857, 18.857143, 24.571429, 30.285714, 36.000000, 41.714286, 47.428571, 53.142857], 'high_bin': [18.857143, 24.571429, 30.285714, 36.000000, 41.714286, 47.428571, 53.142857, 58.857143], 'frequency': [3,5,8,8,7,7,1,1] })
原代码问题分析
原代码中Y[Y>df_fd['frequency']] = np.nan执行失败,核心原因是维度不匹配:
df_fd['frequency']是长度为8的一维数组Y是np.meshgrid生成的二维数组,行数等于最大频率值,列数等于每个分箱的x点数- 直接进行比较会触发numpy广播错误,无法逐行匹配分箱的频率阈值
解决方案一:直接生成点坐标(推荐)
跳过meshgrid,直接为每个分箱生成对应数量的点,逻辑更直观:
import matplotlib.pyplot as plt import numpy as np fig, ax = plt.subplots(figsize=(8, 5)) # 绘制底层柱状图 ax.bar( df_fd.low_bin, df_fd.frequency, width=df_fd.high_bin - df_fd.low_bin, edgecolor='black', alpha=0.3, label='Frequency Bar' ) # 为每个分箱生成区间内的x坐标(均匀分布,可调整点数) x_per_bin = np.linspace(df_fd.low_bin, df_fd.high_bin, num=8, axis=1) # 生成每个分箱对应的y坐标(1到对应frequency的整数) x_points = [] y_points = [] for idx, freq in enumerate(df_fd.frequency): # 取对应分箱的前freq个x点(保证点数和频率一致) selected_x = x_per_bin[idx][:freq] # 生成y值:1到freq selected_y = np.arange(1, freq + 1) # 添加到总列表 x_points.extend(selected_x) y_points.extend(selected_y) # 绘制散点图 ax.scatter(x_points, y_points, color='black', s=20, label='Frequency Points') # 美化图表 ax.set_xlabel('Value Range') ax.set_ylabel('Frequency') ax.legend() plt.tight_layout() plt.show()
解决方案二:修正原代码的维度问题
如果坚持使用meshgrid,需要将频率数组转为二维,实现逐行阈值判断:
import matplotlib.pyplot as plt import numpy as np fig, ax = plt.subplots(figsize=(8, 5)) # 绘制柱状图 ax.bar(df_fd.low_bin, df_fd.frequency, width=df_fd.high_bin - df_fd.low_bin, edgecolor='black', alpha=0.3) # 每个分箱生成10个x点 x_per_bin = np.linspace(df_fd.low_bin, df_fd.high_bin, num=10, axis=1) # 最大频率作为y轴的行数 max_freq = df_fd.frequency.max() # 生成网格 X, Y = np.meshgrid(x_per_bin[0], np.arange(1, max_freq + 1)) # 将频率转为二维数组(行数与Y一致,列数为1) freq_2d = df_fd.frequency.values[:, None] # 创建掩码:Y超过对应分箱频率的位置设为True mask = Y > freq_2d # 掩码应用到Y,超过的设为nan Y[mask] = np.nan # 扁平化数组并过滤nan valid_x = X[~np.isnan(Y)] valid_y = Y[~np.isnan(Y)] # 绘制散点图 ax.scatter(valid_x, valid_y, color='black', s=20) ax.set_xlabel('Value Range') ax.set_ylabel('Frequency') plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者Python_Learner
相关产品推荐
相关产品推荐

