R:读取和操作奇怪格式的文件

时间:2015-04-14 12:18:53

标签: r dataframe bioinformatics

我有一个文件格式有点奇怪,如下:

Cluster 1       Score:3.96  
Category        Term        Count
GOTERM_BP_FAT   GO:0006412  34
KEGG_PATHWAY    hsa00970    9
GOTERM_BP_FAT   GO:0043038  9
GOTERM_BP_FAT   GO:0043039  9

Cluster 2       Score:3.94  
Category        Term        Count
GOTERM_BP_FAT   GO:0006414  21
KEGG_PATHWAY    hsa03010    20
GOTERM_BP_FAT   GO:0034660  16
GOTERM_BP_FAT   GO:0006399  11
GOTERM_BP_FAT   GO:0042254  10
GOTERM_BP_FAT   GO:0022613  12

...还有几个“子数据帧”(包括中间空格)和Cluster X行之后的行的附加(此处省略)列。

我想做的是以某种方式读取每个单独的簇,将其作为数据帧(即名称为Category, Term, Count的数据帧),稍微操纵数据帧(根据计算添加列,大多数情况下)然后将操作数据框和Cluster X行写入一个与其开始时格式完全相同的新文件。

我已经绞尽脑汁想要做一些聪明的方法,但除了分别阅读每一行并根据行的类型做不同的事情之外,我还没有真正想出任何东西,比如:

con  <- file('test.txt', open="r")

# Read file line for line
while ( length(currentLine <- readLines(con, n=1, warn=FALSE)) > 0 ) {
  line = strsplit(currentLine, '\t')[[1]]

  # Save previous data, initiate new cluster name/score
  if ( grepl('Annotation Cluster', line[1]) ) {

    # Save previous data if available
    if ( exists('currentData') ) {
      ## save the current data somehow
    }

    # Initiate new
    clusterInfo = line
  } 
  # Initiate new, empty data frame
  else if ( grepl('Category', line[1]) ) {
    currentData = data.frame(t(rep(NA, length(line))))
    names(currentData) = line
  } 
  # Add data to data frame
  else if ( grepl('GOTERM', line[1]) || grepl('KEGG', line[1]) ) {
    currentData = rbind(currentData, line)

    # Delete NAs if line row
    if ( nrow(currentData) == 2 ) {
      currentData = na.omit(currentData)
    }
  }
} 

以上显然没有完成(我不确定如何将clusterInfocurrentData一起保存为相同的格式),但我希望我能理解。我并不是真的太喜欢这种方法,但是对我来说,像这样逐行创建数据帧似乎很奇怪,并且在你启动的同时尝试保存数据下一个数据块的开始。

有没有更好的方法呢?

2 个答案:

答案 0 :(得分:5)

您可以从我的GitHub read.mtable尝试"SOfun" package

用法如下:

library(SOfun)
read.mtable(x, "Cluster", header = TRUE) ## Replace "x" with your file name
# $`Cluster 1       Score:3.96`
#        Category       Term Count
# 1 GOTERM_BP_FAT GO:0006412    34
# 2  KEGG_PATHWAY   hsa00970     9
# 3 GOTERM_BP_FAT GO:0043038     9
# 4 GOTERM_BP_FAT GO:0043039     9
# 
# $`Cluster 2       Score:3.94`
#        Category       Term Count
# 1 GOTERM_BP_FAT GO:0006414    21
# 2  KEGG_PATHWAY   hsa03010    20
# 3 GOTERM_BP_FAT GO:0034660    16
# 4 GOTERM_BP_FAT GO:0006399    11
# 5 GOTERM_BP_FAT GO:0042254    10
# 6 GOTERM_BP_FAT GO:0022613    12

如您所见,“群集”信息将保留为列表名称。因此,您可以继续使用lapply进行您需要做的任何计算,然后以您需要的任何形式重新编写数据。


可重复的样本数据:

x <- tempfile()

writeLines("Cluster 1       Score:3.96  
Category        Term        Count
GOTERM_BP_FAT   GO:0006412  34
KEGG_PATHWAY    hsa00970    9
GOTERM_BP_FAT   GO:0043038  9
GOTERM_BP_FAT   GO:0043039  9

Cluster 2       Score:3.94  
Category        Term        Count
GOTERM_BP_FAT   GO:0006414  21
KEGG_PATHWAY    hsa03010    20
GOTERM_BP_FAT   GO:0034660  16
GOTERM_BP_FAT   GO:0006399  11
GOTERM_BP_FAT   GO:0042254  10
GOTERM_BP_FAT   GO:0022613  12", con = x, sep = "\n")

答案 1 :(得分:1)

您可以使用readLinessplit来读取文件,并使用基于具有“群集”的行创建的数字索引('indx')。使用read.table读取列表元素,创建两个新列('Cluster'和'Score')并对列表元素进行rbind以创建单个数据集。

lines <- readLines('Clusterfile.txt')
indx <- cumsum(grepl('^Cluster', lines))
res <-  do.call(rbind,lapply(split(lines, indx), function(x) {
        d1 <-read.table(text=x[-1], header=TRUE, stringsAsFactors=FALSE)
        d2 <- read.table(text=gsub('[^0-9.]+', ' ', x[1]), 
          col.names=c('Cluster', 'Score'))
        cbind(d1, d2)}))

row.names(res) <- NULL
head(res,3)
#       Category       Term Count Cluster Score
#1 GOTERM_BP_FAT GO:0006412    34       1  3.96
#2  KEGG_PATHWAY   hsa00970     9       1  3.96
#3 GOTERM_BP_FAT GO:0043038     9       1  3.96