在对多个列进行排序时移除 Dataframe 中的极值R

9ceoxa92  于 2023-02-06  发布在  其他
关注(0)|答案(2)|浏览(144)

我有这样一个 Dataframe :

mydf <- data.frame(A = c(40,9,55,1,2), B = c(12,1345,112,45,789))
mydf
   A    B
1 40   12
2  9 1345
3 55  112
4  1   45
5  2  789

我只想保留95%的观测值,并丢弃5%具有极值的数据。首先,我计算它们有多少个观测值:

th <- length(mydf$A) * 0.95

然后我想删除th上面的所有行(或者保留th下面的行,根据您的需要),我需要按升序对mydf排序,以便只删除那些极值。

mydf[order(mydf["A"], mydf["B"]),]
mydf[order(mydf$A,mydf$B),]
mydf[with(mydf, order(A,B)), ]
plyr::arrange(mydf,A,B)

但是没有任何效果,所以mydf没有同时按两列升序排序。我看了这里Sort (order) data frame rows by multiple columns,但是最常见的解决方案不起作用,我不知道为什么。
然而,如果我一次只考虑一列(例如A),这些排序方法可以工作,但是我不知道如何丢弃极值,因为:

mydf <- mydf[(order(mydf$A) < th),]

删除值为9的第二行,而我的意图是对mydf进行子集化,只保留th reshold以下的值(在本例中是指观察数,而不是值)。我可以想象,我缺少的是非常简单和基本的东西......而且可能有更好的tidyverse方法。

kcwpcxri

kcwpcxri1#

我认为这里需要 * rank,但是它不能用于多列。要解决这个问题,请注意rank(.)等价于order(order(.))

rank(mydf$A)
# [1] 4 3 5 1 2
order(order(mydf$A))
# [1] 4 3 5 1 2

这样,我们就可以在两列(所有列)上使用order,然后再次排序,再将得到的排名与th值进行比较。

mydf[order(do.call(order, mydf)) < th,]
#    A    B
# 1 40   12
# 2  9 1345
# 4  1   45
# 5  2  789

这种方法的优点是保留了行的自然排序。
如果您希望只调用一次order,那么可以重新排序并使用head

head(mydf[order(mydf$A, mydf$B),], th)
#    A    B
# 4  1   45
# 5  2  789
# 2  9 1345
# 1 40   12

尽管这不会保留行的原始顺序(这对您可能重要,也可能不重要)。

wrrgggsh

wrrgggsh2#

可能的方法

另一种方法是使用dplyr排名函数,如cume_dist()percent_rank(),它们可以接受 Dataframe 作为输入,并返回基于所有列的排名/百分点。

set.seed(13)
dat_all <- data.frame(
  A = sample(1:60, 100, replace = TRUE),
  B = sample(1:1500, 100, replace = TRUE)
)
nrow(dat_all)
# 100

dat_95 <- dat_all[cume_dist(dat_all) <= .95, ]
nrow(dat_95)
# 95

关于分位数的一般注意事项

更一般地说,请记住,定义分位数是不容易的,比如are multiple possible approaches。你需要考虑一下在给定目标的情况下,什么是最有意义的。举个例子,从dplyr docs
cume_dist(x)计算小于或等于x_i的值的总数,并将其除以观测数。
percent_rank(x)计算小于x_i的值的总数,并将其除以观测数减去1
这意味着,对于cume_dist(),最小值总是1 / nrow(),而对于percent_rank(),最大值总是1,这意味着根据方法的不同,可能会排除不同的情况,也意味着我提供的代码将 * 总是 * 删除排名最高的行。这可能符合也可能不符合你的期望。(例如,在一个只有5个元素的向量中,最高值是“高于第95百分位数”吗?这取决于你如何定义它。)

相关问题