如何将分层范围扩展到数据框中的最大值之外?

How to extend the range of stratification beyond the maximum value in a data frame?

假设我们从以下数据框开始,其下方有生成代码:

> stratData
  ID  Period Values
1  1 2020-03     -5
2  1 2020-04     25
3  2 2020-01     35
4  2 2020-02     45
5  2 2020-03     55
6  2 2020-04     87
7  3 2020-02     10
8  3 2020-03     20
9  3 2020-04     30

stratData <- 
   data.frame(
     ID = c(1,1,2,2,2,2,3,3,3),
     Period = c("2020-03", "2020-04", "2020-01", "2020-02", "2020-03", "2020-04", "2020-02", "2020-03", "2020-04"),
     Values = c(-5, 25, 35, 45, 55, 87, 10, 20, 30)
     )

我有一个闪亮的应用程序,它允许用户根据不同的标准(包括分层带的大小)对数据框中的某些值进行分层。底部是分层 MWE 代码。我遇到的问题是分层范围没有正确标记范围内的最大值。如下所示,最大范围显示 NA,而不是正确的 (85,90] 以包含来自 stratData 数据框的最大值。如何解决这个问题?

# A tibble: 7 x 5
  Range   Count Values Count_pct Values_pct
  <fct>   <dbl>  <dbl>     <dbl>      <dbl>
1 [25,35]     2     55      66.7       38.7
2 (35,45]     0      0       0          0  
3 (45,55]     0      0       0          0  
4 (55,65]     0      0       0          0  
5 (65,75]     0      0       0          0  
6 (75,85]     0      0       0          0  
7 NA          1     87      33.3       61.3

这是生成上述内容的 MWE 代码 table(有来自更完整的 App 的遗迹;我考虑过制作 max = round(value, -1) 或类似的东西,但很困难用户是否能够输入不同的范围以自定义分层):

custom_min <- function(x) {if (length(x)>0) min(x, na.rm=TRUE) else Inf}
custom_max <- function(x) {if (length(x)>0) max(x, na.rm=TRUE) else Inf}

filter_exp1 <- parse(text=paste0("Period",  "==", "'","2020-04", "'"))
stratData_1 <- stratData %>% filter(eval(filter_exp1))

min <- custom_min(stratData_1[[3]])
max <- custom_max(stratData_1[[3]])
breaks <- if(any(is.infinite(c(min,max)))) c(0, 10) else seq(min, max, by = 10) # < in full code, the 10 is a variable the user can change via Shiny

tmp <- stratData %>% 
  filter(eval(filter_exp1)) %>%
  mutate(Range = cut(!!sym("Values"), breaks=breaks, include.lowest=TRUE, right = TRUE, dig.lab = 5)) %>% 
  group_by(Range) %>% 
  summarise(Count = n(),Values = sum(!!sym("Values"))) %>% 
  complete(Range, fill = list(Count = 0,Values = 0)) %>% 
  ungroup %>% 
  mutate(Count_pct = Count/sum(Count)*100, Values_pct = Values/sum(Values)*100) %>% 
  dplyr::select(everything(), Count, Count_pct, Values, Values_pct)
tmp

您需要使用例如seq(min, max, length.out = 5)。这里不能使用by参数,因为max=87不是10的倍数:

min <- 25
max <- 87
# does not include the max
seq(min, max, by = 10)
#> [1] 25 35 45 55 65 75 85
# does include the max
seq(min, max, length.out = 5)
#> [1] 25.0 40.5 56.0 71.5 87.0

reprex package (v2.0.1)

创建于 2022-02-07

以上danlooo解决方案暂时在大App中使用。 Danlooo 解决方案允许用户在 seq() 函数中使用 length.out = 而不是 by = 来指定分层中的波段数。但是,随着应用程序的发展,我可能会更改它以允许用户指定最小波段值、最大波段值和波段厚度。 (需要评估这种增加的复杂性是否值得)。为了允许用户指定带厚度并添加另一个带以包含每个 OP 的最大数据框值,您可以 add/change OP MWE 中的以下内容:

# New line:
tmpSeq <- seq(min, max, by = 10) 

# Replace "breaks" in OP with the following using the append() function:
breaks <- if(any(is.infinite(c(min,max)))) c(0, 10) else append(tmpSeq,tmpSeq[length(tmpSeq)]+10)