Суммируйте только некоторые уровни группы [dplyr] - PullRequest
0 голосов
/ 19 июня 2020

Я пытаюсь понять (с помощью dplyr), как суммировать только один уровень группирующей переменной, сохраняя все остальное неизменным. Например:

library(dplyr)

dat <- starwars %>% 
  select(height, hair_color) %>% 
  filter(!is.na(hair_color))

dat %>% 
  group_by(hair_color) %>% 
  summarise(mean_height = mean(height))
#> `summarise()` ungrouping output (override with `.groups` argument)
#> # A tibble: 12 x 2
#>    hair_color    mean_height
#>    <chr>               <dbl>
#>  1 auburn               150 
#>  2 auburn, grey         180 
#>  3 auburn, white        182 
#>  4 black                 NA 
#>  5 blond                177.
#>  6 blonde               168 
#>  7 brown                 NA 
#>  8 brown, grey          178 
#>  9 grey                 170 
#> 10 none                  NA 
#> 11 unknown               NA 
#> 12 white                156

будет суммировать каждый уровень hair_color. Но мой вопрос: что, если бы я хотел только суммировать светлые волосы, но оставил все остальные уровни hair_color?

Я вижу путь с split, как показано ниже:

dat_split <- dat %>% 
  mutate(is_blond = ifelse(hair_color %in% c("blond"), "blond", "not_blond")) %>% 
  split(.$is_blond)


d1 <- dat_split[["blond"]] %>% 
  group_by(hair_color) %>% 
  summarise(height = mean(height))
#> `summarise()` ungrouping output (override with `.groups` argument)

d2 <- dat_split[["not_blond"]] %>% 
  select(-is_blond)


dat_final <- bind_rows(d1, d2)
dat_final
#> # A tibble: 80 x 2
#>    hair_color    height
#>    <chr>          <dbl>
#>  1 blond           177.
#>  2 none            202 
#>  3 brown           150 
#>  4 brown, grey     178 
#>  5 brown           165 
#>  6 black           183 
#>  7 auburn, white   182 
#>  8 auburn, grey    180 
#>  9 brown           228 
#> 10 brown           180 
#> # ... with 70 more rows

Это, однако, кажется немного многословным (и неуклюжим). Мне интересно, подходит ли это rowwise, но я еще не решил это в своей голове.

Ответы [ 2 ]

1 голос
/ 19 июня 2020

Мы могли бы сделать это без группировки, replace добавив 'height', где 'hair_color' «блондин», до mean 'height' для соответствующего 'hair_color'

library(dplyr)
dat %>% 
    mutate(height = replace(height, 
          hair_color == 'blond', mean(height[hair_color == 'blond'])))
# A tibble: 82 x 2
#   height hair_color   
#    <dbl> <chr>        
# 1   177. blond        
# 2   202  none         
# 3   150  brown        
# 4   178  brown, grey  
# 5   165  brown        
# 6   183  black        
# 7   182  auburn, white
# 8   177. blond        
# 9   180  auburn, grey 
#10   228  brown        
# … with 72 more rows

Это было бы более компактно в data.table (если это столбец numeri c)

library(data.table)
setDT(dat)[hair_color == 'blond', height := mean(height)]
1 голос
/ 19 июня 2020

Вы можете попробовать

dat %>% 
  mutate(valid = hair_color == "blond") %>%
  group_by(valid) %>%
  mutate(mean_h = ifelse(valid, mean(height), height), .keep="unused") 

, что дает

# A tibble: 82 x 2
   hair_color    mean_h
   <chr>          <dbl>
 1 blond           177.
 2 none            202 
 3 brown           150 
 4 brown, grey     178 
 5 brown           165 
 6 black           183 
 7 auburn, white   182 
 8 blond           177.
 9 auburn, grey    180 
10 brown           228 
# ... with 72 more rows
...