首页 > 解决方案 > 汇总时处理可能丢失的列的最佳方法是什么?

问题描述

财务报表很好地说明了这个问题。这是一个示例数据框:

df <- data.frame(   date = sample(seq(as.Date('2020/01/01'), as.Date('2020/12/31'), by="day"), 10),
                    category = sample(c('a','b', 'c'), 10, replace=TRUE),
                    direction = sample(c('credit', 'debit'), 10, replace=TRUE),
                    value = sample(0:25, 10, replace = TRUE) )

我想为每个类别生成一个包含incoming,outgoing和列的汇总表。total

df %>% 
    pivot_wider(names_from = direction, values_from = value) %>% 
    group_by(category) %>% 
    summarize(incoming = sum(credit, na.rm=TRUE), outgoing=sum(debit,na.rm=TRUE) ) %>% 
    mutate(total= incoming-outgoing)

在大多数情况下,这与上面的示例数据框完美配合。

但在某些情况下,df$direction可能包含单个值,例如credit,从而导致错误。

Error: Problem with `summarise()` column `outgoing`.
object 'debit' not found

鉴于我无法控制数据框,处理此问题的最佳方法是什么?

我一直在使用 summarise 方法中的条件语句来检查列是否存在,但没有设法让它工作。

...
summarize( outgoing = case_when(
    "debit" %in% colnames(.) ~ sum(debit,na.rm=TRUE), 
    TRUE ~ 0 ) )
...

我是否犯了语法错误,或者我的方向完全错误?

标签: rdplyr

解决方案


只有当其中一个元素出现时,即“贷方”而没有“借方”或反之亦然,才会出现此问题。然后,pivot_wider不会创建缺少的列。而不是旋转然后汇总,而是直接使用summariseand执行此操作,==即如果“借方”不存在,sum将通过返回 0 来处理它

library(dplyr)
df %>%  
   slice(-c(9:10)) %>% # just removed the 'debit' rows completely
   group_by(category) %>% 
   summarise(total  = sum(value[direction == 'credit']) - 
          sum(value[direction == "debit"])) 

-输出

# A tibble: 3 × 2
  category total
  <chr>    <int>
1 a           15
2 b           30
3 c           63

pivot_wider情况并非如此

df %>% 
      slice(-c(9:10)) %>%
     pivot_wider(names_from = direction, values_from = value) 
# A tibble: 8 × 3
  date       category credit
  <date>     <chr>     <int>
1 2020-07-25 c            19
2 2020-05-09 b            15
3 2020-08-27 a            15
4 2020-03-27 b            15
5 2020-04-06 c             6
6 2020-07-06 c            11
7 2020-09-22 c            25
8 2020-10-06 c             2

它只创建“贷方”列,因此当我们调用未创建的“借方”列时,它会引发错误

 df %>% 
      slice(-c(9:10)) %>%
      pivot_wider(names_from = direction, values_from = value)  %>%
      group_by(category) %>% 
      summarize(incoming = sum(credit, na.rm=TRUE), 
           outgoing=sum(debit,na.rm=TRUE) )

错误:summarise()列有问题outgoing。ℹ outgoing = sum(debit, na.rm = TRUE)。✖ 未找到对象“借方”ℹ 组 1 中发生错误:类别 =“a”。运行rlang::last_error()以查看错误发生的位置。

在这种情况下,我们可以complete创建一些行,这些行debit也将NA用于其他列

library(tidyr)
df %>% 
   slice(-c(9:10)) %>%
   complete(category, direction = c("credit", "debit")) %>% 
   pivot_wider(names_from = direction, values_from = value) %>% 
   group_by(category) %>% 
   summarize(incoming = sum(credit, na.rm=TRUE), 
        outgoing=sum(debit,na.rm=TRUE) ) %>% 
   mutate(total= incoming-outgoing)
# A tibble: 3 × 4
  category incoming outgoing total
  <chr>       <int>    <int> <int>
1 a              15        0    15
2 b              30        0    30
3 c              63        0    63

推荐阅读