将data.frame列从因子转换为字符

Mik*_*war 329 r dataframe

我有一个数据框.我们叫他bob:

> head(bob)
                 phenotype                         exclusion
GSM399350 3- 4- 8- 25- 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399351 3- 4- 8- 25- 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399352 3- 4- 8- 25- 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399353 3- 4- 8- 25+ 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399354 3- 4- 8- 25+ 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
GSM399355 3- 4- 8- 25+ 44+ 11b- 11c- 19- NK1.1- Gr1- TER119-
Run Code Online (Sandbox Code Playgroud)

我想连接这个数据框的行(这将是另一个问题).但看:

> class(bob$phenotype)
[1] "factor"
Run Code Online (Sandbox Code Playgroud)

Bob列是因素.所以,例如:

> as.character(head(bob))
[1] "c(3, 3, 3, 6, 6, 6)"       "c(3, 3, 3, 3, 3, 3)"      
[3] "c(29, 29, 29, 30, 30, 30)"
Run Code Online (Sandbox Code Playgroud)

我没有开始理解这一点,但我想这些是列(因为caractacus宫廷)的因素水平的指数bob?不是我需要的.

奇怪的是,我可以bob手工完成这些专栏

bob$phenotype <- as.character(bob$phenotype)
Run Code Online (Sandbox Code Playgroud)

哪个工作正常.并且,在进行一些输入后,我可以得到一个data.frame,其列是字符而不是因子.所以我的问题是:我怎么能自动完成这个?如何将带有因子列的data.frame转换为带有字符列的data.frame,而无需手动遍历每列?

奖金问题:为什么手动方法有效?

Sha*_*ane 345

就在马特和德克身上.如果要在不更改全局选项的情况下重新创建现有数据框,可以使用apply语句重新创建它:

bob <- data.frame(lapply(bob, as.character), stringsAsFactors=FALSE)
Run Code Online (Sandbox Code Playgroud)

这会将所有变量转换为类"字符",如果您只想转换因子,请参阅下面的Marek解决方案.

正如@hadley指出的那样,以下内容更为简洁.

bob[] <- lapply(bob, as.character)
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,lapply输出一个列表; 但是,由于R的神奇属性,[]在第二种情况下的使用保留了bob对象的data.frame类,从而消除了使用as.data.frame参数转换回data.frame的需要stringsAsFactors = FALSE.

  • Shane,这也将数字列转换为字符. (23认同)
  • 一种仅使用匿名函数将因子列转换为字符的变体:`iris [] < - lapply(iris,function(x)if(is.factor(x))as.character(x)else {x})` (6认同)
  • @piccolbo你在例子中使用`bob [] < - `还是`bob < - `?; 第一个保存data.frame; 第二个将data.frame更改为列表,删除rownames.我会更新答案 (2认同)

Mar*_*rek 291

仅替换因素:

i <- sapply(bob, is.factor)
bob[i] <- lapply(bob[i], as.character)
Run Code Online (Sandbox Code Playgroud)

版本0.5.0的mutate_if dplyr包引入了新功能:

library(dplyr)
bob %>% mutate_if(is.factor, as.character) -> bob
Run Code Online (Sandbox Code Playgroud)

来自RStudio的包装purrr提供了另一种选择:

library(purrr)
library(dplyr)
bob %>% map_if(is.factor, as.character) %>% as_tibble -> bob
Run Code Online (Sandbox Code Playgroud)

(请记住它的新鲜包装)

  • 注意:`purrr`行返回一个列表,而不是`data.frame`! (2认同)

Dir*_*tel 39

全球选择

stringsAsFactors:data.frame和read.table参数的默认设置.

可能是您想要FALSE在启动文件中设置的内容(例如〜/ .Rprofile).请看help(options).

  • 这个问题是当你在缺少.Rprofile文件的环境中执行代码时,你会遇到错误! (5认同)
  • 我倾向于在脚本的开头调用它,而不是在.Rprofile中设置它. (4认同)

小智 22

我知道这个答案有点晚,但是如果你了解了因子的存储方式,你可以避免使用基于应用的函数来实现这一点.这并不意味着应用解决方案效果不佳.

因素被构造为与"水平"列表相关联的数字索引.如果将因子转换为数字,则可以看到这一点.所以:

> fact <- as.factor(c("a","b","a","d")
> fact
[1] a b a d
Levels: a b d

> as.numeric(fact)
[1] 1 2 1 3
Run Code Online (Sandbox Code Playgroud)

最后一行返回的数字对应于因子的级别.

> levels(fact)
[1] "a" "b" "d"
Run Code Online (Sandbox Code Playgroud)

请注意,levels()返回一个字符数组.您可以使用此事实轻松,紧凑地将因子转换为字符串或数字,如下所示:

> fact_character <- levels(fact)[as.numeric(fact)]
> fact_character
[1] "a" "b" "a" "d"
Run Code Online (Sandbox Code Playgroud)

如果将表达式包装在其中,这也适用于数值as.numeric().

> num_fact <- factor(c(1,2,3,6,5,4))
> num_fact
[1] 1 2 3 6 5 4
Levels: 1 2 3 4 5 6
> num_num <- as.numeric(levels(num_fact)[as.numeric(num_fact)])
> num_num
[1] 1 2 3 6 5 4
Run Code Online (Sandbox Code Playgroud)


sce*_*oni 18

如果您想要一个新的数据框bobc,其中每个因子向量bobf都转换为字符向量,请尝试以下方法:

bobc <- rapply(bobf, as.character, classes="factor", how="replace")
Run Code Online (Sandbox Code Playgroud)

如果您想要将其转换回来,可以创建一个逻辑向量,其中列是因子,并使用它来选择性地应用因子

f <- sapply(bobf, class) == "factor"
bobc[,f] <- lapply(bobc[,f], factor)
Run Code Online (Sandbox Code Playgroud)

  • 这个例子应该在rapply的`Examples'部分中,例如:http://stat.ethz.ch/R-manual/R-devel/library/base/html/rapply.html.有人知道如何要求那样吗? (3认同)
  • +1只做必要的事情(即不将整个data.frame转换为字符).此解决方案对包含混合类型的data.frame很稳健. (2认同)

by0*_*by0 13

我通常将此功能与我的所有项目区分开来.快捷方便.

unfactorize <- function(df){
  for(i in which(sapply(df, class) == "factor")) df[[i]] = as.character(df[[i]])
  return(df)
}
Run Code Online (Sandbox Code Playgroud)


Geo*_*tas 8

另一种方法是使用apply转换它

bob2 <- apply(bob,2,as.character)
Run Code Online (Sandbox Code Playgroud)

还有一个更好的(前一个是'矩阵'类)

bob2 <- as.data.frame(as.matrix(bob),stringsAsFactors=F)
Run Code Online (Sandbox Code Playgroud)


Mat*_*ker 7

更新:这是一个不起作用的例子.我认为它会,但我认为stringsAsFactors选项只适用于字符串 - 它只留下因素.

试试这个:

bob2 <- data.frame(bob, stringsAsFactors = FALSE)
Run Code Online (Sandbox Code Playgroud)

一般来说,每当你遇到应该是字符的因素的问题时,就会有一个stringsAsFactors设置来帮助你(包括全局设置).


aL3*_*3xa 7

或者您可以尝试transform:

newbob <- transform(bob, phenotype = as.character(phenotype))
Run Code Online (Sandbox Code Playgroud)

请务必将您想要转化的每个因素都转换为角色.

或者你可以做这样的事情,一击就杀死所有的害虫:

newbob_char <- as.data.frame(lapply(bob[sapply(bob, is.factor)], as.character), stringsAsFactors = FALSE)
newbob_rest <- bob[!(sapply(bob, is.factor))]
newbob <- cbind(newbob_char, newbob_rest)
Run Code Online (Sandbox Code Playgroud)

在这样的代码中推送数据并不是一个好主意,我可以sapply单独执行该部分(实际上,这样做更容易),但是你明白了......我没有检查代码,因为我不在家,所以我希望它有效!=)

然而,这种方法有一个缺点...你必须在之后重新组织列,而transform你可以做任何你喜欢的事情,但代价是"行人风格的代码写作" ......

那么...... =)


jan*_*cki 6

如果您使用data.table包来对 data.frame 进行操作,那么问题就不存在。

library(data.table)
dt = data.table(col1 = c("a","b","c"), col2 = 1:3)
sapply(dt, class)
#       col1        col2 
#"character"   "integer" 
Run Code Online (Sandbox Code Playgroud)

如果数据集中已有因子列并且想要将它们转换为字符,您可以执行以下操作。

library(data.table)
dt = data.table(col1 = factor(c("a","b","c")), col2 = 1:3)
sapply(dt, class)
#     col1      col2 
# "factor" "integer" 
upd.cols = sapply(dt, is.factor)
dt[, names(dt)[upd.cols] := lapply(.SD, as.character), .SDcols = upd.cols]
sapply(dt, class)
#       col1        col2 
#"character"   "integer" 
Run Code Online (Sandbox Code Playgroud)


小智 6

在数据框的开头包括stringsAsFactors = FALSE忽略所有误解.