多维尺度分析(MDS)内存超限求助:smacof包INDSCAL实现问题
解决INDSCAL分析中的内存溢出问题
问题背景
我有一个包含9位听众对语音对相似度评分的数据框,计划使用R的smacof包进行个体差异尺度分析(INDSCAL),以可视化语音间的多重关系。原实现代码如下:
# 获取唯一语音标识 voices <- unique(c(results$voice1, results$voice2)) # 语音数量 n_voices <- length(voices) # 创建存储个体相异矩阵的列表 dissimilarity_list <- list() # 为每位听众构建对称相异矩阵 for (subject_id in unique(results$subject)) { # 筛选当前听众的评分数据 subject_responses <- results %>% filter(subject == subject_id) # 初始化空矩阵 dissimilarity_matrix <- matrix(NA, nrow = n_voices, ncol = n_voices, dimnames = list(voices, voices)) # 填充矩阵 for (i in 1:nrow(subject_responses)) { voice1 <- subject_responses$voice1[i] voice2 <- subject_responses$voice2[i] response <- subject_responses$response[i] dissimilarity_matrix[voice1, voice2] <- response dissimilarity_matrix[voice2, voice1] <- response # 假设评分对称 } # 将矩阵加入列表 dissimilarity_list[[subject_id]] <- dissimilarity_matrix } # 将矩阵列表转换为3D数组 dissimilarity_array <- array(NA, dim = c(n_voices, n_voices, length(dissimilarity_list))) for (i in 1:length(dissimilarity_list)) { dissimilarity_array[,,i] <- dissimilarity_list[[i]] } # 替换数组中的NA为0 dissimilarity_array[is.na(dissimilarity_array)] <- 0 # 执行INDSCAL分析 indscal_result <- smacofIndDiff(dissimilarity_array, ndim = 2)
触发的错误
运行代码时,在转换为3D数组的步骤出现内存溢出错误:
Error: vector memory limit of 16.0 Gb reached, see mem.maxVSize()
注:存储矩阵的列表仅约0.09GB,设备为全新MBair,此前处理过更大数据集,且SPSS可正常运行该分析,需在不平均评分掩盖方差的前提下解决问题。
解决方案
1. 直接传入列表格式的相异矩阵(最优方案)
smacofIndDiff函数支持直接传入列表格式的相异矩阵,无需手动转换为3D数组,这能避免数组初始化阶段的内存浪费。修改后的代码可跳过数组转换步骤,直接传入列表:
# 保留原矩阵构建逻辑,跳过数组转换 # ...(原代码中构建dissimilarity_list的部分不变) # 先为每个矩阵填充NA为0 dissimilarity_list <- lapply(dissimilarity_list, function(mat) { mat[is.na(mat)] <- 0 mat }) # 直接用列表作为输入执行INDSCAL分析 indscal_result <- smacofIndDiff(dissimilarity_list, ndim = 2)
2. 优化矩阵构建逻辑,减少内存冗余
原代码用双重循环构建矩阵效率较低,可改用tidyr的pivot_wider函数直接从长格式数据转换为对称矩阵,避免循环中的内存开销:
library(tidyr) library(dplyr) dissimilarity_list <- lapply(unique(results$subject), function(subj) { results %>% filter(subject == subj) %>% select(voice1, voice2, response) %>% # 补充对称行,确保矩阵对称 bind_rows(rename(., voice1 = voice2, voice2 = voice1)) %>% # 转换为宽格式矩阵 pivot_wider(names_from = voice2, values_from = response, values_fill = 0) %>% column_to_rownames("voice1") %>% # 补全缺失的语音行列,确保矩阵维度统一 rowwise() %>% mutate(across(all_of(voices), ~ ifelse(is.na(.), 0, .))) %>% ungroup() %>% as.matrix() }) # 执行INDSCAL分析 indscal_result <- smacofIndDiff(dissimilarity_list, ndim = 2)
3. 临时调整R的内存限制(备选方案)
如果上述方法仍有内存问题,可临时调高R的内存上限(根据设备内存调整):
# 设置内存上限为32GB options(mem.maxVSize = 32e9)
此方法仅为临时 workaround,优先推荐前两种方法从根源优化内存使用。
内容的提问来源于stack exchange,提问作者Alice P
相关产品推荐
相关产品推荐

