2017-09-13 4 views
0

나는 게시 데이터 ~ 100 개 XML 파일과 같은 형식의 각> 10기가바이트이 ​​: 참고 문헌의 수의 변화와 함께,R : 데이터 프레임 대형, 가변 노드 XML 입력 및 변환에 xmlEventParse

<?xml version="1.0" encoding="UTF-8"?> 
<records xmlns="http://website”> 
<REC rid=“this is a test”> 
    <UID>ABCD123</UID> 
    <data_1> 
     <fullrecord_metadata> 
      <references count=“3”> 
       <reference> 
        <uid>ABCD2345</uid> 
       </reference> 
       <reference> 
        <uid>ABCD3456</uid> 
       </reference> 
       <reference> 
        <uid>ABCD4567</uid> 
       </reference> 
      </references> 
     </fullrecord_metadata> 
    </data_1> 
</REC> 
<REC rid=“this is a test”> 
    <UID>XYZ0987</UID> 
    <data_1> 
     <fullrecord_metadata> 
      <references count=“N”> 
      </references> 
     </fullrecord_metadata> 
    </data_1> 
</REC> 
</records> 

을 각 고유 항목 (UID로 색인화 됨)에 대해, 일부는 0 일 수 있습니다.

목표 : 인해 파일의 크기에 follows-

UID  reference 
ABCD123 ABCD2345 
ABCD123 ABCD3456 
ABCD123 ABCD4567 
XYZ0987 NULL 

같은 XML 파일 당 1 간단한 data.frame을 만들고, 내가 메모리 사용을 제한하는 xmlEventParse을 탐구 한 많은 파일을 통해 효율적인 루프에 필요한 . 나는 성공적 각 "REC"에 대한 키 독특한 "UID"의를 추출하고 이전 질문에서 다음 코드를 사용하여 data.frame을 만들 수 있습니다

branchFunction <- function() { 
store <- new.env() 
func <- function(x, ...) { 
ns <- getNodeSet(x, path = "//UID") 
key <- xmlValue(ns[[1]]) 
value <- xmlValue(ns[[1]]) 
print(value) 
store[[key]] <- value 
} 
getStore <- function() { as.list(store) } 
list(UID = func, getStore=getStore) 
} 

myfunctions <- branchFunction() 

xmlEventParse(
    file = "test.xml", 
    handlers = NULL, 
    branches = myfunctions 
) 

DF <- do.call(rbind.data.frame, myfunctions$getStore()) 

을하지만 성공적으로 참조 데이터를 저장도의 변화를 처리 할 수 ​​없습니다 단일 UID에 대한 참조 x 호. 어떤 제안을 주셔서 감사합니다!

답변

1

요소 데이터에 대한 임시 저장 영역과 a가 발견 될 때마다 호출되는 함수를 생성하는 함수를 설정하십시오.

library(XML) 

uid_traverse <- function() { 

    # we'll store them as character vectors and then make a data frame out of them. 
    # this is likely one of the cheapest & fastest methods despite growing a vector 
    # inch by inch. You can pre-allocate space and modify this idiom accordingly 
    # for another speedup. 

    uids <- c() 
    refs <- c() 

    REC <- function(x) { 

    uid <- xpathSApply(x, "//UID", xmlValue) 
    ref <- xpathSApply(x, "//reference/uid", xmlValue) 

    if (length(uid) > 0) { 

     if (length(ref) == 0) { 

     uids <<- c(uids, uid) 
     refs <<- c(refs, NA_character_) 

     } else { 

     uids <<- c(uids, rep(uid, length(ref))) 
     refs <<- c(refs, ref) 

     } 

    } 

    } 

    # we return a named list with the element handler and another 
    # function that turns the vectors into a data frame 

    list(
    REC = REC, 
    uid_df = function() { 
     data.frame(uid = uids, ref = refs, stringsAsFactors = FALSE) 
    } 
) 

} 

이 함수는 하나의 인스턴스가 필요합니다.

invisible(
    xmlEventParse(
    file = path.expand("~/data/so.xml"), 
    branches = uid_f["REC"]) 
) 

:

uid_f <- uid_traverse() 

지금, 우리는 우리가 xmlEventParse() 반환하지만 단지 부작용이 원하는 것을 필요로하지 않기 때문에() 보이지 않는 사용 xmlEventParse()를 호출하고 그것을 우리의 기능을 제공 결과는 다음과 같습니다.

uid_f$uid_df() 
##  uid  ref 
## 1 ABCD123 ABCD2345 
## 2 ABCD123 ABCD3456 
## 3 ABCD123 ABCD4567 
## 4 XYZ0987  <NA> 
+1

대단한 결과입니다. 이는 매우 효율적이며 데이터의 다른 부분을 추출하기 위해 쉽게 수정할 수 있습니다. 감사합니다 hrbrmstr! – km5041

+0

전체 크기의 파일로 메모리 한계에 도달했습니다. 데이터 프레임을 write.csv에 간헐적으로 출력하고 메모리를 밝게 유지하도록 코드를 수정하려고합니다. 그러나, 나는 중반 실행하는 벡터를 취소하는 방법을 알아낼 수 없습니다. 나는 "uids"의 길이를 시험해보고 데이터 프레임의 csv를 작성해 보았습니다. 특정 제한을 넘어서고 "uids"와 "vars"를 NULLing하는 경우 함수가 진행됨에 따라 메모리에 계속 저장됩니다. 하지만 ... 생각을 알아낼 수 없습니까? – km5041

+0

메모리 문제에 대한 추가 정보 - 중간 실행 기능을 중지하고 모든 객체 (숨김 포함) 및 가비지 수집을 제거한 경우에도 메모리는 여전히 R에 의해 사용중인 것으로 나타납니다. 메모리는 R이 될 때까지 사용 가능하지 않습니다. 종료되었습니다. "rm"조차도 제거 할 수없는이 프로세스에 의해 생성되는 개체가 있습니까? – km5041