2014-01-21 105 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

對不起,我看到你已經有了一個解決方案。我想我應該更好地閱讀你的答案! –