Для каждой строки возвращаем имя столбца наибольшего значения

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

DF <- matrix(sample(1:9,9),ncol=3,nrow=3) DF  DF V1 V2 V3 1 2 7 9 2 8 3 6 3 1 5 4 

Теперь, как я могу получить

 > DF2 RE 1 V3 2 V1 3 V2 

Один вариант использования ваших данных (для справки в будущем используйте set.seed() для создания примеров с использованием воспроизводимого sample ):

 DF <- data.frame(V1=c(2,8,1),V2=c(7,3,5),V3=c(9,6,4)) colnames(DF)[apply(DF,1,which.max)] [1] "V3" "V1" "V2" 

Более быстрым решением, чем использование apply может быть max.col :

 colnames(DF)[max.col(DF,ties.method="first")] #[1] "V3" "V1" "V2" 

... где ties.method может быть любым из "random" "first" или "last"

Это, конечно, вызывает проблемы, если у вас есть два столбца, которые равны максимальному. Я не уверен, что вы хотите сделать в этом экземпляре, поскольку у вас будет несколько результатов для некоторых строк. Например:

 DF <- data.frame(V1=c(2,8,1),V2=c(7,3,5),V3=c(7,6,4)) apply(DF,1,function(x) which(x==max(x))) [[1]] V2 V3 2 3 [[2]] V1 1 [[3]] V2 2 

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

Здесь я создал данные ваших измерений (26746 * 18).

Данные

 set.seed(45) DF <- data.frame(matrix(sample(10, 26746*18, TRUE), ncol=18)) 

data.table ответ:

 require(data.table) DT <- data.table(value=unlist(DF, use.names=FALSE), colid = 1:nrow(DF), rowid = rep(names(DF), each=nrow(DF))) setkey(DT, colid, value) t1 <- DT[J(unique(colid), DT[J(unique(colid)), value, mult="last"]), rowid, mult="first"] 

Сравнительный анализ:

 # data.table solution system.time({ DT <- data.table(value=unlist(DF, use.names=FALSE), colid = 1:nrow(DF), rowid = rep(names(DF), each=nrow(DF))) setkey(DT, colid, value) t1 <- DT[J(unique(colid), DT[J(unique(colid)), value, mult="last"]), rowid, mult="first"] }) # user system elapsed # 0.174 0.029 0.227 # apply solution from @thelatemail system.time(t2 <- colnames(DF)[apply(DF,1,which.max)]) # user system elapsed # 2.322 0.036 2.602 identical(t1, t2) # [1] TRUE 

Это примерно в 11 раз быстрее по данным этих измерений, а data.table тоже очень хорошо.


Изменить: если какой-либо из максимальных значений в порядке, то:

 DT <- data.table(value=unlist(DF, use.names=FALSE), colid = 1:nrow(DF), rowid = rep(names(DF), each=nrow(DF))) setkey(DT, colid, value) t1 <- DT[J(unique(colid)), rowid, mult="last"] 

Основываясь на приведенных выше предложениях, для меня очень быстро работало следующее решение data.table :

 set.seed(45) DT <- data.table(matrix(sample(10, 10^7, TRUE), ncol=10)) system.time( DT[, MAX := colnames(.SD)[max.col(.SD, ties.method="first")]] ) user system elapsed 0.10 0.02 0.21 DT V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 MAX 1: 7 4 1 2 3 7 6 6 6 1 V1 2: 4 6 9 10 6 2 7 7 1 3 V4 3: 3 4 9 8 9 9 8 8 6 7 V3 4: 4 8 8 9 7 5 9 2 7 1 V4 5: 4 3 9 10 2 7 9 6 6 9 V4 --- 999996: 4 6 10 5 4 7 3 8 2 8 V3 999997: 8 7 6 6 3 10 2 3 10 1 V6 999998: 2 3 2 7 4 7 5 2 7 3 V4 999999: 8 10 3 2 3 4 5 1 1 4 V2 1000000: 10 4 2 6 6 2 8 4 7 4 V1 

А также имеет то преимущество, что всегда можно указать, какие столбцы .SD следует учитывать, указав их в .SDcols :

 DT[, MAX2 := colnames(.SD)[max.col(.SD, ties.method="first")], .SDcols = c("V9", "V10")] 

Одним из решений могло бы быть изменение даты от широкого до длинного размещения всех отделов в одном столбце и подсчета в другой группе с идентификатором работодателя (в данном случае, с номером строки), а затем фильтрацией в отдел (ы) с помощью максимальное значение. Существует несколько вариантов обработки связей с этим подходом.

 library(tidyverse) # sample data frame with a tie df <- data_frame(V1=c(2,8,1),V2=c(7,3,5),V3=c(9,6,5)) # If you aren't worried about ties: df %>% rownames_to_column('id') %>% # creates an ID number gather(dept, cnt, V1:V3) %>% group_by(id) %>% slice(which.max(cnt)) # A tibble: 3 x 3 # Groups: id [3] id dept cnt    1 1 V3 9. 2 2 V1 8. 3 3 V2 5. # If you're worried about keeping ties: df %>% rownames_to_column('id') %>% gather(dept, cnt, V1:V3) %>% group_by(id) %>% filter(cnt == max(cnt)) %>% # top_n(cnt, n = 1) also works arrange(id) # A tibble: 4 x 3 # Groups: id [3] id dept cnt    1 1 V3 9. 2 2 V1 8. 3 3 V2 5. 4 3 V3 5. # If you're worried about ties, but only want a certain department, you could use rank() and choose 'first' or 'last' df %>% rownames_to_column('id') %>% gather(dept, cnt, V1:V3) %>% group_by(id) %>% mutate(dept_rank = rank(-cnt, ties.method = "first")) %>% # or 'last' filter(dept_rank == 1) %>% select(-dept_rank) # A tibble: 3 x 3 # Groups: id [3] id dept cnt    1 2 V1 8. 2 3 V2 5. 3 1 V3 9. # if you wanted to keep the original wide data frame df %>% rownames_to_column('id') %>% left_join( df %>% rownames_to_column('id') %>% gather(max_dept, max_cnt, V1:V3) %>% group_by(id) %>% slice(which.max(max_cnt)), by = 'id' ) # A tibble: 3 x 6 id V1 V2 V3 max_dept max_cnt       1 1 2. 7. 9. V3 9. 2 2 8. 3. 6. V1 8. 3 3 1. 5. 5. V2 5. 

Также может быть удобен простой цикл:

 > df<-data.frame(V1=c(2,8,1),V2=c(7,3,5),V3=c(9,6,4)) > df V1 V2 V3 1 2 7 9 2 8 3 6 3 1 5 4 > df2<-data.frame() > for (i in 1:nrow(df)){ + df2[i,1]<-colnames(df[which.max(df[i,])]) + } > df2 V1 1 V3 2 V1 3 V2 
  • backtransform `scale ()` для построения графика
  • Замените все значения 0 на NA
  • Как я могу прерывать текущий код в R с помощью команды клавиатуры?
  • Функция не найдена в R doParallel 'foreach' - Ошибка в {: task 1 failed - "не удалось найти функцию" растровый "
  • Удаление пустых строк файла данных в R
  • нумерация по группам
  • poly () в lm (): разница между исходным и ортогональным
  • Разница между `% in%` и `==`
  • Разделить вектор по его последовательностям
  • Как увидеть исходный код функции R .Internal или .Primitive?
  • Создайте последовательность, такую ​​как 112123123412345
  • Давайте будем гением компьютера.