R - объединить переменное количество строк в нескольких столбцах на основе непустых строк в другом столбце - PullRequest
2 голосов
/ 17 октября 2019

Я извлек таблицу из PDF-файла с помощью extract_tables (), но текст был разбит на несколько строк. Количество строк варьируется в зависимости от записи. Я хотел бы объединить текст в одно значение.

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

Пример. Одна запись может занимать четыре строки, поскольку столбец «Имя и местоположение» распределен по четырем строкам (тогда как другие столбцы занимают только две строки для этой записи; остальная часть заполнена символом NA. ). Для другой записи текст может быть распределен по 6 строкам из-за длины текста в столбце «Экспертиза».

Новая запись начинается каждый раз, когда столбец «Уровень» содержит значение, а не NA. Редактировать: значения "Уровень" не являются уникальными

Мои данные выглядят так:

Name & location                 Expertise           Type            Sector               Payment            Level
 1:   Ms. Jane                  Student             Higher          Government and       payment               1
 2:   Doe,                      <NA>                Education       education            has been           <NA>
 3:   NUS                       <NA>                institute       <NA>                 received           <NA>
 4:   Andrew Saunders Phd.,     Chief               Municipal       Government and       payment               5
 5:   Municipality of           Education           government      education            has not            <NA>
 6:   Amsterdam                 Officer             <NA>            <NA>                 been               <NA>
 7:   <NA>                      <NA>                <NA>            <NA>                 received           <NA>
 8:   Mr. Stephen               Spokesperson for    Municipal       Government and       payment               3
 9:   Johnson,                  Sustainability,     government      education            has not            <NA>
10:   Orange County             Health &            <NA>            <NA>                 been               <NA>
11:   <NA>                      Wellbeing and       <NA>            <NA>                 received           <NA>
12:   <NA>                      Wellfare            <NA>            <NA>                 <NA>               <NA>
13:   Mrs. Susan                Junior              national        Government and       payment               4
14:   Andrews,                  Research            government      education            has not            <NA>
15:   Police                    Manager             <NA>            <NA>                 been               <NA>
16:   <NA>                      Money               <NA>            <NA>                 received           <NA>
17:   <NA>                      Laundering          <NA>            <NA>                 <NA>               <NA>

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

structure(list(`Name & location` = c("1:   Ms. Jane", "2:   Doe,", 
"3:   NUS", "4:   Andrew Saunders Phd.,", "5:   Municipality of", 
"6:   Amsterdam", "7:   <NA>", "8:   Mr. Stephen", "9:   Johnson,", 
"10:   Orange County", "11:   <NA>", "12:   <NA>", "13:   Mrs. Susan", 
"14:   Andrews,", "15:   Police", "16:   <NA>", "17:   <NA>"), 
    Expertise = c("Student", NA, NA, "Chief", "Education", "Officer", 
    NA, "Spokesperson for", "Sustainability,", "Health &", "Wellbeing and", 
    "Wellfare", "Junior", "Research", "Manager", "Money", "Laundering"
    ), Type = c("Higher", "Education", "Insititute", "Municipal", 
    "Government", NA, NA, "Municipal", "Government", NA, NA, 
    NA, "National", "Government", NA, NA, NA), Sector = c("Government and", 
    "education", NA, "Government and", "education", NA, NA, "Government and", 
    "education", NA, NA, NA, "Government and", "education", NA, 
    NA, NA), Payment = c("payment", "has been", "received", "Payment", 
    "has not", "been", "received", "Payment", "has not", "been", 
    "received", NA, "Payment", "has not", "been", "received", 
    NA), Level = c(1, NA, NA, 5, NA, NA, NA, 3, NA, NA, NA, NA, 
    4, NA, NA, NA, NA)), row.names = c(NA, -17L), class = c("tbl_df", 
"tbl", "data.frame"))

До сих пор я пробовал разные версии кода ниже

DF_clean <- DF %>% mutate(Level = ifelse(grepl(NA, Level))) %>%
  group_by(id = cumsum(!is.na(Level))) %>% 
  mutate(Level = first(Level)) %>% 
  group_by(Level) %>% 
  summarise(Name = paste(Name, collapse = " "),
            Expertise = paste(Expertise, collapse = " "),
            Type = paste(Type, collapse = " "),
            Sector = paste(Sector, collapse = " "),
            Level = paste(Level, collapse = " "))


Но, похоже, это сводит весь текст в одну запись.

Есть идеи, как это решить?

Ответы [ 2 ]

3 голосов
/ 17 октября 2019

Конечно, есть более красивые решения, но, похоже, это работает. Это также работает, если Level содержит повторяющиеся значения.

# Remove row numbers and <NA> from Name & Location
df <- df %>%
  mutate(`Name & location` = gsub("[0-9]+:\\s+", "", `Name & location`)) %>%
  mutate(`Name & location` = gsub("<NA>", "", `Name & location`))

# Compute ranges to merge
starts <- c(which(!is.na(df$Level)), nrow(df) + 1)
ranges <- sapply(
  1:(length(starts) - 1), 
  function(x) 
    starts[x]:(starts[x + 1] - 1)
)

# Merge lines based on ranges
combined_df <- lapply(
  ranges,
  function(x)
    lapply(df[x, ], function(x) gsub(" +$| NA", "", paste0(x, collapse = " ")))
) %>%
  bind_rows


# A tibble: 4 x 6
  `Name & location`                               Expertise                                                        Type                        Sector                   Payment                       Level
  <chr>                                           <chr>                                                            <chr>                       <chr>                    <chr>                         <chr>
1 Ms. Jane Doe, NUS                               Student                                                          Higher Education Insititute Government and education payment has been received     1    
2 Andrew Saunders Phd., Municipality of Amsterdam Chief Education Officer                                          Municipal Government        Government and education Payment has not been received 5    
3 Mr. Stephen Johnson, Orange County              Spokesperson for Sustainability, Health & Wellbeing and Wellfare Municipal Government        Government and education Payment has not been received 3    
4 Mrs. Susan Andrews, Police                      Junior Research Manager Money Laundering                         National Government         Government and education Payment has not been received 4   

РЕДАКТИРОВАТЬ: Я использовал решение Эндрю @, чтобы вычислить новый столбец unique_level и заставить его работать. Это красивее, чем мое первое решение. ИМХО:

library(tidyverse)

df <- df %>%
  mutate(`Name & location` = gsub("[0-9]+:\\s+", "", `Name & location`)) %>%
  mutate(`Name & location` = gsub("<NA>", "", `Name & location`)) %>%
  mutate(unique_level = ifelse(!is.na(Level), 1, NA) * 1:nrow(df)) %>%
  fill(unique_level, .direction = "down") %>%
  group_by(unique_level) %>%
  summarise_all(~ gsub(" +$| NA", "", paste(., collapse = " "))) %>%
  select(-unique_level)

Первые два вызова mutate удаляют номера строк и <NA> из столбца Name & location. Вызов gsub в summarise_all удаляет завершающие пробелы и NA добавляется при вставке строк вместе.

2 голосов
/ 17 октября 2019

Отредактировано :

Здесь это немного очищает, а также работает с неуникальными уровнями. Вам также понадобится установить data.table, потому что я использую rleid для создания новой переменной уровня (при условии, что можно было перезаписать ее и потерять фактические значения уровня). Если вам нужно сохранить исходные уровни, просто создайте новый столбец уровня rleid и сгруппируйте его по нему. Дайте мне знать, если у вас есть какие-либо вопросы!

df1 %>%
  fill(Level, .direction = "down") %>%
  mutate(`Name & location` = gsub("[0-9]+:\\s+(<NA>)*", "", `Name & location`)) %>%
  replace(is.na(.), "") %>%
  group_by(Level = data.table::rleid(Level)) %>%
  summarise_all(~trimws(paste(., collapse = " ") 

Level `Name & location`                  Expertise                                 Type              Sector           Payment            
  <chr> <chr>                              <chr>                                     <chr>             <chr>            <chr>              
1 1     Ms. Jane Doe, NUS                  Student                                   Higher Education~ Government and ~ payment has been r~
2 2     Andrew Saunders Phd., Municipalit~ Chief Education Officer                   Municipal Govern~ Government and ~ Payment has not be~
3 3     Mr. Stephen Johnson, Orange County Spokesperson for Sustainability, Health ~ Municipal Govern~ Government and ~ Payment has not be~
4 4     Mrs. Susan Andrews, Police         Junior Research Manager Money Laundering  National Governm~ Government and ~ Payment has not be~
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...