tidyverse r中的虚拟代码分类/序数变量

时间:2018-03-22 16:52:17

标签: r tidyverse purrr dummy-variable

假设我有一个小组。

library(tidyverse) 
tib <- as.tibble(list(record = c(1:10), 
                      gender = as.factor(sample(c("M", "F"), 10, replace = TRUE)), 
                      like_product = as.factor(sample(1:5, 10, replace = TRUE)))
tib

    # A tibble: 10 x 3
   record gender like_product
    <int> <fctr>       <fctr>
 1      1      F            2
 2      2      M            1
 3      3      M            2
 4      4      F            3
 5      5      F            4
 6      6      M            2
 7      7      F            4
 8      8      M            4
 9      9      F            4
10     10      M            5

我想用1和0编码我的数据代码,以便数据看起来更像/更少。

# A tibble: 10 x 8
   record gender_M gender_F like_product_1 like_product_2 like_product_3 like_product_4 like_product_5
    <int>    <dbl>    <dbl>          <dbl>          <dbl>          <dbl>          <dbl>          <dbl>
 1      1        0        1              0              0              1              0              0
 2      2        0        1              0              0              0              0              0
 3      3        0        1              0              1              0              0              0
 4      4        0        1              1              0              0              0              0
 5      5        1        0              0              0              0              0              0
 6      6        0        1              0              0              0              0              0
 7      7        0        1              0              0              0              0              0
 8      8        0        1              0              1              0              0              0
 9      9        1        0              0              0              0              0              0
10     10        1        0              0              0              0              0              1

我的工作流程要求我知道一系列变量到虚拟代码(即gender:like_product),但不想手动识别每个变量(可能有数百个变量)。同样,我不希望必须将每个变量的每个级别/唯一值标识为伪代码。我最终正在寻找tidyverse解决方案。

我知道有几种方法可以做到这一点,但是没有一种方法可以完美地适应整齐。我知道我可以使用mutate ......

tib %>%
     mutate(gender_M = ifelse(gender == "M", 1, 0), 
            gender_F = ifelse(gender == "F", 1, 0), 
            like_product_1 = ifelse(like_product == 1, 1, 0), 
            like_product_2 = ifelse(like_product == 2, 1, 0), 
            like_product_3 = ifelse(like_product == 3, 1, 0), 
            like_product_4 = ifelse(like_product == 4, 1, 0), 
            like_product_5 = ifelse(like_product == 5, 1, 0)) %>%
     select(-gender, -like_product)

但这会破坏我需要指定每个虚拟编码输出的工作流程规则。

我以前使用stats包中的model.matrix完成了这项工作。

model.matrix(~ gender + like_product, tib) 

简单明了,但我希望在tidyverse中找到解决方案。 编辑:原因是,我仍然必须指定每个变量,并且能够使用选择帮助程序来指定类似gender:like_product的内容将更受欢迎。

我认为解决方案在purrr

library(purrr)
dummy_code <- function(x) {
     lvls <- levels(x)
     sapply(lvls, function(y) as.integer(x == y)) %>% as.tibble
} 

tib %>%
     map_at(c("gender", "like_product"), dummy_code)

$record
 [1]  1  2  3  4  5  6  7  8  9 10

$gender
# A tibble: 10 x 2
       F     M
   <int> <int>
 1     1     0
 2     0     1
 3     0     1
 4     1     0
 5     1     0
 6     0     1
 7     1     0
 8     0     1
 9     1     0
10     0     1

$like_product
# A tibble: 10 x 5
     `1`   `2`   `3`   `4`   `5`
   <int> <int> <int> <int> <int>
 1     0     1     0     0     0
 2     1     0     0     0     0
 3     0     1     0     0     0
 4     0     0     1     0     0
 5     0     0     0     1     0
 6     0     1     0     0     0
 7     0     0     0     1     0
 8     0     0     0     1     0
 9     0     0     0     1     0
10     0     0     0     0     1

这个尝试会产生一个包含排序变量record的异常列表,而且我将它们全部组合成一个单独的tibble是不成功的。此外,我仍然需要指定每一列,总体来说它看起来很笨重。

有更好的想法吗?谢谢!

1 个答案:

答案 0 :(得分:3)

model.matrix的替代方法是使用包recipes。这仍然是一项正在进行中的工作,尚未包括在tidyverse中。在某些时候,它可能/将被包含在tidyverse packages中。

我会留给您阅读食谱,但在步骤step_dummy中,您可以使用tidyselect包中的特殊选择器(与recipes一起安装),例如选择器您可以在dplyr中使用starts_with()。我创建了一个小例子来展示步骤。

以下示例代码。

但如果这更方便,我会留下你,因为评论中已经指出了这一点。函数bake()使用model.matrix来创建假人。差异主要在于列名,当然也包括在所有单独步骤的基础代码中进行的内部检查。

library(recipes)
library(tibble)

tib <- as.tibble(list(record = c(1:10), 
                      gender = as.factor(sample(c("M", "F"), 10, replace = TRUE)), 
                      like_product = as.factor(sample(1:5, 10, replace = TRUE))))

dum <- tib %>% 
  recipe(~ .) %>% 
  step_dummy(gender, like_product) %>% 
  prep(training = tib) %>% 
  bake(newdata = tib)

dum

# A tibble: 10 x 6
   record gender_M like_product_X2 like_product_X3 like_product_X4 like_product_X5
    <int>    <dbl>           <dbl>           <dbl>           <dbl>           <dbl>
 1      1       1.              1.              0.              0.              0.
 2      2       1.              1.              0.              0.              0.
 3      3       1.              1.              0.              0.              0.
 4      4       0.              0.              1.              0.              0.
 5      5       0.              0.              0.              0.              0.
 6      6       0.              1.              0.              0.              0.
 7      7       0.              1.              0.              0.              0.
 8      8       0.              0.              0.              1.              0.
 9      9       0.              0.              0.              0.              1.
10     10       1.              0.              0.              0.              0.