核心内容摘要
欧美老女人
项目技术框架与环境准备本次实践的核心目标是完成 “数据获取 - 数据预处理 - 聚类分析 - 可视化展示” 的全流程闭环技术选型围绕 Python 生态的成熟工具展开兼顾开发效率和实战效果。
1 核心技术工具数据爬取Requests网络请求 BeautifulSoup4页面解析轻量高效适合静态页面数据抓取满足链家二手房列表页的解析需求数据预处理Pandas数据清洗、结构化 Numpy数值计算处理缺失值、异常值将爬取的非结构化数据转换为结构化 DataFrame聚类分析Scikit-learn机器学习库使用 K-Means 算法实现房源的无监督聚类挖掘数据内在规律数据可视化Matplotlib基础可视化 Pyecharts交互式可视化分别实现静态统计图表和交互式地理、维度分析图表。
2 开发环境配置
链家二手房数据爬取实现本次爬取目标为链家北京二手房列表页数据可根据需求替换城市域名爬取字段包括房源标题、户型、建筑面积、朝向、装修情况、挂牌价格、单价、所属区域共 8 个核心字段爬取后存储为 CSV 文件便于后续处理。
1 爬取核心思路分析链家二手房页面结构列表页为静态 HTML房源信息存储在指定 class 的标签中分页通过 URL 参数font stylecolor:rgb(0, 0,
;background-color:rgba(0, 0, 0,
;pg/font控制构造请求头添加 User-Agent、Cookie可选模拟浏览器访问避免被反爬循环请求分页数据解析每个页面的房源信息提取目标字段处理字段格式如去除单位、转换数值类型数据持久化将解析后的结构化数据保存为 CSV 文件方便后续数据预处理。
2 完整爬取代码实现python运行import requests from bs4 import BeautifulSoup import pandas as pd import time import random # 配置请求头模拟浏览器访问 HEADERS { User-Agent: Mozilla/
0 (Windows NT
1
0; Win64; x
AppleWebKit/
5
36 (KHTML, like Gecko) Chrome/
120.
0.
0 Safari/
5
36, Accept-Language: zh-CN,zh;q
9, Connection: keep-alive } # 爬取单页数据 def crawl_single_page(page_num, citybj): 爬取链家指定城市二手房单页数据 :param page_num: 页码 :param city: 城市域名bj北京、sh上海、gz广州默认北京 :return: 单页房源数据列表 base_url fhttps://{city}.lianjia.com/ershoufang/pg{page_num}/ try: # 发送GET请求添加随机延迟避免反爬 time.sleep(random.uniform(1,
) response requests.get(base_url, headersHEADERS, timeout
response.raise_for_status() # 抛出HTTP请求异常 soup BeautifulSoup(response.text, html.parser) # 定位房源列表标签 house_items soup.find_all(div, class_info clear) page_data [] for item in house_items: house_dict {} # 提取房源标题 title item.find(a, class_noresultRecommend img LOGCLICKDATA).get_text(stripTrue) # 提取户型、面积、朝向、装修等基础信息 house_info item.find(div, class_address).get_text(stripTrue).split(|) # 提取挂牌价格和单价 price_total item.find(div, class_priceInfo).find(div, class_totalPrice).get_text(stripTrue) price_unit item.find(div, class_priceInfo).find(div, class_unitPrice).get_text(stripTrue) # 提取所属区域 area item.find(div, class_flood).find(div, class_positionInfo).get_text(stripTrue).split(-)[0] # 字段清洗与赋值处理数据缺失情况 house_dict[标题] title if title else None house_dict[户型] house_info[0].strip() if len(house_info)1 else None house_dict[建筑面积] house_info[1].strip() if len(house_info)2 else None house_dict[朝向] house_info[2].strip() if len(house_info)3 else None house_dict[装修情况] house_info[3].strip() if len(house_info)4 else None house_dict[挂牌价格(万)] price_total.replace(万, ).strip() if price_total else None house_dict[单价(元/平)] price_unit.replace(单价, ).replace(元/平, ).strip() if price_unit else None house_dict[所属区域] area if area else None page_data.append(house_dict) print(f第{page_num}页爬取完成共{len(page_data)}条房源数据) return page_data except Exception as e: print(f第{page_num}页爬取出错{str(e)}) return [] # 批量爬取多页数据 def crawl_lianjia(total_pages, citybj): 批量爬取链家多页二手房数据 :param total_pages: 总爬取页码 :param city: 城市域名 :return: 所有房源数据的DataFrame all_data [] for page in range(1, total_pages
: page_data crawl_single_page(page, city) all_data.extend(page_data) # 转换为DataFrame df pd.DataFrame(all_data) # 保存为CSV文件去除索引 df.to_csv(链家二手房数据.csv, indexFalse, encodingutf-8-sig) print(f全部数据爬取完成共{len(df)}条房源已保存为链家二手房数据.csv) return df # 主函数执行爬取北京前5页数据可根据需求调整 if __name__ __main__: df crawl_lianjia(total_pages5, citybj) # 打印前5条数据预览 print(df.head())
3 爬取
注意事项反爬机制规避添加随机请求延迟
秒、使用真实浏览器 User-Agent避免短时间内高频请求爬取量较大时可使用代理 IP 池数据完整性部分房源可能存在字段缺失代码中已做缺失值处理后续数据预处理阶段需进一步清洗平台规则遵守本次爬取仅用于技术研究请勿将数据用于商业用途爬取频率需控制在合理范围避免给平台服务器造成压力。
数据预处理为聚类分析做准备爬取的原始数据存在格式不统
缺失值、异常值等问题无法直接用于聚类分析。
聚类分析作为数值型机器学习算法要求输入数据为标准化的数值类型因此需通过 Pandas 完成数据清洗和特征工程核心步骤包括缺失值处理、字段格式转换、异常值剔除、特征标准化。
1 数据预处理核心思路读取 CSV 原始数据查看数据基本信息字段类型、缺失值占比、数据范围缺失值处理采用 “删除法” 剔除缺失值较多的行缺失值占比 5% 时保证数据完整性格式转换将 “建筑面积平”“挂牌价格万”“单价元 / 平” 转换为浮点型数值去除非数值字符异常值剔除通过四分位数法IQR剔除单价、面积的极端值如单价过高的豪宅、面积过小的公寓避免影响聚类效果特征选择聚类分析选取建筑面积、挂牌价格、单价三个核心数值特征作为模型输入特征标准化使用 Z-Score 标准化将特征值转换为均值为
方差为 1 的标准分布消除量纲影响K-Means 算法对量纲敏感。
2 数据预处理代码实现python运行import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler # 数据预处理主函数 def preprocess_data(file_path): 链家二手房数据预处理为聚类分析做准备 :param file_path: 原始数据CSV文件路径 :return: 标准化后的特征矩阵、原始清洗后数据、特征标准化器 #
读取原始数据 df pd.read_csv(file_path, encodingutf-8-sig) print(原始数据基本信息) print(df.info()) print(原始数据描述性统计) print(df[[挂牌价格(万), 单价(元/平), 建筑面积]].describe()) #
字段格式转换转换为浮点型处理转换失败的行 df[挂牌价格(万)] pd.to_numeric(df[挂牌价格(万)], errorscoerce) df[单价(元/平)] pd.to_numeric(df[单价(元/平)], errorscoerce) df[建筑面积] pd.to_numeric(df[建筑面积].str.replace(平, ), errorscoerce) #
缺失值处理删除任意特征缺失的行 df df.dropna(subset[挂牌价格(万), 单价(元/平), 建筑面积]) print(f缺失值处理后剩余数据量{len(df)}) #
异常值剔除四分位数法IQR处理单价和建筑面积 def remove_outlier(data, col): q1 data[col].quantile(
0.
q3 data[col].quantile(
0.
iqr q3 - q1 lower q1 -
5 * iqr upper q3
5 * iqr return data[(data[col] lower) (data[col] upper)] df remove_outlier(df, 单价(元/平)) df remove_outlier(df, 建筑面积) print(f异常值剔除后剩余数据量{len(df)}) #
特征选择选取3个核心数值特征 features df[[建筑面积, 挂牌价格(万), 单价(元/平)]] #
特征标准化Z-Score标准化 scaler StandardScaler() features_scaled scaler.fit_transform(features) print(数据预处理完成标准化后特征矩阵形状, features_scaled.shape) return features_scaled, df, scaler # 执行预处理 if __name__ __main__: features_scaled, df_clean, scaler preprocess_data(链家二手房数据.csv) # 保存清洗后的数据 df_clean.to_csv(链家二手房清洗后数据.csv, indexFalse, encodingutf-8-sig)预处理完成后将得到标准化的特征矩阵用于聚类模型训练和清洗后的结构化数据用于后续可视化同时保存标准化器便于后续对新数据进行相同的标准化处理。
基于 K-Means 的二手房数据聚类分析聚类分析是无监督学习的核心应用之一旨在将相似的数据点归为同一簇将差异较大的数据点归为不同簇。
本次实践选用 K-Means 算法该算法简单高效、适合大规模数值型数据能够快速将二手房房源按建筑面积、挂牌价格、单价三个维度进行聚类挖掘房源的内在分类规律如刚需小户型、改善型大户型、高端豪宅等。
1 K-Means 聚类核心思路确定最优聚类数 KK-Means 算法需要预先指定聚类数本次通过肘部法则Elbow Method计算不同 K 值对应的平方和误差SSE选取 SSE 下降趋势骤缓的点作为最优 K训练 K-Means 模型使用最优 K 值对标准化后的特征矩阵进行模型训练得到每个房源的聚类标签聚类结果融合将聚类标签添加到清洗后的原始数据中便于后续分析各簇的特征聚类结果分析计算各簇的特征均值建筑面积、价格、单价
总结每类房源的核心特征。
2 聚类分析代码实现python运行import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler import warnings warnings.filterwarnings(ignore) # 加载预处理后的数据 features_scaled, df_clean, scaler preprocess_data(链家二手房数据.csv) #
肘部法则确定最优聚类数K def select_optimal_k(features, max_k
: 肘部法则选取最优K值 :param features: 标准化后的特征矩阵 :param max_k: 最大尝试K值 :return: 最优K值 sse [] for k in range(1, max_k
: kmeans KMeans(n_clustersk, random_state42, n_init
kmeans.fit(features) sse.append(kmeans.inertia_) # 平方和误差SSE # 绘制肘部法则图 plt.figure(figsize(10,
) plt.plot(range(1, max_k
, sse, markero, linestyle-, color#FF
plt.xlabel(聚类数K, fontsize
plt.ylabel(平方和误差(SSE), fontsize
plt.title(肘部法则确定最优K值, fontsize14, fontweightbold) plt.grid(alpha
0.
plt.savefig(肘部法则图.png, dpi300, bbox_inchestight) plt.show() return sse # 计算不同K值的SSE sse select_optimal_k(features_scaled, max_k
#
训练K-Means模型根据肘部法则本次选取K3 k 3 kmeans KMeans(n_clustersk, random_state42, n_init
cluster_labels kmeans.fit_predict(features_scaled) #
融合聚类标签到清洗后的数据中 df_clean[聚类标签] cluster_labels #
分析各簇的特征均值 cluster_analysis df_clean.groupby(聚类标签)[[建筑面积, 挂牌价格(万), 单价(元/平)]].mean().round(
print(各聚类簇核心特征均值) print(cluster_analysis) # 保存带聚类标签的数据 df_clean.to_csv(链家二手房聚类后数据.csv, indexFalse, encodingutf-8-sig) print(聚类分析完成带标签数据已保存为链家二手房聚类后数据.csv)
3 聚类结果解读以本次爬取的北京前 5 页二手房数据为例肘部法则显示 K3 时 SSE 下降趋势骤缓聚类结果将房源分为 3 类典型特征解读如下实际数据会因爬取范围不同略有差异簇 0刚需型建筑面积约
㎡挂牌价格约
万单价约
万 / 平主要为一居、两居小户型分布在通州、昌平、房山等远郊区域适合刚需购房者簇 1改善型建筑面积约
㎡挂牌价格约
万单价约
万 / 平主要为三居、四居改善型户型分布在朝阳、海淀、丰台等近郊区域兼顾居住品质和交通便利性簇 2高端型建筑面积约 150㎡以上挂牌价格约 1500 万以上单价约
万 / 平主要为大平层、别墅等高端房源分布在西城、东城、海淀核心学区或朝阳 CBD 区域面向高端改善和投资客群。
二手房数据可视化展示数据可视化是将分析结果直观呈现的核心环节本次实践采用Matplotlib实现静态统计可视化Pyecharts实现交互式可视化分别从维度统计、聚类分布、地理分布三个角度展示数据规律让分析结果更易理解。
1 静态可视化Matplotlib 实现维度统计与聚类分布通过 Matplotlib 绘制各区域房源数量分布、各簇价格箱线图、建筑面积与价格散点图直观展示房源的区域分布和聚类特征代码实现如下python运行import pandas as pd import matplotlib.pyplot as plt import seaborn as sns plt.rcParams[font.sans-serif] [SimHei] # 解决中文显示问题 plt.rcParams[axes.unicode_minus] False # 解决负号显示问题 # 加载聚类后的数据 df pd.read_csv(链家二手房聚类后数据.csv, encodingutf-8-sig) #
各所属区域房源数量TOP10柱状图 plt.figure(figsize(12,
) area_count df[所属区域].value_counts().head(
sns.barplot(xarea_count.index, yarea_count.values, paletteviridis) plt.xlabel(所属区域, fontsize
plt.ylabel(房源数量, fontsize
plt.title(链家二手房各区域房源数量TOP10, fontsize14, fontweightbold) plt.xticks(rotation
plt.tight_layout() plt.savefig(各区域房源数量TOP
png, dpi
#
各聚类簇挂牌价格箱线图 plt.figure(figsize(10,
) sns.boxplot(x聚类标签, y挂牌价格(万), datadf, paletteSet
plt.xlabel(聚类标签, fontsize
plt.ylabel(挂牌价格(万), fontsize
plt.title(各聚类簇二手房挂牌价格分布, fontsize14, fontweightbold) plt.savefig(各簇价格箱线图.png, dpi
#
建筑面积与挂牌价格散点图按聚类标签着色 plt.figure(figsize(10,
) sns.scatterplot(x建筑面积, y挂牌价格(万), hue聚类标签, datadf, palettetab10, s
plt.xlabel(建筑面积(平), fontsize
plt.ylabel(挂牌价格(万), fontsize
plt.title(建筑面积与挂牌价格散点图按聚类着色, fontsize14, fontweightbold) plt.legend(title聚类标签) plt.grid(alpha
0.
plt.savefig(建筑面积-价格散点图.png, dpi
plt.show()
2 交互式可视化Pyecharts 实现地理与维度分析Pyecharts 支持生成交互式 HTML 图表本次实现北京各区域房源数量地图、各聚类簇特征雷达图、单价与面积热力图支持鼠标悬停查看详细数据代码实现如下python运行import pandas as pd from pyecharts import options as opts from pyecharts.charts import Bar, Scatter, Radar, HeatMap, Map from pyecharts.globals import ThemeType import numpy as np # 加载聚类后的数据 df pd.read_csv(链家二手房聚类后数据.csv, encodingutf-8-sig) # 简化区域名称适配Pyecharts地图 df[区域简化] df[所属区域].str.replace(区, ).str.replace(市, ).str.replace(县, ) #
北京各区域房源数量交互式地图 area_count df[区域简化].value_counts() map_chart ( Map(init_optsopts.InitOpts(themeThemeType.LIGHT, width1200px, height600px)) .add(房源数量, [list(z) for z in zip(area_count.index, area_count.values)], 北京) .set_global_opts( title_optsopts.TitleOpts(title北京各区域二手房房源数量分布, font_size
, visualmap_optsopts.VisualMapOpts(max_area_count.max(), is_piecewiseTrue), ) ) map_chart.render(北京二手房区域分布地图.html) #
各聚类簇核心特征雷达图 cluster_mean df.groupby(聚类标签)[[建筑面积, 挂牌价格(万), 单价(元/平)]].mean().round(
# 雷达图指标标准化
def normalize(x): return (x - x.min()) / (x.max() - x.min()) * 100 cluster_norm cluster_mean.apply(normalize, axis
# 构造雷达图数据 radar_data [] for i in range(
: radar_data.append(cluster_norm.iloc[i].tolist()) schema [ opts.RadarIndicatorItem(name建筑面积, max_
, opts.RadarIndicatorItem(name挂牌价格, max_
, opts.RadarIndicatorItem(name单价, max_
, ] radar_chart ( Radar(init_optsopts.InitOpts(themeThemeType.LIGHT, width800px, height600px)) .add_schema(schemaschema, shapepolygon) .add(簇0(刚需型), [radar_data[0]], color#FF
.add(簇1(改善型), [radar_data[1]], color#1E90FF) .add(簇2(高端型), [radar_data[2]], color#32CD
.set_global_opts(title_optsopts.TitleOpts(title各聚类簇核心特征雷达图, font_size
) ) radar_chart.render(各簇特征雷达图.html) #
单价与建筑面积热力图 # 数据分箱 df[面积区间] pd.cut(df[建筑面积], bins[0, 60, 90, 120, 150, 200, 300], labels[
,
,
,
,
, 200]) df[单价区间] pd.cut(df[单价(元/平)], bins[0, 4, 6, 8, 10, 15], labels[
万,
万,
万,
万, 10万]) heat_data df.groupby([面积区间, 单价区间]).size().reset_index(name数量) # 构造热力图数据格式 heat_map_data [] for _, row in heat_data.iterrows(): heat_map_data.append([row[面积区间], row[单价区间], row[数量]]) heat_chart ( HeatMap(init_optsopts.InitOpts(themeThemeType.LIGHT, width1000px, height600px)) .add_xaxis([x for x in df[面积区间].cat.categories]) .add_yaxis(房源数量, [y for y in df[单价区间].cat.categories], heat_map_data) .set_global_opts( title_optsopts.TitleOpts(title二手房建筑面积与单价热力图, font_size
, visualmap_optsopts.VisualMapOpts(min_0, max_heat_data[数量].max()), xaxis_optsopts.AxisOpts(name建筑面积区间(平)), yaxis_optsopts.AxisOpts(name单价区间(元/平)), ) ) heat_chart.render(面积-单价热力图.html) print(交互式可视化完成已生成3个HTML图表文件)
3 可视化结果价值区域分布可快速识别北京二手房房源的核心分布区域如朝阳、海淀、丰台反映区域房产市场的活跃度聚类特征雷达图直观展示三类房源的特征差异刚需型房源面积小、价格低高端型房源面积大、单价高改善型房源处于中间区间维度关联热力图清晰呈现 “面积越大单价越高” 的关联规律为购房决策提供数据支撑如刚需购房者可重点关注
㎡、
万 / 平的房源。
项目
总结与拓展方向本次实践完成了链家二手房数据从爬取、预处理到聚类分析、可视化展示的全流程实现通过 Python 生态工具构建了一套完整的房产数据分析方案最终成功将北京二手房房源分为刚需型、改善型、高端型三类并通过多维度可视化呈现了数据规律。
本次实践的