辐射归并算法和聚类实践
- 算法运作基本原理
- 算法的 Python 实现
- 聚类结果
算法运作基本原理 【聚类|2022年MathorCup数学建模竞赛(基站聚类思路)】题中给出的弱覆盖点聚类原理是一种“传染机制”:距离不大于 20 的两点属于同一类别,因此通过点和点之间的“传染标记”得到一个完整的类别,算法原理如同病毒扩散。因此,我们将“类别传染者”命名为“辐射点”,未归类点命名为“待归类点”。
因此,如果想得到一类,应当从一个辐射点开始在所有待归类点中寻找与其距离不超过 20 的点后将它们标记为相同类别,并将每次迭代后类中的新增点作为下一次迭代的辐射点,将每次迭代后剩下的为归类点作为下一次迭代的待归类点……在某一次迭代后如果没有出现新增点(即下一次迭代无辐射点),则本轮迭代结束。依照这种迭代规则,每一轮迭代停止后可以得到一类;下一轮迭代将重新从所有剩下的“待归类”点中进行。
算法的 Python 实现 首先,撰写用于分出聚类单类别的函数SingleClass(*args, **kwargs)
'''
df 代表用 DataFrame 格式存放的点集
classtype 为人工输入的类编号
dis_square 为距离阈值的平方(题中为 20 ** 2 即 400)
'''
def SingleClass(df, classtype, dis_square):
# 初始迭代,“class”字段存放点被归入的类别编号,因此没有被归类的点该字段存放空值
newdf = df.loc[df['class'].isnull()].copy()
startindex = newdf.index[0]
# “dis”字段存放两点间欧氏距离的平方,而并非欧氏距离
df.loc[:, 'dis'] = (df.loc[startindex, 'x'] - df['x']) ** 2 + (df.loc[startindex, 'y'] - df['y']) ** 2
df.loc[df['dis'] <= dis_square, 'class'] = classtype
index_update = df.loc[df['dis'] <= dis_square].index
# 完成了从空到有类的步骤,然后进入循环
while True:
newdf = df.loc[df['class'].isnull()].copy()
last_increased_index = []
for i in index_update:
newdf.loc[:, 'dis'] = (newdf.loc[:, 'x'] - df.loc[i, 'x']) ** 2 + (newdf.loc[:, 'y'] - df.loc[i, 'y']) ** 2
last_increased_index.extend(newdf[newdf['dis'] <= dis_square].index)
# 去除重复的点索引
last_increased_index = list(set(last_increased_index))if last_increased_index == []: # 如果没有找到满足要求的点则跳出循环
break
else: # 更改类值添加分类
df.loc[last_increased_index, 'class'] = classtype
index_update = last_increased_index
return df
第二步,撰写利用SingleClass(*args, **kwargs)函数进行迭代的总聚类函数Cluster(*args, **kwargs)
'''
df 为输入的点集
dis_square 为距离阈值的平方(本题中即为400)
'''
def Cluster(df, dis_square):
count = 1
while True:
df_null = df[df['class'].isnull()]
if df_null.shape[0] == 0:
return df
else:
df = SingleClass(df, f'Classed-{count}', dis_square)
print(f'类别{count}, 完成!')
count += 1
使用两个函数进行聚类的前提是预处理数据集,使其具有“class”字段和“dis_square”字段。因此,在调用函数Cluster(*args, **kwargs)之前,要对原数据集进行预处理。
if __name__ == '__main__':
# 使用文件路径读取数据集
df = pd.read_csv('*****.csv')
df[['dis', 'class']] = np.nan
df = Cluster(df, dis_square = 400)
df.drop(['dis'], axis = 1, inplace = True)
# df.to_csv('聚类结果.csv', index=False)
聚类结果 最后,通过作图,可以直观看出聚类结果。下方两张图分别为聚类前和聚类后的点簇图。经过聚类,一共得到898类,所有弱覆盖栅格点均被归类
推荐阅读
- 数学建模|2022年第十二届MathorCup高校数学建模挑战赛
- matlab|2022年MathorCup建模赛D题(MATLAB代码与若干问题)
- matlab|2022 MathorCup 数学建模B题思路解析
- 努力学习人工智能|基于图像识别的跌倒检测
- 算法|魔改YOLOv5!一种实时多尺度交通标志检测网络
- 神经网络|YOLO7 姿势识别实例
- sklearn|【OpenCV 例程200篇】235. 特征提取之主成分分析(sklearn)
- 如何用 Python 自动化监控文件夹完成服务部署!
- 计算机毕业论文|基于Python的招聘网站爬虫及可视化的设计与实现