首页 > 解决方案 > 获取同一轮中的两行或多行价值差异小于 20%

问题描述

假设我有这样的数据:

# Data frame
df <- data.frame(round = factor(c(rep(1,4),rep(2,3),rep(3,4),rep(4,2))),
                 value = c(100,150,200,250,200,160,900,500,600,900,1200,100,120),
                 SE = c(1.3,1.5,0.7,2,1,2,1,1,1,0.5,0.75,20,3))
df
   round value    SE
1      1   100  1.30
2      1   150  1.50
3      1   200  0.70
4      1   250  2.00
5      2   200  1.00
6      2   160  2.00
7      2   900  1.00
8      3   500  1.00
9      3   600  1.00
10     3   900  0.50
11     3  1200  0.75
12     4   100 20.00
13     4   120  3.00
  1. 我想在同一轮中获得 2 行或更多行的值差异小于 20%(例如在第 1 轮:将排除所有行,第 2 轮:将排除 value = 900 的行,并且在轮3:将排除 value = 900 和 1200 的行)

到目前为止,我尝试过的是:

library(dplyr)
 df %>%
    group_by(Round) %>%
    mutate(medians = median(value),
           deviation = abs(value - medians) * 100 / medians) %>%
    mutate(rowcounts = n()) %>%
    mutate(passORfailed = ifelse(
      rowcounts == 2,
      ifelse((max(value) - min(value)) * 100 / max(value) > 20, "failed", "pass"),
      ifelse(deviation > 20, "failed", "pass"))) %>%
    filter(passORfailed != "failed") %>%
    filter(sum(rowcounts) != 1) 

结果:

# A tibble: 8 x 7
# Groups:   round [4]
  round value    SE medians deviation rowcounts passORfailed
  <fct> <dbl> <dbl>   <dbl>     <dbl>     <int> <chr>       
1 1       150   1.5     175     14.3          4 pass  # -> not right     
2 1       200   0.7     175     14.3          4 pass  # -> not right       
3 2       200   1       200      0            3 pass  # -> ok      
4 2       160   2       200     20            3 pass  # -> ok      
5 3       600   1       750     20            4 pass  # -> not right (500 was excluded)       
6 3       900   0.5     750     20            4 pass  # -> not right       
7 4       100  20       110      9.09         2 pass  # -> ok      
8 4       120   3       110      9.09         2 pass  # -> ok 

正如您所看到的,当行数为偶数且 >3 时,事情变得疯狂。问题是当我使用中位数时,为标准计算的实际值是一半(由于两个中心值之间的平均值)。无论如何调整代码以使其在所有情况下都成为可能?

  1. 如果可能,如何调整代码以在值 +- SE 范围内计算此数据?

如果问题不清楚,我很抱歉,但我已尽力解释。问候

标签: rdplyr

解决方案


这是一种方法,我们在一轮中生成每个可能的对,然后仅过滤彼此相距 20% 以内的行。它的逻辑与您的逻辑略有不同,因此它会导致更少的匹配,但如果您使用不同的阈值(例如 +/- 35%,而不是 +/- 20%),作为替代方法可能会很有用。

df <- df %>% mutate(row = row_number()) 
df %>% 
  left_join(df, by = "round") %>%
  mutate(ratio = value.x / value.y) %>%
  filter(row.x != row.y,
         ratio %>% between(1/1.2, 1.2))

这是解决问题第二部分的变体。我为每个计算值 +/- SE 并在每一轮中找到重叠的行对。

df <- df %>% 
  mutate(row = row_number()) %>%
  mutate(low = value - SE,
         high = value + SE)

df %>% 
  left_join(df, by = "round") %>%
  filter(row.x != row.y,
         (high.x >= low.y & high.x <= high.y) | (low.x >= low.y & low.x <= high.y))


  round value.x SE.x row.x low.x high.x value.y SE.y row.y low.y high.y
1     4     100   20    12    80    120     120    3    13   117    123
2     4     120    3    13   117    123     100   20    12    80    120

推荐阅读