繁体   English   中英

使用 dplyr R 按行查找第二个最大值

[英]Find the second largest value rowwise with dplyr R

问题:

我正在处理工资数据,我想将异常值标记为可能的测量错误。 为此,我结合了两个标准:

  1. 相对于我的数据集上的整个工资分布(个人之间的比较标准,一年内),在给定的一年内获得超过 99% 工资值的两倍以上

  2. 跨年获得同一个人第二高工资价值的两倍以上。 那是一个个体内的标准(人内、年际的比较标准)。

我完成了第一个标准的编码,但我在编码第二个标准时遇到了一些麻烦。

我的数据是宽格式的。 也许通过将数据重塑为长格式可以更轻松地解决我的问题,但是当我在一个多作者项目中工作时,如果我使用这个解决方案,我需要再次将其重塑回宽格式。

数据示例:

下面,我提供了一些数据行,其中包含已经满足第一个条件的案例:

df <- structure(list(
    wage_2010 = c(120408.54, 11234.67, 19918.64, NA, 66006.32, 40581.36, 344587.84, 331970.28, NA, 161351.45, NA, 115310.68, 323336.27, 9681.69, NA, 682324.53, 43764.76, 134023.61, 78195.16, 141231.5, 48163.23, 71259.66, 73858.65, 57737.6, NA, 182837.23), wage_2011 = c(413419.86, 24343.04, 36349.02, NA, 99238.53, 18890.34, 129921.58, 108714.29, NA, 169289.89, 36158.73, 129543.51, 130791.99, 13872.76, 4479.58, 222327.52, 826239.14, 48892.78, 78506.06, 111569.8, 653239.41, 813158.54, 72960.17,     80193.15, NA, 209796.19), wage_2012 = c(136750.86, 77386.62, 177528.17, 86512.48, 375958.76, 20302.29, 145373.42, 91071.64, 95612.23, 176866.72, 85244.44, 225698.7, 181093.52, 162585.23, 147918.83, 254057.11, 72845.46, 86001.31, 80958.22, 105629.12, 77723.77, 115217.74, 68959.04, 111843.87, 85180.26, 261942.95    ), 
wage_2013 = c(137993.48, 104584.84, 239822.37, 95688.8, 251573.14, 21361.93, 142771.58, 92244.51, 111058.93, 208013.94, 111326.07, 254276.36, 193663.33, 225404.84, 84135.55, 259772.16, 100031.38, 100231.81, 824271.38, 107336.19, 95292.2, 217071.19, 125665.58, 74513.66, 116227.01, 245161.73), wage_2014 = c(134914.8, 527180.87, 284218.4, 112332.41, 189337.74, 23246.46, 144070.09, 92805.77, 114123.3, 251389.07, 235863.98, 285511.12, 192950.23, 205364.45, 292988.3, 318408.56, 86255.91, 497960.18, 85467.13, 152987.99, 145663.31, 242682.93, 184123.01, 107423.03, 132046.43, 248928.89), wage_2015 = c(168812.65, 145961.09, 280556.86, 256268.69, 144549.45, 23997.1, 130253.75, NA, 115522.88,     241031.91, 243697.87, 424135.76, 15927.33, 213203.96, 225118.19, 298042.59, 77749.09, 151336.85, 88596.38, 121741.45, 34054.26, 206284.71, 335127.7, 201891.17, 189409.04, 246440.69), 
wage_2016 = c(160742.14, 129892.09, 251333.29, 137192.73, 166127.1, 537611.12, 139350.84, NA, 115395.21, 243154.02, 234685.36, 903334.7, NA, 205664.08, 695079.91, 33771.37, 100938.19, 138864.28, 58658.4, 98576.95, NA, 144613.53, 430393.04, 217989.1, 229369.56, 600079.86), wage_2017 = c(175932.3, 138128.41, 584536.47, 143506.22, 61674.63, 1442.8, 126084.46, NA, 575771.83, 586909.69, 372954.89, 701815.37, NA, 402347.33, 93873.2, NA, 96792.96, 172908.08, 89006.92, 631645.41, NA, 72183.55, 579455.71, 294539.56, 353615.43, 151327.43), wage_2018 = c(146111.42, 149313.9, 627679.77, 850182.4, 72654.62, 9129.35, 41544.24, NA, 248020.12, 334280.68, 611781.99, 597465.2, NA, 535628.5, 63369.44, NA, 93710.71, 146769.63, 100736.71, 108022.87, NA, 79019.43, 772012.47, 549097.81, 504183.59, 99129.6), 
outlier_2010 = c(0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), outlier_2011 = c(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0), outlier_2012 = c(0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), outlier_2013 = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), outlier_2014 = c(0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0), outlier_2015 = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), outlier_2016 = c(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), outlier_2017 = c(0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0),     outlier_2018 = c(0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0)), 
groups = structure(list(.rows = structure(list(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L, 21L, 22L, 23L, 24L, 25L, 26L), ptype = integer(0), class = c("vctrs_list_of",     "vctrs_vctr", "list"))), row.names = c(NA, -26L), class = c("tbl_df", "tbl", "data.frame")), row.names = c(NA, -26L), class = c("rowwise_df", "tbl_df", "tbl", "data.frame"))

我有 2010 年到 2018 年的平均年薪,也就是 9 个时间点。 然而,似乎很难使用quantile为 function 的解决方案,因为某些人在某些年份可能存在缺失值。

我试过的:

到目前为止,我在 dplyer 方法中使用了中值 function。 如果在给定的一年中,个人收到的收入是他多年来收到的中位数的两倍以上,我将其标记为异常值(可能的错误):

library(dplyr)

df1 <- df %>%
   rowwise %>%
   mutate(
      median_wage = median(c(wage_2010, wage_2011, wage_2012, wage_2013, wage_2014, wage_2015, wage_2016, wage_2017, wage_2018), na.rm=T)) %>%
    mutate(
      individual_threshold = median_wage * 2,
   ) %>%
   mutate(
      outlier_2010 = case_when (wage_2010 > individual_threshold ~ 1, TRUE ~ 0),
      outlier_2011 = case_when (wage_2011 > individual_threshold ~ 1, TRUE ~ 0),
      outlier_2012 = case_when (wage_2012 > individual_threshold ~ 1, TRUE ~ 0),
      outlier_2013 = case_when (wage_2013 > individual_threshold ~ 1, TRUE ~ 0),
      outlier_2014 = case_when (wage_2014 > individual_threshold ~ 1, TRUE ~ 0),
      outlier_2015 = case_when (wage_2015 > individual_threshold ~ 1, TRUE ~ 0),
      outlier_2016 = case_when (wage_2016 > individual_threshold ~ 1, TRUE ~ 0),
      outlier_2017 = case_when (wage_2017 > individual_threshold ~ 1, TRUE ~ 0),
      outlier_2018 = case_when (wage_2018 > individual_threshold ~ 1, TRUE ~ 0))

然而,当我检查数据时,我发现我正在将可能的合法工资编码为异常值。 例如,在我的数据的第三行/人中,我将 2017 年和 2018 年的工资标记为异常值。但是,正如我们所见,此人的工资存在增长模式。 尽管这些年来他的工资中位数是他的两倍多,但这可能不是一个错误,因为这一增长是连续两年记录的。

然而,在第四行中,2018 年的工资更可能被错误报告,因为同一个人的工资没有类似的工资。 在 2018 年,该人的工资比以往任何时候都增长了 4 倍以上(也成为整个分布的 99% 的两倍多)。

加起来:

我想编写一个代码来分析每个人(或按行)的 9 个变量:wage_2010-2018,并将最高值与第二高值进行比较。 如果最大值是第二高值的两倍以上,我将其标记为可能的测量错误。 最好在dplyr内。

这是使用助手 function 执行此操作的方法。

library(dplyr)

compare_2nd_highest <- function(x) {
  #Sort the wages in descending order
  x1 <- sort(x, decreasing = TRUE)
  #Is the highest value more than double of second highest value
  x1[1] > (x1[2] * 2)
}

df %>%
  rowwise() %>%
  mutate(is_outlier = compare_2nd_highest(c_across(starts_with('wage')))) %>%
  ungroup

暂无
暂无

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

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