Использование mutate в dplyr с условиями - PullRequest
0 голосов
/ 26 сентября 2019

Редактировать: Возврат к исходному тексту, на котором основаны ответы ниже.Спасибо всем за вашу помощь и извинения за то, что изменили вопрос после того, как все так любезно помогли мне.

У меня есть фрейм данных, который перечисляет людей, сколько выпитых напитков, какое положение они занимаюти имеют ли они право на новый напиток.

dat <- data.frame(person = c("bill", "hank", "susy", "cliff", "betty"),
           total = c(3, 4, 5, 7, 8),
           position = c(1, 5, 3, 2, 4),
           eligible = c(0, 0, 1, 1, 1))

Цель состоит в том, чтобы для любого, кто имеет право на новый напиток, мы должны добавить к их общему количеству напитков общее количество напитковчеловек один позади них в очереди (например, к общему количеству человека 4 мы добавляем общее количество напитков человека 5).Для тех, кто не имеет права на новый напиток, мы сохраняем их прежнюю сумму.Желаемый вывод выглядит следующим образом:

person   total   position   eligible   new_total
bill     3       1          0          3    
hank     4       5          0          4
susy     5       3          1          13   
cliff    7       2          1          12   
betty    8       4          1          12   

Кто-нибудь знает, как я могу сделать это, используя R и dplyr?

Спасибо!

Ответы [ 3 ]

2 голосов
/ 26 сентября 2019

Вы можете использовать mutate и ifelse.Это помогает отсортировать ваш список в первую очередь.

dat <- dat %>%
      arrange(position) %>%
      mutate(new_total = ifelse(eligible, total+lead(total), total)) %>%
      arrange(total)
1 голос
/ 26 сентября 2019

Допустимое значение уже равно 0/1, поэтому вы можете использовать это в своих интересах, просто умножив сумму для следующего лица на соответствие критериям (или, альтернативно, установив любое истинное / ложное условие, если оно не так просто):

dat %>% arrange(position) %>% 
 mutate(new_total=total+eligible*(lead(total,default=0)))
  person total position eligible new_total
1   bill     3        1        0         3
2  cliff     7        2        1        12
3   susy     5        3        1        13
4  betty     8        4        1        12
5   hank     4        5        0         4

Ради интереса я сравнил три решения (хотя при таком небольшом наборе данных это сравнение может быть неточным):

Unit: milliseconds
  expr      min       lq      mean   median        uq      max neval
   iod 2.485992 2.694608  3.535079 2.921297  3.347454 28.47935   100
 brian 3.700652 4.037115  4.759614 4.268713  4.973099 16.12168   100
 arkun(dplyr) 8.173740 9.117087 10.194020 9.715270 10.730906 17.32028   100
1 голос
/ 26 сентября 2019

Можно создать столбец последовательности с rn, arrange по 'position', а затем создать 'new_total', добавив 'total' с lead из 'total', когда eligibleравно 1 и переупорядочивается на основе ранее созданного столбца 'rn

library(dplyr)
dat %>% 
  mutate(rn = row_number())  %>%
  arrange(position) %>%  
  mutate(new_total = case_when(as.logical(eligible) ~
                  total + lead(total), TRUE ~ total)) %>% 
  arrange(rn) %>%
  select(-rn)
#   person total position eligible new_total
#1   bill     3        1        0         3
#2   hank     4        5        0         4
#3   susy     5        3        1        13
#4  cliff     7        2        1        12
#5  betty     8        4        1        12

или с использованием data.table

library(data.table)
setDT(dat)[order(position), new_total := total + shift(total, type = 'lead')
        ][eligible == 0, new_total := total][]
#   person total position eligible new_total
#1:   bill     3        1        0         3
#2:   hank     4        5        0         4
#3:   susy     5        3        1        13
#4:  cliff     7        2        1        12
#5:  betty     8        4        1        12
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...