Tenho uma lista de funcionários e preciso saber em que departamento eles estão com mais frequência. É trivial tabular o ID do funcionário em relação ao nome do departamento, mas é mais complicado retornar o nome do departamento, em vez do número de contagens de escala, da tabela de frequência. Um exemplo simples abaixo (nomes de colunas = departamentos, nomes de linhas = ids de funcionários).
DF <- matrix(sample(1:9,9),ncol=3,nrow=3)
DF <- as.data.frame.matrix(DF)
> DF
V1 V2 V3
1 2 7 9
2 8 3 6
3 1 5 4
Agora como faço para obter
> DF2
RE
1 V3
2 V1
3 V2
Respostas:
Uma opção de usar seus dados (para referência futura, use
set.seed()
para fazer exemplos usandosample
reproduzíveis):Uma solução mais rápida do que usar
apply
pode sermax.col
:... onde
ties.method
pode ser qualquer um"random"
"first"
ou"last"
Isso obviamente causa problemas se acontecer de você ter duas colunas iguais ao máximo. Não tenho certeza do que você deseja fazer nesse caso, pois terá mais de um resultado para algumas linhas. Por exemplo:
fonte
which.max
estará bem então.apply
converte odata.frame
paramatrix
internamente. Você pode não ver uma diferença de desempenho nessas dimensões.colnames(DF)[max.col(replace(DF, cbind(seq_len(nrow(DF)), max.col(DF,ties.method="first")), -Inf), "first")]
Se você estiver interessado em uma
data.table
solução, aqui está uma. É um pouco complicado, pois você prefere obter o id para o primeiro máximo. É muito mais fácil se você preferir o último máximo. No entanto, não é tão complicado e é rápido!Aqui eu gerei dados de suas dimensões (26746 * 18).
Dados
data.table
responda:Avaliação comparativa:
É cerca de 11 vezes mais rápido com dados dessas dimensões e também pode ser
data.table
dimensionado muito bem.Editar: se qualquer um dos ids máximos estiver correto, então:
fonte
Uma solução poderia ser reformular a data de ampla para longa, colocando todos os departamentos em uma coluna e as contagens em outra, agrupar pelo id do empregador (neste caso, o número da linha) e, em seguida, filtrar para o (s) departamento (s) com o Valor máximo. Existem algumas opções para lidar com laços com essa abordagem também.
fonte
Com base nas sugestões acima, a seguinte
data.table
solução funcionou muito rápido para mim:E também vem com a vantagem de sempre poder especificar quais colunas
.SD
devem ser consideradas, mencionando-as em.SDcols
:Caso precisemos do nome da coluna de menor valor, conforme sugerido por @lwshang, basta usar
-.SD
:fonte
which.min
em algo que se pareça com:DT[, MIN := colnames(.SD)[apply(.SD,1,which.min)]]
ouDT[, MIN2 := colnames(.SD)[which.min(.SD)], by = 1:nrow(DT)]
nos dados fictícios acima. Isso não considera empates e retorna apenas o primeiro mínimo. Considere fazer outra pergunta. Também estaria curioso para saber quais outras respostas você obteria.colnames(.SD)[max.col(-.SD, ties.method="first")]
.Uma
dplyr
solução:Idéia:
Código:
Resultado:
Essa abordagem pode ser facilmente estendida para obter as
n
colunas superiores . Exemplo paran=2
:Resultado:
fonte
Um
for
loop simples também pode ser útil:fonte
Uma opção
dplyr 1.0.0
pode ser:Dados de amostra:
fonte
Aqui está uma resposta que funciona com data.table e é mais simples. Isso pressupõe que seu data.table tem o nome
yourDF
:Substitua
("V1", "V2", "V3", "V4")
e(V1, V2, V3, V4)
pelos nomes das suas colunasfonte