我正在尝试将因子变量转换为二进制/布尔值(0或1)。
示例数据:
df <-data.frame(a = c(1,2,3), b = c(1,1,2), c = c("Rose","Pink","Red"), d = c(2,3,4))
尝试将其转换为:a,b,IsRose,IsPink,IsRed,d
为此,我尝试了以下几点,但收效甚微。
library(ade4)
acm.disjonctif(df)
答案 0 :(得分:9)
在基础R中,您可以在关卡上使用sapply()
,使用==
检查是否存在,使用as.integer()
将其强制转换为二进制。
cbind(df[1:2], sapply(levels(df$c), function(x) as.integer(x == df$c)), df[4])
# a b Pink Red Rose d
# 1 1 1 0 0 1 2
# 2 2 1 1 0 0 3
# 3 3 2 0 1 0 4
但是由于你有一百万行,你可能想要使用 data.table 。
library(data.table)
setDT(df)[, c(levels(df$c), "c") :=
c(lapply(levels(c), function(x) as.integer(x == c)), .(NULL))]
给出了
df
# a b d Pink Red Rose
# 1: 1 1 2 0 0 1
# 2: 2 1 3 1 0 0
# 3: 3 2 4 0 1 0
如果您需要使用setcolorder(df, c(1, 2, 4:6, 3))
,则可以重置列顺序。
答案 1 :(得分:8)
您可以通过重塑来完成此操作:
library(dplyr)
library(tidyr)
df %>%
mutate(value = 1,
c = paste0("Is", c)) %>%
spread(c, value, fill = 0)
答案 2 :(得分:1)
使用dplyr并将其放在管道上。 @ bramtayl的答案更清晰,但我找不到使用自定义变量名的方法。这不太干净但更干燥
expand_factor <- function(df,variable){
variable = as.name(variable)
paste0('~ ',variable,' -1',collapse = '') %>%
as.formula ->formulae
current.na.action <- options('na.action')
options(na.action='na.pass')
expanded<-model.matrix(data=df,object = formulae)
options(na.action=current.na.action)
colnames(expanded) <-gsub(replacement = 'is_',x = colnames(expanded),pattern=variable)
expanded %>%
tbl_df %>%
mutate_each(funs(as.integer)) ->expanded
return(bind_cols(df,expanded))
}
library(dplyr)
df <-data_frame(x = iris$Species,y = iris$Petal.Width)
df <- rbind(data_frame(x=NA,y = NA),df)
df %>%
expand_factor('x')
> df %>%
+ expand_factor('x')
# A tibble: 151 <U+00D7> 5
x y is_setosa is_versicolor is_virginica
<chr> <dbl> <int> <int> <int>
1 <NA> NA NA NA NA
2 setosa 0.2 1 0 0
3 setosa 0.2 1 0 0
4 setosa 0.2 1 0 0
5 setosa 0.2 1 0 0
6 setosa 0.2 1 0 0
7 setosa 0.4 1 0 0
8 setosa 0.3 1 0 0
9 setosa 0.2 1 0 0
10 setosa 0.2 1 0 0
# ... with 141 more rows
答案 3 :(得分:1)
dummy <- function(df) {
NUM <- function(dataframe)dataframe[,sapply(dataframe,is.numeric)]
FAC <- function(dataframe)dataframe[,sapply(dataframe,is.factor)]
require(ade4)
if (is.null(ncol(NUM(df)))) {
DF <- data.frame(NUM(df), acm.disjonctif(FAC(df)))
names(DF)[1] <- colnames(df)[which(sapply(df, is.numeric))]
} else {
DF <- data.frame(NUM(df), acm.disjonctif(FAC(df)))
}
return(DF)
}
答案 4 :(得分:0)
为了完整起见,在此解决方案 (https://stackoverflow.com/a/33990970/2725773) 的基础上,这里有最新的 tidyverse 软件包的更新。
library(tidyverse)
df %>%
mutate(value = 1,
c = paste0("Is", c)) %>%
pivot_wider(names_from = c,
values_from = value,
values_fill = 0)