Разбор больших XML-файлов в R с использованием Rcpp - PullRequest
0 голосов
/ 10 июня 2018

Используя пакет R xml2 Мне удалось проанализировать и преобразовать прикрепленный ниже XML-файл в фрейм данных.Я использую следующий код:

    require(magrittr)
    require(xml2)

    res <- read_xml("~/xml_file.xml", as = "parsed")

    vars <- res %>% xml_find_first("./d1:resultProperties") %>% 
                xml_children() %>% xml_text()

    size <- res %>% xml_find_first("./d1:resultsInformation") %>% 
                xml_children() %>% xml_text() %>% as.numeric()

    orgUnits <- res %>% xml_find_first("d1:results") %>% 
                    xml_children()

В узле resultProperties можно заранее определить, какая переменная там находится;в то время как узел resultsInformation дает счет.Я использовал эту полезную информацию, когда пытался найти стратегию для преобразования ее в фрейм данных, хранящий эти значения в переменных vars и size .

Для фактического преобразования в фрейм данных я нашел два метода:

метод 1: (поскольку я знаю ex-ante включенные переменные) пересекает каждый orgUnit узел и извлекать по одной переменной за раз из каждого узла

# method 1 - extract one variable at a time from each orgUnit node

    df <- data.frame(matrix(NA, nrow = size, ncol = length(vars)))

    for (i in 1:length(vars)) {
        df[ ,i] = xml_text(xml_find_first(orgUnits, paste0( "d1:", vars[i])))
    }

метод 2: извлекать каждый узел orgUnit полностью при обходе DOM

# method 2.2
    f <- function(x){
         a <- xml_children(x)
         text <- xml_text(a)
         names(text) <- xml_name(a)
         class(text) <- "list"
         text
    }

    df <- map_dfr(orgUnits, f)

Сложность в том, что я не могу просто использовать такую ​​функцию, как xml_find_all, поскольку не каждый узел orgUnit содержит все переменные.И в методе 2 я должен был назначить список class =, иначе bind_rows жаловался бы.

Я довольно доволен обоими решениями: метод 2 немного быстрее, чемСпособ 1. Однако для анализа ~ 8'000 orgUnits требуемое время находится в диапазоне 4,50-6,30 секунд.Мне нужно использовать эту процедуру для большого XML-файла (~ 1'000'000 orgUnits ), и производительность действительно плохая.

Отказ от ответственности: я начинающий в том, что я объясняю ниже, пожалуйста, прости небрежную номенклатуру.

Я хотел бы использовать Rcpp для интеграции кода C ++ в мой Rscript.Узкое место моего кода начинается, когда я извлекаю узлы orgUnits : создаваемая мной переменная orgUnits больше не является указателем (как, например, переменная res).Я полагаю, что работать с указателями гораздо быстрее, чем с объектами, подобными списку R.

Поэтому я хотел бы написать специальный код C ++, возможно, используя выражения xpath для извлечения текста из узлов.НО я совсем не уверен в C ++.У кого-нибудь есть предложения о том, как написать такой код C ++ или, возможно, написать более эффективный код R?

Большое спасибо заранее

      <orgUnitsResponse>
           <filters>
                  <nace>
                         <ns2:in>
                                <ns2:value>64_11</ns2:value>
                                <ns2:value>64_19</ns2:value>
                         </ns2:in>
                  </nace>
           </filters>
           <resultProperties>
                  <resultProperty>id</resultProperty>
                  <resultProperty>birth_date</resultProperty>
                  <resultProperty>close_date</resultProperty>
                  <resultProperty>code</resultProperty>
                  <resultProperty>name</resultProperty>
                  <resultProperty>nace</resultProperty>
                  <resultProperty>postal_code</resultProperty>
                  <resultProperty>city</resultProperty>
           </resultProperties>
           <resultsInformation>
                  <count>4</count>
           </resultsInformation>
           <results>
                  <orgUnit>
                         <id>1</id>
                         <birth_date>1998-01-01</birth_date>
                         <close_date>9999-12-31</close_date>
                         <code>AT00100</code>
                         <name>Oesterreichische Nationalbank</name>
                         <nace>64_11</nace>
                         <postal_code>1090</postal_code>
                         <city>Wien</city>
                  </orgUnit>
                  <orgUnit>
                         <id>128</id>
                         <birth_date>1998-01-01</birth_date>
                         <close_date>9999-12-31</close_date>
                         <code>AT20607</code>
                         <name>Sparkasse Bludenz Bank AG</name>
                         <nace>64_19</nace>
                         <postal_code>6700</postal_code>
                         <city>Bludenz</city>
                  </orgUnit>
                  <orgUnit>
                         <id>130</id>
                         <birth_date>1998-01-01</birth_date>
                         <close_date>9999-12-31</close_date>
                         <code>AT20702</code>
                         <name>Sparkasse Feldkirchen/Kärnten</name>
                         <nace>64_19</nace>
                         <postal_code>9560</postal_code>
                         <city>Feldkirchen (Ktn.)</city>
                  </orgUnit>
                  <orgUnit>
                         <id>131</id>
                         <birth_date>1998-01-01</birth_date>
                         <close_date>9999-12-31</close_date>
                         <code>AT20706</code>
                         <name>Kärntner Sparkasse Aktiengesellschaft</name>
                         <nace>64_19</nace>
                         <postal_code>9020</postal_code>
                         <city>Klagenfurt</city>
                 </orgUnit>
         </results>
      </orgUnitsResponse>
...