这一章做一个二手房房价分析与预测系统:清洗、画图、分组统计、多特征回归。 数据 1206 行 10 个字段,脏的地方五类;洗完剩 1184 行。 界面用 tkinter,本沙箱没有显示器不执行;界面后面那四件事全部真跑。
第 10 章的数据是日销售流水,有时间序;这一章是房源挂牌表,没有时间序。 差别看着小,切训练集的方式正好相反——这是本章最该记住的一处对照。
一、系统要做什么
一个二手房的小系统:选一个区、看均价、看户型、估一套房值多少。 教材用 tkinter 做界面,窗口里四块:数据区、图表区、预测区、导出区。 界面对分析没有半点帮助,它只是把结果端到人面前。所以这一章的重点不在窗口。
重点是窗口后面那四件事:把数据洗干净、把图画出来、把区域和户型算清楚、把价格预测出来。 这四件事一件压一件:数据不干净,图画出来是错的;图没看明白,模型的特征就选不对。
二、数据长什么样
| 字段 | 含义 | 单位 |
|---|---|---|
| 编号 | 房源编号 | FJ0001 起 |
| 区域 | 所属行政区 | 8 个区 |
| 户型 | 几室几厅 | 7 类 |
| 面积 | 建筑面积 | 平方米 |
| 楼层 | 低/中/高 | 3 档 |
| 朝向 | 主朝向 | 7 类 |
| 装修 | 四档加未知 | 分类 |
| 房龄 | 建成到今年 | 年 |
| 单价 | 每平米单价 | 元 |
| 总价 | 挂牌总价 | 万元 |
单价和总价都在表里,这是好事也是坑。好事是省得自己乘;坑是两列一旦对不上,就得判哪个错了。 第 11.3 节会用这条「两列必须自洽」当规则,一次抓出 9 条错数据。 数据是造的:区域基准价从 9600 到 21000 元,再乘装修、房龄、楼层三个系数,最后叠噪声。
造的时候故意弄脏了:装修缺 18 条、面积缺 4 条、房龄负数 3 条、单价离谱 9 条、完全重复 6 条。
三、四步流程
| 步骤 | 做什么 | 用哪一章的本事 |
|---|---|---|
| 一 | 清洗:缺、重、怪加一致性校验 | 第 3、4 章 |
| 二 | 图表:饼、折线、条形,写成模块 | 第 5 章 |
| 三 | 分组:区域、装修、户型 | 第 3、7 章 |
| 四 | 预测:多特征回归、评分 | 第 8、10 章 |
和第 10 章比,多了一步「图表模块」,少了一步「时间维度」。 图表模块是多出来的那一步,也是这一章唯一的新东西。把三张图写成三个函数,界面才能复用。 其余三步第 10 章都练过,只是特征从一列变成了二十一列。
四、项目准备:别忘了字体那一行
要装四样:pandas、matplotlib、scikit-learn、openpyxl。tkinter 是标准库,不用装。
pip install pandas matplotlib scikit-learn openpyxl
本机这套是 pandas 3.1.0、matplotlib 3.11.1、scikit-learn 1.9.1,都在。
中文图必须多写两行:font.sans-serif 设成 SimHei,axes.unicode_minus 设成 False。
少了第一行,图里所有中文变方框;少了第二行,负号变方框。两个坑都不报错,只是图难看。
五、先把脏数据原样存下来
这一章的数据先落成 二手房数据.csv,1206 行 10 列。
存成 utf-8-sig,用 Excel 双击打开不会乱码——带 BOM 就是为了这个。
脏数据原样存,不提前洗。清洗是下一节要讲的内容,先洗掉就没得讲了。
这也是真实项目的规矩:原始数据永远留一份,清洗是另存一份,不是原地改。
六、动手 Demo:项目概述、效果与准备
这一节不写分析:把系统四块、数据十个字段、四步流程、环境四样交代清楚。 最后把 1206 行脏数据原样落成 CSV,作为全章的地基。
import numpy as np
import pandas as pd
DIST = [("城中", 21000, 0.10), ("城东", 18500, 0.16), ("城西", 17200, 0.15),
("城南", 15800, 0.14), ("城北", 14200, 0.15), ("高新", 16500, 0.12),
("经开", 12500, 0.13), ("郊县", 9600, 0.05)]
HX = [("1室1厅", 38, 55), ("2室1厅", 55, 78), ("2室2厅", 72, 98),
("3室1厅", 82, 105), ("3室2厅", 98, 135), ("4室2厅", 130, 175),
("5室及以上", 168, 255)]
ZX = [("毛坯", 0.90), ("简装", 1.00), ("精装", 1.08), ("豪华", 1.22)]
LC = [("低楼层", 0.97), ("中楼层", 1.00), ("高楼层", 1.02)]
rng = np.random.default_rng(2026)
rows = []
for i in range(1, 1201):
d = DIST[int(rng.integers(0, len(DIST)))]
h = HX[int(rng.integers(0, len(HX)))]
z = ZX[int(rng.integers(0, len(ZX)))]
l = LC[int(rng.integers(0, len(LC)))]
area = float(np.round(rng.uniform(h[1], h[2]), 1))
age = int(np.clip(round(rng.gamma(2.0, 4.0)), 0, 30))
unit = d[1] * z[1] * max(0.55, 1 - 0.015 * age) * l[1] * rng.normal(1.0, 0.06)
rows.append(("FJ%04d" % i, d[0], h[0], area, l[0], z[0], age,
int(round(unit)), round(unit * area / 10000.0, 2)))
df = pd.DataFrame(rows, columns=["编号", "区域", "户型", "面积", "楼层",
"装修", "房龄", "单价", "总价"])
print("干净数据 %s" % (df.shape,))
print("均价 %d 元,平均总价 %.2f 万"
% (df["单价"].mean(), df["总价"].mean()))
df.to_csv("二手房数据.csv", index=False, encoding="utf-8-sig")
实跑输出:
--------------------------------------------------------------------
项目概述、效果与准备
--------------------------------------------------------------------
① 这个项目要做什么
--------------------------------------------------------------------
一个二手房房价分析与预测的小系统:选一个区、看均价、看户型、估一套房值多少。
教材用 tkinter 做界面,四个块:导入数据、画图、预测、导出结果。
[平台原样 · 本沙箱不执行]
| 主窗口
| ├── 数据区:选择文件 → 读进来 → 显示前 20 行
| ├── 图表区:区域占比(饼图)/面积与单价(折线)/区域均价(条形)
| ├── 预测区:填面积、房龄、装修、区域 → 点「估价」→ 出一个数
| └── 导出区:把清洗后的数据和分析结果存成 Excel
界面是桌面程序,本沙箱没有显示器,这一段照原样列出,不执行。
界面对分析没有半点帮助,它只是把结果端到人面前。所以这一章的重点不在窗口,在窗口后面那四件事。
四件事:把数据洗干净、把图画出来、把区域和户型算清楚、把价格预测出来。
② 数据长什么样
--------------------------------------------------------------------
一份二手房挂牌表,1206 行、10 个字段。
| 字段 | 含义 | 单位 |
|---|---|---|
| 编号 | 房源编号 | FJ0001 起 |
| 区域 | 所属行政区 | 8 个区 |
| 户型 | 几室几厅 | 7 类 |
| 面积 | 建筑面积 | 平方米 |
| 楼层 | 低/中/高 | 3 档 |
| 朝向 | 主朝向 | 7 类 |
| 装修 | 毛坯/简装/精装/豪华 | 4 档 |
| 房龄 | 建成到今年 | 年 |
| 单价 | 每平方米单价 | 元 |
| 总价 | 挂牌总价 | 万元 |
单价和总价都在表里,这是好事也是坑。好事是省得自己乘;坑是两列一旦对不上,就得判哪个错了。
数据是造的:区域基准价从 9600 到 21000 元,再乘装修、房龄、楼层三个系数。
! 造的时候故意弄脏了:装修缺 18 条、面积缺 4 条、房龄负数 3 条、单价离谱 9 条、完全重复 6 条。
③ 四步流程
--------------------------------------------------------------------
| 步骤 | 做什么 | 用哪一章的本事 |
|---|---|---|
| 一 | 清洗:缺、重、怪,加一致性校验 | 第 3 章、第 4 章 |
| 二 | 图表:饼图、折线、条形,写成模块 | 第 5 章 |
| 三 | 分组统计:区域、装修、户型 | 第 3 章、第 7 章 |
| 四 | 预测:多特征回归,评分 | 第 8 章、第 10 章 |
和第 10 章比,多了一步「图表模块」,少了一步「时间维度」。
房价数据没有时间序,所以这一次可以随机切训练集和测试集——第 10 章不行,那里一切就漏未来。
④ 项目准备
--------------------------------------------------------------------
[本沙箱已装齐]
| pip install pandas matplotlib scikit-learn openpyxl
tkinter 是标准库,不用装;本沙箱没有显示器,界面部分不执行。
本机 pandas 3.1.0、matplotlib 3.11.1、scikit-learn 1.9.1。
中文字体要单独设一行,不设图里的中文全是方框。这台机器有 SimHei 和微软雅黑。
⑤ 先把数据落成 CSV
--------------------------------------------------------------------
和上一章一样:先把数据准备好,后面每一节都从它读。
存成 UTF-8 带 BOM(utf-8-sig),用 Excel 双击打开也不会乱码。
写到 二手房数据.csv,1206 行 10 列。
! 脏数据留在文件里,不提前洗。清洗是下一节要讲的内容,先洗掉就没得讲了。
这段是简化版:只保留了四个字段的造法,省了朝向和弄脏那两步。全章的脏数据由 Demo 的完整版本造。
utf-8-sig 比 utf-8 多写三个字节的 BOM 头,Excel 靠它认出这是 UTF-8。
np.clip(..., 0, 30) 把房龄卡在 0 到 30,max(0.55, ...) 防止房龄太大把单价压成负数。
30 秒实验
- 把区域的数量从 8 个砍到 3 个,看后面的分组统计还剩几行。
- 把
utf-8-sig改成utf-8,用 Excel 打开那个 CSV,看中文变成什么样。 - 想一想:为什么界面那四块里,「导出」要放在最后一块?
常见误区
- 先做界面再想分析:窗口画得再漂亮,数不对一样没用。
- 忘了设中文字体:图上全是方框,还以为是编码问题,其实是缺字体。
- 清洗前不留原始文件:洗完发现问题,连对照的数据都没有了。
- 以为单价和总价可以随便用:两个单位差一万倍,混着算必错。
自测三问(点开对答案)
1. 这个项目里唯一的新东西是什么? —— 图表模块——把三张图写成三个函数,界面那边只传数据。其余三步第 10 章都练过。 2. 为什么原始脏数据要单独存一份? —— 清洗规则以后可能改,改了要能拿原表重跑。原始数据一覆盖,就再也回不去了。 3. 中文图上出现的方框是什么问题? —— 缺字体,不是缺数据。设好 `font.sans-serif` 就正常,和编码无关。地基打好了。下一篇先把三张图写成模块——曲线、饼、条,一个函数一张。
- ☐ (本篇完,下一篇 11.2 图表工具模块:饼、折线、条形)