От новичка до гуру: Курсы программирования на CyberDuff

Прочитайте XML-файл в R и создайте фрейм данных, когда узлы имеют разную длину и содержимое.

Я пытаюсь создать объект dataframe из файла XML. Задача казалась простой, но после многих попыток я не могу извлечь именно то, что хочу.

Исходные данные взяты отсюда:
https://www.data.gouv.fr/fr/datasets/repertoire-national-des-certifications-professionnelles-et-repertoire-specifique/#resource-071a7029-f237-40b1-81ca-e3c1d78282b7

По сути, документ имеет более 17 тысяч узлов с тем же именем, что и FICHES. Одним из таких подузлов является BLOCS_COMPETENCES. У этого подузла есть еще один под названием BLOC_COMPETENCES (разница в том, что S в BLOC), и у этого есть 2 интересующих меня узла: CODE и LIBELLE.

Однако не все FICHES имеют одинаковые атрибуты и/или дочерние узлы. Более того, некоторые из них имеют 1 BLOC_COMPETENCES с 1, 2, 3 или вообще без элементов.

Следуя этому документу (среди прочих сообщений), я попытался извлечь корневой узел и получить доступ к элементам с помощью xpath:

# Import the file after zip extraction
RNCP_aout2020 <- xmlParse("U:/RNCP_2020/Fiches-rncp-2020-08-03/export_fiches_RNCP_2020-08-03.xml", encoding = "UTF-8")

# Finding root node
rootNode <- xmlRoot(RNCP_aout2020)

BLOCS_COMPETENCES <- as.data.frame(xpathSApply(rootNode, '/FICHES/FICHE/BLOCS_COMPETENCES/BLOC_COMPETENCES/CODE', xmlValue))

Это работает для извлечения всех присутствующих узлов и атрибутов. Например, следующая строка работает при извлечении идентификатора каждой FICHES:

# Extract ID
NUMERO_FICHE <- as.data.frame(xpathSApply(rootNode, '/FICHES/FICHE/NUMERO_FICHE', xmlValue))

Но когда я пытаюсь использовать это для BLOC_COMPETENCES, длина отличается, что делает невозможным слияние с другими столбцами.

Я могу предоставить весь код, который я пробовал, но не репрекс в формате CSS (на данный момент), потому что я не знаю, как подмножить большой файл.

Любая помощь будет действительно оценена!


Ответы:


1

Переменное число BLOC_COMPETENCES действительно усложняет проблему. В приведенном ниже сценарии проанализированы все узлы микрофиши, а затем пройдены по каждому узлу, чтобы получить нужные коды и клеветы. Также необходимо проверить наличие кодов нулевой длины и клеветы. Так как список фиш очень длинный, для выполнения оператора lapply потребуется некоторое время.

library(xml2)
library(dplyr)

#read the document
page <- read_xml("export_fiches_RNCP_2020-08-03.xml")

#read all fiches nodes
fiches <- xml_find_all(page, "//FICHE")

#parse each fiches
dfs <-lapply(fiches, function(node){
   id <- node %>% xml_find_first(".//ID_FICHE")  %>% xml_text()
   codes <-  node %>% xml_find_all(".//BLOC_COMPETENCES/CODE") %>% xml_text()
   libelles <- node %>% xml_find_all(".//BLOC_COMPETENCES/LIBELLE")%>% xml_text()
   #correct for codes which don't exist
   if (length(codes) <1 ) {codes = NA}
   if (length(libelles) <1 ) {libelles = NA}

   df<- data.frame(id, codes, libelles, stringsAsFactors = FALSE)
})

#merge all of the data frames
answer <- bind_rows(dfs)
07.09.2020
  • Большое спасибо за ваш ответ ! Если вы не возражаете, могу я спросить, сколько времени это заняло на вашей машине? Я пробовал даже с параллельным кодом (mclapply), но задача просто не выполняется (ожидание более 30 минут). 08.09.2020
  • Некоторые новости здесь. Оставил на это около часа и выполнил задание. Работает идеально! Я отмечаю это как окончательный ответ, потому что он больше адаптируется к моему опыту работы с R, чем другой. 08.09.2020
  • Я боялся, что ты задашь этот вопрос. На моем Core i5 с частотой 3,2 ГГц это заняло около 20 минут. Я не думаю, что каждая итерация в циклах занимает так много времени, это просто большое количество итераций, поэтому параллельный запуск может не сэкономить время. 09.09.2020

  • 2

    Используйте XSLT для преобразования исходного XML для извлечения необходимых узлов. Затем используйте удобный обработчик xmlToDataFrame, избегая for или apply семейных циклов или логики if.

    Поскольку XSLT 1.0 является независимым переносимым отраслевым языком, существует множество способов его запуска, включая процессоры, такие как xsltproc, через другие языки (Java, Python, PHP) или с пакетом R xslt.

    XSLT (сохранить как файл .xsl, специальный файл .xml, используемый ниже)

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <!-- EXTRACT ONLY FICHE NODES -->
        <xsl:template match="/FICHES">
         <xsl:copy>
           <xsl:apply-templates select="FICHE"/>
         </xsl:copy>
        </xsl:template>
        
        <!-- WITHIN EACH FICHE NODE, EXTRACT ONLY ITS DESCENDANT, BLOC_COMPETENCES NODES-->
        <xsl:template match="FICHE">
           <xsl:apply-templates select="descendant::BLOC_COMPETENCES"/>
        </xsl:template>
        
        <!-- WITHIN EACH BLOC_COMPETENCE, DO TWO THINGS:            -->
        <!--      1. RETRIEVE UPPER LEVEL ANCESTOR NODE, ID_FICHE   -->
        <!--      2. RETRIEVE CODE AND LIBELLE CHILD NODES          -->
        <xsl:template match="BLOC_COMPETENCES">
         <xsl:copy>
           <xsl:copy-of select="ancestor::FICHE/ID_FICHE"/>
           <xsl:copy-of select="CODE | LIBELLE"/>
         </xsl:copy>
        </xsl:template>
        
    </xsl:stylesheet>
    

    Подход 1 (используя описанный выше XSLT в файле с именем style.xsl)

    R + xsltproc

    library(XML)
    
    setwd("...")
    system("xsltproc -o transformed.xml style.xsl export_fiches_RNCP_2020-08-03.xml")
    
    doc <- xmlParse("transformed.xml")
    doc
    # <FICHES>
    #   <BLOC_COMPETENCES>
    #     <ID_FICHE>3614</ID_FICHE>
    #     <CODE>RNCP13004BC01</CODE>
    #     <LIBELLE>Du dérushage au montage</LIBELLE>
    #   </BLOC_COMPETENCES>
    #   <BLOC_COMPETENCES>
    #     <ID_FICHE>3614</ID_FICHE>
    #     <CODE>RNCP13004BC02</CODE>
    #     <LIBELLE>Analyser un projet cinématographique</LIBELLE>
    #   </BLOC_COMPETENCES>
    #   <BLOC_COMPETENCES>
    #     <ID_FICHE>3614</ID_FICHE>
    #     <CODE>RNCP13004BC03</CODE>
    #     <LIBELLE>Tourner sur fond d'incrustation </LIBELLE>
    #   </BLOC_COMPETENCES>
    #   <BLOC_COMPETENCES>
    #   ...
    
    df <- xmlToDataFrame(doc)
    

    Подход 2 (используя описанный выше XSLT в файле с именем style.xsl)

    R + xslt

    library(xml2)
    library(xslt)
    library(XML)
    
    # PARSE XML AND XSLT
    doc <- read_xml('export_fiches_RNCP_2020-08-03.xml')
    style <- read_xml('style.xsl', package = "xslt")
    
    # TRANSFORM NESTED INPUT INTO FLATTER OUTPUT
    new_xml <- as.character(xslt::xml_xslt(doc, style))
    
    # PARSE FLATTER XML
    flat_xml <- XML::xmlParse(new_xml, asText=TRUE)
    
    # BUILD DATA FRAME
    df <- xmlToDataFrame(doc)
    
    07.09.2020
  • Большое спасибо за этот полный ответ! Однако я должен признать, что я не очень хорошо знаком с тем, о чем вы говорите в первой части вашего ответа. Можете ли вы порекомендовать какой-нибудь учебник для начинающих (или, что еще лучше, сертифицированный онлайн-курс)? Мне также любопытно, как вы получили образец или предварительный просмотр в формате JSS. Я попробовал код, который вы написали, но получаю следующую ошибку: Ошибка в (функции (классы, fdef, mtable): невозможно найти унаследованный метод для функции «xmlToDataFrame» для подписи «xml_document, отсутствует, отсутствует, отсутствует, отсутствует». 08.09.2020
  • Я забыл добавить важную инструкцию: (сохранить как файл .xsl, специальный файл .xml). См. редактирование. Специальный курс не нужен. Возможно, вы слышали о SQL, внешнем декларативном языке специального назначения, который R может запускать для извлечения данных из реляционных баз данных. Что ж, XSLT также является внешним декларативным языком специального назначения, который R может запускать для преобразования (например, выравнивания) XML-файлов, используя специальный XML-файл для запуска своего кода. Я покажу два способа сделать это в R: с помощью внешнего процессора, доступного на машинах Unix (Mac/Linux), и с помощью пакета. Примечание: петля не нужна и не занимает часа! 08.09.2020
  • Я снова попробовал вашу альтернативу, потому что другое решение требует огромного количества времени, но я действительно не заставляю его работать. Спасибо в любом случае. Я надеюсь, что это поможет кому-то еще. 15.09.2020
  • Вам не удалось установить пакет xslt (родственный пакету xml2)? В чем ошибка? В вашем сообщении указано, что у вас есть XML, и принятый ответ у вас будет xml2. 15.09.2020
  • У меня работает пакет xslt. Я думаю, что это было связано с проблемой обновления. Во всяком случае, я слышал о SQL, я знаю, что такое реляционная база данных, и я понимаю, что мне не нужны циклы для доступа к информации. Чего я не понимаю, так это первой части вашего ответа (начинающейся с ‹xsl:stylesheet), которую я считаю самой важной частью. Что это все за параметры? Откуда ты знаешь, что туда положить? Откуда вы знаете, где писать ‹xsl:template match=/FICHES› вместо (например) ‹/xsl:copy›. Фрагмент, в котором вы создаете файл xsl, если хотите. В случае, если мне нужно сделать это с другими параметрами. 27.10.2020
  • Первый блок представляет собой отдельный код или файл сценария (например, .sql в SQL, .java в Java, .py в Python или даже скрипт .R в R). На самом деле это специальный файл XML, который отправляет инструкции механизму XSLT. Обучение рекурсивному шаблонному стилю XSLT выходит за рамки вопроса StackOverflow. Однако я добавляю комментарии в первый фрагмент, чтобы показать, что делает каждый шаблон. Немногим это не нравится или не понятно, но XSLT мне нравится! 27.10.2020
  • Ладно, теперь намного понятнее. Сначала я подумал, что это пакет или какой-то простой обходной путь, а потом понял, что это буквально другой язык. Что ж, я полностью согласен с вами в том смысле, что он выглядит потрясающе, полностью обрабатывая файлы xml. Однако, учитывая то короткое время, которое у меня было для управления проектом, я не особо стремился изучать другой язык. НО это идет прямо в мой список дел. Я уже пробовал некоторые настройки с данными, которые я обрабатываю, но должен прочитать документацию и полностью использовать ее. Большое спасибо за ваши ответы и ваше время! 28.10.2020
  • Новые материалы

    Прогрессивная транспиляция
    В последние годы программисты JavaScript (он же EcmaScript) часто используют компиляторы исходного кода , также известные как транспиляторы , для преобразования более усовершенствованной или..

    Алиса в стране машинного обучения — инициатива «100 дней кода машинного обучения»
    Covnets, регрессия, классификация, ReLU, предвзятость… — все это интригующие жаргоны, которые я слышал от своих сверстников, выбравших курс машинного обучения, по касательной во время обычного..

    Иногда учитель, всегда ученик
    Учение Йоды в применении к развитию разработчиков «Делай или не делай. Нет никакой попытки.” Обучение программированию превратилось в современное «создание группы» или «написание книги»...

    Как создать файл конфигурации сборки в Xcode | Серия настроек проекта Xcode
    Эта статья шаг за шагом расскажет вам, как создать новый файл конфигурации сборки в вашем проекте Xcode. Что такое файл конфигурации сборки? Файл конфигурации сборки — это обычный..

    Venv против Virtualenv в Python  — что использовать?
    Когда дело доходит до создания виртуальных сред в Python, есть два популярных варианта: venv и virtualenv. Оба инструмента служат одной цели — созданию изолированных сред для ваших проектов..

    Реализация персептрона на Python (для абсолютных новичков)
    Введение За последние пару десятилетий было довольно много шумихи вокруг искусственного интеллекта и его приложений. В этой статье мы обсудим, что такое искусственный интеллект и его основное..

    С помощью javascript мы можем сделать это в одну строку.
    С помощью javascript мы можем сделать это в одну строку. let x = 5; let y = 7; y = [x, x = y][0]; Но то, что мы можем , не обязательно означает, что мы должны это делать.