简介本资源是一套完整的南京二手房数据分析实战项目面向Python初学者、数据科学入门者及计算机专业本科毕业设计或期末大作业需求者聚焦真实房产数据采集、清洗、可视化与聚类建模全流程。压缩包共157个文件40.04MB含18个核心Python爬虫与分析脚本requestsbs4matplotlibpandask-means、18个CSV数据文件覆盖原始采集、编码转换、清洗后多版本、65张可视化图表PNG、15个HTML地理热力图页面集成高德地图JS API、11个JS前端交互文件及1份完整答辩PPT结构清晰、模块可独立运行。已有997人学习下载提供从链家网页结构解析、反爬应对策略、缺失值与异常值清洗方法到k-means聚类参数调优与结果解读的完整实现路径所有代码均附详细注释数据字段明确可直接复现分析结论并支撑购房决策辅助分析。1. 项目概述与核心价值最近在整理过往的数据分析项目翻到了几年前做的一个关于南京二手房市场的可视化分析案例。这个项目虽然不算复杂但麻雀虽小五脏俱全从数据爬取、清洗、分析到可视化呈现完整地走了一遍数据分析的标准化流程。当时做这个项目的初衷很简单就是想用Python这套技术栈对一个具体的、生活化的场景买房租房进行一次实战演练看看能从数据里挖出什么有意思的结论。项目包里包含了完整的Python源码、分析报告以及用于汇报的PPT文档算是一个比较典型的“数据分析师作品集”项目。这个项目能帮你解决什么问题呢如果你是一个正在学习Python数据分析的入门者或进阶者它提供了一个从零到一的完整参考案例你可以看到每一个环节具体是怎么做的代码怎么写遇到问题如何解决。如果你对房地产市场特别是南京的二手房市场感兴趣它通过数据可视化的方式直观地展示了价格分布、区域差异、户型偏好等关键信息能给你提供一个基于数据的观察视角。整个项目的技术栈围绕Python展开用到了像pandas、matplotlib、seaborn、requests、BeautifulSoup等数据分析与爬虫领域的核心库这些都是数据科学领域的硬通货。2. 项目整体设计与技术选型思路2.1 核心目标与需求拆解做任何数据分析项目第一步永远是明确目标。这个项目的核心目标可以拆解为三个层次数据获取层如何稳定、高效地获取到南京二手房市场的原始数据这涉及到目标网站的选择、反爬策略应对以及数据结构的解析。数据处理与分析层获取到的原始数据通常是杂乱无章的如何清洗、整理并从中提取出有意义的特征和指标例如总价、单价、面积、户型、楼层、朝向、区域、建筑年代等。数据可视化与洞察层如何将分析结果以直观、美观的图表形式呈现如何通过图表发现规律、验证假设或讲述一个数据故事基于这三个层次技术选型就变得清晰了。在Python生态中每个层次都有成熟且优秀的工具链。2.2 技术栈选型与理由数据获取Requests BeautifulSoup / Scrapy对于二手房这种信息结构相对固定、但可能有一定反爬措施的网站我选择了Requests库进行网页请求配合BeautifulSoup进行HTML解析。这是一个轻量级且灵活的组合。为什么不直接用Scrapy对于单次性或结构简单的爬取任务Scrapy框架稍显笨重学习和调试成本在项目初期更高。RequestsBeautifulSoup的组合足以应对分页遍历、提取标签内容等常规操作代码也更直观易懂。当然如果目标网站结构复杂、需要爬取大量数据或要求更高的稳定性和效率Scrapy是更专业的选择。数据处理与分析Pandas这是毫无争议的选择。Pandas的DataFrame数据结构是处理表格型数据的利器。数据清洗处理缺失值、异常值、重复值、数据转换类型转换、字符串分割、特征提取、数据聚合与分组统计这些操作在Pandas中都有高效且优雅的实现。例如从“3室2厅1卫”这样的字符串中提取出卧室数、客厅数或者计算每个行政区的平均单价用Pandas几行代码就能搞定。数据可视化Matplotlib Seaborn (可选) Pyecharts这是一个分层使用的策略。Matplotlib是基础提供了极大的灵活性可以绘制任何你能想到的图表。但默认样式比较“学术”需要手动调整很多参数才能达到美观的效果。在本项目中它主要用于绘制一些需要高度定制化的图表。Seaborn基于Matplotlib提供了更高级的API和更美观的默认样式。它的统计绘图功能非常强大比如分布图distplot、箱线图boxplot、热力图heatmap、关系图relplot等非常适合做探索性数据分析EDA。本项目中的大部分统计图表都使用Seaborn完成能极大提升出图效率和美观度。Pyecharts这是一个生成Echarts图表的库优势在于可以生成交互式图表并且支持在Jupyter Notebook中直接显示或者导出为HTML文件。如果想让最终报告更具互动性比如地图可视化、数据联动筛选Pyecharts是很好的补充。在本项目的PPT中静态图表已足够但源码中也可以加入这部分作为扩展。开发环境Jupyter Notebook / Lab对于数据分析这种探索性强、需要反复试错和即时查看结果的工作流程Jupyter Notebook是绝佳的选择。它支持将代码、可视化结果、文字说明Markdown整合在一个文档中非常适合记录分析过程和呈现最终报告。项目源码通常就是以.ipynb文件的形式提供。注意技术选型没有绝对的对错只有适合与否。这个选型方案平衡了学习成本、开发效率和项目需求是一个经过实践验证的稳健组合。对于初学者建议先掌握这个组合再根据具体项目需求拓展到其他工具。3. 数据获取与清洗的实战细节3.1 目标网站分析与爬虫策略以常见的二手房信息平台为例具体平台名因合规要求隐去但方法是通用的我们首先需要人工浏览几个房源页面用浏览器的开发者工具F12查看网页结构。列表页分析观察列表页的URL规律。通常会有分页参数如page1,page2。找到包含房源标题、链接、总价、单价等概要信息的HTML标签和CSS选择器。详情页分析点击进入一个房源分析详情页的结构。找到面积、户型、朝向、楼层、建筑年代、小区名称、所在区域等详细信息的存放位置。爬虫策略通常采用“列表页抓取链接 - 详情页抓取详细信息”的两级结构。这里有几个关键点请求头Headers设置务必设置合理的User-Agent模拟真实浏览器访问。有时还需要添加Referer等字段以绕过简单的反爬检查。headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ... } response requests.get(url, headersheaders)频率控制在循环抓取页面时一定要使用time.sleep()在请求间加入随机延时如1-3秒避免对目标网站造成过大压力这也是基本的网络礼仪。异常处理网络请求可能失败超时、404等解析HTML时可能找不到预期的标签。代码中必须用try...except包裹核心逻辑记录错误并跳过保证爬虫的健壮性。数据存储每爬取完一个房源的信息可以立即将其追加写入到一个CSV文件或数据库中。我更喜欢先存入一个Python列表list of dicts全部爬取完成后再用pandas.DataFrame()一次性转换成DataFrame并保存为CSV这样更清晰。3.2 数据清洗的典型操作与Pandas技巧爬取到的原始数据就像刚从地里挖出来的土豆沾满了泥土无效字符、缺失值、格式不一清洗就是给土豆去皮、切块的过程。处理缺失值使用df.isnull().sum()快速查看各列缺失情况。对于关键数值列如价格、面积如果缺失比例不高可以考虑用中位数或均值填充df[‘price’].fillna(df[‘price’].median(), inplaceTrue)。对于文本列如朝向如果缺失可以填充为“未知”。如果某条数据关键信息缺失过多直接删除df.dropna(subset[‘key_column’], inplaceTrue)。处理异常值这是保证分析结果可信的关键。例如单价或总价出现明显不符合常识的极低或极高值如单价100元/平米或100万元/平米。可以通过描述性统计df[‘price_per_sqm’].describe()查看分布然后使用分位数如1%和99%进行截断或者基于业务知识如设定单价在5000-100000元/平米为合理范围进行过滤。# 基于分位数过滤异常值 lower_limit df[‘price_per_sqm’].quantile(0.01) upper_limit df[‘price_per_sqm’].quantile(0.99) df df[(df[‘price_per_sqm’] lower_limit) (df[‘price_per_sqm’] upper_limit)]数据转换与特征提取字符串分割从“鼓楼区-山西路”这样的字符串中提取区名。df[‘district’] df[‘location’].str.split(‘-‘).str[0]单位转换与数值化面积可能是“89.5平米”需要去掉“平米”并转为浮点数。df[‘area’] df[‘area_str’].str.replace(‘平米’, ‘’).astype(float)分类变量编码朝向“南/北”是文本对于某些模型可能需要数值化。可以使用pd.Categorical或map函数。衍生特征计算单价 总价 / 面积。df[‘unit_price’] df[‘total_price’] / df[‘area’]处理重复数据使用df.duplicated().sum()检查并用df.drop_duplicates()删除完全重复的行。实操心得数据清洗往往占用整个项目60%以上的时间。一定要耐心每一步清洗操作后都用df.head()、df.info()、df.describe()看看数据状态。清洗过程最好在Jupyter Notebook中分步骤、分单元格进行并附上文字说明这样形成的笔记本身就是一份宝贵的数据清洗文档。4. 探索性数据分析与可视化实战数据清洗干净后就进入了最有趣的环节——探索性数据分析。我们通过可视化让数据自己“说话”。4.1 单变量分析理解每个特征的分布价格与面积分布使用seaborn.histplot或seaborn.displot绘制总价、单价、面积的直方图并叠加核密度估计KDE曲线。这能直观看出市场的主流价格段和面积段集中在哪。例如你可能会发现南京二手房总价集中在200-500万面积集中在70-120平米。import seaborn as sns import matplotlib.pyplot as plt plt.figure(figsize(12, 5)) plt.subplot(1, 2, 1) sns.histplot(datadf, x‘total_price’, kdeTrue, bins30) plt.title(‘总价分布’) plt.subplot(1, 2, 2) sns.histplot(datadf, x‘unit_price’, kdeTrue, bins30) plt.title(‘单价分布’) plt.tight_layout() plt.show()户型与区域分布对于户型如“3室2厅”和区域如“鼓楼区”、“建邺区”这类分类变量使用seaborn.countplot绘制条形图可以快速看出哪种户型最受欢迎哪个区的房源最多。建筑年代分布同样用条形图或直方图观察房龄结构。是次新房5-10年为主还是老小区20年以上居多4.2 双变量与多变量分析发现特征间的关系区域与价格关系这是核心分析之一。使用seaborn.boxplot绘制每个行政区的单价箱线图。箱线图能同时展示中位数、四分位数、异常值非常适合比较不同组别的分布。一眼就能看出鼓楼、建邺等核心区的单价中位数远高于六合、高淳等外围区。plt.figure(figsize(14, 6)) # 按区域分组绘制单价箱线图并按单价中位数排序 order df.groupby(‘district’)[‘unit_price’].median().sort_values(ascendingFalse).index sns.boxplot(datadf, x‘district’, y‘unit_price’, orderorder) plt.xticks(rotation45) # 旋转x轴标签避免重叠 plt.title(‘各行政区二手房单价分布对比’) plt.show()面积与总价关系使用seaborn.scatterplot绘制散点图并可以用hue参数按区域着色。这能直观展示“面积越大总价越高”的正相关关系同时也能看到不同区域的点分布在不同的“价格带”上。户型与单价关系可以分析在相同区域内不同户型如2室 vs 3室的单价是否有显著差异。可以使用分组箱线图或小提琴图seaborn.violinplot来观察。相关性热力图对于数值型特征总价、单价、面积、房龄等计算它们之间的皮尔逊相关系数矩阵并用seaborn.heatmap绘制热力图。颜色越深或越浅取决于配色表示相关性越强。这能快速发现哪些特征与价格强相关。4.3 空间数据可视化进阶如果数据中包含了小区名称或更精确的地址可以通过地理编码调用地图API如高德、百度需申请密钥获取经纬度然后进行地图可视化。基础点图使用scatterplot将经度、纬度作为x, y轴点的大小或颜色代表单价可以绘制出南京二手房价格的“热力地图”。交互式地图使用pyecharts的Geo或BMap组件可以生成更炫酷、可交互的在线地图支持缩放、拖动、点击查看详情。这部分代码可以单独生成一个HTML报告作为PPT的补充材料。注意事项可视化不是为了炫技而是为了传达信息。每个图表都应该有清晰的标题、坐标轴标签和图例。颜色搭配要协调且易于区分可使用seaborn的默认配色或Set2,Set3等分类调色板。避免在一个图中塞入过多信息导致难以阅读。在PPT中呈现时一图一结论将最重要的发现用最直观的图表展示出来。5. 从分析到洞察核心发现与报告撰写可视化之后我们需要解读图表提炼出有商业或参考价值的洞察并组织成一份连贯的报告PPT。5.1 典型分析结论示例基于上述分析你可能会得出以下类似结论以模拟数据为例价格梯队明显南京二手房单价呈现明显的“中心高、外围低”格局。鼓楼、玄武、建邺构成第一梯队单价超4万/平秦淮、栖霞为第二梯队浦口、江宁部分板块为第三梯队六合、高淳为价格洼地。刚需户型主导市场2室和3室户型占据了总房源量的75%以上是市场的绝对主流。其中紧凑型3室90-110平的成交活跃度最高反映了市场以首套刚需和首次改善需求为主。面积与总价强相关但单价与面积关系复杂散点图显示面积与总价呈清晰的线性正相关。然而进一步按区域拆分会发现核心区小户型的单价往往更高单价高而郊区大户型的单价较低但总价可能因为面积大而不低。房龄影响显著在同一区域内房龄10年内的次新房单价普遍比20年以上的老小区高出15%-25%。但超过20年后房龄对价格的边际影响减弱。“学-铁-商”配套溢价通过地图可视化叠加学区、地铁线、商业中心可以定性发现拥有优质学区、临近地铁口、位于成熟商圈的房源其单价存在显著溢价。5.2 PPT报告结构设计一份好的数据分析PPT不是代码和图的堆砌而是一个有逻辑的故事。封面项目名称、作者、日期。目录/分析脉络清晰展示报告结构。项目背景与目标为什么要做这个分析想回答什么问题例如了解南京二手房市场格局为购房决策提供数据参考。数据来源与处理说明简要说明数据怎么来的经过了哪些清洗步骤保证了数据的可信度。核心分析部分这是主体按照“宏观到微观”或“总体到局部”的逻辑展开。例如市场概览总价、单价、面积的整体分布。区域分析各行政区价格对比、房源量对比。产品分析户型、房龄、朝向等对价格的影响。深度洞察结合地理信息的发现如地铁房溢价、特定板块分析如河西新城。总结与建议用一两页PPT总结最重要的发现。如果是商业报告可以提出策略建议如针对刚需客户可重点关注X区Y板块的Z户型。如果是学习项目可以总结技术心得和后续优化方向。QA预留一页。5.3 源码与文档的组织一个负责任的项目其源码和文档应该是清晰、可复现的。源码.ipynb或.py文件注释清晰在每个关键步骤、复杂逻辑处添加注释。模块化可以将爬虫、清洗、分析、绘图分别写成函数或放在不同的代码单元格中。路径处理使用os.path相关函数处理文件路径避免硬编码。将原始数据、清洗后数据、生成的图片分别放在不同的文件夹如/data/raw,/data/cleaned,/output/figures。README.md在项目根目录提供一个README文件说明项目背景、如何配置环境requirements.txt、如何运行代码、数据来源声明等。PPT文档基于分析结果精心制作图表清晰结论突出。可以将最终的可视化图表以高分辨率如300 DPI导出为PNG或PDF再插入PPT保证清晰度。6. 常见问题与避坑指南实录在实际操作这个项目或类似数据可视化项目时你几乎一定会遇到以下问题。这里记录了我的排查过程和解决方法。6.1 爬虫阶段问题问题1请求被拒绝返回403状态码或验证码页面。原因网站识别出爬虫行为。可能因为请求头不完整、频率过高、或IP被暂时封禁。排查与解决检查Headers确保User-Agent是常见的浏览器字符串。可以尝试添加Referer,Accept-Language等字段使其更像浏览器。降低频率在请求间增加随机延时time.sleep(random.uniform(1, 3))。使用Sessionrequests.Session()可以保持会话有时比单次请求更友好。代理IP如果问题严重可能需要使用代理IP池。但对于学习项目前三点通常足够。模拟JavaScript如果数据是通过JS动态加载的requests无法直接获取。此时需要用到Selenium或Playwright这类浏览器自动化工具。这是另一个技术栈如果遇到可以先标记后续专项学习。问题2解析HTML时BeautifulSoup找不到标签返回空列表。原因网页结构发生变化或者你的CSS选择器/XPath写错了。排查与解决打印响应内容print(response.text[:2000])查看实际获取到的HTML与浏览器开发者工具里看到的结构对比。使用更稳健的选择器避免使用过于脆弱的选择器如依赖具体的class名或id这些容易变。尝试使用标签层级关系或属性组合。尝试XPath如果CSS选择器不行可以换用lxml解析器配合XPath。BeautifulSoup也支持find和select方法有时find的文本匹配更灵活。异常处理一定要用try-except包裹解析代码避免因个别页面结构不同导致整个程序崩溃。6.2 数据处理与可视化阶段问题问题3Pandas读取或合并数据时出现内存错误或速度极慢。原因数据量过大几十万行以上或者进行了低效的操作如循环遍历DataFrame。排查与解决指定数据类型用pd.read_csv(..., dtype{‘column1’: ‘int32’, ‘column2’: ‘category’})指定列的数据类型可以大幅减少内存占用。使用向量化操作绝对避免用for循环处理DataFrame的行。使用Pandas内置的向量化函数如.str.replace(),.apply()配合lambda函数要谨慎或NumPy函数。分块处理对于超大文件可以使用pd.read_csv(..., chunksize50000)进行分块读取和处理。过滤早期数据如果不需要所有列用usecols参数只读取需要的列。问题4绘制的图表中文显示为方框乱码。原因Matplotlib默认字体不包含中文字符。解决在绘图前添加以下代码指定中文字体。你需要知道系统里一个中文字体的路径。import matplotlib.pyplot as plt plt.rcParams[‘font.sans-serif’] [‘SimHei’] # 用来正常显示中文标签黑体 plt.rcParams[‘axes.unicode_minus’] False # 用来正常显示负号如果‘SimHei’不行可以尝试‘Microsoft YaHei’微软雅黑或者找到字体文件路径直接指定font FontProperties(fname‘/path/to/your/font.ttf’)然后在绘图函数中设置fontpropertiesfont。问题5Seaborn图表样式被Matplotlib覆盖或者多子图布局混乱。原因Seaborn是基于Matplotlib的两者混用时调用顺序和设置会影响最终样式。解决先设置Seaborn样式在导入matplotlib.pyplot之后尽早执行sns.set_theme(style‘whitegrid’)。这个函数会设置一系列美观的默认参数。使用plt.subplots()创建画布和轴对象这是更推荐的方式可以精确控制每个子图的位置和大小。fig, axes plt.subplots(2, 2, figsize(12, 10)) # 2行2列 sns.histplot(datadf, x‘price’, axaxes[0, 0]) sns.boxplot(datadf, x‘district’, y‘price’, axaxes[0, 1]) # ... 其他绘图 plt.tight_layout() # 自动调整子图间距避免重叠 plt.show()plt.figure()vsplt.subplot()对于简单图表plt.figure()后接plt.subplot(221)等也可行但subplots()方法更现代、更清晰。6.3 项目组织与复现问题问题6别人无法运行我的代码提示缺少库或数据路径错误。原因环境依赖不明确或使用了绝对路径。解决生成requirements.txt在项目根目录使用命令pip freeze requirements.txt导出当前环境的包列表。别人可以通过pip install -r requirements.txt一键安装。使用相对路径在代码中使用os.path.join(‘data’, ‘raw’, ‘houses.csv’)来构建文件路径。将数据和代码放在项目目录的固定结构下。提供清晰的README在README中写明Python版本如3.8、如何安装依赖、如何运行主程序、数据如何放置。问题7分析结论不稳定每次跑结果略有差异。原因数据清洗或分析步骤中存在随机性如随机采样填充缺失值或者爬虫每次抓取的数据有细微变动。解决设置随机种子在任何使用随机数的地方如numpy.random,random模块在程序开头设置一个固定的种子np.random.seed(42)和random.seed(42)确保可复现性。固化数据将清洗后的最终分析数据保存为一个版本文件如cleaned_data_v1.0.csv。后续的分析和可视化都基于这个固定的数据文件进行而不是每次重新爬取和清洗。这在正式报告中尤为重要。这个基于Python的南京二手房数据可视化项目本质上是一个数据科学小闭环的微型演练。它锻炼的不仅仅是写代码的能力更是从模糊需求到清晰问题定义从杂乱数据到清晰洞察从技术实现到成果表达的全流程思维。过程中踩的每一个坑解决的每一个问题都是比单纯学会某个库函数更宝贵的经验。当你完整地跟做或自己实现一遍后再去看那些真实业务中的数据分析需求心里会踏实很多。本文还有配套的精品资源点击获取