【问题标题】:Importing irregular unseparated text files data in R在 R 中导入不规则的未分隔文本文件数据
【发布时间】:2016-12-24 21:27:39
【问题描述】:

我无法在 R 中导入这些数据,因为它不是标准的 csv 格式。我的原始数据如下所示:

BC000068032198109TMAX  232  Q  220  Q  220  Q  244  Q  239  Q  246  Q  270  Q  300  Q  327  Q  279  Q  256  Q  260  Q  289  Q  342  Q  357  Q  359  Q  370  Q  373  Q  367  Q  370  Q  372  Q  357  Q  366  Q  365  Q  355  Q  355  Q  364  Q  343  Q  364  Q  362  Q-9999  
BC000068032198110TMIN  180  Q  170  I  150  I  130  I  150  I  130  I  160  I  190  I  190  I  185  Q-9999     130  I  130  I  160  I  170  I  140  I  160  I  160  I  160  I  160  I  160  I-9999     190  I  180  I  160  I  165  Q  210  I  180  I-9999     190  I  170  I

所以,基本上每行的前 11 个字符是位置的 ID,接下来的 4 个是年份,接下来的 2 个是月份,然后还有 4 个是变量的名称。最后,有 31 个数字是该特定月份和变量的每日测量值。 -9999 表示不可用。通常,每次测量后都有一个标志(例如“Q”或“I”),但 NA 不是。我对导入这些标志不感兴趣。最终,我希望拥有一个长数据集,其中每个日常测量与其日期、位置和变量名称相结合。感谢您的支持。

【问题讨论】:

  • 请修正您的数据格式!
  • 这是固定宽度的格式;请参阅 ?read.fwf?readr::read_fwf,它们提供了一些方便的替代方法来输入或获取宽度。

标签: r text import raw-data


【解决方案1】:

您有一个固定宽度的文件。用于读取此类的基本 R 函数是 read.fwf,尽管 readr 包添加了几种替代方法来输入列宽,这取决于您对文件的了解。在这种情况下,您所知道的与基本版本配合得很好:

x <- 'BC000068032198109TMAX  232  Q  220  Q  220  Q  244  Q  239  Q  246  Q  270  Q  300  Q  327  Q  279  Q  256  Q  260  Q  289  Q  342  Q  357  Q  359  Q  370  Q  373  Q  367  Q  370  Q  372  Q  357  Q  366  Q  365  Q  355  Q  355  Q  364  Q  343  Q  364  Q  362  Q-9999  
BC000068032198110TMIN  180  Q  170  I  150  I  130  I  150  I  130  I  160  I  190  I  190  I  185  Q-9999     130  I  130  I  160  I  170  I  140  I  160  I  160  I  160  I  160  I  160  I-9999     190  I  180  I  160  I  165  Q  210  I  180  I-9999     190  I  170  I'

df <- read.fwf(textConnection(x),    # put the path to your file here
               widths = c(11, 4, 2, 4, rep(c(5, 3), 31)),    # a vector of widths
               na.strings = c('-9999', '   ', '  '))    # set your NA values

df
#>            V1   V2 V3   V4  V5  V6  V7  V8  V9 V10 V11 V12 V13 V14 V15 V16
#> 1 BC000068032 1981  9 TMAX 232   Q 220   Q 220   Q 244   Q 239   Q 246   Q
#> 2 BC000068032 1981 10 TMIN 180   Q 170   I 150   I 130   I 150   I 130   I
#>   V17 V18 V19 V20 V21 V22 V23 V24 V25  V26 V27 V28 V29 V30 V31 V32 V33 V34
#> 1 270   Q 300   Q 327   Q 279   Q 256    Q 260   Q 289   Q 342   Q 357   Q
#> 2 160   I 190   I 190   I 185   Q  NA <NA> 130   I 130   I 160   I 170   I
#>   V35 V36 V37 V38 V39 V40 V41 V42 V43 V44 V45 V46 V47  V48 V49 V50 V51 V52
#> 1 359   Q 370   Q 373   Q 367   Q 370   Q 372   Q 357    Q 366   Q 365   Q
#> 2 140   I 160   I 160   I 160   I 160   I 160   I  NA <NA> 190   I 180   I
#>   V53 V54 V55 V56 V57 V58 V59 V60 V61  V62 V63 V64 V65  V66
#> 1 355   Q 355   Q 364   Q 343   Q 364    Q 362   Q  NA <NA>
#> 2 160   I 165   Q 210   I 180   I  NA <NA> 190   I 170    I

事后通过通常的方式重命名和重塑为长格式。

【讨论】:

    【解决方案2】:

    如果它不是固定宽度的格式,例如:

    library(purrr)
    library(dplyr)
    library(stringi)
    
    lines <- "BC000068032198109TMAX  232  Q  220  Q  220  Q  244  Q  239  Q  246  Q  270  Q  300  Q  327  Q  279  Q  256  Q  260  Q  289  Q  342  Q  357  Q  359  Q  370  Q  373  Q  367  Q  370  Q  372  Q  357  Q  366  Q  365  Q  355  Q  355  Q  364  Q  343  Q  364  Q  362  Q-9999  \nBC000068032198110TMIN  180  Q  170  I  150  I  130  I  150  I  130  I  160  I  190  I  190  I  185  Q-9999     130  I  130  I  160  I  170  I  140  I  160  I  160  I  160  I  160  I  160  I-9999     190  I  180  I  160  I  165  Q  210  I  180  I-9999     190  I  170  I"
    
    readLines(textConnection(lines)) %>%
      map_df(function(x) {
    
        substr(x, 21, nchar(x)) %>%                   # focus on the part of the line with the readings
          stri_match_all_regex("([-[:digit:]]+)") %>% # pull out all the readings by extracting the #'s
          map(~.[,2]) %>%
          flatten_chr() %>%
          map(~ifelse(. == "-9999", NA, .)) %>%       # make -9999 into NA
          as.numeric() -> value                       # make it a number
    
        data_frame(
          location_id = substr(x, 1, 11),
          date = as.Date(sprintf("%s-%s-%02d", substr(x, 12, 12+3), substr(x, 16, 16+1), 1:length(value))),
          variable = substr(x, 18, 18+3),
          value = value
        ) %>% filter(!is.na(date)) # don't include invalid dates
    
      })
    ## # A tibble: 61 × 4
    ##    location_id       date variable value
    ##          <chr>     <date>    <chr> <dbl>
    ## 1  BC000068032 1981-09-01     TMAX   232
    ## 2  BC000068032 1981-09-02     TMAX   220
    ## 3  BC000068032 1981-09-03     TMAX   220
    ## 4  BC000068032 1981-09-04     TMAX   244
    ## 5  BC000068032 1981-09-05     TMAX   239
    ## 6  BC000068032 1981-09-06     TMAX   246
    ## 7  BC000068032 1981-09-07     TMAX   270
    ## 8  BC000068032 1981-09-08     TMAX   300
    ## 9  BC000068032 1981-09-09     TMAX   327
    ## 10 BC000068032 1981-09-10     TMAX   279
    ## # ... with 51 more rows
    

    应该可以。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-16
      • 2021-12-29
      • 2020-08-20
      • 1970-01-01
      相关资源
      最近更新 更多