计算R中某些值在数据框中的行百分比差异

时间:2018-11-28 15:04:08

标签: r dplyr

我有一个看起来像这样的数据框:

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之间的每日百分比差异:

即(A-C)/(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包)而不必使用R中的for或foreach循环遍历每个日期?

我试图做这样的事情,但是它没有考虑到A,B和C的计数为0(即数据帧中缺失)的可能性:

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

2 个答案:

答案 0 :(得分:1)

我们可以使用complete使用Typefill = 0用0填充丢失的Date,然后执行计算。假设每个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 的“ A”,“ B”和“ C”最多只有一个值。

instanceof

答案 1 :(得分:1)

对于这样的计算,我更喜欢将形状重塑为宽的形状,这样我就可以直接访问我要区别的列,即具有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%

reprex package(v0.2.1)于2018-11-28创建