使用dplyr反归一化标准化聚类中心遇错误,求解决方案
解决标准化聚类中心的反归一化问题
问题原因
你原代码的核心问题有两个:
- 直接使用
unlist(sds)和unlist(means)会生成长度为4的向量,与每列3行的数值进行循环回收,无法实现按列对应的反标准化(即Sepal.Length列只能用sds和means中对应的Sepal.Length值)。 - 错误使用
where(Sepal.Length:Petal.Width),where()需要接收判断函数(比如is.numeric),而非列名范围。
解决方案
方法一:使用cur_column()匹配对应列的均值和标准差(最简洁)
利用dplyr的cur_column()获取当前处理的列名,精准匹配means和sds中对应的数值:
library(dplyr) centroids_original_scale <- centroids_standardized %>% mutate(across(-.cluster, ~ .x * sds[[cur_column()]] + means[[cur_column()]]))
方法二:长格式转换后计算(更直观,适合复杂场景)
将所有数据转换为长格式,合并后计算再转回宽格式,避免列名匹配错误:
library(dplyr) library(tidyr) # 将均值和标准差转为长格式 means_long <- means %>% pivot_longer(everything(), names_to = "variable", values_to = "mean") sds_long <- sds %>% pivot_longer(everything(), names_to = "variable", values_to = "sd") # 反标准化计算 centroids_original_scale <- centroids_standardized %>% pivot_longer(-.cluster, names_to = "variable", values_to = "standardized") %>% left_join(means_long, by = "variable") %>% left_join(sds_long, by = "variable") %>% mutate(original = standardized * sd + mean) %>% select(.cluster, variable, original) %>% pivot_wider(names_from = "variable", values_from = "original")
方法三:用purrr遍历列处理
适合习惯函数式编程的场景,明确对每一列单独计算:
library(dplyr) library(purrr) # 提取数值列名 num_cols <- setdiff(names(centroids_standardized), ".cluster") centroids_original_scale <- centroids_standardized %>% bind_cols( map2_dfc( .x = select(., all_of(num_cols)), .y = map2(means[num_cols], sds[num_cols], ~ list(mean = .x, sd = .y)), ~ .x * .y$sd + .y$mean ) %>% set_names(num_cols) ) %>% select(.cluster, all_of(num_cols))
验证结果
以Cluster_1的Sepal.Length为例,手动计算:-1.01 * 0.828 + 5.84 = 5.00372
运行上述代码后,centroids_original_scale中对应值与手动计算一致,说明反标准化正确。
内容的提问来源于stack exchange,提问作者user23438
相关产品推荐
相关产品推荐

