关于r:一次将多列强制转换为因子

Coerce multiple columns to factors at once

我有一个示例数据框,如下所示:

1
data <- data.frame(matrix(sample(1:40), 4, 10, dimnames = list(1:4, LETTERS[1:10])))

我想知道如何选择多个列并将它们一起转换为因子。 我通常以data$A = as.factor(data$A)的方式进行操作。 但是,当数据帧很大并且包含许多列时,这种方式将非常耗时。 有谁知道更好的方法吗?


选择一些列以强制考虑因素:

1
cols <- c("A","C","D","H")

使用lapply()强制并替换所选的列:

1
data[cols] <- lapply(data[cols], factor)  ## as.factor() could also be used

检查结果:

1
2
3
4
5
sapply(data, class)
#        A         B         C         D         E         F         G
#"factor""integer" "factor" "factor""integer""integer""integer"
#        H         I         J
#"factor""integer""integer"


这是使用dplyr的选项。 magrittr中的%<>%运算符使用结果值更新lhs对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
library(magrittr)
library(dplyr)
cols <- c("A","C","D","H")

data %<>%
       mutate_each_(funs(factor(.)),cols)
str(data)
#'data.frame':  4 obs. of  10 variables:
# $ A: Factor w/ 4 levels"23","24","26",..: 1 2 3 4
# $ B: int  15 13 39 16
# $ C: Factor w/ 4 levels"3","5","18","37": 2 1 3 4
# $ D: Factor w/ 4 levels"2","6","28","38": 3 1 4 2
# $ E: int  14 4 22 20
# $ F: int  7 19 36 27
# $ G: int  35 40 21 10
# $ H: Factor w/ 4 levels"11","29","32",..: 1 4 3 2
# $ I: int  17 1 9 25
# $ J: int  12 30 8 33

或者,如果我们使用的是data.table,请对set使用for循环

1
2
3
4
setDT(data)
for(j in cols){
  set(data, i=NULL, j=j, value=factor(data[[j]]))
}

或者我们可以在.SDcols中指定'cols'并将rhs分配(:=)到'cols'

1
setDT(data)[, (cols):= lapply(.SD, factor), .SDcols=cols]

最新的tidyverse方法是使用mutate_at函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
library(tidyverse)
library(magrittr)
set.seed(88)

data <- data.frame(matrix(sample(1:40), 4, 10, dimnames = list(1:4, LETTERS[1:10])))
cols <- c("A","C","D","H")

data %<>% mutate_at(cols, funs(factor(.)))
str(data)
 $ A: Factor w/ 4 levels"5","17","18",..: 2 1 4 3  
 $ B: int  36 35 2 26
 $ C: Factor w/ 4 levels"22","31","32",..: 1 2 4 3
 $ D: Factor w/ 4 levels"1","9","16","39": 3 4 1 2
 $ E: int  3 14 30 38
 $ F: int  27 15 28 37
 $ G: int  19 11 6 21
 $ H: Factor w/ 4 levels"7","12","20",..: 1 3 4 2
 $ I: int  23 24 13 8
 $ J: int  10 25 4 33


您可以使用mutate_if(dplyr):

例如,在factor中强制integer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mydata=structure(list(a = 1:10, b = 1:10, c = c("a","a","b","b",
"c","c","c","c","c","c")), row.names = c(NA, -10L), class = c("tbl_df",
"tbl","data.frame"))

# A tibble: 10 x 3
       a     b c    
   <int> <int> <chr>
 1     1     1 a    
 2     2     2 a    
 3     3     3 b    
 4     4     4 b    
 5     5     5 c    
 6     6     6 c    
 7     7     7 c    
 8     8     8 c    
 9     9     9 c    
10    10    10 c

使用功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
library(dplyr)

mydata%>%
    mutate_if(is.integer,as.factor)

# A tibble: 10 x 3
       a     b c    
   <fct> <fct> <chr>
 1     1     1 a    
 2     2     2 a    
 3     3     3 b    
 4     4     4 b    
 5     5     5 c    
 6     6     6 c    
 7     7     7 c    
 8     8     8 c    
 9     9     9 c    
10    10    10 c

并且,为了完整起见,关于这个仅询问更改字符串列的问题,有一个mutate_if

1
2
3
4
data <- cbind(stringVar = sample(c("foo","bar"),10,replace=TRUE),
              data.frame(matrix(sample(1:40), 10, 10, dimnames = list(1:10, LETTERS[1:10]))),stringsAsFactors=FALSE)    

factoredData = data %>% mutate_if(is.character,funs(factor(.)))

这是一个data.table示例。在本示例中,我使用了grep,因为那是我经常通过对名称使用部分匹配来选择许多列。

1
2
3
4
5
6
library(data.table)
data <- data.table(matrix(sample(1:40), 4, 10, dimnames = list(1:4, LETTERS[1:10])))

factorCols <- grep(pattern ="A|C|D|H", x = names(data), value = TRUE)

data[, (factorCols) := lapply(.SD, as.factor), .SDcols = factorCols]

似乎在data.frame上使用SAPPLY将变量立即转换为因子不起作用,因为它会产生矩阵/数组。我的方法是改为使用LAPPLY,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
## let us create a data.frame here

class <- c("7","6","5","3")

cash <- c(100, 200, 300, 150)

height <- c(170, 180, 150, 165)

people <- data.frame(class, cash, height)

class(people) ## This is a dataframe

## We now apply lapply to the data.frame as follows.

bb <- lapply(people, as.factor) %>% data.frame()

## The lapply part returns a list which we coerce back to a data.frame

class(bb) ## A data.frame

##Now let us check the classes of the variables

class(bb$class)

class(bb$height)

class(bb$cash) ## as expected, are all factors.

这是使用purrr包中的modify_at()函数的另一种方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
library(purrr)

# Data frame with only integer columns
data <- data.frame(matrix(sample(1:40), 4, 10, dimnames = list(1:4, LETTERS[1:10])))

# Modify specified columns to a factor class
data_with_factors <- data %>%
    purrr::modify_at(c("A","C","E"), factor)


# Check the results:
str(data_with_factors)
# 'data.frame':   4 obs. of  10 variables:
#  $ A: Factor w/ 4 levels"8","12","33",..: 1 3 4 2
#  $ B: int  25 32 2 19
#  $ C: Factor w/ 4 levels"5","15","35",..: 1 3 4 2
#  $ D: int  11 7 27 6
#  $ E: Factor w/ 4 levels"1","4","16","20": 2 3 1 4
#  $ F: int  21 23 39 18
#  $ G: int  31 14 38 26
#  $ H: int  17 24 34 10
#  $ I: int  13 28 30 29
#  $ J: int  3 22 37 9

如果您还有另一个从表中获取值然后使用它们进行转换的目的,则可以尝试以下方法

1
2
3
4
5
### pre processing
ind <- bigm.train[,lapply(.SD,is.character)]
ind <- names(ind[,.SD[T]])
### Convert multiple columns to factor
bigm.train[,(ind):=lapply(.SD,factor),.SDcols=ind]

这将选择专门基于字符的列,然后将其转换为因数。