1

I have a df that where some columns are type character and I would like them to be integer values. I know I can switch typing using as.integer:

df$i <- as.integer(df$i)

But I would like to have a loop change a bunch of columns instead of having to run the command multiple times. Here's my code so far:

cols_to_change = c(37:49, 53:61)
  for(i in cols_to_change)
  {
    class(df[, i])  <- 'integer'
  }

I'm getting an error that a list object can't be converted to type 'integer', where am I wrong here? Is there an easier way to do this using one of the apply functions?

SkylerF
  • 60
  • 7
  • 4
    There are lots of options here, but you might as a first step just trying using `as.integer` in the for loop like you normally would: `df[,i] <- as.integer(df[,i])`. – joran Oct 08 '18 at 22:20
  • One more thing: It is generally preferable to use `<-` instead of `=` in R [for a couple of reasons](https://stackoverflow.com/questions/1741820/what-are-the-differences-between-and-in-r). – Roman Oct 09 '18 at 00:06
  • For best results avoid using for loop. You can easily change the specific columns to integer using `mutate_at`, `mutate_if `, `mutate_all` etc in `dplyr` package – discipulus Oct 09 '18 at 01:26

2 Answers2

2

An easier way to do this would be to use dplyr::mutate_at:

df <- dplyr::mutate_at(df, c(37:49, 53:61), as.integer)
dave-edison
  • 3,666
  • 7
  • 19
1

I think purrr::map or lapply offer fairly elegant solutions here (and just say no to for-loops in R if possible):

Let's make you a fake data frame with all character vectors:

> df <- data.frame(let1 = c('a', 'b', 'c'), num1 = c('1', '2', '3'),
             let2 = c('d', 'e', 'f'), num2 = c('4', '5', '6'),
             num3 = c('7', '8', '9'), let3 = c('g', 'h', 'i'),
             stringsAsFactors = FALSE)
> str(df)
'data.frame':   3 obs. of  6 variables:
 $ let1: chr  "a" "b" "c"
 $ num1: chr  "1" "2" "3"
 $ let2: chr  "d" "e" "f"
 $ num2: chr  "4" "5" "6"
 $ num3: chr  "7" "8" "9"
 $ let3: chr  "g" "h" "i"

Then we want to change num1, num2, and num3 into integer vectors (columns 2, 4, and 5). For illustration, copy df to df2 and then use purrr::map. Here I refer to the columns by their column number, but you could also use the names.

> df2 <- df
> df2[, c(2,4,5)] <- purrr::map(df2[, c(2,4,5)], as.integer)
> str(df2)
'data.frame':   3 obs. of  6 variables:
 $ let1: chr  "a" "b" "c"
 $ num1: int  1 2 3
 $ let2: chr  "d" "e" "f"
 $ num2: int  4 5 6
 $ num3: int  7 8 9
 $ let3: chr  "g" "h" "i"

If you don't want to load any other packages, lapply will work:

> df3 <- df
> df3[, c(2,4,5)] <- lapply(df3[, c(2,4,5)], as.integer)
> str(df3)
'data.frame':   3 obs. of  6 variables:
 $ let1: chr  "a" "b" "c"
 $ num1: int  1 2 3
 $ let2: chr  "d" "e" "f"
 $ num2: int  4 5 6
 $ num3: int  7 8 9
 $ let3: chr  "g" "h" "i"
Tyler Byers
  • 131
  • 5