Updating factor levels while filtering R data.frames

Zhubarb picture Zhubarb · Dec 10, 2013 · Viewed 7.8k times · Source

I have a data.frame similar to below. I pre-process it by deleting rows that I am not interested in. Most of my columns are 'factors', whose 'levels' are not updated as I filter the data.frame.

I can see that what I am doing below is not ideal. How do I get the factor levels update as I modify the data.frame? Below is a demonstration of what is going wrong.

# generate data
set.seed(2013)
df <- data.frame(site = sample(c("A","B","C"), 50, replace = TRUE),
                 currency = sample(c("USD", "EUR", "GBP", "CNY", "CHF"),50, replace=TRUE, prob=c(10,6,5,6,0.5)),
                 value = ceiling(rnorm(50)*10))

# check counts to see there is one entry where currency =  CHF
count(df, vars="currency")

>currency freq
>1      CHF    1
>2      CNY   13
>3      EUR   16
>4      GBP    6
>5      USD   14


# filter out all entires where site = A, i.e. take subset of df
df <- df[!(df$site=="A"),]

# check counts again to see how this affected the currency frequencies
count(df, vars="currency")

>currency freq
>1      CNY   10
>2      EUR    8
>3      GBP    4
>4      USD   10

# But, the filtered data.frame's levels have not been updated:
levels(df$currency)

>[1] "CHF" "CNY" "EUR" "GBP" "USD"

levels(df$site)

>[1] "A" "B" "C"

desired outputs:

# levels(df$currency) = "CNY" "EUR" "GBP" "USD
# levels(df$site) = "B" "C"

Answer

A5C1D2H2I1M1N2O1R2T1 picture A5C1D2H2I1M1N2O1R2T1 · Dec 10, 2013

Use droplevels:

> df <- droplevels(df)
> levels(df$currency)
[1] "CNY" "EUR" "GBP" "USD"
> levels(df$site)
[1] "B" "C"