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

我有一个数据框。 让我们给他打电话:

 > 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- 

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

 > class(bob$phenotype) [1] "factor" 

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)" 

我并没有开始明白这一点,但我想这些是bob国王(caractacus国王)的柱子因素水平的指标? 不是我所需要的。

奇怪的是,我可以手工通过bob的列,做

 bob$phenotype <- as.character(bob$phenotype) 

这工作正常。 而且,一些打字后,我可以得到一个data.frame的列是字符而不是因素。 所以我的问题是:我怎么能自动做到这一点? 如何将具有因子列的data.frame转换为具有字符列的data.frame,而无需手动通过每列?

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

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

 bob <- data.frame(lapply(bob, as.character), stringsAsFactors=FALSE) 

这将把所有的变量转换为类“字符”,如果你只想转换因子,请参见下面的Marek解决方案 。

正如@hadley所指出的那样,下面更简洁。

 bob[] <- lapply(bob, as.character) 

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

仅替换因素:

 i <- sapply(bob, is.factor) bob[i] <- lapply(bob[i], as.character) 

在版本0.5.0的包dplyr 中引入了新的函数mutate_if

 library(dplyr) bob %>% mutate_if(is.factor, as.character) -> bob 

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

 library(purrr) library(dplyr) bob %>% map_if(is.factor, as.character) %>% as_data_frame -> bob 

(请记住它是新鲜的包装)

全球选择

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

可能是你想在启动文件中设置为FALSE东西(例如〜/ .Rprofile)。 请参阅help(options)

我知道这个答案有点晚了,但是如果你明白如何存储因素,你可以避免使用基于应用的功能来实现这一点。 这完全不是暗示应用解决方案不能很好地工作。

因素被构建为与“水平”列表相关的数字指标。 如果您将因子转换为数字,可以看到这一点。 所以:

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

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

 > levels(fact) [1] "a" "b" "d" 

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

 > fact_character <- levels(fact)[as.numeric(fact)] > fact_character [1] "a" "b" "a" "d" 

这也适用于数值,只要你用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 

如果你想要一个新的数据帧bobc ,在bobc中的每个因子矢量bobf被转换成一个字符矢量,试试这个:

 bobc <- rapply(bobf, as.character, classes="factor", how="replace") 

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

 f <- sapply(bobf, class) == "factor" bobc[,f] <- lapply(bobc[,f], factor) 

我通常把这个功能作为我所有项目的一部分。 快速简单。

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

另一种方法是使用apply进行转换

 bob2 <- apply(bob,2,as.character) 

而一个更好的(以前是类矩阵)

 bob2 <- as.data.frame(as.matrix(bob),stringsAsFactors=F) 

或者你可以尝试transform

 newbob <- transform(bob, phenotype = as.character(phenotype)) 

只要确保把你想要转换成角色的每个因素。

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

 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) 

用这样的代码来sapply数据不是个好主意,我可以单独做一个sapply部分(实际上,这样做更容易),但是你明白了……我没有检查代码,因为我不在家,所以我希望它的作品! =)

然而,这种方法有一个不足之处……之后你必须重组专栏,而在transform之后,你可以做任何你喜欢的事情,但是要以“行人式代码写作”为代价。

所以那里… =)

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

尝试这个:

 bob2 <- data.frame(bob, stringsAsFactors = FALSE) 

一般来说,无论何时遇到应该是字符的因素,都会在某处设置一个stringsAsFactors设置来帮助您(包括全局设置)。

在数据框的开始部分,包含stringsAsFactors = FALSE来忽略所有的误解。

这对我有用 – 我终于想到了一个班轮

 df <- as.data.frame(lapply(df,function (y) if(class(y)=="factor" ) as.character(y) else y),stringsAsFactors=F) 

如果您使用data.table包进行data.table上的操作,则问题不存在。

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

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

 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" 

这个函数有诀窍

 df <- stacomirtools::killfactor(df)