问题描述
我正在寻找一种简洁的解决方案,最好使用dplyr
来清理dataframe列中的值,以便我可以保留它们,因为它们是与某个特定集合匹配的值,而其他与那些不匹配的值匹配将被重新编码为“其他”。
示例
我有一个带有动物名字的数据框。有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
来使其更简单/简洁吗?
解决方法
您可以照原样保留所需的动物,然后将其余的动物变成"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','cat')
within(df,animals[!animals %in% keep_names] <- "other")
带有dplyr
的{{1}}选项:
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)
。
我知道您最好要求使用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","cat")
df[!animals %in% keep_names,animals := "other"]