Цикл R для подмножества информации из нескольких последующих строк и создания нового столбца

#r #loops #text

#r #циклы #текст

Вопрос:

Я все еще относительно новичок в R, и я получил эту задачу.

У меня есть таблица (код ниже), в которой первый столбец состоит из имен менеджеров и проектов, которые у них есть. Всегда после имени менеджера (например, «Том Джонс») перечислены его проекты (например, «019200 [ytb] ppp») и другие виды деятельности (например, «Управление рисками»). Другие столбцы представляют рабочие часы ( capacity ) и фактические рабочие часы ( actual_hours ), которые менеджер потратил на проекты.

[Обновленный фрейм данных]

 df <- data.frame('Name'=c('Tom Jones', '0192000 [ytb] ppp', 'I-2020020 [BBB] Adm Valid', 'TENT DATZ 20204001 [ASS]','Risk Management', 'Andrea Jose Casteno','2040044 [Amaas] HHHHJ', '0291111 [inezzz] plmi', 'Training', 'Gerard van der Dike', '20200222 20203333 [Ttt ID/ZZ] HHH SSS DD  Dpp', 'Other' , 'R-20204444 [Res] Phhh Top SAA', 'Bill Gatea', 'Leave','2019xxxx [zzz] Aap ZZ'), 'capacity' = c(40,0,0,0,0,36,0,0,0,40,0,0,0,38,0,0), 'actual_hours' = c(44,12,2,20,10,40,30,0,10,43,20,10,13,38,20,18))
  

Список менеджеров:

 manager_names= c('Tom Jones', 'Andrea Jose Casteno', 'Gerard van der Dike', 'Bill Gatea')
  

Мне нужно преобразовать эту таблицу в вывод ниже (рисунок ниже). Для каждого менеджера, который работал больше, чем его возможности ( actual_hours > capacity ), мне нужно создать строку в новой таблице. Первым столбцом должно быть имя менеджера. Второй и третий столбцы показывают его capacity и actual_hours . В четвертом столбце должны быть представлены краткие названия проектов, над которыми работал manger (исключить проекты с 0 == actual_hours ). Короткие названия проектов необходимо вычесть из Name столбца — они заключены в квадратные скобки (например, BBB)

вывод

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

 z=(which(df$actual_hours > df$capacity))

output_df=df[z,c("Name","capacity","actual_hours")]

y=which(output_df$capacity==0, arr.ind=TRUE)

newdf <- output_df[-y, ]
  

Заранее спасибо за вашу помощь!

Ответ №1:

Вот базовый параметр R

 do.call(
  rbind,
  lapply(
    split(df, cumsum(grepl("manager\d ", df$Name))),
    function(v) {
      if (v$capacity[1] <= v$actual_hours[1]) {
        cbind(v[1, ], projects = toString(gsub(".*\[(\w )\].*", "\1", v$Name[-1])))
      } else {
        NULL
      }
    }
  )
)
  

что дает

       Name capacity actual_hours      projects
1 manager1       40           44 ytb, ytv, COM
2 manager2       36           40   TYU, inezzz
3 manager3       40           43   TYUKKK, ine
  

Комментарии:

1. Большое спасибо за ваш ответ, Томас. На самом деле, реальные данные в столбце «Имя» содержат имя и фамилию менеджера, поэтому шаблона «менеджер» нет. В функции я вижу, что это скорее связано с «емкостью» (т. Е. Если «емкость» равна = 0, то …) Кроме того, проекты, у которых нулевые часы в ‘actual_hours’, не должны быть перечислены в ‘projects’. У вас есть какие-то предложения по этому поводу? Заранее спасибо

Ответ №2:

Вот вариант с tidyverse . После создания столбца группировки путем взятия совокупной суммы логического вектора, т.Е. Где подстрока ‘manager’ находится в ‘Name’, затем summarise путем paste ввода извлеченных слов в квадратные скобки, а также получения значений столбцов first строки с помощью across

 library(dplyr)
library(stringr)
df %>% 
  group_by(grp = cumsum(str_detect(Name, 'manager'))) %>%
  summarise(projects = str_c(str_extract(Name[-1],
              "(?<=\[)\w "), collapse="; "), 
     across(c(Name, capacity, actual_hours), first), .groups = 'drop') %>% 
  select(names(df), 'projects')
  

-вывод

 # A tibble: 3 x 4
#  Name     capacity actual_hours projects     
#  <chr>       <dbl>        <dbl> <chr>        
#1 manager1       40           44 ytb; ytv; COM
#2 manager2       36           40 TYU; inezzz  
#3 manager3       40           43 TYUKKK; ine  
  

Комментарии:

1. Большое спасибо за ваш ответ Akrun. Я уже упоминал в решении Thomas, что на самом деле реальные данные в столбце «Имя» содержат имя и фамилию менеджера, поэтому шаблона «менеджер» нет. В коде я вижу, что это скорее связано с «емкостью» (т. Е. Если «емкость» равна = 0, то …) Кроме того, проекты, у которых нулевые часы в ‘actual_hours’, не должны быть перечислены в ‘projects’. Есть ли у вас какие-либо предложения в этом случае? Заранее спасибо

2. @Просто есть ли в данных какой-либо шаблон, который мы можем использовать

3. @JustT если вы измените шаблон на cumsum(str_detect(Name, '^[A-Za-z])) , это сработает? Я нахожу цифры, начинающиеся в других строках

4. Имена структурированы так, как вы описали, например, «Том Джонс», но также и «Бен ван дер Дайк». Названия проектов иногда начинаются с цифр, иногда с буквы цифры, затем в [ ] есть краткое название проекта и полное название проекта буквами — как короткие, так и полные названия проектов содержат заглавные и строчные буквы (иногда только заглавные), например ‘11101 [Nama] Naa Maa’ или ‘R-2000[Hor] Prop Hut’ . Мне также нужно исключить проекты, которые имеют нулевые часы в «actual_hours». Надеюсь, это поможет 🙂

5. Я мог бы также создать список с именами менеджеров, но я не уверен, как тогда адаптировать код…