
简介这份2025年江苏省住宅小区点位数据面向城市规划、房地产研究、交通评估与公共安全等领域的GIS从业者和研究者以Shp矢量格式提供全省住宅小区空间分布采用Wgs1984地理坐标系统可直接用于空间分布模式分析、人口密度测算与城市精细化管理等场景。压缩包共7个文件约2.83MB涵盖shp主图形文件、dbf属性表、prj投影定义、shx形状索引以及sbn、sbx空间索引和xml元数据属性表可承载小区名称、地址、房屋数量、物业类型等字段索引文件提升检索效率元数据则记录数据来源与精度信息。目前已有66人学习下载。借助ArcGIS、QGIS等工具读者可快速完成数据导入、地图绘制与空间查询为住宅市场研究、商业选址和城市空间资源规划提供可复用的基础数据支撑。1. 拿到一份住宅小区点位 Shp 数据先搞清楚它能干什么你手上如果有一份「2025年江苏省住宅小区点位数据」格式是 Shp 矢量、坐标系 WGS1984那它本质上就是一张带坐标的点表每个点代表一个住宅小区属性表里通常挂着小区名称、所在城市、区县可能还有经纬度、数据年份。别小看这一列点它能直接支撑三类活做楼盘分布热力图、给配送或选址模型补「居住密度」特征、把小区点位和路网/POI/人口栅格做空间连接。适合谁做城市数据分析的、做本地生活选址的、做 GIS 入门练手的以及需要一份底图点位来验证自己空间处理链路的人。WGS1984 是地理坐标系单位是度不是米这一点决定了你后面量距离、做缓冲区之前必须先投影否则算出来的数全是错的。下面按「先验数据、再跑通、再避坑、最后进阶」的顺序把这份数据从打开到出结果讲透。2. 先验后动Shp 数据打开前的字段与坐标系核对2.1 用 Python 把 Shp 读进来并打印字段结构拿到压缩包解压后你会看到一组同名文件.shp、.shx、.dbf、.prj可能还有.cpg。这四个必须放在同一目录少一个都读不了。我一般先用 GeoPandas 读一遍确认字段名、类型、坐标系和记录数再决定后面怎么处理。import geopandas as gpd # 读取解压后的 shp注意路径指向 .shp 文件本身 gdf gpd.read_file(jiangsu_residential_2025.shp) # 基本信息记录数、坐标系、几何类型 print(记录数:, len(gdf)) print(坐标系:, gdf.crs) print(几何类型:, gdf.geom_type.unique()) # 字段名与类型重点看有没有名称、城市、区县、年份 print(gdf.dtypes) # 看前 5 行属性确认字段含义 print(gdf.drop(columnsgeometry).head())逻辑说明read_file会自动读取同目录的.prj来填充crs如果输出是EPSG:4326说明 WGS1984 被正确识别。参数上gdf.crs是后续所有空间操作的基准一旦这里为空或报错说明.prj缺失需要手动指定。geom_type应该全是Point如果混进MultiPoint后面做连接时要注意统一。2.2 坐标系核对WGS1984 是度不是米WGS1984 的 EPSG 代码是 4326单位是十进制度。很多人拿到点位直接gdf.buffer(1000)以为画的是 1 公里缓冲区其实画的是 1000 度整个地球都包进去了。正确做法是先投影到适合江苏的投影坐标系比如 UTM 50NEPSG:32650或 CGCS2000 高斯投影单位变成米之后再算距离。# 先确认当前是地理坐标系 print(gdf.crs.is_geographic) # True 表示单位是度 # 投影到 UTM 50N江苏大部分落在这一带单位变为米 gdf_proj gdf.to_crs(epsg32650) # 现在 buffer(1000) 才是真正的 1 公里 gdf_proj[buffer_1km] gdf_proj.geometry.buffer(1000) print(gdf_proj.crs.is_projected) # True参数说明epsg32650是 UTM 50N覆盖东经 114° 到 120°江苏全境基本适用如果数据偏东到 120° 以东可换 32651。投影只影响几何计算不影响属性表。做完距离类分析后如果要出图或和在线底图叠加再转回 4326。2.3 属性表清洗重名、空值和编码三个检查点住宅小区点位最常见的脏数据是名称重复、城市字段为空、以及 dbf 中文乱码。读进来后先做三件事统计名称重复、检查关键字段空值率、确认中文是否正常。# 名称重复情况 dup gdf[gdf.duplicated(name, keepFalse)] print(重名记录数:, len(dup)) # 关键字段空值率 for col in [name, city, district]: if col in gdf.columns: print(col, 空值率:, gdf[col].isna().mean()) # 中文乱码时尝试指定编码重读 gdf2 gpd.read_file(jiangsu_residential_2025.shp, encodinggbk) print(gdf2[name].head())逻辑说明重名不一定是错误可能是同名小区分布在不同城市所以判断时要结合city字段一起看。空值率高的字段不要直接用于分组统计。编码问题在 dbf 里很常见GeoPandas 默认按 UTF-8 读遇到 GBK 编码的中文会乱码这时显式传encodinggbk往往能救回来。这一步做完你才对数据能不能用有底。3. 从点位到可用结果空间连接与密度统计的完整链路3.1 把小区点位和行政区划做空间连接点位本身只有坐标要按城市或区县汇总就得和行政区划面做空间连接。常见做法是准备一份江苏省区县边界 Shp用sjoin把每个点落到对应面里。# 读取区县边界同样确认坐标系 districts gpd.read_file(jiangsu_districts.shp) # 统一到同一坐标系避免连接失败 districts districts.to_crs(gdf.crs) # 空间连接每个点带上所在区县属性 joined gpd.sjoin(gdf, districts[[district, city, geometry]], howleft, predicatewithin) # 检查有没有没落进任何面的点 print(未匹配点数:, joined[district].isna().sum())逻辑说明predicatewithin表示点落在面内才算匹配比intersects更严格适合点位在边界附近时避免重复归属。howleft保留所有点未匹配的会显示空值方便你回头查是边界数据不全还是点位本身有问题。参数上两个图层坐标系必须一致否则sjoin会报错或结果错乱。3.2 按城市统计小区数量并导出结果表连接完成后按城市分组计数就能得到每个城市的小区数量这是最基础的汇总也是后面做密度图、做对比的输入。# 按城市统计小区数量 city_count joined.groupby(city).size().reset_index(namecommunity_count) city_count city_count.sort_values(community_count, ascendingFalse) print(city_count) # 导出为 CSV方便后续在 Excel 或 BI 里用 city_count.to_csv(city_community_count.csv, indexFalse, encodingutf-8-sig)参数说明encodingutf-8-sig是为了 Excel 打开不乱码多一个 BOM 头。reset_index把分组键变回普通列否则导出的 CSV 会丢城市名。这一步的结果可以直接拿去做柱状图也可以和人口数据做人均对比。3.3 生成小区密度栅格从点到面的热力表达如果要做热力图或密度分析可以用核密度估计把点转成栅格。常见做法是用seaborn的kdeplot快速出图或者用rasterio做更正式的栅格输出。import matplotlib.pyplot as plt import seaborn as sns # 提取经纬度注意用原始 4326 坐标 x gdf.geometry.x y gdf.geometry.y plt.figure(figsize(10, 8)) sns.kdeplot(xx, yy, cmapReds, fillTrue, bw_adjust0.5) plt.title(江苏省住宅小区点位密度) plt.xlabel(经度) plt.ylabel(纬度) plt.savefig(density_map.png, dpi200, bbox_inchestight)逻辑说明bw_adjust控制核密度带宽值越小越尖锐、越能看出局部聚集值越大越平滑。这个图适合快速看分布不适合做精确面积统计。如果要精确到每平方公里多少小区应该用投影后的坐标配合numpy分箱或rasterio生成规则栅格再统计每格点数。4. 避坑与排查住宅小区点位数据最容易翻车的 5 个地方4.1 现象缓冲区大得离谱整个地图都被盖住原因直接对 WGS1984 地理坐标系做buffer单位是度而不是米1000 度等于绕地球好几圈。解决先to_crs投影到 UTM 或高斯投影确认crs.is_projected为 True 后再做缓冲区参数按米给。4.2 现象空间连接后大量点没有区县归属原因两个图层坐标系不一致或者行政区划边界没有覆盖到所有点比如省界边缘、飞地。解决先统一crs再用howleft保留未匹配点单独导出这些点检查坐标是否落在边界外必要时用nearest做最近面匹配。4.3 现象中文小区名显示成乱码原因dbf 文件用 GBK 编码读取时按 UTF-8 解码。解决read_file时显式传encodinggbk或者用QGIS打开确认编码后再导出为 UTF-8 的 GeoPackage后续处理更省心。4.4 现象统计出来的城市小区数量和实际感觉差很多原因属性表里的city字段可能为空、写法不统一如「南京」和「南京市」或者点位本身有重复。解决先做字段值标准化去掉「市」后缀统一比较再用drop_duplicates按名称加坐标去重最后重新分组。4.5 现象导出 CSV 用 Excel 打开全是乱码原因默认to_csv用 UTF-8 无 BOMExcel 在中文环境下按 GBK 解析。解决导出时加encodingutf-8-sig或者导出为xlsx。这个坑很小但每次交付都有人踩。5. 进阶用法把小区点位变成选址模型的特征层5.1 用小区点位算居住密度特征选址模型里「周边有多少住宅小区」是一个强特征。做法是先投影到米制坐标系对每个候选点画 1 公里缓冲区统计缓冲区内的点数量。from shapely.geometry import Point # 假设有一个候选点经纬度已知 candidate gpd.GeoDataFrame( {name: [candidate_1]}, geometry[Point(118.78, 32.05)], crsEPSG:4326 ).to_crs(epsg32650) # 投影后的小区点 gdf_proj gdf.to_crs(epsg32650) # 1 公里缓冲区内的点数 buffer candidate.geometry.iloc[0].buffer(1000) count gdf_proj[gdf_proj.intersects(buffer)].shape[0] print(1 公里内小区数:, count)逻辑说明intersects比within更适合点与面的关系判断因为点落在缓冲区边界上也算。参数上buffer(1000)的单位是米前提是已经投影。这个计数可以直接作为特征喂给模型也可以按不同半径500 米、1 公里、3 公里生成多列特征。5.2 验证数据时效性的一个土办法标题写的是 2025 年数据但你怎么知道它真的是 2025 年的我一般会抽几个城市拿最近一年新交付的知名小区去比对看点位在不在、名称对不对。如果数据里连最近两年的新盘都没有那它的「2025」可能只是文件命名实际采集时间更早。这个验证不需要写代码但能帮你判断这份数据值不值得投入生产。5.3 我自己的习惯每次拿到新的点位 Shp我第一件事不是画图而是先print(gdf.crs)和print(gdf.dtypes)确认坐标系和字段再决定后面所有操作。这个习惯帮我省掉了至少三次「算完才发现单位是度」的返工。数据这东西先验后动比事后补救便宜得多。希望帮到你。本文还有配套的精品资源点击获取