#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 с использованием регулярного выражения, поэтому было приятно увидеть это в действии. В регулярном выражении значения в () обозначают значения, которые нужно разделить на столбцы? Интересует, можно ли это сделать без цикла, хотя цикл обрабатывается довольно быстро — просто я не могу вывести его в виде списка.