tidyverse r 中的虚拟代码分类/有序变量
Dummy code categorical / ordinal variables in the tidyverse r
假设我有一个问题。
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 对我的数据进行虚拟编码,以便数据看起来 more/less 像这样。
# 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
),但不想手动识别每个变量(可能有数百个变量)。同样,我不想将每个变量的每个 level/unique 值都标识为虚拟代码。我最终正在寻找 tidyverse
解决方案。
我知道有几种方法可以做到这一点,但其中 none 非常适合 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)
但这会破坏我需要指定每个虚拟编码输出的工作流程规则。
我过去曾使用 model.matrix 从 stats
包中完成此操作。
model.matrix(~ gender + like_product, tib)
简单明了,但我想要 tidyverse 中的解决方案。 编辑: 原因是,我仍然必须指定每个变量,并且能够使用 select 助手来指定 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
此尝试生成了一个 tibbles 列表,排除的变量 record
除外,但我未能将它们全部组合回一个 tibble。此外,我仍然必须指定每一列,总的来说它看起来很笨重。
有什么更好的主意吗?谢谢!!
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.
假设我有一个问题。
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 对我的数据进行虚拟编码,以便数据看起来 more/less 像这样。
# 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
),但不想手动识别每个变量(可能有数百个变量)。同样,我不想将每个变量的每个 level/unique 值都标识为虚拟代码。我最终正在寻找 tidyverse
解决方案。
我知道有几种方法可以做到这一点,但其中 none 非常适合 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)
但这会破坏我需要指定每个虚拟编码输出的工作流程规则。
我过去曾使用 model.matrix 从 stats
包中完成此操作。
model.matrix(~ gender + like_product, tib)
简单明了,但我想要 tidyverse 中的解决方案。 编辑: 原因是,我仍然必须指定每个变量,并且能够使用 select 助手来指定 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
此尝试生成了一个 tibbles 列表,排除的变量 record
除外,但我未能将它们全部组合回一个 tibble。此外,我仍然必须指定每一列,总的来说它看起来很笨重。
有什么更好的主意吗?谢谢!!
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.