Создайте новый столбец, который ищет значения в других столбцах

#r #dplyr

#r #dplyr

Вопрос:

У меня есть следующие данные:

 df <- data.frame(a=c(0,0,0,1,1,1),
                 b=c(1,2,3,1,2,3), 
                 c=c("a","b","c","x","y","z"),
                 stringsAsFactors = FALSE) 

df

#>   a b c
#> 1 0 1 a
#> 2 0 2 b
#> 3 0 3 c
#> 4 1 1 x
#> 5 1 2 y
#> 6 1 3 z
  

Я хотел бы создать 4-й столбец «d», который возвращает значение из «c», где «a» = 0 и b = b, вот так:

 #>   a b c d
#> 1 0 1 a a
#> 2 0 2 b b
#> 3 0 3 c c
#> 4 1 1 x a
#> 5 1 2 y b
#> 6 1 3 z c
  

Я пытался:

 df %>% mutate(d = c[a==0 amp; b==b])
  

Но это не работает.

Как я могу создать столбец «d» с помощью dplyr?

Комментарии:

1. b == b Это опечатка?

2. b = b всегда будет TRUE , поэтому вы можете исключить это условие, если это так. Также вы сказали b = b amp; a = 0 , но в вашем примере вы все еще предоставляете значения для столбца, d где a != 0 . Можете ли вы объяснить это подробнее?

3. Итак, для строки # 4 я хочу вернуть значение из «c», где a== 0 и b ==1 («a»). Для строки # 5 я хочу вернуть значение из «c», где a== 0 и b ==2 («b»). И для строки # 6 я хочу вернуть значение из «c», где a== 0 и b ==3 («c»).

Ответ №1:

dplyr решение:

 df1 <-  df[df$a == 0,-1]
inner_join(df, df1, by = "b")

#   a b c.x c.y
# 1 0 1   a   a
# 2 0 2   b   b
# 3 0 3   c   c
# 4 1 1   x   a
# 5 1 2   y   b
# 6 1 3   z   c
  

Комментарии:

1. Базовый вариант R для этого является merge(df, df[df$a == 0, c("b","c")], by="b") или с переименованием merge(df, transform(df[df$a==0,], d=c)[c("b","d")], by="b")

Ответ №2:

С помощью base R вы можете сделать следующее.

 inx <- match(df$b, df$b[df$a == 0])
df$d <- df$c[inx]

df
#  a b c d
#1 0 1 a a
#2 0 2 b b
#3 0 3 c c
#4 1 1 x a
#5 1 2 y b
#6 1 3 z c
  

Ответ №3:

Единственная tidyverse возможность может быть:

 df %>%
 mutate(d = ifelse(a == 0, c, NA_character_)) %>%
 group_by(b) %>%
 fill(d)

      a     b c     d    
  <dbl> <dbl> <chr> <chr>
1     0     1 a     a    
2     1     1 x     a    
3     0     2 b     b    
4     1     2 y     b    
5     0     3 c     c    
6     1     3 z     c  
  

Вы также можете упорядочить его:

 df %>%
 mutate(d = ifelse(a == 0, c, NA_character_)) %>%
 group_by(b) %>%
 fill(d) %>%
 arrange(a, b, c)

      a     b c     d    
  <dbl> <dbl> <chr> <chr>
1     0     1 a     a    
2     0     2 b     b    
3     0     3 c     c    
4     1     1 x     a    
5     1     2 y     b    
6     1     3 z     c 
  

Чтобы справиться со сценариями, упомянутыми @divibisan, вы можете сделать:

 df %>%
 mutate(d = ifelse(a == 0, c, NA_character_)) %>%
 group_by(b) %>%
 fill(d, .direction = "up") %>%
 fill(d, .direction = "down") %>%
 arrange(a, b, c)
  

Комментарии:

1. Умное решение! Одна из проблем заключается в том, что для fill правильного поведения строка, отличная от NA (где a ==0 ), должна быть первой (попробуйте сделать это на df2 <- df[6:1,] ).

2. Спасибо — но по какой-то причине вывод столбца d является числовым, где a = 1, b = 2 и c = 3. Есть идеи?

3. @Rez99 Потому что столбец c на самом деле является фактором, а не символом. Вы можете исправить это с помощью as.character или использовать stringsAsFactor=F аргумент при создании фрейма данных

4. @divibisan обновил сообщение, спасибо, что заметили это 🙂