dplyr:使用 TRUE 和 FALSE 将具有 3 个级别的因子列突变为 3 个逻辑列
dplyr: mutate a factor column with 3 levels to 3 logical columns with TRUE and FALSE
在 Iris 数据集中,Species 是一个具有 3 个水平的因子变量(“setosa”“versicolor”“virginica”)。
我想创建另外 3 个名为 ("setosa" "versicolor" "virginica") 的列,并将 False 和 True 作为每列的逻辑因子变量。
简而言之:我想将 Iris 数据集中变量 Species 的级别二分为 3 个新列作为逻辑变量。我的代码有效,但我想知道是否有更直接的方法:
df <- iris %>%
select(Species) %>%
mutate(setosa = case_when(Species=="setosa" ~ 1,
TRUE ~ 0),
versicolor = case_when(Species=="versicolor" ~ 1,
TRUE ~ 0),
virginica = case_when(Species=="virginica" ~ 1,
TRUE ~ 0),
)
df$setosa <- as.logical(df$setosa)
df$versicolor <- as.logical(df$versicolor)
df$virginica <- as.logical(df$virginica)
尝试直接为 Species
创建一个逻辑变量以及一个副本,然后使用 tidyverse
函数重塑为宽变量。您的行还需要一个 id
变量。这里的代码:
library(dplyr)
library(tidyr)
#Data
data(iris)
#Code
df <- iris %>% mutate(id=row_number(),Species2=Species) %>%
select(c(id,Species,Species2)) %>%
mutate(Value=T) %>%
pivot_wider(names_from = Species2,values_from=Value,values_fill=F) %>%
select(-id)
输出:
# A tibble: 150 x 4
Species setosa versicolor virginica
<fct> <lgl> <lgl> <lgl>
1 setosa TRUE FALSE FALSE
2 setosa TRUE FALSE FALSE
3 setosa TRUE FALSE FALSE
4 setosa TRUE FALSE FALSE
5 setosa TRUE FALSE FALSE
6 setosa TRUE FALSE FALSE
7 setosa TRUE FALSE FALSE
8 setosa TRUE FALSE FALSE
9 setosa TRUE FALSE FALSE
10 setosa TRUE FALSE FALSE
# ... with 140 more rows
使用其中任何一个:
iris %>% cbind(sapply(levels(.$Species), `==`, .$Species))
iris %>% cbind(model.matrix(~ Species + 0, .) == 1)
iris %>% cbind(outer(.$Species, setNames(levels(.$Species), levels(.$Species)), "=="))
expand_factor <- function(f) {
m <- matrix(0, length(f), nlevels(f), dimnames = list(NULL, levels(f)))
replace(m, cbind(seq_along(f), f), 1)
}
iris %>% cbind(expand_factor(.$Species) == 1)
library(nnet)
iris %>% cbind(class.ind(.$Species) == 1)
这是另一种 tidyverse 方式。我觉得它很乏味,个人不会将它用于任何像你的例子一样简单的事情,但它对更复杂的应用程序很有用。例如,如果您是“one hot”编码多个变量,出于某种原因,将单个变量全部存储在一列中可能会很好。然后你可以提取它,而不必不断地为不同的变量获取不同数量的列。
这利用了将 list()
存储在 tibble
中的能力,然后将其取消嵌套到列中。
library(purrr)
library(dplyr)
library(tidyr)
iris %>%
mutate(species_one_hot = map(Species, ~ set_names(levels(Species) == .x, levels(Species)))) %>%
unnest_wider(species_one_hot)
您可以通过以下方式提前停止一个步骤,以便仅存储编码以备后用。
iris2 <- iris %>%
mutate(species_one_hot = map(Species, ~ set_names(levels(Species) == .x, levels(Species))))
# now you can grab a single column and have the full encoding
bind_rows(iris2$species_one_hot)
在 Iris 数据集中,Species 是一个具有 3 个水平的因子变量(“setosa”“versicolor”“virginica”)。 我想创建另外 3 个名为 ("setosa" "versicolor" "virginica") 的列,并将 False 和 True 作为每列的逻辑因子变量。 简而言之:我想将 Iris 数据集中变量 Species 的级别二分为 3 个新列作为逻辑变量。我的代码有效,但我想知道是否有更直接的方法:
df <- iris %>%
select(Species) %>%
mutate(setosa = case_when(Species=="setosa" ~ 1,
TRUE ~ 0),
versicolor = case_when(Species=="versicolor" ~ 1,
TRUE ~ 0),
virginica = case_when(Species=="virginica" ~ 1,
TRUE ~ 0),
)
df$setosa <- as.logical(df$setosa)
df$versicolor <- as.logical(df$versicolor)
df$virginica <- as.logical(df$virginica)
尝试直接为 Species
创建一个逻辑变量以及一个副本,然后使用 tidyverse
函数重塑为宽变量。您的行还需要一个 id
变量。这里的代码:
library(dplyr)
library(tidyr)
#Data
data(iris)
#Code
df <- iris %>% mutate(id=row_number(),Species2=Species) %>%
select(c(id,Species,Species2)) %>%
mutate(Value=T) %>%
pivot_wider(names_from = Species2,values_from=Value,values_fill=F) %>%
select(-id)
输出:
# A tibble: 150 x 4
Species setosa versicolor virginica
<fct> <lgl> <lgl> <lgl>
1 setosa TRUE FALSE FALSE
2 setosa TRUE FALSE FALSE
3 setosa TRUE FALSE FALSE
4 setosa TRUE FALSE FALSE
5 setosa TRUE FALSE FALSE
6 setosa TRUE FALSE FALSE
7 setosa TRUE FALSE FALSE
8 setosa TRUE FALSE FALSE
9 setosa TRUE FALSE FALSE
10 setosa TRUE FALSE FALSE
# ... with 140 more rows
使用其中任何一个:
iris %>% cbind(sapply(levels(.$Species), `==`, .$Species))
iris %>% cbind(model.matrix(~ Species + 0, .) == 1)
iris %>% cbind(outer(.$Species, setNames(levels(.$Species), levels(.$Species)), "=="))
expand_factor <- function(f) {
m <- matrix(0, length(f), nlevels(f), dimnames = list(NULL, levels(f)))
replace(m, cbind(seq_along(f), f), 1)
}
iris %>% cbind(expand_factor(.$Species) == 1)
library(nnet)
iris %>% cbind(class.ind(.$Species) == 1)
这是另一种 tidyverse 方式。我觉得它很乏味,个人不会将它用于任何像你的例子一样简单的事情,但它对更复杂的应用程序很有用。例如,如果您是“one hot”编码多个变量,出于某种原因,将单个变量全部存储在一列中可能会很好。然后你可以提取它,而不必不断地为不同的变量获取不同数量的列。
这利用了将 list()
存储在 tibble
中的能力,然后将其取消嵌套到列中。
library(purrr)
library(dplyr)
library(tidyr)
iris %>%
mutate(species_one_hot = map(Species, ~ set_names(levels(Species) == .x, levels(Species)))) %>%
unnest_wider(species_one_hot)
您可以通过以下方式提前停止一个步骤,以便仅存储编码以备后用。
iris2 <- iris %>%
mutate(species_one_hot = map(Species, ~ set_names(levels(Species) == .x, levels(Species))))
# now you can grab a single column and have the full encoding
bind_rows(iris2$species_one_hot)