使用dplyr

时间:2019-11-19 17:04:09

标签: r dplyr tidyr

我知道如何使用dplyr / tidyr有条件地替换变量的级别。这是一些玩具数据(真实的数据集更大而且更复杂):

dat <- data.frame(animal=c("cat", "cat", "dog", "cat"),
              size=c("big", "big", "big", "small"))

 newdata <- dat %>% mutate(newanimal=replace(animal, animal=='cat' & size=='big', "fatcat"))

我不断收到“无效的因子水平,NA生成的信息”-为什么?这些是因子变量,数据框中存在“猫”和“大”的特定组合。为什么会出现此错误?

3 个答案:

答案 0 :(得分:2)

正如@camille所提到的,一旦有了一个因素,它就会被锁定,如果您引入新的“条目”,它将变成NA。

例如:

x <- factor(letters[1:3])
x[3] = "d"
Warning message:
In `[<-.factor`(`*tmp*`, 3, value = "d") :
  invalid factor level, NA generated
x
[1] a    b    <NA>
Levels: a b c

摆脱这种情况的唯一方法是先将其转换为字符并替换:

newdata <- dat %>% mutate(newanimal=replace(as.character(animal), animal=='cat' & size=='big', "fatcat"))
newdata
  animal  size newanimal
1    cat   big    fatcat
2    cat   big    fatcat
3    dog   big       dog
4    cat small       cat

您的新列现在是一个字符,但是如果需要,您随时可以将其转换回一个因数。

str(newdata)
'data.frame':   4 obs. of  3 variables:
 $ animal   : Factor w/ 2 levels "cat","dog": 1 1 2 1
 $ size     : Factor w/ 2 levels "big","small": 1 1 1 2
 $ newanimal: chr  "fatcat" "fatcat" "dog" "cat"

答案 1 :(得分:1)

tidyverse中的另一种选择是使用forcats::fct_expand添加新级别,然后将此向量通过管道传递到原来的replace中,现在可以正常工作了。新变量是一个因数,不需要进一步转换(假设您所需的输出是一个因数)。

library(tidyverse)

dat <- dat %>% 
  mutate(newanimal = fct_expand(animal, "fatcat") %>% 
                     replace(., animal == "cat" & size == "big", "fatcat")
         ) 

glimpse(dat)
Observations: 4
Variables: 3
$ animal    <fct> cat, cat, dog, cat
$ size      <fct> big, big, big, small
$ newanimal <fct> fatcat, fatcat, dog, cat

如果您经常使用这种因子替换,则可以编写自己的辅助函数:

replace_fct <- function(x, list, values) {

  .x = forcats::fct_expand(x, unique(values))
  replace(.x, list, values)

}  

然后执行:

dat %>% 
  mutate(newanimal = replace_fct(animal, animal == "cat" & size == "big", "fatcat")
  ) 

答案 2 :(得分:0)

您可以尝试

library(tidyverse)

dat <- tibble(animal = c("cat","dog","cat","dog","dog","dog"), 
             size =  c("big", "small", "big", "big", "big","big"))

dat %>% mutate(new_animal = ifelse(animal=='cat' & size=='big','fatcat',animal) ) %>% 
  mutate_if(is.character, as.factor)