【问题标题】:Select last non-NA column of a list of dataframes选择数据框列表的最后一个非 NA 列
【发布时间】:2014-01-19 23:15:37
【问题描述】:

我目前正在尝试在 R 中解析 RDP 多分类器层次结构文件,但该问题更普遍适用。基本上我创建了一个列表,其中包含几个文件的数据帧,这些文件包含“分层”行:

dput(corner(hierlist$hier_M2MID06_Trimmed_noGaps.fas_fixrank.txt,n=c(7,10)))
structure(list(X1 = structure(c(30L, 31L, 163L, 45L, 64L, 65L, 
66L), .Label = c("-1071", "-1102", "-1153", "-1159", "-1176", 
"-1177", "-1207", "-1241", "-1256", "-1281", "-1332", "-1353", 
"-1354", "-1502", "-1567", "-18", "-2", "-2715", "-423", "-460", 
"-463", "-471", "-567", "-568", "-828", "-842", "-843", "-871", 
"-980", "0", "1", "1031", "1069", "1070", "1093", "1101", "1126", 
"1151", "1152", "1158", "1159", "1164", "1165", "1166", "1175", 
"1176", "1195", "1200", "1206", "1207", "1215", "1216", "1217", 
"1219", "1240", "1251", "1255", "1256", "1261", "1269", "1279", 
"1280", "1282", "1330", "1331", "1339", "1341", "1343", "1348", 
"1352", "1353", "1354", "1355", "1356", "1357", "1358", "1360", 
"1501", "1566", "16", "1668", "1672", "1674", "17", "1762", "1763", 
"1764", "1767", "1883", "1884", "1885", "1891", "1893", "1894", 
"2", "2164", "2179", "2180", "2183", "2184", "2187", "2192", 
"2195", "2208", "2209", "2210", "2211", "2259", "2260", "2333", 
"2371", "2372", "254", "255", "261", "264", "2684", "2713", "2714", 
"274", "3", "35", "422", "458", "459", "46", "462", "470", "48", 
"49", "54", "565", "566", "567", "570", "577", "581", "648", 
"653", "657", "659", "804", "805", "806", "807", "808", "817", 
"818", "819", "820", "822", "824", "825", "826", "827", "829", 
"832", "834", "837", "838", "839", "840", "841", "842", "843", 
"844", "846", "848", "870", "886", "887", "908", "918", "927", 
"929", "950", "957", "978", "979", "taxid"), class = "factor"), 
X2 = structure(c(3L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("Root", 
"lineage", "null"), class = "factor"), X3 = structure(c(1L, 
3L, 3L, 3L, 3L, 3L, 3L), .Label = c("Root", "name", "rootrank"
), class = "factor"), X4 = structure(c(2L, 1L, 1L, 1L, 1L, 
1L, 1L), .Label = c("Bacteria", "no rank", "rank"), class = "factor"), 
X5 = structure(c(1L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("194", 
"M2MID06_Trimmed_noGaps.fas", "domain"), class = "factor"), 
X6 = structure(c(NA, NA, 10L, 10L, 10L, 10L, 10L), .Label = c("", 
"Acidobacteria", "Actinobacteria", "Bacteroidetes", "Cyanobacteria/Chloroplast", 
"Firmicutes", "Gemmatimonadetes", "Nitrospira", "Planctomycetes", 
"Proteobacteria", "Spirochaetes", "Verrucomicrobia", "unclassified_Bacteria"
), class = "factor"), X7 = structure(c(NA, 2L, 3L, 3L, 3L, 
3L, 3L), .Label = c("", "Bacteria", "phylum"), class = "factor"), 
X8 = structure(c(NA, 21L, NA, 8L, 8L, 8L, 8L), .Label = c("", 
"Acidobacteria_Gp3", "Acidobacteria_Gp4", "Actinobacteria", 
"Alphaproteobacteria", "Bacilli", "Bacteroidetes_incertae_sedis", 
"Betaproteobacteria", "Chloroplast", "Deltaproteobacteria", 
"Flavobacteria", "Gammaproteobacteria", "Gemmatimonadetes", 
"Nitrospira", "Phycisphaerae", "Planctomycetacia", "Sphingobacteria", 
"Spirochaetes", "Subdivision3", "Verrucomicrobiae", "domain", 
"unclassified_Bacteroidetes", "unclassified_Proteobacteria"
), class = "factor"), X9 = structure(c(NA, 2L, 11L, 14L, 
14L, 14L, 14L), .Label = c("", "194", "Acidobacteria", "Actinobacteria", 
"Bacteroidetes", "Cyanobacteria/Chloroplast", "Firmicutes", 
"Gemmatimonadetes", "Nitrospira", "Planctomycetes", "Proteobacteria", 
"Spirochaetes", "Verrucomicrobia", "class", "unclassified_Bacteria"
), class = "factor"), X10 = structure(c(NA, NA, 29L, NA, 
22L, 22L, 22L), .Label = c("", "Actinobacteridae", "Bdellovibrionales", 
"Burkholderiales", "Caulobacterales", "Chloroplast", "Chromatiales", 
"Flavobacteriales", "Gemmatimonadales", "Gp3", "Gp4", "Lactobacillales", 
"Legionellales", "Methylophilales", "Nitrospirales", "Ohtaekwangia", 
"Phycisphaerales", "Planctomycetales", "Pseudomonadales", 
"Rhizobiales", "Rhodobacterales", "Rhodocyclales", "Rhodospirillales", 
"Sphingobacteriales", "Sphingomonadales", "Spirochaetales", 
"Subdivision3_genera_incertae_sedis", "Verrucomicrobiales", 
"phylum", "unclassified_Alphaproteobacteria", "unclassified_Betaproteobacteria", 
"unclassified_Deltaproteobacteria", "unclassified_Gammaproteobacteria"
), class = "factor")), .Names = c("X1", "X2", "X3", "X4", 
"X5", "X6", "X7", "X8", "X9", "X10"), row.names = 2:8, class = "data.frame")

这基本上意味着我有渐进的行,在渐进的列中用 NA 填充。但是,无法确定第一个 NA 将在哪里的特定行。在第一个NA 列之前,我有两列实际上是我感兴趣的:指定分类级别的重叠群数量的计数,以及分类级别名称之前的两列。

我已经创建了一个列表,其中包含每个数据框的索引,该列表将通过以下方式选择最后一行:

library(plyr)
lastcollist<-lapply(hierlist,function(p)lapply(apply(p, 1, function(x) which(!is.na(x)) ),function(x)if(length(x)>0){max(x)}else{0}))
lastcollist<-lapply(lastcollist,unlist)
lastcollist.idx<-llply(lastcollist,function(x)cbind(seq(1,length(x)),x))

这里lastcollist.idx 将包含最后一个非NA 列的每一行的索引:

head(lastcollist.idx$hier_M2MID06_Trimmed_noGaps.fas_fixrank.txt)
        x
[1,] 1  5
[2,] 2  5
[3,] 3  9
[4,] 4 11
[5,] 5 13
[6,] 6 15

所以我现在基本上想要做的是创建一个新列表,其中包含数据框(或者在只有最后一列的情况下,lastcollist.idx 中的变量 x)对于每个给定行都有最后选择的列.

这将是给定示例的所需输出:

 dput(rbind(c('domain','194'),c('Proteobacteria','Phylum'),c('Betaproteobacteria','class'),c ('class','Rhodocyclales'),c('class','Rhodocyclales'),c('class','Rhodocyclales')))
structure(c("domain", "Proteobacteria", "Betaproteobacteria", 
"class", "class", "class", "194", "Phylum", "class", "Rhodocyclales", 
"Rhodocyclales", "Rhodocyclales"), .Dim = c(6L, 2L))

我不得不承认,我不会马上知道该怎么做。任何指针都受到热烈欢迎。我不是 R 的新手,所以你不必费劲地解释。

对于更大的可重现示例,请考虑来自 bioconductor library impute (bioconductor library impute) 的数据集“khanmiss”。

 source("http://bioconductor.org/biocLite.R")
 biocLite("impute")
 require(impute)
 data(khanmiss)

这基本上是一个在多个地方引入了 NA 的数据框。它与我的文件的层次结构不完全相同,但它符合目的。由于这是一个非常不方便的数据框,有 2309 个观察值,并且其中只有 222 行包含缺失值,因此我选择了具有缺失值的行,并在新的 data.frame 中随机添加了 78 行没有缺失值的行。然后,此 data.frame 被拆分为 4 个任意大小的数据帧列表(加起来为 300)。

isnadf<-as.data.frame(which(is.na(khanmiss),arr.ind=T))
na.rows<-sort(unique(isnadf$row))
length(na.rows) #the dataset has 222 rows which contain NA
na.khanmiss<-khanmiss[na.rows,]
notna.rows<-setdiff(rownames(khanmiss),na.rows)
notna.rows.selected<-sort(as.numeric(sample(notna.rows,78)))
notna.selected.khanmiss<-khanmiss[notna.rows.selected,]
khanmiss.selected<-rbind(na.khanmiss,notna.selected.khanmiss)
dfsizes<-c(82,74,79,65) #arbitrarily selected, adds up to 300
khanmiss.list<-split(khanmiss.selected,rep(letters[1:4],dfsizes))

这最终给出了一个与我的数据集有些相似的列表。

【问题讨论】:

  • 我们应该了解 RDP 多分类器层次结构文件 才能提供帮助吗?如果没有,我不得不承认这很难遵循。你能把它简化成一些小的东西(例如,为什么告诉我们你有一个 data.frames 列表,而不仅仅是一个 data.frame?)并且易于理解,并带有输入和预期输出的示例。
  • 不过,我会指出矩阵索引是一种可能的解决方案。例如看看这是做什么的:m &lt;- matrix(1:12, 3, 4); m[cbind(c(1:3), c(3,2,4))]
  • 嗨@flodel,这是一个更笼统的问题,但输入列表很难通用生成。一个 dput 结构将是巨大的(它是一个 2 Mb 的列表)。我将尝试重新提出我的问题:我有一个数据框列表,因为我使用 read.table 读取了多个(30 个)文件。每个文件在列表中形成一个新的 data.frame。手动制作每个数据框非常费力,而且这些文件是通过从目录中抓取某些文件来读取的,因此文件的数量可以改变。 (...)
  • (...) ctd 然后的问题是,对于每个数据帧,我需要每行的最后一列的值,其中不包含“NA”,以及同一行前两列的值那。最后一列的索引可以更改每一行。最后,我的输出应该是一个包含两列 data.frames 的列表。感谢您提供有关矩阵索引的提示,但我宁愿不必为了操作而从 df 到矩阵来回转换。
  • 好吧,理想的情况是您手动创建一个 data.frame,例如,六列和五行,在适当的位置使用 NA 来处理所有情况。以及随之而来的预期输出。您的corner(hierlist$hier_M2MID06_Trimmed_noGaps.fas_fixrank.txt,n=c(7,10)) 是一个不错的示例,您可以将dput 全部称为您的数据。另外,当我说预期输出时,我指的是确切的数据结构以及解释。

标签: r list dataframe lapply


【解决方案1】:

这些未经测试的方法可能会起作用:

apply(dfrm, 1, function(r) { r[ (which(is.na(r))[1]-1):(which(is.na(r))[1]-2)) ] } )

对于此示例,我通常将文本输出加载为数据框的方式失败了,因此我的建议是发布 dput 输出而不是屏幕抓取。 (在我看来,您应该使用 header =TRUE 完成数据输入,因为您的第一行数据看起来不像数据。)

有了新数据(并意识到需要测试没有 NA:

 apply(hierlist, 1, function(r) { r[ 
                      if( any(is.na(r))){ 
                          (which(is.na(r))[1]-1):( which(is.na(r))[1]-2) 
                       }else{
                          (length(r)-2): (length(r)-1)}
                                      ] }
       )
#--------------------------------------
     2         3          4                5                   
[1,] "194"     "domain"   "phylum"         "class"             
[2,] "no rank" "Bacteria" "Proteobacteria" "Betaproteobacteria"
     6                    7                    8                   
[1,] "Betaproteobacteria" "Betaproteobacteria" "Betaproteobacteria"
[2,] "class"              "class"              "class" 

【讨论】:

  • 嗨@IShouldBuyABoat,我没有加载 header=T 的原因是源文件中的列数可变。我知道第一行是“像标题一样”,但实际上我对这一行并不感兴趣。我只是用一些模式 grepped 我的文件列表:filen&lt;-grep("^h.*noGaps.fas_fixrank.txt",list.files(),value=T) 然后我加载列表中的每个文件 hierlist&lt;-list() for(i in filen){no.col&lt;-max(count.fields(i,sep=";"));hierlist[[i]]&lt;-read.table(i,header=F,sep=";",fill=T,col.names=1:no.col)} 没有 header=F 这会导致错误。
  • 我试图对列表进行 dput,但它太大了 (2Mb)。即使尝试仅输入列表中的 2 个元素也是不可能的,因为 R 控制台没有提供足够长的输出,而且我也无法在 SO 上发布。在bit.ly/1hFfNwh 上,您将找到指向列表第一个数据框的 dput 的链接。其他数据帧具有类似的结构。
  • dput(head(dfrm, 30))
  • 正如您在编辑中看到的那样,我对问题所做的编辑以及我与上面的 flodel 的讨论我现在提供了数据框角的 dput(角是 BurStMisc 包中的一个函数,它基本上是一个二维头部函数)。
猜你喜欢
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
  • 2021-07-16
  • 1970-01-01
  • 2021-11-30
  • 2022-01-03
  • 2022-10-04
  • 2016-01-07
相关资源
最近更新 更多