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

学习笔记(34):matplotlib绘制图表-房价数据分析与可视化

学习笔记(34):matplotlib绘制图表-房价数据分析与可视化

分析房价分布情况,通过直方图、核密度估计和正态分布拟合来直观展示房价的分布特征,并进行统计检验。

一、房价数据分析与可视化,代码分析

1.1、导入必要的库

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from scipy import stats
import os

  • 导入数据处理 (pandas)、绘图 (matplotlib, seaborn)库
  • 导入数学计算 (numpy, scipy) 和文件操作 (os) 库

1.2、设置中文字体和负号显示

# 设置 Windows 系统的中文字体
plt.rcParams["font.family"] = ["SimHei", "Microsoft YaHei"]
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

  • 设置了适用于 Windows 系统的中文字体,确保图表中的中文能正常显示
  • 解决了负号显示为方块的问题

1.3、数据加载函数 load_data()

def load_data(file_path):"""加载房价数据"""try:# 尝试读取CSV文件data = pd.read_csv(file_path)print(f"数据加载成功,共{data.shape[0]}条记录,{data.shape[1]}个特征")print(f"数据特征: {', '.join(data.columns.tolist())}")return dataexcept FileNotFoundError:print(f"错误: 文件 '{file_path}' 不存在")# 创建示例数据用于演示print("创建示例数据用于演示...")np.random.seed(42)size = 500data = pd.DataFrame({'price': np.random.normal(15000, 3000, size),  # 房价,单位:万元'area': np.random.normal(100, 20, size),  # 面积,单位:平方米'age': np.random.randint(1, 30, size),  # 房龄,单位:年})# 确保房价与面积正相关,与房龄负相关data['price'] = data['price'] + 50 * data['area'] - 100 * data['age']data['price'] = data['price'].clip(lower=5000)  # 设置价格下限return data
  • 尝试从指定路径加载 CSV 文件
  • 如果文件不存在,会生成模拟数据:
    • 使用正态分布生成房价、面积数据
    • 使用均匀分布生成房龄数据
    • 通过公式price = base_price + 50*area - 100*age确保房价与面积正相关,与房龄负相关
    • 设置房价下限为 5000 万元

1.4、房价分布可视化函数 plot_price_distribution()

def plot_price_distribution(data, price_col='price'):"""绘制房价分布直方图"""plt.figure(figsize=(10, 6))# 绘制直方图和核密度估计sns.histplot(data[price_col], kde=True, bins=30, color='skyblue')# 添加均值和中位数线mean_val = data[price_col].mean()median_val = data[price_col].median()plt.axvline(mean_val, color='red', linestyle='dashed', linewidth=2, label=f'均值: {mean_val:.2f}')plt.axvline(median_val, color='green', linestyle='dashed', linewidth=2, label=f'中位数: {median_val:.2f}')# 添加正态分布拟合曲线mu, sigma = stats.norm.fit(data[price_col])x = np.linspace(data[price_col].min(), data[price_col].max(), 100)plt.plot(x, stats.norm.pdf(x, mu, sigma) * len(data) * (x.max() - x.min()) / 100,'r--', linewidth=2, label=f'正态分布拟合: μ={mu:.2f}, σ={sigma:.2f}')plt.title('房价分布直方图')plt.xlabel('房价 (万元)')plt.ylabel('频数')plt.legend()plt.grid(axis='y', alpha=0.5)plt.tight_layout()# 保存图像if not os.path.exists('plots'):os.makedirs('plots')plt.savefig('plots/price_distribution.png', dpi=300)plt.show()# 打印统计信息print("\n房价统计信息:")print(data[price_col].describe())# 检验正态性stat, p = stats.normaltest(data[price_col])print(f"\n正态性检验 (p值): {p:.4f}")if p < 0.05:print("房价分布显著偏离正态分布")else:print("房价分布近似正态分布")
  • 创建 10x6 英寸的图表
  • 使用 seaborn 绘制直方图和核密度估计曲线
  • 添加均值 (红色虚线) 和中位数 (绿色虚线) 参考线
  • 拟合正态分布曲线并绘制 (红色虚线)
  • 设置图表标题、轴标签,添加图例和网格线
  • 将图表保存到 plots 文件夹,并显示图表
  • 打印房价的描述性统计信息 (计数、均值、标准差等)
  • 使用stats.normaltest进行正态性检验并输出结果

1.5、主函数 main()

def main():"""主函数:执行数据加载和价格分布分析"""file_path = '../../data/house_prices.csv'  # 替换为实际文件路径# 1. 加载数据data = load_data(file_path)# 2. 绘制房价分布直方图plot_price_distribution(data)print("\n数据分析完成!图表已保存到 'plots' 文件夹")
  • 设置数据文件路径
  • 调用load_data()加载数据
  • 调用plot_price_distribution()分析并可视化房价分布
  • 打印分析完成信息

1.6、程序入口

if __name__ == "__main__":
main()

  • 确保程序作为脚本直接运行时才执行main()函数
  • 如果作为模块导入,则不会执行

代码优化建议

  1. 添加更多错误处理,如处理空数据的情况
  2. 可以将图表保存路径作为参数传入
  3. 正态分布曲线的高度计算可以更精确
  4. 可以添加更多的房价分析维度,如不同房龄、面积段的价格分布

二、代码和执行结果

2.1、代码

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from scipy import stats
import os# 设置 Windows 系统的中文字体
plt.rcParams["font.family"] = ["SimHei", "Microsoft YaHei"]
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题def load_data(file_path):"""加载房价数据"""try:# 尝试读取CSV文件data = pd.read_csv(file_path)print(f"数据加载成功,共{data.shape[0]}条记录,{data.shape[1]}个特征")print(f"数据特征: {', '.join(data.columns.tolist())}")return dataexcept FileNotFoundError:print(f"错误: 文件 '{file_path}' 不存在")# 创建示例数据用于演示print("创建示例数据用于演示...")np.random.seed(42)size = 500data = pd.DataFrame({'price': np.random.normal(15000, 3000, size),  # 房价,单位:万元'area': np.random.normal(100, 20, size),  # 面积,单位:平方米'age': np.random.randint(1, 30, size),  # 房龄,单位:年})# 确保房价与面积正相关,与房龄负相关data['price'] = data['price'] + 50 * data['area'] - 100 * data['age']data['price'] = data['price'].clip(lower=5000)  # 设置价格下限return datadef plot_price_distribution(data, price_col='price'):"""绘制房价分布直方图"""plt.figure(figsize=(10, 6))# 绘制直方图和核密度估计sns.histplot(data[price_col], kde=True, bins=30, color='skyblue')# 添加均值和中位数线mean_val = data[price_col].mean()median_val = data[price_col].median()plt.axvline(mean_val, color='red', linestyle='dashed', linewidth=2, label=f'均值: {mean_val:.2f}')plt.axvline(median_val, color='green', linestyle='dashed', linewidth=2, label=f'中位数: {median_val:.2f}')# 添加正态分布拟合曲线mu, sigma = stats.norm.fit(data[price_col])x = np.linspace(data[price_col].min(), data[price_col].max(), 100)plt.plot(x, stats.norm.pdf(x, mu, sigma) * len(data) * (x.max() - x.min()) / 100,'r--', linewidth=2, label=f'正态分布拟合: μ={mu:.2f}, σ={sigma:.2f}')plt.title('房价分布直方图')plt.xlabel('房价 (万元)')plt.ylabel('频数')plt.legend()plt.grid(axis='y', alpha=0.5)plt.tight_layout()# 保存图像if not os.path.exists('plots'):os.makedirs('plots')plt.savefig('plots/price_distribution.png', dpi=300)plt.show()# 打印统计信息print("\n房价统计信息:")print(data[price_col].describe())# 检验正态性stat, p = stats.normaltest(data[price_col])print(f"\n正态性检验 (p值): {p:.4f}")if p < 0.05:print("房价分布显著偏离正态分布")else:print("房价分布近似正态分布")def main():"""主函数:执行数据加载和价格分布分析"""file_path = '../../data/house_prices.csv'  # 替换为实际文件路径# 1. 加载数据data = load_data(file_path)# 2. 绘制房价分布直方图plot_price_distribution(data)print("\n数据分析完成!图表已保存到 'plots' 文件夹")if __name__ == "__main__":main()

2.2、执行结果

数据加载成功,共21条记录,4个特征
数据特征: area, price, age, bedrooms

房价统计信息:
count       21.000000
mean     15619.047619
std       2854.403449
min      12000.000000
25%      13000.000000
50%      16000.000000
75%      18000.000000
max      20000.000000
Name: price, dtype: float64

正态性检验 (p值): 0.0725
房价分布近似正态分布

数据分析完成!图表已保存到 'plots' 文件夹

三、1.4中的部分详解

1.4.1、正态分布拟合曲线绘制代码详解

mu, sigma = stats.norm.fit(data[price_col])
x = np.linspace(data[price_col].min(), data[price_col].max(), 100)
plt.plot(x, stats.norm.pdf(x, mu, sigma) * len(data) * (x.max() - x.min()) / 100,
'r--', linewidth=2, label=f'正态分布拟合: μ={mu:.2f}, σ={sigma:.2f}')

1. 计算正态分布参数

mu, sigma = stats.norm.fit(data[price_col])

  • stats.norm.fit() 是 SciPy 库中用于拟合正态分布的函数
  • 它使用最大似然估计方法,根据输入数据计算最匹配的正态分布参数
  • 返回两个值:
    • mu:正态分布的均值(位置参数)
    • sigma:正态分布的标准差(尺度参数)
2. 生成曲线绘制的 x 坐标

x = np.linspace(data[price_col].min(), data[price_col].max(), 100)

  • np.linspace() 在房价数据的最小值和最大值之间生成 100 个均匀分布的点
  • 这 100 个点将作为曲线的 x 坐标,确保曲线覆盖整个数据范围
  • 例如,如果房价最小值是 5000,最大值是 25000,则会生成从 5000 到 25000 的 100 个点
3. 计算正态分布曲线的 y 坐标(核心难点)

stats.norm.pdf(x, mu, sigma) * len(data) * (x.max() - x.min()) / 100

这部分代码可以分解为三个关键部分:

3.1 计算理论概率密度值

stats.norm.pdf(x, mu, sigma)

  • stats.norm.pdf() 计算正态分布的概率密度函数 (Probability Density Function, PDF)
  • 输入参数:
    • x:前面生成的 100 个房价坐标点
    • mu 和 sigma:前面拟合得到的正态分布参数
  • 输出:每个 x 点对应的正态分布概率密度值
3.2 缩放因子 - 样本量调整

* len(data)

  • 乘以样本数量(数据行数)
  • 这一步将概率密度转换为理论频数
  • 例如,如果某个房价区间的理论概率是 0.05,样本量是 500,则理论频数是 0.05 * 500 = 25
3.3 缩放因子 - 区间宽度调整

* (x.max() - x.min()) / 100

  • (x.max() - x.min()) / 100 计算每个区间的宽度
  • 这一步调整曲线高度以匹配直方图的区间宽度
  • 例如,如果房价范围是 20000(25000-5000),分成 100 个区间,则每个区间宽度是 200
4. 绘制正态分布曲线

plt.plot(x, y, 'r--', linewidth=2, label=f'正态分布拟合: μ={mu:.2f}, σ={sigma:.2f}')

  • 使用 matplotlib 的 plot 函数绘制曲线
  • 参数说明:
    • x:横坐标(房价值)
    • y:纵坐标(调整后的理论频数)
    • 'r--':红色虚线
    • linewidth=2:线宽 2
    • label:图例标签,显示拟合的正态分布参数(保留两位小数)

为什么需要这些缩放因子?

正态分布的概率密度函数 (PDF) 返回的是概率密度值,范围通常很小(例如 0-0.0001),直接绘制会与直方图的高度不匹配。通过乘以样本量和区间宽度,可以将理论概率密度转换为与直方图可比的理论频数,使曲线与直方图在同一尺度上显示,便于直观比较数据分布与正态分布的拟合程度。

示例说明

假设:

  • 房价数据范围:5000-25000 万元
  • 样本量:500 条
  • 拟合的正态分布参数:μ=15000, σ=3000
  • 某点 x=15000 处的概率密度值:stats.norm.pdf (15000, 15000, 3000) ≈ 0.000133

经过缩放计算:

0.000133 * 500 * (25000-5000)/100 ≈ 0.000133 * 500 * 200 ≈ 13.3

这意味着在 x=15000 处,理论上该区间的频数约为 13.3,这个值与直方图在该区间的高度可比。

常见问题与优化

  1. 如果直方图的 bins 数量不是 100,需要相应调整缩放因子中的分母
  2. 对于偏态分布,正态拟合可能不佳,可以考虑使用其他分布(如对数正态、伽马分布等)
  3. 可以添加判断逻辑,根据 bins 数量自动计算缩放因子,提高代码通用性

http://www.xdnf.cn/news/15258.html

相关文章:

  • 【数据结构与算法】203.移除链表元素(LeetCode)图文详解
  • 05 唤醒词检测:让语音助手随时待命
  • 平板柔光屏与镜面屏的区别有哪些?技术原理与适用场景全解析
  • Kotlin 常用语法糖完整整理
  • 如何准确查看服务器网络的利用率?
  • 云防火墙有什么用?
  • SoC程序如何使用单例模式运行
  • 企业网络安全的“金字塔”策略:构建全方位防护体系的核心思路
  • OSCP官方靶场-Solstice WP
  • AI驱动的业务系统智能化转型:从静态配置到动态认知的范式革命
  • 【办公类-107-01】20250710视频慢速与视频截图
  • mysql join语句、全表扫描 执行优化与访问冷数据对内存命中率的影响
  • MySQL索引:数据库的超级目录
  • 第35周—————糖尿病预测模型优化探索
  • Android 插件化实现原理详解
  • Apache Dubbo实战:JavaSDK使用
  • 动态物体滤除算法
  • MyBatis-Plus 中使用 Wrapper 自定义 SQL
  • Linux C 文件基本操作
  • 【oscp】超长攻击链vulhub靶机,TommyBoy1dot0
  • 登录为图片验证时,selenium通过token直接进入页面操作
  • ResolvableType 解密Java泛型反射
  • 【会员专享数据】2013-2024年我国省市县三级逐月SO₂数值数据(Shp/Excel格式)
  • 深入拆解Spring核心思想之一:IoC
  • 北京-4年功能测试2年空窗-报培训班学测开-第四十七天
  • 常见射频电路板工艺流程
  • Spring Boot项目中大文件上传的高级实践与性能优化
  • 打破技术债困境:从“保持现状”到成为变革的推动者
  • 机器学习11——支持向量机上
  • 【博主亲测可用】PS2025最新版:Adobe Photoshop 2025 v26.8.1 激活版(附安装教程)