具有固定列结构的R虚拟/单热编码

时间:2018-12-23 20:27:14

标签: r dummy-variable one-hot-encoding

假设我的机器学习训练数据集包含3列,其类别多达50个不同级别。我一口气地编码列。测试数据集只有一行。编码测试数据集时,我可以保持训练数据集的结构吗?

一切都适合训练数据...

v1 <- factor(c("a","b","c","a"))
v2 <- factor(c("A","A","B","C"))
train <- data.frame(v1 = v1,v2 = v2)
train_dummy <- as.data.frame(model.matrix(~ v1 + v2 -1 , data=train, 
    contrasts.arg=list(v1=contrasts(train$v1, contrasts=F), 
            v2=contrasts(train$v2, contrasts=F))))
print(train)
v1 v2
a  A
b  A
c  B
a  C

print(train_dummy )
v1a v1b v1c v2A v2B v2C
1   0   0   1   0   0
0   1   0   1   0   0
0   0   1   0   1   0
1   0   0   0   0   1

...但是对于测试数据,它失败。当我尝试将训练数据的因子水平应用于测试数据时,它不起作用:

test <-  data.frame(v1 = factor("a"),v2 = factor("A"))
test_dummy <- as.data.frame(model.matrix(~ v1 + v2 -1 , data=test, 
    contrasts.arg=list(v1=contrasts(train$v1, contrasts=F), 
            v2=contrasts(train$v2, contrasts=F))))
Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : 
  contrasts can be applied only to factors with 2 or more levels

我当然可以行绑定训练和测试数据,然后进行虚拟编码,但这是生产代码,我不能接受这是唯一的解决方案:

train_test <- rbind(train,test)
train_test_dummy <- as.data.frame(model.matrix(~ v1 + v2 -1 , data=train_test, 
     contrasts.arg=list(v1=contrasts(train_test$v1, contrasts=F), 
          v2=contrasts(train_test$v2, contrasts=F))))

print(train_test_dummy)
v1a v1b v1c v2A v2B v2C
1   0   0   1   0   0
0   1   0   1   0   0
0   0   1   0   1   0
1   0   0   0   0   1
1   0   0   1   0   0

还有什么更好的吗?

这是duplicate,但未回答问题,所有其他问题仅解决从一个数据集中生成伪变量的问题。

1 个答案:

答案 0 :(得分:2)

如果您另外添加

levels(test$v1) <- levels(train$v1)
levels(test$v2) <- levels(train$v2)

或者,如果所有列都是因子,则在一行中

test[] <- Map(function(x, y) factor(x, level = levels(y)), test, train)

如果只有其中一些是因素,

test[] <- Map(function(x, y) if(is.factor(x)) factor(x, level = levels(y)) else x, test, train)

然后根据需要最终结果:

test_dummy
#   v1a v1b v1c v2A v2B v2C
# 1   1   0   0   1   0   0