我对机器学习还不太熟悉,所以正在尝试理解以下代码。具体来说
- 在
for run in np.arange(1, num_runs+1)
中,这个循环的目的是什么?为什么作者没有使用KMeans
的setMaxIter
方法? - 在聚类中设定种子的重要性是什么?
- 为什么作者选择明确设置种子而不是使用默认的种子?
from pyspark.ml.clustering import KMeansfrom pyspark.ml.evaluation import ClusteringEvaluator def optimal_k(df_in,index_col,k_min, k_max,num_runs): ''' 通过使用Silhouette Score分析确定最佳聚类数量。 :param df_in: 输入数据框 :param index_col: 索引列的名称 :param k_min: 训练数据集 :param k_min: 聚类最小数量 :param k_max: 聚类最大数量 :param num_runs: 每个固定聚类运行的次数 :return k: 最佳聚类数量 :return silh_lst: Silhouette分数 :return r_table: 运行结果表 :author: Wenqiang Feng :email: [email protected] ''' start = time.time() silh_lst = [] k_lst = np.arange(k_min, k_max+1) r_table = df_in.select(index_col).toPandas() r_table = r_table.set_index(index_col) centers = pd.DataFrame() for k in k_lst: silh_val = [] for run in np.arange(1, num_runs+1): # 训练一个k-means模型。 kmeans = KMeans()\ .setK(k)\ .setSeed(int(np.random.randint(100, size=1))) model = kmeans.fit(df_in) # 进行预测 predictions = model.transform(df_in) r_table['cluster_{k}_{run}'.format(k=k, run=run)]= predictions.select('prediction').toPandas() # 通过计算Silhouette分数评估聚类 evaluator = ClusteringEvaluator() silhouette = evaluator.evaluate(predictions) silh_val.append(silhouette) silh_array=np.asanyarray(silh_val) silh_lst.append(silh_array.mean()) elapsed = time.time() - start silhouette = pd.DataFrame(list(zip(k_lst,silh_lst)),columns = ['k', 'silhouette']) print('+------------------------------------------------------------+') print("| 寻找最佳k的阶段花费了%8.0f秒。 |" %(elapsed)) print('+------------------------------------------------------------+') return k_lst[np.argmax(silh_lst, axis=0)], silhouette , r_table
回答:
我将根据我对材料的阅读尝试回答你的问题。
- 这个循环的原因是作者在每次循环中使用
int(np.random.randint(100, size=1))
设置一个新的seed
。如果特征变量显示出自动将它们分组到可见聚类中的模式,那么起始种子应该不会影响最终的聚类成员。然而,如果数据分布均匀,那么我们可能会根据初始随机变量得到不同的聚类成员。我认为作者在每次运行中改变这些种子是为了测试不同的初始分布。使用setMaxIter
将为相同的seed
(初始分布)设置最大迭代次数。 - 与上文类似 – 种子定义了你将要聚类的
k
个点的初始分布。根据你的基础数据分布,聚类可能会收敛到不同的最终分布。 - 正如第1点和第2点所讨论的,作者对种子有控制权。你可以看到你的代码在哪些种子下收敛到期望的聚类,以及在哪些种子下可能无法收敛。此外,如果你迭代了,比如说,100个不同的种子,你的代码仍然收敛到相同的最终聚类,你可以移除默认种子,因为它可能不重要。另一个用途是从软件工程的角度来看,明确设置种子对于例如编写代码测试并避免其随机失败非常重要。