Импорт нескольких счетов (.PDF) в R. Превращение их из строк в таблицу - PullRequest
0 голосов
/ 01 апреля 2019

Итак, я делаю проект, в котором мне нужно загрузить большое количество .pdfs в R. Эта часть несколько освещена. Проблема в том, что при импорте PDF-файлов в R каждая строка является строкой. Не вся информация в строке является актуальной. И в некоторых случаях информация отсутствует. Поэтому я хочу выбрать необходимую информацию и поместить ее в таблицу для дальнейшего анализа.

Импорт файлов в формате pdf производится pdftools. Это работает, подсказки или советы приветствуются, хотя

invoice_pdfs = list.files(pattern="*.pdf")                   # gather all the .pdf in current wd. 

invoice_list <- map(invoice_pdfs, .f = function(invoices){   # Using the purrr::map function .
                            pdf_text(invoices) %>%           # extracting text from listed pdf file(s)            
                            readr::read_lines() %>%          # read all text from pdf
                            str_squish() %>%                 # clear all white space in text.
                            str_to_lower                     # convert string to lower case
                         })

Я сделал пример в PDF: https://drive.google.com/file/d/1oZMgFd406lHeX18Vr9OWmSachEW0qDsA/view?usp=sharing

Воспроизводимый пример:

invoice_example <- c("invoice",                                                                         
"to: rade ris",                                                                    
"cane nompany",                                                                   
"kakber street 23d",                                                               
"nork wey",                                                                        
"+223 (0)56 015 6542",                                                             
"invoice id: 85600023",                                                            
"date reference product product reference weigth amount",                           
"01-02-2016 840000023 product a 24.45.6 de6583621 14.900 kg a 50 per tonne 745,00",
"07-02-2016 840000048 product b 24.45.7 qf8463641 19.000 kg a 50 per tonne 950,00", 
"03-02-2016 840000032 product b 24.34.2 qf8463641 4.000 kg per tonne 250,00",      
"02-02-2016 840000027 ke7801465 1.780 kg per tonne 89,00",                         
"subtotal 2.034,00",                                                               
"sales tax 183,06",                                                                
"total 2.217,06")

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

word_finder <- function(x, findWord){
                word_hit <- x %>%                           # temp for storing TRUE or FALSE
                  str_detect(pattern = fixed(findWord)) 
                 which(word_hit == TRUE)                    # give rownumber if TRUE
                }

И следующие поисковые шаблоны:

detect_date <- dgt(2) %R% "-" %R% dgt(2) %R% "-" %R% dgt(2)
detect_money <-  optional(DIGIT) %R% optional(".") %R% one_or_more(DIGIT) %R% "," %R% dgt(2) 
detect_invoice_num <- str_trim(SPC %R% dgt(8) %R% optional(SPC))

Следующим шагом должно быть создание тибла (или фрейма данных) с именами столбцов c("date", "reference", "product", "product reference", "weight", "amount") Я также пытался сделать тиббл из всего invoice_example Проблема в том, что в некоторых полях и именах столбцов отсутствует информация. не совпадают с соответствующими значениями.

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

конечный результат должен быть примерно таким.

Воспроизводимый пример:

invoice_nr <- c("85600023", "85600023", "85600023", "85600023" )
date <- c( "01-02-2016", "07-02-2016", "03-02-2016", "02-02-2016")
reference <- c( "840000023", "840000048", "840000032", "840000027")
product_id <- c( "de6583621", "qf8463641", "qf8463641", "ke7801465")
weight <- c("14.900", "19.000", "4.000", "1.780")
amount <- c("745.00", "950.00", "250.00", "89.00")

example_tibble <- tibble(invoice_nr, date, reference, product_id, weight, amount)

Результат:

# A tibble: 4 x 6
  invoice_nr date       reference product_id weight amount
  <chr>      <chr>      <chr>     <chr>      <chr>  <chr> 
1 85600023   01-02-2016 840000023 de6583621  14.900 745.00
2 85600023   07-02-2016 840000048 qf8463641  19.000 950.00
3 85600023   03-02-2016 840000032 qf8463641  4.000  250.00
4 85600023   02-02-2016 840000027 ke7801465  1.780  89.00 

Будем благодарны за любые предложенные способы борьбы с этим!

Ответы [ 2 ]

0 голосов
/ 01 апреля 2019

На самом деле вы можете использовать функции library(stringr) для достижения своей цели (я пропустил часть rebus, так как в любом случае это выглядит как «просто» помощник для создания регулярного выражения, которое я сделал вручную):

library(tidyverse)
parse_invoice <- function(in_text) {
  ## define regex, some assumptions:
  ## product id is 2 lower characters followed by 7 digits
  ## weight is some digits with a dot followed by kg
  ## amount is some digits at the end with a comma
  all_regex <- list(date       = "\\d{2}-\\d{2}-\\d{4}",
                    reference  = "\\d{9}",
                    product_id = "[a-z]{2}\\d{7}",
                    weight     = "\\d+\\.\\d+ kg",
                    amount     = "\\d+,\\d+$")
  ## look only at lines where there is invoice data
  rel_lines <- str_subset(in_text, all_regex$date)
  ## extract the pieces from the regex
  ret <- as_tibble(map(all_regex, str_extract, string = rel_lines))
  ## clean up the data
  ret %>%
    mutate(invoice_nr = str_extract(str_subset(in_text, "invoice id:"), "\\d{8}"),
           date       = as.Date(date, "%d-%m-%Y"),
           weight     = as.numeric(str_replace(weight, "(\\d+.\\d+) kg", "\\1")),
           amount     = as.numeric(str_replace(amount, ",", "."))
    ) %>%
    select(invoice_nr,
           date,
           reference,
           product_id,
           weight,
           amount)

}
str(parse_invoice(invoice_example))
# Classes ‘tbl_df’, ‘tbl’ and 'data.frame':       4 obs. of  6 variables:
#  $ invoice_nr: chr  "85600023" "85600023" "85600023" "85600023"
#  $ date      : Date, format: "2016-02-01" "2016-02-07" ...
#  $ reference : chr  "840000023" "840000048" "840000032" "840000027"
#  $ product_id: chr  "de6583621" "qf8463641" "qf8463641" "ke7801465"
#  $ weight    : num  14.9 19 4 1.78
#  $ amount    : num  745 950 250 89
0 голосов
/ 01 апреля 2019

Поскольку я не знаком с rebus, я переписал ваш код. Предполагая, что счета, по крайней мере, несколько структурированы, я могу сгенерировать tibble из вашего примера. Вам просто нужно применить это ко всему списку, а затем purrr::reduce к большому tibble:

df <- tibble(date=na.omit(str_extract(invoice_example,"\\d{2}-\\d{2}-\\d{4}")))
df %>% mutate(invoice_nr=na.omit(sub("invoice id: ","",str_extract(invoice_example,"invoice id: [0-9]+"))),
              reference=na.omit(sub("\\d{2}-\\d{2}-\\d{4} ","",str_extract(invoice_example,"\\d{2}-\\d{2}-\\d{4} \\d{9}"))),
              product_id=na.omit(str_extract(invoice_example,"[:lower:]{2}\\d{7}")),
              weight=na.omit(sub(" kg","",str_extract(invoice_example,"[0-9\\.]+ kg"))),
              amount=na.omit(sub("tonne ","",str_extract(invoice_example,"tonne [0-9,]+"))))
...