Рассчитать процентную разницу строк в кадре данных для определенных значений в R - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть фрейм данных, который выглядит следующим образом:

Date       Type   Count
<date>     <fct>  <int>
1 2018-11-01 B      2
2 2018-11-01 A      4
3 2018-11-02 A      1
4 2018-11-03 A      4
5 2018-11-04 A      3
6 2018-11-05 A      2
7 2018-11-06 C      1
8 2018-11-06 A      1
9 2018-11-07 A      1

Для каждой даты в фрейме данных существует 3 возможных типа (A, B, C), которые могут существовать или не существовать (т. Е. Countможет быть 0).

Я хотел бы рассчитать дневную разницу в процентах между A и C для каждого дня:

т.е. (AC) / (A + B + C) * 100%

Например, для 2018-11-01 (A = 4, B = 2, C = 0) процентная разница должна быть: (4-0) / 6 * 100% = 66,7%

Получившийсятаблица должна быть:

Date          Count
<date>        <int>
1 2018-11-01    66.7%
2 2018-11-02   some %
3 2018-11-03   some %
4 2018-11-04   some %
5 2018-11-05   some %
6 2018-11-06   some %
7 2018-11-07   some %

Есть ли способ для меня рассчитать это (возможно, с использованием пакета dplyr) без необходимости циклически проходить через каждую дату, используя цикл for или foreach в R?

Я пытался сделать что-то вроде этого, но он не учитывает возможность того, что A, B и C имеют счетчик 0 (т.е. отсутствует в кадре данных):

abc %>% group_by(DATE) %>%
arrange(DATE) %>%
mutate(diff = n - lag(n, default = first(n)))

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

Для таких расчетов я предпочитаю изменить форму в широкую форму, чтобы иметь прямой доступ к столбцам, с которыми я беру различия, т. Е. Иметь столбцы A, B и C. Это немного более многословно, но дает мнеЛучше понять, что находится в моих данных.

Подобно ответу @Ronak Shah, я бы сначала использовал что-то вроде complete, чтобы заполнить любые пропущенные комбинации даты и типа.Я также суммирую подсчеты по группам, на случай, если есть несколько наблюдений любых комбинаций типа даты.

library(tidyverse)

df_complete <- df %>%
  group_by(Date, Type) %>%
  summarise(Count = sum(Count)) %>%
  ungroup() %>%
  complete(Date, Type, fill = list(Count = 0))

df_complete
#> # A tibble: 21 x 3
#>    Date       Type  Count
#>    <date>     <chr> <dbl>
#>  1 2018-11-01 A         4
#>  2 2018-11-01 B         2
#>  3 2018-11-01 C         0
#>  4 2018-11-02 A         1
#>  5 2018-11-02 B         0
#>  6 2018-11-02 C         0
#>  7 2018-11-03 A         4
#>  8 2018-11-03 B         0
#>  9 2018-11-03 C         0
#> 10 2018-11-04 A         3
#> # ... with 11 more rows

Затем, используя spread, я получаю столбцы для каждого типа, затем выполняюрасчет.Если вы хотите отформатировать в виде процентных строк, как в вашем примере, вы можете передать значения в scales::percent, что, например, отформатирует 0,75 как 75%.Затем вы можете отбросить столбцы, кроме даты и числа, или в более сложной ситуации вам может потребоваться дальнейшее изменение формы.

df_complete %>%
  spread(key = Type, value = Count) %>%
  mutate(Count = (A - C) / (A + B + C)) %>%
  mutate(Count = scales::percent(Count)) %>%
  select(Date, Count)
#> # A tibble: 7 x 2
#>   Date       Count
#>   <date>     <chr>
#> 1 2018-11-01 67%  
#> 2 2018-11-02 100% 
#> 3 2018-11-03 100% 
#> 4 2018-11-04 100% 
#> 5 2018-11-05 100% 
#> 6 2018-11-06 0%   
#> 7 2018-11-07 100%

Небольшой вариант заключается в использовании rowwise для группировки по каждой строке, что позволяет вамвызовите sum для столбцов типа.

df_complete %>%
  spread(key = Type, value = Count) %>%
  rowwise() %>%
  mutate(Count = (A - C) / sum(A, B, C)) %>%
  mutate(Count = scales::percent(Count)) %>%
  select(Date, Count)
#> Source: local data frame [7 x 2]
#> Groups: <by row>
#> 
#> # A tibble: 7 x 2
#>   Date       Count
#>   <date>     <chr>
#> 1 2018-11-01 66.7%
#> 2 2018-11-02 100% 
#> 3 2018-11-03 100% 
#> 4 2018-11-04 100% 
#> 5 2018-11-05 100% 
#> 6 2018-11-06 0%   
#> 7 2018-11-07 100%

Создано в 2018-11-28 пакетом Представить (v0.2.1)

0 голосов
/ 28 ноября 2018

Мы можем использовать complete, чтобы заполнить недостающие Type 0, используя fill = 0, а затем выполнить расчет.Это предполагает, что у вас есть максимум только одно значение на Date для «A», «B» и «C».

library(tidyverse)
df %>%
  group_by(Date) %>%
  complete(Type, fill = list(Count = 0)) %>%
  summarise(Count = (Count[Type == "A"] - Count[Type == "C"])/sum(Count))


#       Date   Count
#  <fct>       <dbl>
#1 2018-11-01  0.667
#2 2018-11-02  1    
#3 2018-11-03  1    
#4 2018-11-04  1    
#5 2018-11-05  1    
#6 2018-11-06  0    
#7 2018-11-07  1    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...