繁体   English   中英

在 R 中检查总和

[英]Checking sums with condition in R

我需要检查一些 dataframe 中的总和。 但它的元素不能总结,因为其中一些包含其他元素。 在这个例子中,051040 是 051043 的一部分。虽然大多数元素以“0”结尾,但最后一位为 3 的元素总是大于或等于最后一位为 0 的对应元素。换句话说,我需要找到所有以“3”结尾的元素并跳过那些带有“0”的对应物。 在此示例中,必须跳过 051040 和 051050,因为存在 051043 和 051053。 注意元素“05000”是一个控制和,显然它也必须被跳过。 所以我需要找出差异:05000 - SUM ("051010", "051043", "051053", "052020", "052100", "052220", "052310") = 0 类似的东西。 这是一个人工的例子(实际的dataframe真的很大)。

Area <- c("050000", "051010", "051040", "051043", "051050", "051053", "052020", "052100", "052220", "052310")
Total <- c(100,  28,  16,  22,  10,  10,  10,  10,  10,  10)
sodf <- data.frame(Area, Total)

首先十分感谢!

您可以使用子字符串。

sodf[with(sodf, ave(substring(Area, 6) == 3, substr(Area, 1, 5), FUN=\(x) {
  if (any(x)) x else TRUE
})), ] |>
  (\(x) x[1, 2] - sum(x[-1, 2]))()
# [1] 0

在多个区域的应用程序中,我稍微sodf lapply进行演示(但不完全确定您的区号看起来如何,但前两位数字似乎相关)。

lapply(split(sodf, substr(sodf$Area, 1, 2)), \(x) {
  x <- x[ave(substring(Area, 6) == 3, substr(Area, 1, 5), FUN=\(x) {
    if (any(x)) x else TRUE
  }), ]
  x[1, 2] - sum(x[-1, 2])
})
# $`05`
# [1] 0
# 
# $`06`
# [1] 111

数据:

sodf <- structure(list(Area = c("050000", "051010", "051040", "051043", 
"051050", "051053", "052020", "052100", "052220", "052310", "060000", 
"061010", "061040", "061043", "061050", "061053", "062020", "062100", 
"062220", "062310"), Total = c(100, 28, 16, 22, 10, 10, 10, 10, 
10, 10, 211, 28, 16, 22, 10, 10, 10, 10, 10, 10)), row.names = c(NA, 
-20L), class = "data.frame")

一行解决方案可以是这样的:

sum(sodf[!sodf$Area %in% stringr::str_replace_all(sodf[!grepl('0$',sodf$Area),"Area"],'[1-9]$','0') & !sodf$Area %in% sodf[grepl('^[0]+[1-9]{1}[0]+$',sodf$Area),"Area"] ,"Total"])

它是如何工作的?

  1. 您会发现 Area 不以 0 结尾的行。 sodf[,grepl('0$',sodf$Area),"Area"] # "051043" "051053"
  2. 如果他们有一个 0,你会发现这一行应该如何结束。我使用了来自 stringr package 的 function。 stringr::str_replace_all(sodf[,grepl('0$',sodf$Area),"Area"],'[1-9]$','0') # "051040" "051050"
  3. 您会找到未包含在第 2 组中且不具有 '050000' 结构(^[0]+[1-9]{1}[0]+$)的行,然后将它们的总数相加。 sum(sodf[:sodf$Area %in% stringr:,str_replace_all(sodf[,grepl('0$',sodf$Area),"Area"],'[1-9]$','0') &,sodf$Area %in% sodf[grepl('^[0]+[1-9]{1}[0]+$',sodf$Area),"Area"] ,"Total"] ) # 100

使用 dplyr package 将代码拆分为多行可以实现相同的结果。

我的同事建议了以下变体。

library(tidyverse)
check_diff <- function(df) {
   # Find value Total, for instance ends with 0000
   sum_control <- df |>
       filter(str_detect(Area, "0{4}$")) |>
       select(Total)

   # Find second number from the end where the last character is 3 and connect them into one string
   before_last_3 <- df |>
       filter(str_detect(Area, "3$")) |>
       pull(Area) |>
       str_sub(-2, -2) |>
       str_flatten()

   # Create string for filter pattern
   filter3 <- str_c("[", before_last_3, "]0$")

   # filter data on new conditions and find sum
   sum <- df |>
       filter(!str_detect(Area, "0{4}$"),
              !str_detect(Area, filter3)) |>
       summarise(sum(Total))

   sum_control - sum
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM