将矩阵列表转换为单个数据框

3

I have a dataframe:

 data=read.table(text="region     plot    species
 1          1A      A_B  
 1          1B      B_C
 1          1C      A_B
 1          1D      C_D
 2          2A      B_C
 2          2A      E_F
 2          2B      B_C
 2          2B      E_F     
 2          2C      E_F
 2          2D      B_C
 3          3A      A_B
 3          3B      A_B",stringsAsFactors=F,h=T) 

然后,使用该数据框创建了一个矩阵列表:

sublist=NA
for (i in unique(data$region)){   
  sublist[i]<-list(subset(data, data[,1] == i))  
  print(i)
}

 results = list()
 for (r in unique(data$region)){
  myset<-split(sublist[[r]][[3]],sublist[[r]][[2]])
  output<- matrix(NA, nrow = length(myset), ncol = length(myset))
  rownames(output)<-colnames(output)<-unique(sublist[[r]][[2]])
  for (j in 1:(length(myset)-1)){
    for (i in (j+1):length(myset)){
    output[i,j]=sum(myset[[j]] %in% myset[[i]])
     }
   }
 results[[r]]=output
 }

以下是输出的样例(注意:它们的尺寸不同,可能包含NA值):
 [[1]]
   1A 1B 1C 1D
1A NA NA NA NA
1B  0 NA NA NA
1C  1  0 NA NA
1D  0  0  0 NA

[[2]]
   2A 2B 2C 2D
2A NA NA NA NA
2B  2 NA NA NA
2C  1  1 NA NA
2D  1  1  0 NA

[[3]]
   3A 3B
3A NA NA
3B  1 NA 

我想对这个矩阵列表应用一个函数,将其格式更改为一个数据框。 数据框的一列将是矩阵元素,第二列将是矩阵的行和列维度,第三列将是包含矩阵填充值的freq列。 对于此示例,输出如下所示:(注意:NAs不被考虑。)
output<-
      x     y       freq
      1     1A_1B     0     
      1     1A_1C     1
      1     1A_1D     0
      1     1B_1C     0    
      1     1B_1D     0 
      1     1C_1D     0
      2     2A_2B     2     
      2     2A_2C     1
      2     2A_2D     1
      2     2B_2C     1    
      2     2B_2D     1 
      2     2C_2D     0
      3     3A_3B     1  

我不反对更有效的代码,将第一个/原始数据框转换为此输出数据框,以避免循环和矩阵列表。
2个回答

1
这里是使用基础 R 方法和 lapply 的示例。
获取一个数据框列表。
myList <- lapply(seq_along(results), function(i) {
       # get matrix of non NA positions
       pos <- which(!is.na(results[[i]]), arr.ind=TRUE)
       # return data.frame for given list item
       data.frame(x=i,
                  y=paste(rownames(results[[i]])[pos[,1]], colnames(results[[i]])[pos[,2]]),
                  freq=results[[i]][pos])
})

数据框的第一个变量是 lapply 迭代的索引。第二个变量是通过将矩阵列表中的行名和列名粘贴在非 NA 位置的矩阵中构建而成的。第三个变量是使用矩阵子集构建的,其中进行提取。然后使用 rbinddo.call
do.call(rbind, myList)
   x     y freq
1  1 1B 1A    0
2  1 1C 1A    1
3  1 1D 1A    0
4  1 1C 1B    0
5  1 1D 1B    0
6  1 1D 1C    0
7  2 2B 2A    2
8  2 2C 2A    1
9  2 2D 2A    1
10 2 2C 2B    1
11 2 2D 2B    1
12 2 2D 2C    0
13 3 3B 3A    1

我知道在没有真实数据的情况下进行故障排除可能会很具有挑战性,但您是否有任何想法,为什么我会收到这个错误消息:“Error in seq_len(B.list) : argument must be coercible to non-negative integer In addition: Warning message:In seq_len(B.list) : first element used of 'length.out' argument”? - Danielle
糟糕,又打错字了。应该是 seq_along - lmo
你是否有任何方法可以添加一个参数到你上面提供的代码中,以便消除相似性比较?例如,在事件y=1A_1A或y=2B_2B中,我不想要被比较的相同(在这种情况下是图). - Danielle
pos <- which(!is.na(results[[i]]), arr.ind=TRUE) 之后,您可以添加一行 pos <- pos[pos[, 1] != pos[, 2], ] 来删除任何非 NA 对角线元素。 - lmo
太好了。谢谢你。 - Danielle

1
使用 tidyverse:
library(tidyverse)
data %>% group_by(region,species) %>% 
  filter(n()>1)%>%
  summarize(y=list(combn(plot,2, paste, collapse="_"))) %>% 
  unnest %>%
  group_by(region,y) %>% 
  summarize(freq=n())

  region     y  freq
   <int> <chr> <int>
1      1 1A_1C     1
2      2 2A_2B     2
3      2 2A_2C     1
4      2 2A_2D     1
5      2 2B_2C     1
6      2 2B_2D     1
7      3 3A_3B     1

你有没有办法在你上面提供的代码中添加一个参数,以删除类似的比较?例如,在事件y= 1A _1A或y= 2B_2B中,我不希望进行相同的比较(在这种情况下是绘图)。 - Danielle
顺便说一句,我应该感谢你,你的代码是回答我的问题更加高效的完美方式。我选择了其他答案,因为那个答案解决了问题标题。感谢你的时间。 - Danielle
欢迎,@Danielle!要去除重复项,请尝试在第一个 group_by 后添加 filter(!duplicated(plot)) - HubertL
返回错误:n < m。如果你有时间,能否帮忙看一下https://stackoverflow.com/questions/44808793/conditional-statement-in-dplyr-tidyverse-function-to-exclude-comparisons-among-s?noredirect=1#comment76599458_44808793 我已经更新了这个问题以适应我目前的问题。 - Danielle
filter(n()>1)是什么意思? - Danielle
filter(n()>1):删除物种组中少于2个元素的区域/物种组(一个地区中没有一对物种)。 - HubertL

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接