Как искать определенные элементы в хронологическом порядке в тексте, чтобы создать упрощенный фрейм данных - PullRequest
0 голосов
/ 11 июля 2019

Введение в данные

У меня есть текстовый файл документа или CSV, который содержит код с веб-сайта, где я не мог экспортировать данные в лист Excel.Это означает, что сами данные представляют собой набор кода, в котором элементы различаются по определенным частям текста.

Понимание данных

Fx.Каждый вариант начинается с <a:FN>.у каждого элемента в varaible, x, есть код, который начинается с <a:DT>..., а у y есть код, который начинается с <a:KY>..., где значение для этого элемента начинается с <a:VL>.Кодирование для каждой переменной, а также базовый код, связанный с этой переменной, начинается с <a:PLI>.

Структура данных

So the structure of the file is as following: 


   `<a:PLI>`
      <a:DT>...
       `<a:FN>...` 
          `<a:KY>...`
           <a:VL>...
    `<a:PLI>`
      <a:DT>...
       `<a:FN>...` 
           `<a:KY>...`
            <a:VL>...

При импорте в R, кадр данных имеет только 1 столбец и всего ок.35 000 строк.Каждый бит кода имеет свою строку.

Что я хочу сделать и ожидаемый результат

Что я хочу сделать, это преобразовать этот сложный текстовый файл в новый фрейм данных, содержащий все элементы, которыми я являюсьинтересует.

Например, для каждой группы / переменной (a<:FN) я хочу найти X (<a:DT>), где я затем хочу найти Y (<a:KY>org-key</a:KY>) и Z (<a:VL) для клавиши org.Я хочу сделать это для всех X во всех группах / переменных, что приводит к выводу, где каждый X сгруппирован с соответствующими значениями Y и Z.

Я не уверен, как решить мой вопрос.Я думал, что цикл for может быть подходящим, или использовать что-то из семейства apply, например, sapply.Честно говоря, я не уверен, с чего начать, поэтому я обращаюсь.

То, что я предполагал сделать, - это настроить функцию, которая описывает, что именно я хочу сделать:

bespoke <- function (x) {

find x in df      ## X could be one of the varaibles I am looking for
find y after x    ## Find y for x in df
find z after x    ## find z for x in df
return all elements to a df  ## I wnat to repeat this function for all variables in df. 
}

df2 <- adply(keys, bespoke) 

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

Я надеюсь, что кто-то может помочь мне двигаться вперед.

Часть данных:

    <a:PLI>
       <a:DT>False</a:DT>
       <a:DTR>False</a:DTR>
       <a:Desc>text text text</a:Desc>
       <a:FN>Type</a:FN>
       <a:PSPS>
          <a:PSP>
             <a:KY>org-group</a:KY>
             <a:VL>40100</a:VL>
          </a:PSP>
          <a:PSP>
             <a:KY>org-key</a:KY>
             <a:VL>60205</a:VL>
          </a:PSP>
          <a:PSP>
             <a:KY>org-systemkey</a:KY>
             <a:VL>1005</a:VL>
          </a:PSP>
          <a:PSP>
             <a:KY>org-report-type</a:KY>
             <a:VL>text text text</a:VL>
          </a:PSP>
       </a:PSPS>
       <a:TI>80200</a:TI>
    </a:PLI>
    <a:PLI>
       <a:DT>Room</a:DT>
       <a:DTR>Room</a:DTR>
       <a:Desc/>
       <a:FN>StartRoom</a:FN>
       <a:PSPS>
          <a:PSP>
             <a:KY>org-group</a:KY>
             <a:VL>13020</a:VL>
          </a:PSP>
          <a:PSP>
             <a:KY>org-key</a:KY>
             <a:VL>13130</a:VL>
          </a:PSP>
       </a:PSPS>
       <a:TI>12500</a:TI>
    </a:PLI>
    <a:PLI>
       <a:DT>Other room</a:DT>
       <a:DTR>Other room</a:DTR>
       <a:Desc/>
       <a:FN>StartRoom</a:FN>
       <a:PSPS>
          <a:PSP>
             <a:KY>org-group</a:KY>
             <a:VL>11160</a:VL>
          </a:PSP>
          <a:PSP>
             <a:KY>org-key</a:KY>
             <a:VL>15152</a:VL>
          </a:PSP>
       </a:PSPS>
       <a:TI>15552</a:TI>
    </a:PLI>

Ответы [ 2 ]

1 голос
/ 11 июля 2019

Вы на самом деле имеете дело с типом XML, где a перед : называется его "пространством имен". Предполагая, что остальные данные аналогичны предоставленному вами примеру, вы можете извлечь данные, используя следующий код, где s - предоставленные вами данные (вам нужно заменить s на имя вашего файла. ):

library(rvest)
library(purrr)
library(dplyr)

vars <- c("dt", "dtr", "desc", "fn", "ti", "ky", "vl")

read_html(s) %>% 
    html_nodes("pli") %>% 
    unclass() %>% 
    map_df(~ map2(list(.), vars, ~ html_text(html_nodes(.x, .y))) %>% 
               set_names(vars) %>% 
               as_tibble,
           .id = "pli"
           )

Я использую read_html вместо read_xml, потому что в этом случае он довольно хорошо разбирает XML, и мне не хочется дурачиться с пространствами имен. Я не могу гарантировать, что это всегда будет работать. Кажется, что в ваших примерах данных есть только одно пространство имен, так что, возможно, вы будете в порядке.

После этого я извлекаю три pli узла, используя html_nodes, а затем преобразую набор узлов XML в список с unclass. В map_df я перебираю каждый из трех элементов списка (три pli узла) и применяю map2, где я извлекаю все соответствующие узлы, используя значения в vars, и сохраняю вывод в виде таблицы. Результаты должны выглядеть так:

# A tibble: 8 x 8
  pli   dt         dtr        desc           fn        ti    ky              vl            
  <chr> <chr>      <chr>      <chr>          <chr>     <chr> <chr>           <chr>         
1 1     False      False      text text text Type      80200 org-group       40100         
2 1     False      False      text text text Type      80200 org-key         60205         
3 1     False      False      text text text Type      80200 org-systemkey   1005          
4 1     False      False      text text text Type      80200 org-report-type text text text
5 2     Room       Room       ""             StartRoom 12500 org-group       13020         
6 2     Room       Room       ""             StartRoom 12500 org-key         13130         
7 3     Other room Other room ""             StartRoom 15552 org-group       11160         
8 3     Other room Other room ""             StartRoom 15552 org-key         15152    
1 голос
/ 11 июля 2019

(извините за предыдущий неправильный ответ, я пропустил важную часть вашего вопроса)

Вот как я бы это сделал:

  1. Оберните текст в парутеги, чтобы он действовал xml (то есть, добавить корневой узел)
  2. Удалить все 'a:' (префиксы пространства имен)

Затем в R:

library(xml2)
foo <- read_xml("tmp.xml")

# convert to a nodeset
allplis <- xml_find_all(foo, "//PLI")

xtractpli <- function(x) {
  dt <- xml_text(xml_find_first(x, "DT"))
  fn <- xml_text(xml_find_first(x, "FN"))
  orgkey <- xml_find_first(x, "PSPS/PSP[KY='org-key']")
  orgkey <- xml_text(xml_find_first(orgkey, "VL"))
  return(c(fn, dt, orgkey))
}

t(sapply(allplis, xtractpli))

Результат:

     [,1]        [,2]         [,3]   
[1,] "Type"      "False"      "60205"
[2,] "StartRoom" "Room"       "13130"
[3,] "StartRoom" "Other room" "15152"

Это то, что вы хотели?

...