2017-09-13 6 views
0

私はそれぞれ> 10ギガバイト出版物データの〜100個のXMLファイルを持っているが、このようにフォーマット: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によってインデックス付けされている)ごとに、その一部はゼロかもしれません。

目標:原因ファイルのサイズにfollows-

UID  reference 
ABCD123 ABCD2345 
ABCD123 ABCD3456 
ABCD123 ABCD4567 
XYZ0987 NULL 

としてXMLファイルごとに1つの簡単なdata.frameを作成し、多くのファイル上で効率的なループ実行のために必要な、私はメモリ使用量を制限するxmlEventParseを模索してきました。私は正常にそれぞれ「REC」のためにキーのユニークな「UID」Sを抽出して、前の質問から次のコードを使用して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の参照番号。何か提案ありがとう!

答えて

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) 
    } 
) 

} 

この関数のインスタンスが1つ必要です。

uid_f <- uid_traverse() 

今、私たちは何をxmlEventParse()が復帰を必要とするが、単なる副作用をしたくないので)、私たちはxmlEventParse(コール)と(目に見えないを使用して、それを私達の機能を与える:

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

そして、我々は結果を見る:

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"をNULLにしようとしましたが、関数が進行するにつれて何かがメモリに保存され続けます。しかし、私は何が考え...考え出すことができないのですか? – km5041

+0

メモリの問題の詳細 - たとえ私が中途半端な機能を停止し、すべてのオブジェクト(隠しを含む)とガベージコレクトを削除しても、メモリはまだRによって使用中です。メモリはRまではフリーではありません終了しました。 このプロセスで作成されたオブジェクトで、「rm」でも削除できないものはありますか? – km5041

関連する問題