如何重新编码数据帧值以仅保留满足特定集合的值,将其他值替换为 "other"
How to recode dataframe values to keep only those that satisfy a certain set, replace others with "other"
我正在寻找一个简洁的解决方案,最好是使用 dplyr
来清理数据框列中的值,这样我就可以保留它们匹配特定集合的值,但其他不匹配的值t 匹配将被重新编码为“其他”。
例子
我有一个包含动物名称的数据框。有 4 个合法的动物名称,但其他行包含乱码而不是名称。我想清理该列,只保留合法的动物名称:zebra
、lion
、cow
或 cat
.
数据
library(tidyverse)
library(stringi)
real_animals_names <- sample(c("zebra", "cow", "lion", "cat"), size = 50, replace = TRUE)
gibberish <- do.call(paste0, Map(stri_rand_strings, n = 50, length=c(5, 4, 1),
pattern = c('[a-z]', '[0-9]', '[A-Z]')))
df <- tibble(animals = sample(c(animals, gibberish)))
> df
## # A tibble: 100 x 1
## animals
## <chr>
## 1 zebra
## 2 zebra
## 3 rbzal0677O
## 4 lion
## 5 cat
## 6 cfsgt0504G
## 7 cat
## 8 jhixe2566V
## 9 lion
## 10 zebra
## # ... with 90 more rows
解决问题的一种方法 -- 我觉得很烦人而且不简洁
使用 dplyr 1.0.2
df %>%
mutate(across(animals, recode,
"lion" = "lion",
"zebra" = "zebra",
"cow" = "cow",
"cat" = "cat",
.default = "other"))
这就完成了,但是这段代码重复了每个动物的名字两次,我觉得它很笨拙。有没有更清洁的解决方案,最好使用 dplyr
?
编辑下面给出的建议答案
因为我喜欢 dplyr::recode
的可读性,但不喜欢每个动物的名字重复两次;由于下面的答案使用 %in%
– 我可以将 %in%
合并到我自己的 recode
解决方案中以使其 simpler/more 简洁吗?
你可以保留你需要的动物,把剩下的变成"Others"
:
library(dplyr)
keep_names <- c('lion', 'zebra', 'cow', 'cat')
df %>% mutate(animals = ifelse(animals %in% keep_names, animals, 'Others'))
一个base
解决方案:
keep_names <- c('lion', 'zebra', 'cow', 'cat')
within(df, animals[!animals %in% keep_names] <- "other")
dplyr
选项 replace()
:
library(tidyverse)
df %>%
mutate(animals = replace(animals, !animals %in% keep_names, "other"))
使用recode()
,可以使用命名字符向量与!!!
进行反引号拼接。
df %>%
mutate(animals = recode(animals, !!!set_names(keep_names), .default = "other"))
注: set_names(keep_names)
等同于setNames(keep_names, keep_names)
.
我知道你更喜欢 dplyr 解决方案,但这里是 data.table
解决方案(请注意,我将 tibble()
调用更改为 data.table()
):
library(stringi)
library(data.table)
real_animals_names <- sample(c("zebra", "cow", "lion", "cat"), size = 50, replace = TRUE)
gibberish <- do.call(paste0, Map(stri_rand_strings, n = 50, length=c(5, 4, 1),
pattern = c('[a-z]', '[0-9]', '[A-Z]')))
df <- data.table(animals = sample(c(real_animals_names, gibberish)))
keep_names <- c("lion", "zebra", "cow", "cat")
df[!animals %in% keep_names, animals := "other"]
我正在寻找一个简洁的解决方案,最好是使用 dplyr
来清理数据框列中的值,这样我就可以保留它们匹配特定集合的值,但其他不匹配的值t 匹配将被重新编码为“其他”。
例子
我有一个包含动物名称的数据框。有 4 个合法的动物名称,但其他行包含乱码而不是名称。我想清理该列,只保留合法的动物名称:zebra
、lion
、cow
或 cat
.
数据
library(tidyverse)
library(stringi)
real_animals_names <- sample(c("zebra", "cow", "lion", "cat"), size = 50, replace = TRUE)
gibberish <- do.call(paste0, Map(stri_rand_strings, n = 50, length=c(5, 4, 1),
pattern = c('[a-z]', '[0-9]', '[A-Z]')))
df <- tibble(animals = sample(c(animals, gibberish)))
> df
## # A tibble: 100 x 1
## animals
## <chr>
## 1 zebra
## 2 zebra
## 3 rbzal0677O
## 4 lion
## 5 cat
## 6 cfsgt0504G
## 7 cat
## 8 jhixe2566V
## 9 lion
## 10 zebra
## # ... with 90 more rows
解决问题的一种方法 -- 我觉得很烦人而且不简洁
使用 dplyr 1.0.2
df %>%
mutate(across(animals, recode,
"lion" = "lion",
"zebra" = "zebra",
"cow" = "cow",
"cat" = "cat",
.default = "other"))
这就完成了,但是这段代码重复了每个动物的名字两次,我觉得它很笨拙。有没有更清洁的解决方案,最好使用 dplyr
?
编辑下面给出的建议答案
因为我喜欢 dplyr::recode
的可读性,但不喜欢每个动物的名字重复两次;由于下面的答案使用 %in%
– 我可以将 %in%
合并到我自己的 recode
解决方案中以使其 simpler/more 简洁吗?
你可以保留你需要的动物,把剩下的变成"Others"
:
library(dplyr)
keep_names <- c('lion', 'zebra', 'cow', 'cat')
df %>% mutate(animals = ifelse(animals %in% keep_names, animals, 'Others'))
一个base
解决方案:
keep_names <- c('lion', 'zebra', 'cow', 'cat')
within(df, animals[!animals %in% keep_names] <- "other")
dplyr
选项 replace()
:
library(tidyverse)
df %>%
mutate(animals = replace(animals, !animals %in% keep_names, "other"))
使用recode()
,可以使用命名字符向量与!!!
进行反引号拼接。
df %>%
mutate(animals = recode(animals, !!!set_names(keep_names), .default = "other"))
注: set_names(keep_names)
等同于setNames(keep_names, keep_names)
.
我知道你更喜欢 dplyr 解决方案,但这里是 data.table
解决方案(请注意,我将 tibble()
调用更改为 data.table()
):
library(stringi)
library(data.table)
real_animals_names <- sample(c("zebra", "cow", "lion", "cat"), size = 50, replace = TRUE)
gibberish <- do.call(paste0, Map(stri_rand_strings, n = 50, length=c(5, 4, 1),
pattern = c('[a-z]', '[0-9]', '[A-Z]')))
df <- data.table(animals = sample(c(real_animals_names, gibberish)))
keep_names <- c("lion", "zebra", "cow", "cat")
df[!animals %in% keep_names, animals := "other"]