首页 > 解决方案 > 处理 R 中的阻塞数据

问题描述

我有一个来自 WISE 土壤数据库的土壤数据的大文本文件(位于此处https://www.dropbox.com/s/k2jqbpgtxw7d66m/test.txt?dl=0),有点混乱,我需要提取一些信息出它。

文本文件被组织成某种组,由空行分隔,每个组遵循相同的结构,如下图所示:

*WI_CLAF001  WISE        L       150 WISE DATABASE, SOIL AF001
@SITE        COUNTRY          LAT     LONG SCS Family
 -99         Afganistan    34.500   69.167 Luvic Calcisol (CLl)
@ SCOM  SALB  SLU1  SLDR  SLRO  SLNF  SLPF  SMHB  SMPX  SMKE
    BN  0.13  9.60  0.60 75.00  1.00  1.00 SA001 SA001 SA001
@  SLB  SLMH  SLLL  SDUL  SSAT  SRGF  SSKS  SBDM  SLOC  SLCL  SLSI  SLCF  SLNI  SLHW  SLHB  SCEC  SADC
    15     - 0.129 0.283 0.459  1.00  1.56  1.35  0.76 20.00 40.00 20.00  0.06  7.90 -99.0 -99.0 -99.0
    60     - 0.184 0.327 0.466  0.47  0.69  1.37  0.23 35.00 55.00 -99.0  0.03  7.90 -99.0 -99.0 -99.0
   150     - 0.178 0.311 0.461  0.12  0.87  1.39  0.09 35.00 55.00 -99.0  0.03  7.90 -99.0 -99.0 -99.0
@  SLB  SLPX  SLPT  SLPO CACO3  SLAL  SLFE  SLMN  SLBS  SLPA  SLPB  SLKE  SLMG  SLNA  SLSU  SLEC  SLCA
    15 -99.0 -99.0 -99.0   9.3 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0   0.4 -99.0
    60 -99.0 -99.0 -99.0  17.7 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0   0.3 -99.0
   150 -99.0 -99.0 -99.0  18.2 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0   0.3 -99.0

*WI_FLAF002  WISE        L       170 WISE DATABASE, SOIL AF002
@SITE        COUNTRY          LAT     LONG SCS Family
 -99         Afganistan    34.500   69.000 Calcaric Fluvisol (FLc)
@ SCOM  SALB  SLU1  SLDR  SLRO  SLNF  SLPF  SMHB  SMPX  SMKE
    BN  0.13  9.60  0.25 75.00  1.00  1.00 SA001 SA001 SA001
@  SLB  SLMH  SLLL  SDUL  SSAT  SRGF  SSKS  SBDM  SLOC  SLCL  SLSI  SLCF  SLNI  SLHW  SLHB  SCEC  SADC
    20     - 0.136 0.312 0.477  0.82  1.17  1.29  1.28 20.00 40.00 -99.0  0.09  8.50 -99.0 -99.0 -99.0
    60     - 0.110 0.235 0.502  0.45  4.84  1.24  0.60 20.00 65.00 -99.0  0.06  8.60 -99.0 -99.0 -99.0
   110     - 0.210 0.344 0.472  0.18  0.53  1.35  0.39 35.00 55.00 -99.0  0.06  8.50 -99.0 -99.0 -99.0
   170     - 0.115 0.268 0.441  0.06  1.68  1.41  0.27 20.00 40.00 -99.0  0.03  8.80 -99.0 -99.0 -99.0
@  SLB  SLPX  SLPT  SLPO CACO3  SLAL  SLFE  SLMN  SLBS  SLPA  SLPB  SLKE  SLMG  SLNA  SLSU  SLEC  SLCA
    20 -99.0 -99.0 -99.0  19.1 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0   0.4 -99.0
    60 -99.0 -99.0 -99.0  19.2 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0   0.3 -99.0
   110 -99.0 -99.0 -99.0  20.3 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0   0.3 -99.0
   170 -99.0 -99.0 -99.0  24.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0   0.3 -99.0

*WI_FLAF003  WISE        L       110 WISE DATABASE, SOIL AF003
@SITE        COUNTRY          LAT     LONG SCS Family
 -99         Afganistan    34.500   69.167 Calcaric Fluvisol (FLc)
@ SCOM  SALB  SLU1  SLDR  SLRO  SLNF  SLPF  SMHB  SMPX  SMKE
    BN  0.13  9.60  0.05 75.00  1.00  1.00 SA001 SA001 SA001
@  SLB  SLMH  SLLL  SDUL  SSAT  SRGF  SSKS  SBDM  SLOC  SLCL  SLSI  SLCF  SLNI  SLHW  SLHB  SCEC  SADC
    20     A 0.106 0.276 0.453  0.82  1.66  1.37  0.59 20.00 40.00 -99.0  0.07  8.80 -99.0 -99.0 -99.0
    50    Bg 0.135 0.238 0.404  0.50  2.14  1.49  0.24 10.00 25.00 -99.0  0.04  9.20 -99.0 -99.0 -99.0
   110    Cg 0.081 0.214 0.428  0.20  3.86  1.46 -99.0 25.00 15.00 -99.0 -99.0  8.90 -99.0 -99.0 -99.0
@  SLB  SLPX  SLPT  SLPO CACO3  SLAL  SLFE  SLMN  SLBS  SLPA  SLPB  SLKE  SLMG  SLNA  SLSU  SLEC  SLCA
    20 -99.0 -99.0 -99.0  16.9 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0   1.9 -99.0
    50 -99.0 -99.0 -99.0  13.8 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0   0.6 -99.0
   110 -99.0 -99.0 -99.0  19.6 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0 -99.0   0.4 -99.0

第 1 行:*WI_... 有一些详细信息。对我没用

第 2 行:具有国家名称、纬度、经度等标题

第 3 行:包含这些标题的数据

第 4 行:另一组标题

第 5 行:包含第 4 行中的标题数据

第 6 行:包含标题

第 7:9 行:包含第 6 行的数据

第 10 行:是第 6 行标题的延续

第 11:13 行:包含第 10 行的数据

问题是如果您移动到其他一些数据组(不同的国家/地区),第 6 行的行数会发生变化

我正在尝试为每个组做两件事:

1)第 2 行到第 5 行有一个单独的数据框,应该如下所示:

  COUNTRY   LAT LONG SCS Family SCOM SALB SLU1 SLDR SLRO SLNF SLPF SMHB SMPX SMKE 
  Afghanistan
  Afghanistan
  Afghanistan
  .
  .
  .
  Argentina
  Argentina
  Argentina
  .
  .
  .

2)第6行到第N行的单独数据框

  COUNTRY     LAT       LONG    SLB  SLMH  SLLL  SDUL  SSAT  SRGF  SSKS  SBDM  SLOC  SLCL  SLSI  SLCF  SLNI  SLHW  SLHB  SCEC  SADC  SLPX  SLPT  SLPO CACO3  SLAL  SLFE  SLMN  SLBS  SLPA  SLPB  SLKE  SLMG  SLNA  SLSU  SLEC  SLCA
  Afganistan  34.500   69.167   15
  Afganistan  34.500   69.167   60
  Afganistan  34.500   69.167   150

我以前没有处理过这种类型的数据,但这是我的一些逻辑,我将如何实现这一点:

对于 1) 部分,我可以读取数据:

  dat <- readLines("dat.txt")

删除其中包含“WISE”的行。这是冗余行,然后使用空格
R 在空行上拆分文本将数据拆分为列表

对于列表的每个元素(组):取第 2 - 5 行并转换为我想要的格式。

对于问题的第二部分,不知道我应该从第 6 行开始做什么。

我会很感激这方面的一些帮助。非常感谢。

标签: rtextscanf

解决方案


我将代替您的图片插入的文本复制到命名字符变量txt中,然后:

tL <- readLines(textConnection(txt))
Site_lines=grep("@SITE",tL)
Site_lines
#[1]  2 16 32
lapply( Site_lines , function(L) read.table(text= tL, header=TRUE, skip=L-1, nrow=1) )
#-----------------------
[[1]]
        X.SITE COUNTRY    LAT  LONG      SCS Family
-99 Afganistan    34.5 69.167 Luvic Calcisol  (CLl)

[[2]]
        X.SITE COUNTRY LAT     LONG      SCS Family
-99 Afganistan    34.5  69 Calcaric Fluvisol  (FLc)

[[3]]
        X.SITE COUNTRY    LAT     LONG      SCS Family
-99 Afganistan    34.5 69.167 Calcaric Fluvisol  (FLc)
# ------- now something that can pull them together ---------
do.call("rbind", lapply( Site_lines , function(L) read.table(text= tL, header=TRUE, skip=L-1, nrow=1) ) )

         X.SITE COUNTRY    LAT     LONG      SCS Family
-99  Afganistan    34.5 69.167    Luvic Calcisol  (CLl)
-991 Afganistan    34.5 69.000 Calcaric Fluvisol  (FLc)
-992 Afganistan    34.5 69.167 Calcaric Fluvisol  (FLc)

不幸的是,该表并不像起初看起来的那样是常规的。如果您查看完整文件(将近 60,000 行)中“@SITE”位置的间距,您会得到:

table(diff(Site_lines))

 10  12  14  16  18  20  22  24  26 
 47 156 526 664 797 906 169  85  53 

并尝试使用 lapply(, ...read.table方法会导致错误。您可能需要将for-loop 与try. 第一个错误在第 6070 行:

counter <- 0
do.call("rbind", lapply( Site_lines , function(L) { counter <<- L; read.table(text= tL, header=TRUE, skip=L-1, nrow=1) }))
Error in read.table(text = tL, header = TRUE, skip = L - 1, nrow = 1) : 
  more columns than column names
> counter
[1] 6070

推荐阅读