R - 如何在保持其他列静止的同时对单个列进行热编码?

Posted

技术标签:

【中文标题】R - 如何在保持其他列静止的同时对单个列进行热编码?【英文标题】:R - How to one hot encoding a single column while keep other columns still? 【发布时间】:2019-03-03 12:45:33 【问题描述】:

我有一个这样的数据框:

group   student exam_passed subject 
A       01      Y           Math
A       01      N           Science
A       01      Y           Japanese
A       02      N           Math
A       02      Y           Science
B       01      Y           Japanese
C       02      N           Math

我想要实现的是以下结果:

group   student exam_passed subject_Math  subject_Science  subject_Japanese   
A       01      Y           1             0                0
A       01      N           0             1                0
A       01      Y           0             0                1
A       02      N           1             0                0           
A       02      Y           0             1                0
B       01      Y           0             0                1
C       02      N           1             0                0

这里是测试数据框:

df <- data.frame(
group = c('A', 'A', 'A', 'A', 'A', 'B', 'C'),
student = c('01', '01', '01', '02', '02', '01', '02'),
exam_pass = c('Y', 'N', 'Y', 'N', 'Y', 'Y', 'N'),
subject = c('Math', 'Science', 'Japanese', 'Math', 'Science', 'Japanese', 'Math')
)

我试过for循环,但是原始数据太大,处理不了,

mltools::one_hot(df, col = 'subject')

由于此错误也不起作用:

Error in `[.data.frame`(dt, , cols, with = FALSE) :
unused argument (with = FALSE)

谁能帮我解决这个问题?谢谢!

【问题讨论】:

看起来mltools 假定您的数据是data.table 而不是data.frame 【参考方案1】:
require(tidyr)
require(dplyr)

df %>% mutate(value = 1)  %>% spread(subject, value,  fill = 0 ) 


group student exam_pass Japanese Math Science
1     A      01         N        0    0       1
2     A      01         Y        1    1       0
3     A      02         N        0    1       0
4     A      02         Y        0    0       1
5     B      01         Y        1    0       0
6     C      02         N        0    1       0

【讨论】:

巧妙使用spread。你知道它的性能如何随着行数或独特元素的数量而变化吗? 我实际上没有,但如果它不能很好地扩展我会感到惊讶。如果你发现了,请告诉我! 是的,这很酷,之前没有想到这种方法【参考方案2】:

另一种选择

library(dplyr)
df %>% 
  mutate(subject_Math = ifelse(subject=='Math', 1, 0),
         subject_Science = ifelse(subject=='Science', 1, 0),
         subject_Japanese = ifelse(subject=='Japanese', 1, 0))

【讨论】:

【参考方案3】:

您可以使用神秘命名的 contrasts 函数来做到这一点。

文档的相关部分:

如果contrasts = FALSE 返回一个单位矩阵。

所以这是一个基本的实现:

encode_onehot <- function(x, colname_prefix = "", colname_suffix = "") 
  if (!is.factor(x)) 
      x <- as.factor(x)
  

  encoding_matrix <- contrasts(x, contrasts = FALSE)
  encoded_data <- encoding_matrix[as.integer(x)]

  colnames(encoded_data) <- paste0(colname_prefix, colnames(encoded_data), colname_suffix)

  encoded_data



df <- cbind(df, encode_onehot(df$subject, "subject_"))

这是相当通用的,不依赖于其他库,并且应该相当快,除了非常大的数据集。

【讨论】:

【参考方案4】:

这是使用data.table 库和caret 的更通用的解决方案

library(caret)
library(data.table)

dt <- data.table(
  group = c('A', 'A', 'A', 'A', 'A', 'B', 'C'),
  student = c('01', '01', '01', '02', '02', '01', '02'),
  exam_pass = c('Y', 'N', 'Y', 'N', 'Y', 'Y', 'N'),
  subject = c('Math', 'Science', 'Japanese', 'Math', 'Science', 'Japanese', 'Math')
)

vars <- 'subject'
separator <- '_'


bin_vars <- predict(dummyVars( as.formula(paste0("~",paste0(vars,collapse = "+"))),
                               data = dt, na.action = na.pass), newdata = dt)

colnames(bin_vars) <- paste0(gsub(vars,paste0(vars,separator),colnames(bin_vars)))

dt[,vars:=NULL]
dt <- cbind(dt,bin_vars)

【讨论】:

【参考方案5】:

您可以利用 R 将布尔值转换为整数。

类似这样的:

new.data<-cbind(
 old.data,
 math=as.integer(old.data$subject=="math")
)

【讨论】:

以上是关于R - 如何在保持其他列静止的同时对单个列进行热编码?的主要内容,如果未能解决你的问题,请参考以下文章

如何避免列在jquery数据表中排序

在 R 中编程灵敏度分析:改变 1 个参数(列),保持其他参数不变。更好的方法?

R语言进行长宽数据转换

从R中的单个数据帧运行几个线性回归

更改数据框索引值,同时保持其他列数据相同

Hive 行转列 & 列转行