You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在R语言中使用asplit()按行和列拆分矩阵的问题

从矩阵中按名称提取非NA比较值的优化方法

问题场景

我们需要从名为matr的矩阵中,提取与指定名称(如A、B、C)对应的所有非NA比较值,初始实现如下:

### 构建示例矩阵 ###
matr <- matrix(c(2,0,3,0,5,0.7,1,0,0.9,6,11,9,0,1,0.5,2,0,1,0.3,3,6,1,0.31,0,0),     nrow = 5, ncol = 5)
dimnames(matr) = list(c("A", "B", "A", "C", "A"),  c("A", "B", "A", "C", "A"))
matr

# 模拟对称矩阵(实际场景中矩阵是对称的)
matr[upper.tri(matr, diag = TRUE)] <- NA # 保留下三角
matr

# 将行名与列名相同的位置设为NA
for (rowLoopCounter in 1:nrow(matr)){
  matr_work <- matr[rowLoopCounter,,drop=FALSE]
  for (colLoopCounter in 1:nrow(matr)) {
    if (row.names(matr)[rowLoopCounter] == colnames(matr)[colLoopCounter]){
      matr[rowLoopCounter, colLoopCounter] <- NA
    }
  }
}

# 提取A对应的所有非NA值
A_row <- c(matr[grepl("A", row.names(matr)), ]) # 行中含A的元素
sA_col <- c(matr[, grepl("A", colnames(matr))]) # 列中含A的元素
total <- as.numeric(na.omit(unlist(c(A_row, sA_col)))) # 合并并去除NA

total
#[1] 0 6 3 0 0 1

现有方法的不足

上述实现不仅繁琐,且只能单独处理单个名称(如A),若要处理B和C还需重复编写代码。尝试用split()函数时结果异常,比如A对应的结果遗漏了值1(该值被错误归入C):

splt <- split(matr, colnames(matr)) # 用rownames(matr)结果一致

#$A
#[1] NA NA NA NA  0  6 NA NA NA NA NA  3 NA NA NA

#$B
#[1]  0 NA NA NA NA

#$C
#[1] 0.0 0.9 1.0  NA  NA

尝试使用asplit()时直接报错:

asplit(matr, c(1, 2))
#Error in array(newx[, i], d.call, dn.call) : 'dims' cannot be of length 0

我们期望得到按名称分组的命名列表,每个列表元素对应该名称的所有非NA比较值。

优化解决方案

方法一:Base R 实现

通过构建行名和列名的分组,结合lapply和na.omit批量处理所有名称:

# 获取所有唯一名称
names <- unique(c(rownames(matr), colnames(matr)))

# 按名称分组提取非NA值
result <- lapply(names, function(x) {
  # 提取行名为x或列名为x的所有元素
  elements <- matr[(rownames(matr) == x) | (colnames(matr) == x)]
  # 去除NA并转为数值型
  as.numeric(na.omit(elements))
})

# 为列表命名
names(result) <- names

# 查看结果
result
#$A
#[1] 0 6 3 0 0 1
#$B
#[1] 0 0.7 1
#$C
#[1] 0.9 0.5 0.3 0.31

方法二:tidyverse 实现

将矩阵转为长格式数据框后处理,逻辑更直观:

library(tidyverse)

# 矩阵转为长格式数据框
matr_df <- as.data.frame.table(matr, responseName = "value") %>%
  rename(row = Var1, col = Var2) %>%
  filter(!is.na(value))

# 按名称分组,提取所有涉及该名称的value
result_tidy <- matr_df %>%
  group_by(name = case_when(row %in% names ~ row, col %in% names ~ col)) %>%
  summarise(values = list(na.omit(value))) %>%
  deframe()

# 查看结果
result_tidy
#$A
#[1] 0 6 3 0 0 1
#$B
#[1] 0 0.7 1
#$C
#[1] 0.9 0.5 0.3 0.31

原方法出错原因

  • split(matr, colnames(matr))是按列名对矩阵的列进行分组,仅会将列名为目标名称的列归入对应组,行名为目标名称但列名不符的元素不会被包含,因此遗漏部分值。
  • asplit()的作用是将数组按指定维度拆分为列表,asplit(matr, c(1,2))尝试同时按行和列拆分,相当于把每个元素拆成单独数组,不符合需求所以报错。

内容的提问来源于stack exchange,提问作者compbiostats

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 03:05:49