同时替换和删除数据帧或多列中的第一个百分比和最后一个百分比



我有这个数据集:

A <- paste0("event_", c(1:100))
some_number <- sample.int(1000,size=100) 
X1 <- c(1:100)
X2 <- c(101:200)
X3 <- c(201:300)
X4 <- c(301:400)
X5 <- c(401:500)
DF <- data.frame(A, some_number, X1, X2, X3, X4, X5)

在处理异常值时,我希望删除包含第1个和最新百分比的行,只考虑百分比计算的X变量和所有X变量作为一组。因此,百分位数将X1X5视为一组。为此,我想到了以下步骤:

  1. X1X5的值替换为1到100(每个百分位数为1(。记住,我不是在寻找每个X的百分位数,而是寻找所有X作为一个整体
  2. 删除变量X1X5包含1或100的行

我的尝试:(基于如何找到百分位数,用第5个和第95个百分位数替换异常值,删除数据帧中大于第95个百分点的数据(

as.data.frame(sapply(select(DF, X1:X5), function (x) {
qx <- quantile(x, probs = c(1:100)/100)
cut(x, qx, labels = c(1:100))
}))

但是。。我的尝试引发了一个错误,即中断的数量与标签的数量不同,我很难在不丢失Asome_number变量的情况下分配新的数据帧(在我的实际问题中,它们不是两列,而是近50列(

有什么建议吗?

dplyr中同时使用acrossc_across,也可以执行此操作-

说明的步骤-

  • c_across通常与row_wise一起使用,因为它通过内部参数创建数据子集的完整副本。但我在没有rowwise()的情况下完成了这项工作,所以它不是创建一行,而是根据需要创建整个数据的副本
  • 此后将推导出该数据的两个分位数。(将是标量(
  • 现在剩下的工作就是将这些值和数据中的其他值进行核对。所以我直接用了across
  • 使用cross,我构建了一个以twiddle开头的lambda公式,其参数仅为.。这个旋转式的公式~ .相当于function(x) x,其余的都很清楚
DF %>% mutate(across(starts_with('X'), ~ifelse(. > quantile(c_across(starts_with('X')), 0.99) |
. < quantile(c_across(starts_with('X')), 0.01),
NA, .) 
)) %>% na.omit()
#>           A some_number X1  X2  X3  X4  X5
#> 6   event_6          69  6 106 206 306 406
#> 7   event_7         871  7 107 207 307 407
#> 8   event_8         356  8 108 208 308 408
.
.
.
#> 93 event_93         432 93 193 293 393 493
#> 94 event_94         967 94 194 294 394 494
#> 95 event_95         516 95 195 295 395 495

由于starts_with仅在acrossc_across中工作,为了避免这里的rowwise较慢,我们也可以直接进行

DF %>% filter(rowSums(cur_data()[str_detect(names(DF), 'X')] > quantile(c_across(starts_with('X')), 0.99)) == 0 &
rowSums(cur_data()[str_detect(names(DF), 'X')] < quantile(c_across(starts_with('X')), 0.01)) == 0)

这也将提供90行输出作为所需

您可以尝试以下操作-

library(dplyr)
vec <- DF %>% select(starts_with('X')) %>% as.matrix() %>% quantile(c(0.01, 0.99))
DF %>% filter(if_all(starts_with('X'), ~. > vec[1] & . < vec[2]))

相关内容

  • 没有找到相关文章

最新更新