Câu trả lời:
Sử dụng partial
đối số của sort()
. Đối với giá trị cao thứ hai:
n <- length(x)
sort(x,partial=n-1)[n-1]
sort(x, TRUE)[2]
mô tả trong câu trả lời của @ Abrar là gì, ngoài việc không thỏa mãn các ràng buộc trong câu hỏi?
Error in sort.int(x, na.last = na.last, decreasing = decreasing, ...) : index 4705 outside bounds
Bất kỳ ý tưởng nào có thể là vấn đề? Một số chi tiết: My x là một vectơ số có độ dài 4706 với một số NA
s trong dữ liệu. Tôi đã cố gắng để có được giá trị cao thứ hai trong vectơ bằng cách sử dụng mã chính xác như @RobHyndman đề xuất.
decreasing
đối số không tương thích với sắp xếp một phần, bạn luôn có thể -sort(-x, partial=n-1)[n-1]
; về mặt logic thì điều tương tự và mất ít thời gian hơn đáng kể sort(x, decreasing=TRUE)[n-1]
.
Thay thế hơi chậm, chỉ cho các hồ sơ:
x <- c(12.45,34,4,0,-234,45.6,4)
max( x[x!=max(x)] )
min( x[x!=min(x)] )
max(x[-which.max(x)])
Tôi kết hợp câu trả lời của Rob thành một hàm tổng quát hơn một chút, có thể được sử dụng để tìm tối đa thứ 2, 3, 4 (v.v.):
maxN <- function(x, N=2){
len <- length(x)
if(N>len){
warning('N greater than length(x). Setting N=length(x)')
N <- length(x)
}
sort(x,partial=len-N+1)[len-N+1]
}
maxN(1:10)
maxN(1:10, 1:3)
(tôi sẽ đặt N mặc định thành 1)
Rfast có một hàm gọi là nth_element thực hiện chính xác những gì bạn yêu cầu và nhanh hơn tất cả các triển khai đã thảo luận ở trên
Ngoài ra, các phương pháp được thảo luận ở trên dựa trên sắp xếp một phần, không hỗ trợ tìm k giá trị nhỏ nhất
Rfast::nth(x, 5, descending = T)
Sẽ trả về phần tử lớn thứ 5 của x, trong khi
Rfast::nth(x, 5, descending = F)
Sẽ trả về phần tử nhỏ thứ 5 của x
Điểm chuẩn dưới đây so với hầu hết các câu trả lời phổ biến.
Cho 10 nghìn số:
N = 10000
x = rnorm(N)
maxN <- function(x, N=2){
len <- length(x)
if(N>len){
warning('N greater than length(x). Setting N=length(x)')
N <- length(x)
}
sort(x,partial=len-N+1)[len-N+1]
}
microbenchmark::microbenchmark(
Rfast = Rfast::nth(x,5,descending = T),
maxn = maxN(x,5),
order = x[order(x, decreasing = T)[5]]
)
Unit: microseconds
expr min lq mean median uq max neval
Rfast 160.364 179.607 202.8024 194.575 210.1830 351.517 100
maxN 396.419 423.360 559.2707 446.452 487.0775 4949.452 100
order 1288.466 1343.417 1746.7627 1433.221 1500.7865 13768.148 100
Đối với 1 triệu số:
N = 1e6 #evaluates to 1 million
x = rnorm(N)
microbenchmark::microbenchmark(
Rfast = Rfast::nth(x,5,descending = T),
maxN = maxN(x,5),
order = x[order(x, decreasing = T)[5]]
)
Unit: milliseconds
expr min lq mean median uq max neval
Rfast 89.7722 93.63674 114.9893 104.6325 120.5767 204.8839 100
maxN 150.2822 207.03922 235.3037 241.7604 259.7476 336.7051 100
order 930.8924 968.54785 1005.5487 991.7995 1031.0290 1164.9129 100
Rfast::nth
có thể trả về nhiều yếu tố (ví dụ như các yếu tố lớn thứ 8 và 9) cũng như các chỉ số của các yếu tố đó.
Đây là một cách dễ dàng để tìm các chỉ số của N giá trị nhỏ nhất / lớn nhất trong một vectơ (Ví dụ cho N = 3):
N <- 3
N nhỏ nhất:
ndx <- order(x)[1:N]
N lớn nhất:
ndx <- order(x, decreasing = T)[1:N]
Vì vậy, bạn có thể trích xuất các giá trị như:
x[ndx]
Đối với giá trị cao thứ n,
sort(x, TRUE)[n]
Tôi thấy rằng việc loại bỏ phần tử max trước và sau đó thực hiện một lần chạy max khác với tốc độ tương đương:
system.time({a=runif(1000000);m=max(a);i=which.max(a);b=a[-i];max(b)})
user system elapsed
0.092 0.000 0.659
system.time({a=runif(1000000);n=length(a);sort(a,partial=n-1)[n-1]})
user system elapsed
0.096 0.000 0.653
Đây là cách đơn giản nhất mà tôi tìm thấy,
num <- c(5665,1615,5154,65564,69895646)
num <- sort(num, decreasing = F)
tail(num, 1) # Highest number
head(tail(num, 2),1) # Second Highest number
head(tail(num, 3),1) # Third Highest number
head(tail(num, n),1) # Generl equation for finding nth Highest number
Khi gần đây tôi đang tìm kiếm một hàm R trả về các chỉ số của các số max / min N hàng đầu trong một vectơ đã cho, tôi đã ngạc nhiên khi không có hàm nào như vậy.
Và đây là một cái gì đó rất giống nhau.
Giải pháp vũ lực sử dụng hàm base :: order dường như là cách dễ nhất.
topMaxUsingFullSort <- function(x, N) {
sort(x, decreasing = TRUE)[1:min(N, length(x))]
}
Nhưng nó không phải là nhanh nhất trong trường hợp giá trị N của bạn tương đối nhỏ so với chiều dài của vectơ x .
Mặt khác, nếu N thực sự nhỏ, bạn có thể sử dụng hàm base :: whichMax lặp đi lặp lại và trong mỗi lần lặp, bạn có thể thay thế giá trị tìm thấy bằng -Inf
# the input vector 'x' must not contain -Inf value
topMaxUsingWhichMax <- function(x, N) {
vals <- c()
for(i in 1:min(N, length(x))) {
idx <- which.max(x)
vals <- c(vals, x[idx]) # copy-on-modify (this is not an issue because idxs is relative small vector)
x[idx] <- -Inf # copy-on-modify (this is the issue because data vector could be huge)
}
vals
}
Tôi tin rằng bạn thấy vấn đề - bản chất sao chép khi sửa đổi của R. Vì vậy, điều này sẽ hoạt động tốt hơn đối với N rất nhỏ (1,2,3) nhưng nó sẽ nhanh chóng chậm lại đối với các giá trị N lớn hơn. Và bạn đang lặp lại tất cả các phần tử trong vectơ x N lần.
Tôi nghĩ rằng giải pháp tốt nhất trong sạch R là sử dụng một phần cơ sở :: sort .
topMaxUsingPartialSort <- function(x, N) {
N <- min(N, length(x))
x[x >= -sort(-x, partial=N)[N]][1:N]
}
Sau đó, bạn có thể chọn mục ( N th) cuối cùng từ kết quả của chức năng defiend ở trên.
Lưu ý: các chức năng được xác định ở trên chỉ là ví dụ - nếu bạn muốn sử dụng chúng, bạn phải kiểm tra / đầu vào sanity (ví dụ: N> length (x) ).
Tôi đã viết một bài viết nhỏ về một cái gì đó rất giống nhau (lấy chỉ số của các giá trị N max / min hàng đầu của một vectơ) tại http://palusga.cz/?p=18 - bạn có thể tìm thấy ở đây một số điểm chuẩn của các hàm tương tự tôi đã xác định ở trên.
head(sort(x),..)
hoặc tail(sort(x),...)
nên làm việc
topn = function(vector, n){
maxs=c()
ind=c()
for (i in 1:n){
biggest=match(max(vector), vector)
ind[i]=biggest
maxs[i]=max(vector)
vector=vector[-biggest]
}
mat=cbind(maxs, ind)
return(mat)
}
hàm này sẽ trả về một ma trận có n giá trị trên cùng và các chỉ số của chúng. hy vọng nó sẽ giúp VDevi-Chou
Điều này sẽ tìm thấy chỉ số của giá trị nhỏ nhất hoặc lớn nhất thứ N trong vectơ số đầu vào x. Đặt bottom = TRUE trong các đối số nếu bạn muốn N'th từ dưới lên hoặc bottom = FALSE nếu bạn muốn N'th từ trên xuống. N = 1 và bottom = TRUE tương đương với which.min, N = 1 và bottom = FALSE tương đương với which.max.
FindIndicesBottomTopN <- function(x=c(4,-2,5,-77,99),N=1,bottom=FALSE)
{
k1 <- rank(x)
if(bottom==TRUE){
Nindex <- which(k1==N)
Nindex <- Nindex[1]
}
if(bottom==FALSE){
Nindex <- which(k1==(length(x)+1-N))
Nindex <- Nindex[1]
}
return(Nindex)
}
dplyr có hàm thứ n, trong đó đối số đầu tiên là vectơ và thứ hai là nơi bạn muốn. Điều này đi để lặp lại các yếu tố là tốt. Ví dụ:
x = c(1,2, 8, 16, 17, 20, 1, 20)
Tìm giá trị lớn thứ hai:
nth(unique(x),length(unique(x))-1)
[1] 17
x[[order(order_by)[[n]]]]
- vì vậy nó yêu cầu sắp xếp toàn bộ vector. Vì vậy, nó sẽ không nhanh như câu trả lời được chấp nhận.
sort
với đối số
dplyr::nth()
? bench::mark(max(x[-which.max(x)]), x[[order(-x)[[2]]]] )
, nth()
dường như chậm hơn gần 10 lần, đâu length(x)
là 3 triệu.
Bạn có thể xác định giá trị cao hơn tiếp theo với cummax()
. Nếu bạn muốn vị trí của mỗi giá trị mới cao hơn chẳng hạn, bạn có thể chuyển vectơ cummax()
giá trị của mình cho diff()
hàm để xác định vị trí tại đó cummax()
giá trị thay đổi. nói rằng chúng ta có vector
v <- c(4,6,3,2,-5,6,8,12,16)
cummax(v) will give us the vector
4 6 6 6 6 6 8 12 16
Bây giờ, nếu bạn muốn tìm vị trí thay đổi trong cummax()
bạn có nhiều tùy chọn tôi có xu hướng sử dụng sign(diff(cummax(v)))
. Bạn phải điều chỉnh cho phần tử đầu tiên bị mất vì diff()
. Mã hoàn chỉnh cho vector v
sẽ là:
which(sign(diff(cummax(v)))==1)+1
Bạn có thể sử dụng sort
từ khóa như thế này:
sort(unique(c))[1:N]
Thí dụ:
c <- c(4,2,44,2,1,45,34,2,4,22,244)
sort(unique(c), decreasing = TRUE)[1:5]
sẽ cho 5 số tối đa đầu tiên.
topn
chức năng mà là nhanh hơnsort
,order
vànth
. Nhìn vào tài liệu.