如何从文本文件中读取信息?

6

我有数百个文本文件,每个文件中都包含以下信息:

*****Auto-Corelation Results******
1     .09    -.19     .18     non-Significant

*****STATISTICS FOR MANN-KENDELL TEST******
S=  609
VAR(S)=      162409.70
Z=           1.51
Random : No trend at 95%

*****SENs STATISTICS ******
SEN SLOPE =  .24

现在,我想读取所有这些文件,并从每个文件中“收集”Sen的统计数据(例如.24),并将其编译到一个文件中,同时保留相应的文件名。我必须在R中完成此操作。
我已经使用CSV文件工作过,但不确定如何使用文本文件。
这是我现在正在使用的代码:
require(gtools)
GG <- grep("*.txt", list.files(), value = TRUE)
GG<-mixedsort(GG)
S <- sapply(seq(GG), function(i){
X <- readLines(GG[i])
grep("SEN SLOPE", X, value = TRUE)
})
spl <- unlist(strsplit(S, ".*[^.0-9]"))
SenStat <- as.numeric(spl[nzchar(spl)])
SenStat<-data.frame( SenStat,file = GG)
write.table(SenStat, "sen.csv",sep = ", ",row.names = FALSE)

当前代码无法正确读取所有值,导致出现此错误:
Warning message:
NAs introduced by coercion 

同时,我没有得到另一列输出中的文件名。请帮忙!

诊断 1

代码也读取等号。这是print(spl)的输出结果。

 [1] ""       "5.55"   ""       "-.18"   ""       "3.08"   ""       "3.05"   ""       "1.19"   ""       "-.32"  
[13] ""       ".22"    ""       "-.22"   ""       ".65"    ""       "1.64"   ""       "2.68"   ""       ".10"   
[25] ""       ".42"    ""       "-.44"   ""       ".49"    ""       "1.44"   ""       "=-1.07" ""       ".38"   
[37] ""       ".14"    ""       "=-2.33" ""       "4.76"   ""       ".45"    ""       ".02"    ""       "-.11"  
[49] ""       "=-2.64" ""       "-.63"   ""       "=-3.44" ""       "2.77"   ""       "2.35"   ""       "6.29"  
[61] ""       "1.20"   ""       "=-1.80" ""       "-.63"   ""       "5.83"   ""       "6.33"   ""       "5.42"  
[73] ""       ".72"    ""       "-.57"   ""       "3.52"   ""       "=-2.44" ""       "3.92"   ""       "1.99"  
[85] ""       ".77"    ""       "3.01"

诊断2

我认为找到了问题所在。负号有点棘手。在一些文件中,它是

SEN SLOPE =-1.07
SEN SLOPE = -.11

由于等号后面有空格,第一个得到了NAs,但是代码读取了第二个。我该如何修改正则表达式以修复这个问题?谢谢!
4个回答

10
假设"text.txt"是你的其中一个文本文件,使用readLines函数将其读入到R中,你可以使用grep函数查找包含SEN SLOPE的那一行。如果没有其他参数,grep函数将返回正则表达式所在元素的索引号码。这里我们发现它是第11行。添加value = TRUE参数以获取完整的行内容。
x <- readLines("text.txt")
grep("SEN SLOPE", x)
## [1] 11
( gg <- grep("SEN SLOPE", x, value = TRUE) )
## [1] "SEN SLOPE =  .24"

为了找到工作目录中所有的.txt文件,我们可以使用带有正则表达式的list.files
list.files(pattern = "*.txt")
## [1] "text.txt"

遍历多个文件

我创建了第二个文本文件 text2.txt,它具有不同的 SEN SLOPE 值,以说明如何在多个文件上应用此方法。我们可以使用 sapply,然后使用strsplit来获取所需的spl值。

GG <- list.files(pattern = "*.txt")
S <- sapply(seq_along(GG), function(i){
    X <- readLines(GG[i])
    ifelse(length(X) > 0, grep("SEN SLOPE", X, value = TRUE), NA)
    ## added 04/23/14 to account for empty files (as per comment)
})
spl <- unlist(strsplit(S, split = ".*((=|(\\s=))|(=\\s|\\s=\\s))"))
## above regex changed to capture up to and including "=" and 
## surrounding space, if any - 04/23/14 (as per comment)
SenStat <- as.numeric(spl[nzchar(spl)])

接着我们可以将结果放入数据框中,并使用write.table函数将其写入文件。

( SenStatDf <- data.frame(SenStat, file = GG) )
##   SenStat      file
## 1    0.46 text2.txt
## 2    0.24  text.txt

我们可以使用以下方式将其写入文件:
write.table(SenStatDf, "myFile.csv", sep = ", ", row.names = FALSE)

更新于07/21/2014:

由于结果将被写入文件,因此可以使用以下方法使其更加简单(也更快速):

( SenStatDf <- cbind(
      SenSlope = c(lapply(GG, function(x){
          y <- readLines(x)
          z <- y[grepl("SEN SLOPE", y)]
          unlist(strsplit(z, split = ".*=\\s+"))[-1]
          }), recursive = TRUE),
      file = GG
 ) )
#      SenSlope file       
# [1,] ".46"   "test2.txt"
# [2,] ".24"   "test.txt" 

然后使用以下代码将其写入并读取到 R 中:

write.table(SenStatDf, "myFile.txt", row.names = FALSE)
read.table("myFile.txt", header = TRUE)
#   SenSlope      file
# 1     1.24 test2.txt
# 2     0.24  test.txt

代码之前是可以运行的,但现在突然出现了这个错误:Error in strsplit(S, ".*[^(-|\s).0-9]") : non-character argument。我不确定出了什么问题。:-( 你能帮忙看一下吗?另外,期望值应该在-5到5之间。@richard - Geekuna Matata
谢谢!你是救命恩人! - Geekuna Matata
是的,同样的代码,同样的地方。:( 一切都很好,直到几天前。 - Geekuna Matata
嗨,Richard,代码现在可以运行了。但是我没有在第二列中得到文件名。而且一些NA值被添加了进去。不知道为什么。没有读取所有的值。在第一次运行中,44个文件中有5个值无法读取。我已经添加了一些诊断。 - Geekuna Matata
哈哈。谢谢。项目报告还有两天就要交了,很难保持冷静。我已经完成了所有的工作,现在卡在了排序上。谢谢!:P - Geekuna Matata
显示剩余4条评论

4

首先创建一个样本文本文件:

cat('*****Auto-Corelation Results******
1     .09    -.19     .18     non-Significant

*****STATISTICS FOR MANN-KENDELL TEST******
S=  609
VAR(S)=      162409.70
Z=           1.51
Random : No trend at 95%

*****SENs STATISTICS ******
SEN SLOPE =  .24',file='samp.txt')

然后将其读入:

tf <- readLines('samp.txt')

现在提取相应的行:
sen_text <- grep('SEN SLOPE',tf,value=T)

然后获取等号后面的值:

sen_value <- as.numeric(unlist(strsplit(sen_text,'='))[2])

然后将这些结果针对每个文件进行合并(原问题中没有提到文件结构)


这与我的答案完全相同。 :) - Rich Scriven
@RichardScriven 好的,那么你已经有了一个非常好的答案;-) readLines 真的很酷。 - Gary Weissman
谢谢。我该如何在循环中将所有Sen值添加到单个数据框中?然后将其导出到CSV文件中,该文件基本上具有此格式(文件名,sen_value)。 - Geekuna Matata
请参考@richardscriven上面的答案,了解如何循环遍历每个文本文件。 - Gary Weissman

1
如果你的文本文件始终是那种格式(例如,Sen Slope总是在第11行),并且所有文件中的文本都相同,你只需要两行就可以完成所需操作。
char_vector <- readLines("Path/To/Document/sample.txt")
statistic <- as.numeric(strsplit(char_vector[11]," ")[[1]][5])

这将给你0.24。

然后,您可以通过apply语句或for循环迭代所有文件。

为了清晰起见:

> char_vector[11]
[1] "SEN SLOPE =  .24"

并且

> strsplit(char_vector[11]," ")
[[1]]
[1] "SEN"   "SLOPE" "="     ""      ".24"  

因此,您希望从strsplit的结果中获取[[1]][5]。

1
步骤1:将完整的文件名保存在一个变量中:
fileNames <- dir(dataDir,full.names=TRUE)

步骤2:读取并处理其中一个文件,并确保它能给出正确的结果:
data.frame(
  file=basename(fileNames[1]), 
  SEN.SLOPE= as.numeric(tail(
    strsplit(grep('SEN SLOPE',readLines(fileNames[1]),value=T),"=")[[1]],1))
  )

第三步:在所有的fileNames上执行此操作。
do.call(
  rbind,
  lapply(fileNames, 
         function(fileName) data.frame(
           file=basename(fileName), 
           SEN.SLOPE= as.numeric(tail(
             strsplit(grep('SEN SLOPE',
                           readLines(fileName),value=T),"=")[[1]],1)
             )
           )
         )
  )

希望这能帮到你!

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