在R中导入不规则的未分离文本文件数据

时间:2016-12-24 21:27:40

标签: r text import raw-data

我在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”),但不是。我对导入这些标志不感兴趣。最后,我希望有一个长数据集,每个日常测量结果与其日期,位置和变量名称相结合。感谢您的支持。

2 个答案:

答案 0 :(得分:2)

你有一个固定宽度的文件。用于读取的基本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

通过常规手段重命名并重塑为长形式。

答案 1 :(得分:1)

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

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

应该有用。