Selecting range in a data.frame containing of factors

Viewed 81

If i have a data.frame like this, but much bigger

> df
#     df 
#  1  G0100
#  2  G0546
#  3  G1573
#  4  G1748
#  5  G2214
#  6  G2473
#  7  G2764
#  8  G3421
#  9  G5748
#  10 G8943

is there a beautiful way to select a range between G1500 and G2500 in much bigger data set?

3 Answers

We can use parse_number with between

library(dplyr)
library(readr)
df %>%
  filter(between(parse_number(df), 1500, 2500))

It is not really clear from the question what the general case is but we provide a variety of solutions based on different assumptions.

1) Assuming

  • the input shown reproducibly in the Note at the end
  • the lower and upper bounds are both 5 characters, as in the question

then use subset as shown. If all values in the data frame are 5 characters the first condition could be omitted.

subset(df, nchar(df) == 5 & df >= "G1500" & df <= "G2500")

giving:

     df
3 G1573
4 G1748
5 G2214
6 G2473

2) Another possibility which relaxes the second assumption above is the following which gives the same output as above. The second argument of strapply is a function given in formula notation. x is the first argument corresponding to the first capture group and y is the second argument corresponding to the second capture group.

library(gsubfn)
subset(df, strapply(df, "(.)(.*)", 
   ~ x=='G' & as.numeric(y) >= 1500 & as.numeric(y) <= 2500, 
   simplify = TRUE))

3) If every entry in the data frame begins with G or if we can ignore the letter then we could just omit it.

num <- as.numeric(sub("G", "", df$df))
subset(df, num >= 1500 & num <= 2500)

4) Another variation to read the first character and the rest into separate columns of a new data frame DF and then use subset:

DF <- read.table(text = sub("(.)", "\\1 ", df$df))
subset(df, DF$V1 == "G" & DF$V2 >= 1500 & DF$V2 <= 2500)

Note

Lines <- "
        df 
  1  G0100
  2  G0546
  3  G1573
  4  G1748
  5  G2214
  6  G2473
  7  G2764
  8  G3421
  9  G5748
  10 G8943"
df <- read.table(text = Lines)

A data.table option

> setDT(df)[, .SD[between(as.numeric(gsub("\\D", "", df)), 1500, 2500)]]
      df
1: G1573
2: G1748
3: G2214
4: G2473
Related