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

学习笔记(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.lryc.cn/news/584910.html

相关文章:

  • Anaconda及Conda介绍及使用
  • 基于生产者消费者模型的线程池【Linux操作系统】
  • React之旅-05 List Key
  • 《探索电脑麦克风声音采集多窗口实时可视化技术》
  • 基于MuJoCo的宇树科技G1机器人基础动作仿真研究
  • Java 大视界 -- Java 大数据在智能医疗远程手术机器人操作数据记录与分析中的应用(342)
  • 两台电脑通过网线直连形成局域网,共享一台wifi网络实现上网
  • 项目开发日记
  • 【web应用】若依框架中,使用Echarts导出报表为PDF文件
  • Kafka——应该选择哪种Kafka?
  • XPath 语法【Web 自动化-定位方法】
  • 【操作系统】线程
  • [特殊字符] 扫描式处理:Python 自动提取 PDF 中关键词相关表格并导出为 Excel
  • 云、实时、时序数据库混合应用:医疗数据管理的革新与展望(下)
  • lodash不支持 Tree Shaking 而 lodash-es可以
  • 零基础入门指南:华为数通认证体系详解
  • 代码随想录|图论|10水流问题
  • 视频人脸处理——人脸面部动作提取
  • 静电式 vs UV 光解:哪种油烟净化技术更适合你的餐厅?
  • python的病例管理系统
  • 【JMeter】执行系统命令
  • VS 按F12 提示cannot navigate to the symbol under the caret
  • 机器学习详解
  • linux中INIT_MM_CONTEXT宏对pgd的重复赋值
  • Windows 10 2021 LTSC【版本号:19044.6036】
  • 设计模式笔记_结构型_代理模式
  • 小白学Python,标准库篇——随机库、正则表达式库
  • 【跟着PMP学习项目管理】每日一练 - 5
  • C++,从汇编角度看《虚拟继承的邪恶》
  • 【Linux】GDB/CGDB 调试器学习笔记