一列含多分类的哑变量处理

问题描述

最近在天池找了个数据挖掘竞赛题目玩了一下,发现有一列数据形如:<分类1>;<分类2>,有一列是固定两个分类,有一个是有多个分类,而且是不定长的,固定长度的应该来说还是容易处理,不定长的就感觉有点难。我猜应该要把他们分离出来,然后再做哑变量处理,然后再做机器学习,于是到统计之都去问了一下,很快就得到了tctcab的回复,后来也到stackoverflow上面搜了一下,下面总结了几个方法。

上码

testdf <- data.frame(id = c(1,2,3,4,5), 
                     v = c("A", "A;B", "A;C", "A;B;C", "C;D"))

tdf <- testdf
for(i in 1:2000) {
  tdf <- rbind(tdf, testdf)
}
dim(tdf)
## [1] 10005     2
tdf$id <- seq(1, nrow(tdf))

# === tidyverse
# 从tctcab回复学到的

system.time({
  rst1 <- tidyr::separate_rows(tdf,v) %>%
    mutate(val=1) %>%
    spread(v,val,fill = 0)
})
##    user  system elapsed 
##    0.17    0.02    0.19
rst1 %>% head
##   id A B C D
## 1  1 1 0 0 0
## 2  2 1 1 0 0
## 3  3 1 0 1 0
## 4  4 1 1 1 0
## 5  5 0 0 1 1
## 6  6 1 0 0 0
# base R

system.time({
  rst2 <- cbind(tdf[,1], as.data.frame.matrix(t(table(stack(setNames(strsplit(as.character(tdf$v), ';'), 
                                                tdf$id))))) )
})
##    user  system elapsed 
##    0.03    0.00    0.03
rst2 %>% dim
## [1] 10005     5
rst2 %>% head
##   tdf[, 1] A B C D
## 1        1 1 0 0 0
## 2        2 1 1 0 0
## 3        3 1 0 1 0
## 4        4 1 1 1 0
## 5        5 0 0 1 1
## 6        6 1 0 0 0
setNames(strsplit(as.character(tdf$v), ';'), 
         tdf$id) %>%
  stack %>%
  table %>%
  t %>%
  as.data.frame.matrix() %>%
  cbind(tdf[1], .) %>% 
  head
##   id A B C D
## 1  1 1 0 0 0
## 2  2 1 1 0 0
## 3  3 1 0 1 0
## 4  4 1 1 1 0
## 5  5 0 0 1 1
## 6  6 1 0 0 0
# splitstackshape

library(splitstackshape)
system.time({
  rst3 <- cSplit_e(tdf, 'v', ';', type= 'character', fill=0, drop=TRUE)
  names(rst3) <-  sub('.*_', '', names(rst3))
})
##    user  system elapsed 
##    0.15    0.00    0.15
rst3 %>% head
##   id A B C D
## 1  1 1 0 0 0
## 2  2 1 1 0 0
## 3  3 1 0 1 0
## 4  4 1 1 1 0
## 5  5 0 0 1 1
## 6  6 1 0 0 0
# qdapTools::mtabulate 

library(qdapTools)
system.time({
  rst4 <- cbind(tdf[1],mtabulate(strsplit(as.character(tdf$v), ';')))
})
##    user  system elapsed 
##    0.14    0.00    0.14
rst4 %>% head()
##   id A B C D
## 1  1 1 0 0 0
## 2  2 1 1 0 0
## 3  3 1 0 1 0
## 4  4 1 1 1 0
## 5  5 0 0 1 1
## 6  6 1 0 0 0
# data.table

library(data.table)
setDT(tdf)
tfun <- function() 1
system.time({
  rst5 <- tdf[, strsplit(as.character(v), ";"), by = id] %>%
    dcast(id ~ V1,function(x) {ifelse(0,0,1)}, drop=FALSE, fill=0, )
})
##    user  system elapsed 
##    0.16    0.00    0.16
rst5 %>% head
##    id A B C D
## 1:  1 1 0 0 0
## 2:  2 1 1 0 0
## 3:  3 1 0 1 0
## 4:  4 1 1 1 0
## 5:  5 0 0 1 1
## 6:  6 1 0 0 0

参考资料