2016-08-29 3 views
6

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

Вот это игрушка набор данных:

id <- c(seq.int(1,11), seq.int(2,12)) 
mgr_id <- as.integer(c(NA, 1, 1, 2, 2, 2, 2, 3, 3, 5, 5, #period 1 
         NA, 2, 5, 2, 5, 5, 3, 3, 5, 10, 10)) #period 2 
period <- c(rep(1, 11), rep(2, 11)) 
left_company <- c(1, rep(0, 21)) 
joined_company <- c(rep(0, 21), 1) 

df <- data.frame(id, mgr_id, period, left_company, joined_company) 

А вот функция, которую я написал, что возвращает ожидаемые результаты.

# finds the employee's manager in the correct period, and returns that manager's id 

    get_mgr_mgr_id <- function(manager_id, period){ 
     mgr_mgr_id <- df$mgr_id[df$id == manager_id & df$period == period] 
     return(mgr_mgr_id[1]) 
    } 

Когда я использую функцию с mapply, все хорошо. Обратите внимание, что сотрудник 1 покинул компанию, и они были заменены на сотрудника 5, который был заменен на сотрудника 10, который был заменен на сотрудника 12, нового найма.

df$mgr_mgr_id <- mapply(get_mgr_mgr_id, df$mgr_id, df$period) 

df 
    id mgr_id period left joined mgr_mgr_id 
1 1  NA  1 1  0   NA 
2 2  1  1 0  0   NA 
3 3  1  1 0  0   NA 
4 4  2  1 0  0   1 
5 5  2  1 0  0   1 
6 6  2  1 0  0   1 
7 7  2  1 0  0   1 
8 8  3  1 0  0   1 
9 9  3  1 0  0   1 
10 10  5  1 0  0   2 
11 11  5  1 0  0   2 
12 2  NA  2 0  0   NA 
13 3  2  2 0  0   NA 
14 4  5  2 0  0   2 
15 5  2  2 0  0   NA 
16 6  5  2 0  0   2 
17 7  5  2 0  0   2 
18 8  3  2 0  0   2 
19 9  3  2 0  0   2 
20 10  5  2 0  0   2 
21 11  10  2 0  0   5 
22 12  10  2 0  1   5 

Мой вопрос: есть более эффективный способ, чтобы получить этот результат? В настоящее время требуется довольно много времени, чтобы работать даже на 10 000 строк, а мой набор данных имеет более чем миллион.

Я также открыт для предложений на более общее название вопроса (возможно, версия этого SQL вопрос: Most efficient way to find something recursively in a table?)

ответ

5

Вы можете запустить присоединиться data.table. Я не уверен, насколько быстрее будет:

library(data.table) 
setDT(df) 

df[, m2id := df[.(id = mgr_id, period = period), on=c("id", "period"), mgr_id]] 

    id mgr_id period left_company joined_company m2id 
1: 1  NA  1   1    0 NA 
2: 2  1  1   0    0 NA 
3: 3  1  1   0    0 NA 
4: 4  2  1   0    0 1 
5: 5  2  1   0    0 1 
6: 6  2  1   0    0 1 
7: 7  2  1   0    0 1 
8: 8  3  1   0    0 1 
9: 9  3  1   0    0 1 
10: 10  5  1   0    0 2 
11: 11  5  1   0    0 2 
12: 2  NA  2   0    0 NA 
13: 3  2  2   0    0 NA 
14: 4  5  2   0    0 2 
15: 5  2  2   0    0 NA 
16: 6  5  2   0    0 2 
17: 7  5  2   0    0 2 
18: 8  3  2   0    0 2 
19: 9  3  2   0    0 2 
20: 10  5  2   0    0 2 
21: 11  10  2   0    0 5 
22: 12  10  2   0    1 5 
    id mgr_id period left_company joined_company m2id 

Как это работает

Синтаксис для соединения является x[i, on=, j]. Он использует i и on для подмножества x, а затем возвращает j. Ключевым моментом здесь является установка id = mgr_id в i, поэтому мы подмножаемся по строкам менеджера.

Синтаксис для назначения столбца: DT[, col_name := value]. В этом случае значение происходит от соединения, объясненного в последнем абзаце.

+1

Я отредактировал свой пример, чтобы mgr_id объявлялся как целое число. – BLT

+0

@BLT Ладно спасибо, я сейчас отбросил этот шаг. – Frank

+1

Используя «microbenchmark», на моей машине кажется, что время, затраченное на оба метода (по крайней мере на этом небольшом наборе данных), сопоставимо. Возможно, OP может сообщить нам, как они сравнивают, скажем, 10000 строк? –

Смежные вопросы