提前感谢所有
因此,我有一个来自.tsv的数据框,类似于此:
##ID_value=1829
##exportDate=1-18-2019
ChemID BasedMaterial State
MSO11D Oxygen Gas
GSX55E Carbon Liquid
对吗?因此,我只想做的就是添加一个名为ID的新列,其中填充了##注释中ID_value的值,从而得到了这样的内容:
ID ChemID BasedMaterial State
1829 MSO11D Oxygen Gas
1829 GSX55E Carbon Liquid
问题是,当我从.tsv导入时,我松开了所有注释值,这很好,我实际上并不需要它们在输出文件(excel表)中。但是这样做,我也会丢失该信息,这对于公开的目的很有用。
那么,有没有一种方法可以使用##注释中的值来创建所述列,也可以摆脱这些注释以创建表?非常感谢
答案 0 :(得分:2)
虽然StupidWolf的答案有效,但我认为篡改经过验证的read.table
的文件操作来代替解析文本通常不是一个好主意:随着文件变大,这会带来一定的损失(通常增加20%) 10万行,更多则更大)。
如果已知模式在顶部,请阅读前几行,找到相关部分,然后在原始文件上调用read.table
(带有原始参数)。
#' @param file 'character', the name of the file which the data are to be read from
#' @param ... other arguments passed to 'read.table'
#' @param meta_char 'character', the string (or pattern) that indicates a 'key=val' or 'note'
#' @param meta_rows 'integer', maximum number of rows to look for meta
#' @param meta_unnamed 'character', used for column-header of meta when no '=' is found
#' @param meta_skip_more 'integer', number of lines beyond the meta rows to skip for real data
#' @return 'data.frame', with any meta data augmented as columns
read_table_with_meta <- function(file, ...,
meta_char = "#", meta_rows = 10L, meta_unnamed = "meta",
meta_skip_more = 0L) {
toplines <- readLines(file, n = meta_rows)
meta_ptn <- paste0("^", meta_char)
dots <- list(...)
if ("skip" %in% names(dots)) {
warning("'skip' is determined by 'read_table_with_meta' and should not be assigned; if you need to skip more rows after meta rows, then use 'meta_skip_more'; 'skip=' is ignored here")
dots$skip <- NULL
}
if (all(grepl(meta_ptn, toplines))) {
stop("all lines looked like header rows, suggest you increase 'meta_rows'")
}
toplines <- toplines[ grepl(meta_ptn, toplines) ]
skip <- length(toplines) + meta_skip_more
toplines <- gsub(paste0("^", meta_char, "+\\s*"), "", toplines)
if (length(toplines)) {
keys <- gsub("\\s*=.*", "", toplines)
vals <- gsub("^[^=]*\\s*=\\s*", "", toplines)
unnamed <- (keys == vals)
keys[unnamed] <- paste0(meta_unnamed, seq_along(keys[unnamed]))
keyvals <- setNames(as.list(vals), keys)
} else keyvals <- NULL
dat <- do.call("read.table", c(list(file, skip = skip), dots))
if (is.null(keyvals)) dat else cbind(dat, keyvals)
}
注意:
这仅搜索前10行(默认情况下),以为一旦找到未注释的行,您就不应该尝试解析整个文件;如果您在文件中间有评论,那么这个答案是不够的;
此函数将所有这些行分配给字段;这可能不是最通用的处理方式,但我认为它可以解决您的要求;阅读后,您可以丢弃不需要的字段;
如果不是所有注释掉的标题中都包含unnamed
,请使用=
部分;只是一个技巧,不确定对您是否必要或有用。
演示:
### safe with no-meta files
text=c("ChemID BasedMaterial State", "MSO11D Oxygen Gas", "GSX55E Carbon Liquid")
writeLines(text, "test.txt")
read_table_with_meta("test.txt", header=T)
# ChemID BasedMaterial State
# 1 MSO11D Oxygen Gas
# 2 GSX55E Carbon Liquid
### simple case
text=c("##ID_value=1829", "##exportDate=1-18-2019 ", "ChemID BasedMaterial State", "MSO11D Oxygen Gas", "GSX55E Carbon Liquid")
writeLines(text, "test.txt")
read_table_with_meta("test.txt", header = TRUE)
# ChemID BasedMaterial State ID_value exportDate
# 1 MSO11D Oxygen Gas 1829 1-18-2019
# 2 GSX55E Carbon Liquid 1829 1-18-2019
### unnamed meta
text=c("##ID_value=1829", "##exportDate=1-18-2019 ", "##somethingelse", "ChemID BasedMaterial State", "MSO11D Oxygen Gas", "GSX55E Carbon Liquid")
writeLines(text, "test.txt")
read_table_with_meta("test.txt", header = TRUE)
# ChemID BasedMaterial State ID_value exportDate meta1
# 1 MSO11D Oxygen Gas 1829 1-18-2019 somethingelse
# 2 GSX55E Carbon Liquid 1829 1-18-2019 somethingelse
### multiple unnamed meta
text=c("##ID_value=1829", "##exportDate=1-18-2019 ", "##somethingelse", "##key=val", "##more", "ChemID BasedMaterial State", "MSO11D Oxygen Gas", "GSX55E Carbon Liquid")
writeLines(text, "test.txt")
read_table_with_meta("test.txt", header = TRUE)
# ChemID BasedMaterial State ID_value exportDate meta1 key meta2
# 1 MSO11D Oxygen Gas 1829 1-18-2019 somethingelse val more
# 2 GSX55E Carbon Liquid 1829 1-18-2019 somethingelse val more
答案 1 :(得分:1)
您可以尝试下面的功能,解释在注释中。
func = function(FILE,COMMENTCHAR,VALUE){
allLines = readLines(FILE)
#exclude lines with comments
# and make table
tab = read.table(text=allLines[!grepl(COMMENTCHAR,allLines)],header=TRUE)
#find the line which has the value in comments
value = allLines[grepl(VALUE,allLines) & grepl(COMMENTCHAR,allLines)]
# we split to get the name and value
value = unlist(strsplit(gsub("#","",value),"="))
df = data.frame(value[2],tab)
colnames(df)[1] = value[1]
return(df)
}
主要思想是使用readLines来获取所有内容。我们将没有注释的行转换为表。然后从带有注释的行中搜索所需的值,并将其作为第一列。然后在您的文本文件上尝试一下:
text=c("##ID_value=1829", "##exportDate=1-18-2019 ", "ChemID BasedMaterial State",
"MSO11D Oxygen Gas", "GSX55E Carbon Liquid"
)
writeLines(text,"test.txt")
func("test.txt","#","ID")
ID_value ChemID BasedMaterial State
1 1829 MSO11D Oxygen Gas
2 1829 GSX55E Carbon Liquid