【问题标题】:How do I read information from text files?如何从文本文件中读取信息?
【发布时间】:2014-05-27 03:08:00
【问题描述】:

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

*****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

现在,我想读取所有这些文件,并从每个文件(例如.24)中“收集”Sen's Statistics,并与相应的文件名一起编译成一个文件。我必须在 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

由于 = 之后的差距,我得到了第一个的 NA,但代码正在读取第二个。如何修改正则表达式来解决这个问题?谢谢!

【问题讨论】:

    标签: r text-files text-processing logfile-analysis


    【解决方案1】:

    假设"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)
    

    2014 年 7 月 21 日更新:

    由于将结果写入文件,因此使用

    可以使这变得更简单(更快)
    ( 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
    

    【讨论】:

    • 糟糕。需要一些帮助。有些值是负数。并且代码将它们视为积极的。我必须做出哪些改变才能正确阅读它们?
    • 该代码以前可以工作,但我现在突然看到这个错误: strsplit(S, ".*[^(-|\\s).0-9]") 中的错误:非-character 参数我不确定出了什么问题。 :-(你能帮忙吗?另外,预期值在-5和5之间@richard
    • 谢谢!你是救命稻草!
    • 是的,相同的代码,相同的位置。 :( 直到几天前一切正常。
    • 嗨,Richard,代码正在运行。但我没有得到第 2 列中的文件名。并且正在添加一些 NA 值。不知道为什么。不读取所有值。在第一次运行的 44 个文件中,我无法读取 5 个值。我添加了一些诊断
    【解决方案2】:

    步骤1:将完整的fileNames保存在单个变量中:

    fileNames <- dir(dataDir,full.names=TRUE)
    

    第二步:让我们读取和处理其中一个文件,并确保它给出正确的结果:

    data.frame(
      file=basename(fileNames[1]), 
      SEN.SLOPE= as.numeric(tail(
        strsplit(grep('SEN SLOPE',readLines(fileNames[1]),value=T),"=")[[1]],1))
      )
    

    第 3 步:在所有 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)
                 )
               )
             )
      )
    

    希望这会有所帮助!

    【讨论】:

      【解决方案3】:

      首先制作一个示例文本文件:

      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])
      

      然后为您的每个文件组合这些结果(原始问题中没有提到文件结构)

      【讨论】:

      • 这和我的回答一模一样。 :)
      • @RichardScriven 好吧,那么你有一个很好的答案 ;-) readLines 真的很酷。
      • 谢谢。如何在循环中的单个数据框中添加所有 Sen 值?然后导出成CSV文件,基本上就是这个格式(filename,sen_value)
      • 查看上面@richardscriven 的回答,了解如何遍历每个文本文件
      【解决方案4】:

      如果您的文本文件始终采用该格式(例如,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"  
      

      因此你想要 [[1]] [5] 的 strsplit 结果。

      【讨论】:

        猜你喜欢
        • 2011-05-09
        • 2011-09-14
        • 2013-06-28
        • 1970-01-01
        • 2019-02-28
        • 2016-07-23
        • 1970-01-01
        • 2015-08-20
        • 2013-09-19
        相关资源
        最近更新 更多