基于对数似然的Python聚类成员分配与SPSS结果不符问题排查
问题背景
我有100个通过SPSS两步聚类预定义好的簇,每个簇包含均值和标准差,且分布已完成数据适配优化。针对新的未观测数据,我希望通过选择对数似然最大的簇来分配成员归属,因此编写了Python代码,目标是和SPSS的输出结果一致。
测试发现:用最小化到簇均值的RMSE标注的准确率约42%(非SPSS采用的方法),而用代码实现的最大对数似然法标注时,准确率不足20%,远低于预期。
代码实现
import pandas as pd import numpy as np from sklearn.metrics import mean_squared_error import math from scipy import stats # import raw files clusters_df = pd.read_csv('ClusterCoordinates.csv') # clusters are in order of cluster numbers enabling us to use index for identification clusters_df = clusters_df.drop(columns=['Cluster']) print(clusters_df.shape) clusters = clusters_df.to_numpy() frames_df_raw = pd.read_csv('FrameCoordinates.csv') frames_df = frames_df_raw.drop(columns=['frame','replica','voltage','system','ff','cluster']) print(frames_df.shape) frames = frames_df.to_numpy() clusters_sd_df = pd.read_csv('ClusterCoordinates_SD.csv') clusters_sd_df = clusters_sd_df.drop(columns=['Cluster']) print(clusters_sd_df.shape) clusters_sd = clusters_sd_df.to_numpy() rmseCalc = [] llCalc = [] assignedCluster_RMSE = [] assignedCluster_LL = [] # create tables with RMSE and LL values for frame in frames: for cluster, cluster_sd in zip(clusters, clusters_sd): # we compare cluster assignment using minimum RMSE vs maximum log likelihood methods. rmseCalc.append(math.sqrt(mean_squared_error(np.array(cluster),np.array(frame)))) llCalc.append(-np.sum(stats.norm.logpdf(frame, loc=cluster, scale=cluster_sd))) rmseCalc=np.array(rmseCalc) llCalc=np.array(llCalc) llCalc=np.nan_to_num(llCalc) minRMSE = np.where(rmseCalc==rmseCalc.min()) maxLL = np.where(llCalc==llCalc.min()) print(maxLL[0][0]+1) assignedCluster_RMSE.append(minRMSE[0][0]+1) assignedCluster_LL.append(maxLL[0][0]+1) rmseCalc=[] llCalc=[] frames_df_raw['predCluster_RMSE'] = np.array(assignedCluster_RMSE) frames_df_raw['predCluster_LL'] = np.array(assignedCluster_LL) frames_df_raw.to_csv('frames_clustered.csv')
可能的问题排查方向
1. 变量预处理不匹配
SPSS两步聚类默认会对输入变量做标准化处理(如Z-score转换),如果导出的簇均值/标准差是标准化后的值,但你的新数据frames_df没有执行完全相同的预处理(比如没有按SPSS聚类时的均值和标准差做Z-score转换),会直接导致对数似然计算完全偏离。
2. 对数似然计算遗漏簇先验概率
SPSS在分配簇时,会结合簇的先验概率(即簇的样本占比)来计算总对数似然,公式应为:总对数似然 = log(簇的先验概率) + 样本在该簇下的对数似然
你的代码只计算了样本在簇下的对数似然,完全忽略了簇的先验概率,这会导致分配结果和SPSS不一致——尤其是当簇的大小差异较大时,影响会非常明显。
3. 标准差的类型不匹配
SPSS计算的标准差可能是总体标准差(除以N),而你导出的ClusterCoordinates_SD.csv如果是样本标准差(除以N-1),会导致scale参数错误,进而扭曲对数似然的计算结果。需要确认SPSS导出的标准差类型,并在代码中做对应调整。
4. 异常值/零标准差的处理差异
如果某个簇的标准差为0,stats.norm.logpdf会返回负无穷,你的代码用nan_to_num将其转为0,这和SPSS对零标准差的处理逻辑可能完全不同,导致该簇的对数似然计算失效,影响分配结果。
5. 对数似然的符号验证
虽然你的代码通过取负总和后找最小值来等价于原对数似然的最大值,但需要验证SPSS的对数似然计算是否包含相同的常数项或符号约定——比如SPSS是否对对数似然做了缩放或偏移处理,导致直接对比时出现偏差。
内容的提问来源于stack exchange,提问作者Billy Noonan

