ifelse 语句中的 sum() 条件

sum() condition in ifelse statement

这个问题与这个问题相关

基本上重复的地方都有编号。例如两次重复:1,2;三次重复:1、2、3 等...但是如果该值是唯一的(只有一次),它应该不是 1,而是 NA

数据:(来自akrun,非常感谢!)

df1 <- structure(list(Fullname = c("Peter", "Peter", "Alison", "Warren", 
                                   "Jack", "Jack", "Jack", "Jack", "Susan", "Susan", "Henry", "Walison", 
                                   "Tinder", "Peter", "Henry", "Tinder")), row.names = c(NA, -16L
                                   ), class = "data.frame")

我的解决方案是这样的:

df1 %>% 
  group_by(Fullname) %>% 
  mutate(newcol = seq_along(Fullname)) 

  Fullname newcol
   <chr>     <int>
 1 Peter         1
 2 Peter         2
 3 Alison        1
 4 Warren        1
 5 Jack          1
 6 Jack          2
 7 Jack          3
 8 Jack          4
 9 Susan         1
10 Susan         2
11 Henry         1
12 Walison       1
13 Tinder        1
14 Peter         3
15 Henry         2
16 Tinder        2

现在我尝试将出现一次的每个值(例如 Alison、Warren 和 Henry)设置为 NA,就像 akrun 在这里所做的那样

我的代码带有一个 ifelse 语句,用于检查组的总和是否 >1。

df1 %>% 
  group_by(Fullname) %>% 
  mutate(newcol = seq_along(Fullname)) %>% 
  mutate(newcol = ifelse(sum(newcol)>1, newcol, NA))

但我得到:

 Fullname newcol
   <chr>     <int>
 1 Peter         1
 2 Peter         1
 3 Alison       NA
 4 Warren       NA
 5 Jack          1
 6 Jack          1
 7 Jack          1
 8 Jack          1
 9 Susan         1
10 Susan         1
11 Henry         1
12 Walison      NA
13 Tinder        1
14 Peter         1
15 Henry         1
16 Tinder        1

我不明白为什么?

我们在这里需要 if/else 而不是 ifelse 因为 ifelse 要求所有参数的长度相同, sum returns 一个值,如果它为TRUE,则全部变为TRUE

library(dplyr)
df1 %>% 
  group_by(Fullname) %>% 
  mutate(newcol = row_number(), 
       newcol = if(sum(newcol)> 1) newcol else NA) %>%
  ungroup

-输出

# A tibble: 16 × 2
   Fullname newcol
   <chr>     <int>
 1 Peter         1
 2 Peter         2
 3 Alison       NA
 4 Warren       NA
 5 Jack          1
 6 Jack          2
 7 Jack          3
 8 Jack          4
 9 Susan         1
10 Susan         2
11 Henry         1
12 Walison      NA
13 Tinder        1
14 Peter         3
15 Henry         2
16 Tinder        2

现在,我们来看这个问题。 'newcol2' 值是单个 TRUE/FALSE 的回收值。在 ifelse 中,由于所有参数的长度都需要相同,因此逻辑部分的长度仅为 1。

df1 %>% 
   group_by(Fullname) %>% 
   mutate(newcol = row_number(), newcol2 = sum(newcol) > 1)
# A tibble: 16 × 3
# Groups:   Fullname [8]
   Fullname newcol newcol2
   <chr>     <int> <lgl>  
 1 Peter         1 TRUE   
 2 Peter         2 TRUE   
 3 Alison        1 FALSE  
 4 Warren        1 FALSE  
 5 Jack          1 TRUE   
 6 Jack          2 TRUE   
 7 Jack          3 TRUE   
 8 Jack          4 TRUE   
 9 Susan         1 TRUE   
10 Susan         2 TRUE   
11 Henry         1 TRUE   
12 Walison       1 FALSE  
13 Tinder        1 TRUE   
14 Peter         3 TRUE   
15 Henry         2 TRUE   
16 Tinder        2 TRUE  

解决方法是rep尽量使长度相同

df1 %>% 
  group_by(Fullname) %>% 
  mutate(newcol = seq_along(Fullname)) %>% 
  mutate(newcol = ifelse(rep(sum(newcol)>1, n()), newcol, NA))
# A tibble: 16 × 2
# Groups:   Fullname [8]
   Fullname newcol
   <chr>     <int>
 1 Peter         1
 2 Peter         2
 3 Alison       NA
 4 Warren       NA
 5 Jack          1
 6 Jack          2
 7 Jack          3
 8 Jack          4
 9 Susan         1
10 Susan         2
11 Henry         1
12 Walison      NA
13 Tinder        1
14 Peter         3
15 Henry         2
16 Tinder        2

为了更好的理解,就拿一个简单的向量来说吧

> v1 <- c(1:5)
> sum(v1) > 4
[1] TRUE
> ifelse(sum(v1) > 4, v1, NA)
[1] 1

这里的sum是15,肯定大于4。一找到TRUE,就returns向量的第一个元素,即1和停止。在 %>% 中,这也是正在发生的事情,但是因为有循环,所以 1 会重复填充整个组

前提是您已经了解错误发生的原因。但是,我认为 sum 不是在这里使用的正确函数。是的,你可以让它工作,但它看起来很复杂。您可以使用 n() 获取组中的行数并使用 if 条件检查它。

library(dplyr)

df1 %>%
  group_by(Fullname) %>%
  mutate(newcol = if(n() == 1) NA else row_number()) %>%
  ungroup

# Fullname newcol
#   <chr>     <int>
# 1 Peter         1
# 2 Peter         2
# 3 Alison       NA
# 4 Warren       NA
# 5 Jack          1
# 6 Jack          2
# 7 Jack          3
# 8 Jack          4
# 9 Susan         1
#10 Susan         2
#11 Henry         1
#12 Walison      NA
#13 Tinder        1
#14 Peter         3
#15 Henry         2
#16 Tinder        2