提问



我有一个数据框。我们叫他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-


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


> 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栏目(王妃法院)的因素水平的指数?不是我需要的。


奇怪的是,我可以手工完成bob的专栏,并且做到了


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


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


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

最佳参考


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


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


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


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


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


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

其它参考1


仅替换因素:


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


在版本0.5.0的dplyr包中引入了新函数mutate_if:[49]


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


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


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


(记住它的新鲜包装)

其它参考2


全球选择



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



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

其它参考3


我知道这个答案有点晚了,但是如果你理解了因子的存储方式,你可以避免使用基于应用的函数来实现这一点。这根本不意味着应用解决方案不能很好地运作。


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


> 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


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


> 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

其它参考4


如果你想要一个新的数据框bobc,其中 bobf中的每个因子向量被转换为一个字符向量,试试这个:


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


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


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

其它参考5


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


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

其它参考6


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


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


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


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

其它参考7


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


尝试这个:


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


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

其它参考8


或者你可以试试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部分(实际上,它更容易做到)就像那样),但你明白了......我没有检查过代码,因为我不在家,所以我希望它有效!=)


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


那么...... =)

其它参考9


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

其它参考10


如果您将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" 


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


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" 

其它参考11


这对我有用 - 我终于找到了一个班轮


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

其它参考12


这个功能起到了作用


df <- stacomirtools::killfactor(df)