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

9
我是一名辅助翻译,以下是您需要翻译的内容:

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

6
我很惊讶你们没有提到 model.matrix。类似这样的代码model.matrix(~ 0 + c, df)可以实现大部分你所需求的功能。然后,只需要将其与其他列绑定即可。 - A5C1D2H2I1M1N2O1R2T1
5个回答

10
在基础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))重置列的顺序。


谢谢Richard,它有效。数据集几乎有10万行 - 这个解决方案的行数会有任何问题吗? - prasanth
@RichardScriven - 我会标记这个作为答案。只想看一下您是否能解释一下这个错误。[.data.table(setDT(df), , :=(levels(c), lapply(levels(c), : LHS of := isn't column names ('character') or positions ('integer' or 'numeric')) - prasanth
感谢您的时间,@RichardScriven。非常有帮助。 - prasanth

9

您可以通过重新塑形来完成此操作:

library(dplyr)
library(tidyr)

df %>%
  mutate(value = 1,
         c = paste0("Is", c)) %>%
  spread(c, value, fill = 0)

感谢 @bramtayl。最后3列(IsPink、IsRed、IsRose)显示了两次。 - prasanth
1
@prasanth - 这可能是因为您已经根据我的答案添加了一组新列。当从原始数据集开始时,这个答案对我来说很好用。 - Rich Scriven
@RichardScriven 是的,那就是问题所在 :) 谢谢。 - prasanth
这个答案只适用于c没有重复实例的情况。 - timothy.s.lau

3

为了完整性,基于此解决方案(https://dev59.com/D5Hea4cB1Zd3GeqPq5GN#33990970),这里提供了使用最新的tidyverse包进行更新。

library(tidyverse)

df %>%
  mutate(value = 1,
         c = paste0("Is", c)) %>%
  pivot_wider(names_from  = c,
              values_from = value,
              values_fill = 0)

1
使用dplyr并将其放在管道中。@bramtayl的答案更简洁,但我找不到使用自定义变量名的方法。这种方法不太简洁,但更加DRY。
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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接