2014-01-21 67 views
0

我试图导入了一系列的自定义数据文件到R.R数据导入自定义标记

的文件组织成块,这是由类似XML的标记标签标记。我知道这些文件不是真正的XML文件,它们不包含标记语言的定义。

每个块可能是单行或制表符分隔的矩阵。评论往往会用%来标记%

这些文件长度约10K行,我需要大约2700行,所以我宁愿避免循环。此外,文件长度和所需行数也会因不可预知的因素而有所不同。

我已经尝试了一些XML包中的方法,但总会遇到一堆错误,如“StartTag:invalid element name”和“标签MERGED-PUPIL-DATA行5443中的数据提前结束”。

你有什么想法吗?有没有接受自定义标记标签的方法?

一个典型的文件可能看起来像这样(点表示的东西,我切出)

<SESSION> 
<VERSION> 
2 
<\VERSION> 
<DATE> 
2014-01-20 14:29:43 
<\DATE> 
<SUBJECT-ID> 
SUB001 
<\SUBJECT-ID> 
<NOTE> 
red300os 
<\NOTE> 
<MIN-MAX-PLOT> 
0.100000 8707.554688 
<\MIN-MAX-PLOT> 
<STIMULUS-DEFINED> 
redOS300 
Default Human Relative Spectral Sensitivity 
1 0 
1 10.000000 20.000000 60.000000 1 3 2.000000 -100.000000 0.000000 0.000000 1 
<\STIMULUS-DEFINED> 
. 
. 
. 
. 
. 
. 
<MERGED-PUPIL-DATA> 
% time is in sec; diameter is in mm; loci is in pixel; color code -> 100 = unknown, 0 = white, 1 = red, 2 = green, 3 = blue; intensity is in Lux or W/m2 
% real time logical time R. valid R. diameter R. x loci R. y loci L. valid L. diameter L. x loci L. y loci R. led color  R. led intensity L. led color L. led intensity 
2703 
-0.049000 -0.049000 1 5.483765 266.668732 268.837402 1 5.441666 272.687500 272.724976 100 0.000000 100 0.000000 
-0.018000 -0.018000 1 5.478448 265.918732 267.837402 1 5.438361 270.687500 273.406219 100 0.000000 100 0.000000 
. 
. 
. 
. 
89.932000 89.932000 1 5.604879 289.575165 273.574738 1 5.255306 301.056091 303.812744 3 0.000000 3 0.000000 
89.964000 89.964000 1 5.650856 289.575165 269.574738 1 5.255306 301.056091 301.812744 3 0.000000 3 0.000000 
<\MERGED-PUPIL-DATA> 
. 
. 
. 
<\SESSION> 
+0

我认为这将是更喜欢,如果<\TAG>小号是有效的XML小号 – Spacedman

+0

如果外部工具是可以接受的,你有一个UNIX工具集我会使用'awk'来匹配你想要的部分,切成输出到R可以读取的新文件。 – Spacedman

+0

你能发布一个链接到完整的数据集吗?我认为你的问题之一是'颜色代码 - > 100 =未知'行。 XML包不喜欢元素文本中的'<' or '>'。 – jlhoward

回答

0

逆行斜线要挫败任何企图利用XML处理,除非你首先做一个搜索和替换。另一种方法是以行的形式读取文件并搜索标签。

读取数据文件:

txt = readLines("dummy.txt") 

下面是返回匹配标签之间的文本,作为一个列表的情况下,有不止一个部分的功能:

getSection <- function(txt, tag){ 
    start=paste0("^<",tag,">$") 
    end = paste0("^<\\\\",tag,">$") 
    startLines = grep(start,txt) 
    endLines = grep(end,txt) 
    lapply(1:length(startLines),function(i){ 
     txt[(startLines[i]+1):(endLines[i]-1)] 
    }) 
} 

因此,例如与测试文件有:

<DATE> 
2014-01-20 14:29:43 
<\DATE> 
<DATE> 
Never! 
<\DATE> 

我得到:

> getSection(txt,"DATE") 
[[1]] 
[1] "2014-01-20 14:29:43" 

[[2]] 
[1] "Never!" 

建议你写的这个包装为要解析的各个部分,例如功能我已经稍微修改您的文件给这部分多一点规律:

<STIMULUS-DEFINED> 
redOS300 
Default Human Relative Spectral Sensitivity 
1 10.000000 20.000000 60.000000 1 
3 2.000000 -100.000000 0.000000 0.000000 
<\STIMULUS-DEFINED> 

,然后写入:

getStimulusDefined <- function(lines){ 
    section = getSection(lines,"STIMULUS-DEFINED")[[1]] # only one of these 
    data = read.table(textConnection(section),skip=1,head=TRUE) 
    data 
} 

因此,我可以再做:

> getStimulusDefined(txt) 
    Default Human Relative Spectral Sensitivity 
1  1 10  20  60   1 
2  3  2  -100  0   0 

并且我得到一个数据框(你需要根据你对该部分的理解来重写)。

它会做一些奇怪的事情,如果标签嵌套,但我怀疑这种文件格式会有。

速度足够快吗?直到您尝试使用您的数据,我们才会知道,但至少是解决方案。

+0

谢谢你的回答。你的方法证明非常有效。我曾假设(错误!)任何涉及readLines的方法都会太慢。 虽然在函数中使用了参数“lines”和“tag”,但在语句中使用了“txt”和“tag”,但函数中存在轻微错误。我假设两行中的“行”应该是“txt”。 –

+0

是的,当然,当我开发这个时,我已经将文本读入'txt',并且在函数内部匹配而不是名称'lines'参数。编辑。好点。 – Spacedman

0

对不起,我在这里做了一个完整的混乱,但我是新来的Stackoverflow。我想扩展一下Spacedman的出色答案,但无法在代码中获得我的代码。

我已经改变了Spacedman的函数来制作更通用的函数来读取数据帧。

的startSkip和endSkip参数可以被用来忽略在每个块的开始和结束行。

我似乎至少在我的文件上工作得非常快。

getSection <- function(file, tag,startSkip=0,endSkip=0){ 
    txt<-readLines(file) 
    start=paste0("^<",tag,">$") 
    end = paste0("^<\\\\",tag,">$") 
    startLines = grep(start,txt) 
    endLines = grep(end,txt) 
    noLines=endLines-startLines-startSkip-endSkip-1 
    read.table(file,skip=startLines+startSkip,nrows=noLines) 
} 
+0

我将文件的读取与部分提取分开,因为那样您就不需要每次都读取整个文件来提取每个标记的部分。 – Spacedman

+0

这是一个很好的观点。尽管每次读取文件时似乎都运行得非常快,但最好避免这种情况。 我只是不知道如何读取数据帧而不使用read.table()和整个文件 –

+0

对不起,我看到你已经有了一个解决方案。我想我应该更好地阅读你的答案! –