暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

关于机器学习-基于2023年度各省统计数据的数据标准化、Kmean聚类和结果可视化

追梦IT人 2025-02-17
64

sklearn.cluster.KMeans 是 Python 中 Scikit-learn 库提供的一个非常流行和常用的聚类算法,用于将数据分成预先指定的数量(即“k”个)集群。尽管 KMeans 算法在很多情况下表现良好,但它也有一些缺点和局限性:

对初始化的敏感性:KMeans 算法的性能很大程度上依赖于初始质心(centroids)的选择。不同的初始化可能导致算法收敛到局部最优解,而非全局最优解。

对异常值敏感:异常值(或称为噪声点)可以显著影响 KMeans 的聚类结果,因为这些点可能会被误分类到离它们最近的质心所在的集群中。

对球形簇形的假设:KMeans 假设所有簇是球形且各向同性的,这意味着簇的形状应该是圆形的,并且每个维度上的方差应该是相同的。

难以确定最佳簇数:确定最佳的簇数 K 是一个挑战。KMeans 需要用户事先指定 K 的值,而实际上选择一个合适的 K 值并不总是直观的。

计算复杂度:KMeans 的计算复杂度是 O(tkn),其中 t 是迭代次数,k 是簇的数量,n 是样本数。随着数据集的增大和/或簇的数量增加,算法的运行时间可能会显著增加。

在provicedata.csv中,涉及地区(几千到上百万平方公里),GDP以亿为单位,从几百到十几万不等,人口增长率以百分位计量,进出口以万元为单位等等,导致各列的数据、单位、量级不在一个水平上,在进行聚类的过程中,必然导致部分数据无法被正确使用,从而导致分类的错误。因此有必要将数据进行标准化处理。
‌sklearn.StandardScaler‌是scikit-learn库中的一个类,用于对数据进行标准化处理。标准化处理的目标是将特征缩放到均值为0,标准差为1的标准正态分布。通过对数据进行线性变换,使每个特征(即每个属性或每列)的数据都服从标准正态分布,即均值为0,标准差为1。这种转换是通过计算特征的均值和标准差来完成的
下列代码就是实现数据标准化的过程。
  1. from sklearn.preprocessing import StandardScaler # 标准化库
  2. # 数据归一化
  3. scaler = StandardScaler()
  4. scalerX = scaler.fit_transform(X)

  5. for k in range(3,6):
  6.     # 模型训练
  7.     KmeansModel = KMeans(n_clusters=k, random_state=42)
  8.     KmeansModel.fit(scalerX)
  9.     # 计算轮轴系数:
  10.     # 轮廓系数用于计算每个样本的平均簇内距离a(样本i到同簇其他样本的平均距离,ai值越小说明该样本越应该被聚到该类,即簇内不相似度)和平均邻近簇距离b(样本i到其他相邻簇的所有样本的平均距离bibi越大说明样本i越不属于其他簇,即簇间不相似度)。
  11.     # 每个样本的轮廓系数计算公式为:(b-a)/Max(a,b),轮廓系数越接近1说明结果越好(聚类越准确),越接近-1说明结果越差,若值在0值附近,则说明样本在两个簇的边界上
  12.     score = silhouette_score(scalerX, KmeansModel.labels_, metric='euclidean')
  13.     print("For n_clusters={}, The Silhouette Coefficient is {}".format(k, score))
  14.     # 合并数据和特征
  15.     kmeans_labels = pd.DataFrame(KmeansModel.labels_, columns=['scaler kmean labels'+str(k)])
  16.     df = df.join(kmeans_labels)
  17. df.to_csv('provicedatav2.csv', index=False, header=True, encoding='utf-8')

在实现数据标准化后,我们查看一下数据的规律和分布情况,基本都满足正态分布

  1. import numpy as np
  2. scaler = StandardScaler()
  3. scalerX = scaler.fit_transform(X)
  4. max_values = np.amax(scalerX, axis=0)
  5. print("列上的最大值:", max_values)

  6. # 计算列上的最小值
  7. min_values = np.amin(scalerX, axis=0)
  8. print("列上的最小值:", min_values)

  9. # 计算列上的平均值
  10. mean_values = np.mean(scalerX, axis=0)
  11. print("列上的平均值:", mean_values)
  12. # 列上的最大值:
  13. # [2.95274386 1.94360996 1.94360996 1.94360996 2.71394433
  14. # 3.05643864  3.58884568 3.81979393 2.92766957 3.29469106
  15. # 2.85150009 3.18538812  3.12650613 3.53887138]
  16. # 列上的最小值:
  17. # [-1.17588455 -1.50879078 -1.50879078 -1.50879078 -1.38798558
  18. # -1.95537756  -0.69273214 -0.62470284 -0.68714838 -1.15992496
  19. # -1.53665505 -0.95225614  -1.08900741 -0.79803214]
  20. # 列上的平均值:
  21. # [-2.65020980e-16 -2.44428134e-16 -2.44428134e-16 -2.44428134e-16 -5.73018335e-17
  22. # -5.01391043e-17  3.58136460e-17  0.00000000e+00  -2.50695522e-17  7.52086565e-17
  23. # 1.66029824e-16 -1.21766396e-16  -1.75486865e-16  1.43254584e-17]

接下来是数据可视化,基于cartopy和matplotlib实现地理数据的展示,基于geopandas实现矢量地图文件的加载。

china.rar文件包括各省边界、各市边界、各县边界、中国边界(含九/十段线),已共享到百度网盘中,见链接: https://pan.baidu.com/s/128281wae901QfViNHtlUwA?pwd=8888 提取码: 8888

一般用geopandas来读取shp文件

  1. china = gpd.read_file(r'E:\shp\china\中国_省_Areas.shp')
  2. print(china.head())

我们看一下数据格式,包括了各省市自治区名称,面积和边界点,shp文件中的各省市自治区名称和国家统计局是一样的,因此不需要转换。


               LAYER    name         gb                                           geometry

0  Unknown Area Type  河南省  156410000  MULTIPOLYGON (((111.02261 33.17939, 111.00594 ...

1  Unknown Area Type  浙江省  156330000  MULTIPOLYGON (((121.08199 27.47084, 121.09719 ...

2  Unknown Area Type  海南省  156460000  MULTIPOLYGON (((112.05623 3.83753, 112.04267 3...

3  Unknown Area Type  台湾省  156710000  MULTIPOLYGON (((121.60056 22.02062, 121.59325 ...

4  Unknown Area Type  甘肃省  156620000  POLYGON ((97.17195 42.79342, 97.84515 41.65423...


下面代码是实现聚类后各省分类的可视化代码,有一个在不同pandas之间进行数据赋值转换的过程。

  1. import matplotlib.pyplot as plt
  2. import cartopy.crs as ccrs
  3. import cartopy.feature as cfeature
  4. import geopandas as gpd
  5. import pandas as pd

  6. pd.set_option('display.max_columns', None)
  7. # 显示所有行
  8. pd.set_option('display.max_rows', None)
  9. # 不换行显示
  10. pd.set_option('display.width', 1000)
  11. # 行列对齐显示,显示不混乱
  12. pd.set_option('display.unicode.ambiguous_as_wide', True)
  13. pd.set_option('display.unicode.east_asian_width', True)
  14. # 显示精度
  15. pd.set_option('display.precision', 4)
  16. # 显示小数位数
  17. pd.get_option("display.precision")

  18. # 加载中国各省的地理数据
  19. # 你需要从网上下载中国各省的shapefile文件,例如从GADM (https://gadm.org/download_country_v3.html)
  20. china = gpd.read_file(r'E:\shp\china\中国_省_Areas.shp')
  21. # 加载九段线数据,九段线数据可以从自然资源部或其他公开数据源获取
  22. nine_dash_line = gpd.read_file(r'E:\shp\china\中国_省_Lines.shp')
  23. # 加载上次另存的数据
  24. data_path = r'E:\JetBrains\PythonProject\DeepLearning\Sklearn\provicedatav2.csv'
  25. df = pd.read_csv(data_path)
  26. # kmean label3kmean label4 kmean label5
  27. china['scaler kmean labels3'] = china['name'].map(df.set_index('city')['scaler kmean labels3'])
  28. china['scaler kmean labels4'] = china['name'].map(df.set_index('city')['scaler kmean labels4'])
  29. china['scaler kmean labels5'] = china['name'].map(df.set_index('city')['scaler kmean labels5'])

  30. def drawchina(df,columnname):
  31.     # 创建地图
  32.     fig = plt.figure(figsize=(12, 8))
  33.     ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
  34.     # 设置地图范围为中国(包括南海区域)
  35.     ax.set_extent([73, 135, 3, 54], crs=ccrs.PlateCarree())
  36.     # 添加地理特征
  37.     ax.add_feature(cfeature.COASTLINE.with_scale('50m'))
  38.     ax.add_feature(cfeature.BORDERS.with_scale('50m'), linestyle=':')
  39.     ax.add_feature(cfeature.LAND.with_scale('50m'), edgecolor='black')
  40.     ax.add_feature(cfeature.OCEAN.with_scale('50m'))
  41.     ax.add_feature(cfeature.LAKES.with_scale('50m'))

  42.     # 绘制各省地图并根据数据着色
  43.     df.plot(column=columnname, ax=ax, legend=True, cmap='OrRd', legend_kwds={'label': "Data by Province"})
  44.     # df.plot(column=columnname, ax=ax, linewidth=2,legend_kwds={'label': "Data by Province"})
  45.     # 绘制九段线
  46.     nine_dash_line.plot(ax=ax, color='blue', linewidth=2, label='Nine-Dash Line')
  47.     plt.legend()
  48.     # 添加标题
  49.     plt.title('China Provinces Data with Nine-Dash Line')
  50.     # 显示地图
  51.     plt.tight_layout()
  52.     plt.show()

  53. drawchina(china, 'scaler kmean labels3')
  54. drawchina(china, 'scaler kmean labels4')
  55. drawchina(china, 'scaler kmean labels5')

可视化呈现效果如下:三个分类的,似乎不太准,北京上海浙江属于经济发达的小省市,橙色区域经济一般。

四个分类的,北京上海浙江属于经济发达的小省市;广东、江苏、山东是经济大省,人口也多;其他分类的有些看不太懂。
五个分类的,将新疆、内蒙两个区域大省给单独分开了。

最后欢迎关注公众号:python与大数据分析


文章转载自追梦IT人,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论