Eu tenho um quadro de dados contendo um factor
. Quando eu crio um subconjunto desse quadro de dados usando subset
ou outra função de indexação, um novo quadro de dados é criado. No entanto, a factor
variável mantém todos os seus níveis originais, mesmo quando / se eles não existirem no novo quadro de dados.
Isso causa problemas ao fazer plotagens facetadas ou ao usar funções que dependem de níveis de fatores.
Qual é a maneira mais sucinta de remover níveis de um fator no novo quadro de dados?
Aqui está um exemplo:
df <- data.frame(letters=letters[1:5],
numbers=seq(1:5))
levels(df$letters)
## [1] "a" "b" "c" "d" "e"
subdf <- subset(df, numbers <= 3)
## letters numbers
## 1 a 1
## 2 b 2
## 3 c 3
# all levels are still there!
levels(subdf$letters)
## [1] "a" "b" "c" "d" "e"
mydf <- droplevels(mydf)
é preferível a solução sugerida por Roman Luštrik e Tommy O'Dell abaixo.Desde a versão 2.12 do R, há uma
droplevels()
função.fonte
factor()
é que não é necessário modificar o quadro de dados original ou criar um novo quadro de dados persistente. Posso envolverdroplevels
um quadro de dados subconjunto e usá-lo como argumento de dados para uma função de treliça, e os grupos serão tratados corretamente.Se você não deseja esse comportamento, não use fatores, use vetores de caracteres. Eu acho que isso faz mais sentido do que consertar as coisas depois. Tente o seguinte antes de carregar seus dados com
read.table
ouread.csv
:A desvantagem é que você está restrito à ordem alfabética. (reordenar é seu amigo para terrenos)
fonte
É um problema conhecido, e um possível remédio é fornecido
drop.levels()
no pacote gdata em que seu exemplo se tornaHá também a
dropUnusedLevels
função no pacote Hmisc . No entanto, ele funciona apenas alterando o operador de subconjunto[
e não é aplicável aqui.Como corolário, uma abordagem direta por coluna é simples
as.factor(as.character(data))
:fonte
reorder
parâmetro dadrop.levels
função é vale a pena mencionar: se você tem que preservar a ordem original de seus fatores, usá-lo comFALSE
valor.Outra maneira de fazer o mesmo, mas com
dplyr
Editar:
Também funciona! Graças a agenis
fonte
Por uma questão de completude, agora também existe
fct_drop
noforcats
pacote http://forcats.tidyverse.org/reference/fct_drop.html .Difere da
droplevels
maneira como lida comNA
:fonte
Aqui está outra maneira, que acredito ser equivalente à
factor(..)
abordagem:fonte
`[.factor`
método que tem umdrop
argumento e você postou isso em 2009 ...Isso é desagradável. É assim que eu costumo fazer isso, para evitar carregar outros pacotes:
que você recebe:
Observe que os novos níveis substituirão o que ocupa seu índice nos níveis antigos (subdf $ letters), então algo como:
não vai funcionar.
Obviamente, isso não é ideal quando você tem muitos níveis, mas, para alguns, é rápido e fácil.
fonte
Observando o código dos
droplevels
métodos na fonte R, você pode vê- lofactor
funcionar. Isso significa que você pode basicamente recriar a coluna com afactor
funçãoAbaixo da maneira data.table para reduzir os níveis de todas as colunas de fatores.
fonte
data.table
caminho seria algo comofor (j in names(DT)[sapply(DT, is.factor)]) set(DT, j = j, value = factor(DT[[j]]))
[.data.table
apenas uma vezaqui está uma maneira de fazer isso
fonte
Eu escrevi funções utilitárias para fazer isso. Agora que eu sei sobre o drop.levels do gdata, parece bastante semelhante. Aqui estão eles ( daqui ):
fonte
Tópico muito interessante, gostei especialmente da ideia de fatorar novamente a subseleção. Eu tive o problema semelhante antes e acabei de converter em caractere e depois voltar ao fator.
fonte
factor(as.chracter(...))
funciona, mas apenas de forma menos eficiente e sucinta do quefactor(...)
. Parece estritamente pior que as outras respostas.Infelizmente, factor () parece não funcionar ao usar o rxDataStep do RevoScaleR. Eu faço isso em duas etapas: 1) Converta em caractere e armazene no quadro de dados externo temporário (.xdf). 2) Converta de volta ao fator e armazene no quadro de dados externo definitivo. Isso elimina qualquer nível de fator não utilizado, sem carregar todos os dados na memória.
fonte
Tentei a maioria dos exemplos aqui, se não todos, mas nenhum parece estar funcionando no meu caso. Depois de lutar por algum tempo, tentei usar as.character () na coluna de fator para alterá-lo para um col com strings que parece estar funcionando bem.
Não tenho certeza sobre problemas de desempenho.
fonte