在R中将因子转换为二进制

时间:2015-11-30 02:50:26

标签: r

我正在尝试将因子变量转换为二进制/布尔值(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

Actuals Vs Expected Result

为此,我尝试了以下几点,但收效甚微。

library(ade4)
acm.disjonctif(df)

5 个答案:

答案 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)