我有一个数据帧。我们就叫他鲍勃吧:
> 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$phenotype <- as.character(bob$phenotype)
这很好。并且,在一些输入之后,我可以得到一个data.frame,它的列是字符而不是因子。我的问题是:我如何自动地做到这一点?我如何将一个data.frame与因子列转换为一个data.frame与字符列,而不必手动遍历每一列?
附加问题:为什么手动方法有效?
或者你可以尝试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)
像这样把数据塞进代码中并不是一个好主意,我可以单独做spapply部分(实际上,这样做要容易得多),但你明白了…我还没有检查代码,因为我不在家,所以我希望它能工作!=)
然而,这种方法有一个缺点……之后你必须重新组织列,而使用transform你可以做任何你想做的事情,但代价是“行人风格的代码编写”…
所以…=)
仅替换因素:
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
...在1.0.0版本中被across取代:
library(dplyr)
bob %>% mutate(across(where(is.factor), as.character)) -> bob
RStudio中的包purrr提供了另一种选择:
library(purrr)
bob %>% modify_if(is.factor, as.character) -> bob
如果您了解因子是如何存储的,就可以避免使用基于应用程序的函数来实现这一点。这并不是说应用解决方案不能很好地工作。
因素的结构是与“级别”列表相关联的数字索引。如果将因数转换为数字,就可以看到这一点。所以:
> 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
如果你使用数据。表包对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"