Вывод цикла, сохраненный как список

#r #list #loops

#r #Список #циклы

Вопрос:

У меня есть обширные данные наблюдений, где одно наблюдение состоит из сотрудника уровня 1 и его отдела вплоть до уровня 8. Я использую цикл с другими командами для создания списка всех сотрудников и отделов под ними в длинном формате, чтобы я мог видеть, за какие отделы отвечают сотрудники на всех уровнях. Возможно, существует более элегантный способ сделать это, чем цикл, но он работает нормально. Образец данных (через уровень 3 для краткости):

 data <- tibble(LV1_Employee_Name = "Chuck", LV1_Employee_Nbr = "1", LV1_Department = "Tha Boss", LV1_Department_Nbr = "90",
               LV2_Employee_Name = c("Alex", "Alex", "Paul", "Paul", "Jennifer", "Jennifer"), LV2_Employee_Nbr = c("2", "2", "3", "3", "4", "4"), LV2_Department = c("Leadership", "Leadership", "Finance", "Finance", "Philanthropy", "Philanthropy"), LV2_Department_Nbr = c("91", "91", "92", "92",  "93", "93"),
               LV3_Employee_Name = c("Dan", "Wendy", "Sarah", "Monique", "Miguel", "Brandon"), LV3_Employee_Nbr = c("2", "2", "3", "3", "4", "4"), LV3_Department = c("Analytics", "Pop Health", "Acounting", "Investments", "Yacht Aquisitions", "Golf Junkets"), LV3_Department_Nbr = c("94", "95", "96", "97",  "98", "99"))
 

Приведенный ниже цикл сначала создает шесть блоков с именами level1_1, level1_2, level1_3, level2_2, level2_3, level3_3. Каждый tibble содержит имя сотрудника, номер и отдел на том же уровне отдела или ниже. Затем код перечисляет и связывает строки этих tibbles с ls() помощью and bind_rows() , затем применяет distinct() команду, и я получил то, что мне нужно.

 first_department <- 1

data_colnames <- c("Employee", "Employee_Id", "Department", "Department_Number")

for(i in 1:3){
  for(k in first_department:3){
    
    assign(paste0("level", i, "_", k), setNames(distinct(as_tibble(c(data[ ,paste0("LV", i, "_", "Employee_Name")], data[ ,paste0("LV", i, "_", "Employee_Nbr")],
                                                                     data[ ,paste0("LV", k, "_", "Department")],  data[ ,paste0("LV", k, "_", "Department_Nbr")]))), 
                                                data_colnames))
    
  }
  first_department = first_department   1
}

employees_departments <- distinct(bind_rows(mget(ls(pattern = "^level")))) %>%
  filter(is.na(Department) == FALSE)

rm(list = ls(pattern = "^level"))
 

Что я хотел бы сделать, так это вместо того, чтобы создавать начальный вывод из шести tibbles, чтобы сам цикл выводил список. Это избавит меня от огромного списка ошибок в выводе, который, как мне сказали, не очень «похож на R».

Ответ №1:

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

 library(tidyverse)

idx <- 1
first_department <- 1
data_colnames <- c("Employee", "Employee_Id", "Department", "Department_Number")
data_lst <- list()

for(i in 1:3){
  for(k in first_department:3){
    data_lst[[idx]] <- setNames(
      distinct(as_tibble(
        c(data[ ,paste0("LV", i, "_", "Employee_Name")], 
          data[ ,paste0("LV", i, "_", "Employee_Nbr")],
          data[ ,paste0("LV", k, "_", "Department")],  
          data[ ,paste0("LV", k, "_", "Department_Nbr")]))),
      data_colnames)
    idx <- idx   1
  }
  first_department = first_department   1
}

distinct(bind_rows(data_lst)) %>%
  filter(!is.na(Department))
 

Вывод

    Employee Employee_Id Department        Department_Number
   <chr>    <chr>       <chr>             <chr>            
 1 Chuck    1           Tha Boss          90               
 2 Chuck    1           Leadership        91               
 3 Chuck    1           Finance           92               
 4 Chuck    1           Philanthropy      93               
 5 Chuck    1           Analytics         94               
 6 Chuck    1           Pop Health        95               
 7 Chuck    1           Acounting         96               
 8 Chuck    1           Investments       97               
 9 Chuck    1           Yacht Aquisitions 98               
10 Chuck    1           Golf Junkets      99               
11 Alex     2           Leadership        91               
12 Paul     3           Finance           92               
13 Jennifer 4           Philanthropy      93               
14 Alex     2           Analytics         94               
15 Alex     2           Pop Health        95               
16 Paul     3           Acounting         96               
17 Paul     3           Investments       97               
18 Jennifer 4           Yacht Aquisitions 98               
19 Jennifer 4           Golf Junkets      99               
20 Dan      2           Analytics         94               
21 Wendy    2           Pop Health        95               
22 Sarah    3           Acounting         96               
23 Monique  3           Investments       97               
24 Miguel   4           Yacht Aquisitions 98               
25 Brandon  4           Golf Junkets      99 
 

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

1. Интересное решение! К сожалению, с полными данными происходит то, что pivot_longer() шаг создает число из 35 232 наблюдений. Когда я затем перехожу к fuzzy_left_join() шагу, R некоторое время обрабатывает команду, а затем выводит «Ошибка: не удается выделить вектор размером 2,6 ГБ», мне любопытно, что pivot_longer() делает команда; как он выбирает номер уровня, знает, что нужно поместить это число в новый столбец с именем «уровень»,затем присваивает результирующим столбцам общее имя. Я не думал, что смогу использовать pivot, когда я изначально начал эту проблему.

2. pivot_longer «удлиняет» данные (увеличивая строки, уменьшая столбцы)… посмотрите, как data_long это выглядит, и вы увидите, что каждая строка включает в себя: (1) номер строки (поскольку одна и та же строка подразумевает связь с другими отделами), (2) уровень, (3) Имя и идентификатор сотрудника и (4) Номер отдела и отдела. В то время как исходные данные имели 3 имени и 3 отдела в каждой строке, длинная версия имеет только одно имя и отдел. каждая строка.

3. pivot_longer принимает names_pattern значение, которое использует регулярное выражение (регулярное выражение) для определения того, какой ключ / значение должен be…in в этом случае он разделяет число \d в одном столбце, которое является уровнем, и слово \w в другом столбце, которое является одним из 4 (Employee_Name, Employee_Nbr, Department, Department_Nbr). Это определяется путем интерпретации исходных имен столбцов…

4. Пожалуйста, смотрите отредактированную версию. Я добавил аналогичный подход, но выполняю небольшие объединения на основе номера строки исходного фрейма данных. Это должно дать тот же ответ, но лучше работать с большими данными. Пожалуйста, дайте мне знать, если это сработает. Если ваши данные огромны, вы также можете рассмотреть data.table решение и неэквивалентное соединение.

5. Данные представляют собой 4404 obs из 32 переменных (8 уровней). 4613 сотрудников и 281 отдел. Я использовал pivot_longer раньше, но никогда с параметром pattern с использованием регулярного выражения, поэтому было приятно увидеть это в действии. В регулярном выражении значения в () обозначают значения, которые нужно разделить на столбцы? Интересует, можно ли это сделать без цикла, хотя цикл обрабатывается довольно быстро — просто я не могу вывести его в виде списка.