[英]Function for median similar to “which.max” and “which.min” / Extracting median rows from a data.frame
我偶爾需要根據其中一個變量的值從 data.frame 中提取特定行。 R
具有最大值( which.max()
)和最小值( which.min()
)的內置函數,使我可以輕松提取這些行。
中位數有等價物嗎? 或者我最好的選擇是編寫自己的函數?
這是一個示例 data.frame 以及我將如何使用which.max()
和which.min()
:
set.seed(1) # so you can reproduce this example
dat = data.frame(V1 = 1:10, V2 = rnorm(10), V3 = rnorm(10),
V4 = sample(1:20, 10, replace=T))
# To return the first row, which contains the max value in V4
dat[which.max(dat$V4), ]
# To return the seventh row, which contains the min value in V4
dat[which.min(dat$V4), ]
對於這個特定的例子,因為有偶數個觀察值,我需要返回兩行,在這種情況下,第 2 行和第 10 行。
似乎沒有為此提供內置功能。 因此,以Sacha的回復為出發點,我編寫了這個函數:
which.median = function(x) {
if (length(x) %% 2 != 0) {
which(x == median(x))
} else if (length(x) %% 2 == 0) {
a = sort(x)[c(length(x)/2, length(x)/2+1)]
c(which(x == a[1]), which(x == a[2]))
}
}
我可以按如下方式使用它:
# make one data.frame with an odd number of rows
dat2 = dat[-10, ]
# Median rows from 'dat' (even number of rows) and 'dat2' (odd number of rows)
dat[which.median(dat$V4), ]
dat2[which.median(dat2$V4), ]
有什么建議可以改進嗎?
雖然 Sacha 的解決方案非常通用,但中位數(或其他分位數)是順序統計數據,因此您可以根據order (x)
(而不是分位數值的sort (x)
計算相應的索引。
查看quantile
,可以使用類型 1 或 3,所有其他類型在某些情況下會導致兩個值的(加權)平均值。
我選擇了類型 3,從quantile
進行了一些復制和粘貼導致:
which.quantile <- function (x, probs, na.rm = FALSE){
if (! na.rm & any (is.na (x)))
return (rep (NA_integer_, length (probs)))
o <- order (x)
n <- sum (! is.na (x))
o <- o [seq_len (n)]
nppm <- n * probs - 0.5
j <- floor(nppm)
h <- ifelse((nppm == j) & ((j%%2L) == 0L), 0, 1)
j <- j + h
j [j == 0] <- 1
o[j]
}
一個小測試:
> x <-c (2.34, 5.83, NA, 9.34, 8.53, 6.42, NA, 8.07, NA, 0.77)
> probs <- c (0, .23, .5, .6, 1)
> which.quantile (x, probs, na.rm = TRUE)
[1] 10 1 6 6 4
> x [which.quantile (x, probs, na.rm = TRUE)] == quantile (x, probs, na.rm = TRUE, type = 3)
0% 23% 50% 60% 100%
TRUE TRUE TRUE TRUE TRUE
這是你的例子:
> dat [which.quantile (dat$V4, c (0, .5, 1)),]
V1 V2 V3 V4
7 7 0.4874291 -0.01619026 1
2 2 0.1836433 0.38984324 13
1 1 -0.6264538 1.51178117 17
我認為只是:
which(dat$V4 == median(dat$V4))
但要小心,因為如果沒有一個中間數字,中位數取兩個數字的平均值。 例如, median(1:4)
給出了不匹配任何元素的 2.5。
這是一個函數,它可以為您提供中位數的元素或與中位數平均值的第一個匹配項,類似於which.min()
為您提供第一個僅等於最小值的元素:
whichmedian <- function(x) which.min(abs(x - median(x)))
例如:
> whichmedian(1:4)
[1] 2
我編寫了一個更全面的函數來滿足我的需求:
row.extractor = function(data, extract.by, what) {
# data = your data.frame
# extract.by = the variable that you are extracting by, either
# as its index number or by name
# what = either "min", "max", "median", or "all", with quotes
if (is.numeric(extract.by) == 1) {
extract.by = extract.by
} else if (is.numeric(extract.by) != 0) {
extract.by = which(colnames(dat) %in% "extract.by")
}
which.median = function(data, extract.by) {
a = data[, extract.by]
if (length(a) %% 2 != 0) {
which(a == median(a))
} else if (length(a) %% 2 == 0) {
b = sort(a)[c(length(a)/2, length(a)/2+1)]
c(max(which(a == b[1])), min(which(a == b[2])))
}
}
X1 = data[which(data[extract.by] == min(data[extract.by])), ]
X2 = data[which(data[extract.by] == max(data[extract.by])), ]
X3 = data[which.median(data, extract.by), ]
if (what == "min") {
X1
} else if (what == "max") {
X2
} else if (what == "median") {
X3
} else if (what == "all") {
rbind(X1, X3, X2)
}
}
一些示例用法:
> row.extractor(dat, "V4", "max")
V1 V2 V3 V4
1 1 -0.6264538 1.511781 17
> row.extractor(dat, 4, "min")
V1 V2 V3 V4
7 7 0.4874291 -0.01619026 1
> row.extractor(dat, "V4", "all")
V1 V2 V3 V4
7 7 0.4874291 -0.01619026 1
2 2 0.1836433 0.38984324 13
10 10 -0.3053884 0.59390132 14
4 1 -0.6264538 1.51178117 17
假設要從中獲取中值的向量是x
。
函數which.min(x[x>=median(x)])
將得到的中位數,如果length(x)=2*n+1
,或者如果兩個中間值的更大的length(x)=2*n
。 如果您想獲得兩個中間值中較小的一個,您可以稍微調整它。
基於 Sacha 和 cbeleites 給出的答案,這里有一個函數來獲得包含分位數指數。 與以前的答案的一個不同之處在於type
參數是公開的,並且會產生略有不同的分位數結果(請參閱?quantile
)。 如果性能是一個問題,可以用parallel
包中的版本替換 sapply - 類似於unlist(mclapply(...))
。
# Extract indices corresponding to inclusive quantiles
# EXAMPLE:
#
# x <- c(2.34, 5.83, NA, 9.34, 8.53, 6.42, NA, 8.07, NA, 0.77)
# probs <- c(0, .23, .5, .6, 1)
# which.quantile(x, probs, na.rm = TRUE)
#
# OUTPUT: 10 1 6 8 4
#
# x[ which.quantile(x, probs, na.rm = TRUE) ]
#
# OUTPUT: 0.77 2.34 6.42 8.07 9.34
#
# x <- c(2, 1, 3)
# p <- c(0.5)
# x[ which.quantile(x, p) ]
#
# OUTPUT: 2
which.quantile <- function (x,
probs,
na.rm = FALSE,
type = 7) {
stopifnot(all(probs >= 0.0))
stopifnot(all(probs <= 1.0))
quants = quantile(x,
probs = probs,
na.rm = na.rm,
type = type)
which.nearest <- function(quant) {
return(which.min(abs(x - quant)))
}
return(sapply(X = quants, FUN = which.nearest))
}
我們只需要一個通過近似匹配返回值位置的函數:
match.approx <- function(x, y) {
## Purpose: Match Approximately for Numerical Data
## Arguments:
## "x": a vector of numeric values.
## "y": a vector of numeric values.
## RETURN:
## The index in "y" that indicates the closest y value to each of "x" value.
## ________________________________________________
sapply(x, function(x0) which.min(abs(x0 - y)))
}
if (F) {
match.approx(c(4.2, 1.2, 15), 1:10) # 4 1 10
}
以下是查找分位數位置的示例:
set.seed(1)
a <- rnorm(100)
match.approx(quantile(a), a)
# 0% 25% 50% 75% 100%
# 14 29 23 63 61
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.