![](/img/trans.png)
[英]Using ordinal variables in rpart and caret without converting to dummy categorical variables
[英]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 對我的數據進行虛擬編碼,以便數據看起來或多或少像這樣。
# 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
解決方案。
我知道有幾種方法可以做到這一點,但沒有一個完全適合 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)
但這會打破我需要指定每個虛擬編碼 output 的工作流程規則。
我過去曾使用 model.matrix 完成此操作,來自stats
package。
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
這種嘗試會產生一個 tibble 列表,但排除的變量record
除外,並且我未能將它們全部組合回一個 tibble。 此外,我仍然必須指定每一列,總的來說它看起來很笨重。
有更好的想法嗎? 謝謝!!
model.matrix
的替代model.matrix
是使用軟件包recipes
。 這項工作仍在進行中,尚未包含在tidyverse中。 在某個時候它可能會/將被包含在tidyverse軟件包中 。
我將留給您閱讀食譜,但是在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.
如果你不想加載任何額外的包,你也可以像這樣使用 pivot_wider 語句:
tib %>%
mutate(dummy = 1) %>%
pivot_wider(names_from = gender, values_from = dummy, values_fill = 0) %>%
mutate(dummy = 1) %>%
pivot_wider(names_from = like_product, values_from = dummy, values_fill = 0, names_glue = "like_product_{like_product}")
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.