查看原文
其他

[答疑]行数不同,不能cbind了肿么办

豆豆花花 生信星球 2022-06-06
 今天是生信星球陪你的第805天

   大神一句话,菜鸟跑半年。我不是大神,但我可以缩短你走弯路的半年~
   就像歌儿唱的那样,如果你不知道该往哪儿走,就留在这学点生信好不好~
   这里有豆豆和花花的学习历程,从新手到进阶,生信路上有你有我!

0.问题

这个问题来自于gdc下载的数据整理,整理过程中发现同一列表里的数据框行数不相同,绝大多数行数是68,少数几个是69~73,因此无法用cbind合并到一起。

1.思路

(1)cbind换成一个可以连接行数不同的数据框的函数

(2)把行数69~73的数据框里面,多出来的几行去掉,拿共同的行去连接

2.重现问题

下载的是来自TCGA-BLCA的临床数据。

Rlibrary(XML)
xmls = dir("clinical/",pattern = "*.xml$",recursive = T)

td = function(x){
  result <- xmlParse(file.path("clinical/",x))
  rootnode <- xmlRoot(result)
  xmldataframe <- xmlToDataFrame(rootnode[2])
  return(t(xmldataframe))
}

cl = lapply(xmls,td)

# 看看cl的每个元素都有多少列,发现68~73不等,正常来说列数应该是完全相同的。
a = sapply(cl, length)
unique(a)
#> [1] 68 69 72 71 70 73

# 因此合并时就会报错
cl_df <- t(do.call(cbind,cl))
#> Error in (function (..., deparse.level = 1) : 矩阵的行数必需相符(见arg5)

好咯,报错了。第一步,搜一搜

思路1:cbind.fill或者merge

https://stackoverflow.com/questions/3699405/how-to-cbind-or-rbind-different-lengths-vectors-without-repeating-the-elements-o

非常好找的一个链接,里面有个函数:rowr::cbind.fill

接下来就是安装这个R包,装了几下没有成功,搜索发现包被cran移除了,但是可以找到历史版本:

https://cran.r-project.org/src/contrib/Archive/rowr/rowr_1.1.3.tar.gz

下载放在工作目录下,本地安装install.packages("rowr_1.1.3.tar.gz",repos = NULL)

cl_df <- t(do.call(rowr::cbind.fill,cl))
colnames(cl_df) = rownames(cl[[which.max(a)]])
dim(cl_df)
#> [1] 409  73

因为总共73列,所以估计列名是按照最长的数据框行名来算。

连接行数不同的表格的函数,怎么能忘了merge。

cl2 = lapply(cl, function(x){
  tibble::rownames_to_column(as.data.frame(x),var = "a")}
  )
cl_df2 <- do.call("merge",cl2,list(by = "a"))
#> Error in if (quote) args <- lapply(args, enquote): 参数不能作为逻辑值来用
# 发现do.call搞不定的merge,可以交给Reduce
#https://stackoverflow.com/questions/22644780/merging-multiple-csv-files-in-r-using-do-call
m = Reduce(function(x, y) merge(x, y, by="a",all = T), cl2)
dat = as.data.frame(t(tibble::column_to_rownames(m,"a")))
rownames(dat) = NULL
dat[1:4,1:4]
#>   additional_studies age_at_initial_pathologic_diagnosis
#> 1                                                     74
#> 2                                                     62
#> 3                                                     56
#> 4                                                     83
#>   age_began_smoking_in_years anatomic_neoplasm_subdivision
#> 1                         18                  Wall Lateral
#> 2                                            Bladder - NOS
#> 3                         27                 Wall Anterior
#> 4                         14                 Bladder - NOS
head(dat$stage_event,10)
#>  [1] "7thStage IVT1T2N2MX"  "6thStage IIIT3N0M0"   "7thStage IVT4aN2M0"  
#>  [4] "6thStage IVT3bN2MX6"  "NO"                   "7thStage IVT3aN2MX7" 
#>  [7] "6thStage IIIT3bN0MX"  "7thStage IIT2T2bNXM0" "22"                  
#> [10] "7thStage IIIT3N0M0"
table(dat$vital_status)
#> 
#> Alive  Dead 
#>   301   108

检查发现,这样的做法导致了一些列的错位,一开始我以为是cbind.fill的锅,但merge也是一样,我又回去检查了xml文件,发现是xml文件读进来就是错的了,不是循环代码的锅。那就只能哪一个病人的信息错位了单独手动去处理了。

思路2 去掉多余的行

检查数据发现,多出来的几行,行名都是NA

setdiff(rownames(cl[[5]]),rownames(cl[[1]]))
#> [1] NA
setdiff(rownames(cl[[241]]),rownames(cl[[1]]))
#> [1] NA

把行名是NA的行去掉,就恢复到了相同的行数

cl3 = lapply(cl, function(x){x[!is.na(rownames(x)),]})
unique(sapply(cl3, length))
#> [1] 68

去掉na的情况仅仅适用于当前场景,有一个更加普适的方式,就是直接对所有的行名取交集,然后再各自取子集,合并

library(tinyarray)
n = intersect_all(lapply(cl, rownames))
cl3 = lapply(cl, function(x){x[n,]})

所以这个解决办法是最简单的咯。

cl_df <- t(do.call(cbind,cl3))
cl_df[1:3,1:3]
#>      additional_studies tissue_source_site patient_id
#> [1,] ""                 "GU"               "AATP"    
#> [2,] ""                 "CF"               "A1HR"    
#> [3,] ""                 "GV"               "A3QK"
clinical = data.frame(cl_df)
clinical[1:4,1:4]
#>   additional_studies tissue_source_site patient_id bcr_patient_barcode
#> 1                                    GU       AATP        TCGA-GU-AATP
#> 2                                    CF       A1HR        TCGA-CF-A1HR
#> 3                                    GV       A3QK        TCGA-GV-A3QK
#> 4                                    XF       A9SJ        TCGA-XF-A9SJ
我的个人文章从简书全部迁移到了语雀,搜小洁忘了怎么分身即可找到,点击阅读原文可以跳转。如果因为不会R语言导致代码完全看不懂,可以看看下面的几个课程⏬都是滚动开班的。
插个小广告!
生信零基础入门学习小组
生信入门班(四周线上直播课,长期开班)
数据挖掘班(医生/医学生首选,三周线上直播课,长期开班)
一起来学单细胞吗?
生信星球答疑公告

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存