Xóa các điểm không liên quan gần trung tâm của một âm mưu QQ


14

Tôi đang cố gắng vẽ sơ đồ QQ với hai bộ dữ liệu khoảng 1,2 triệu điểm, trong R (sử dụng qqplot và đưa dữ liệu vào ggplot2). Việc tính toán là đủ dễ dàng, nhưng đồ thị kết quả tải rất chậm, bởi vì có rất nhiều điểm. Tôi đã thử xấp xỉ tuyến tính để giảm số điểm xuống 10000 (đây là chức năng của qqplot, nếu một trong các tập dữ liệu của bạn lớn hơn các điểm khác), nhưng sau đó bạn mất rất nhiều chi tiết ở phần đuôi.

Hầu hết các điểm dữ liệu về phía trung tâm về cơ bản là vô dụng - chúng chồng lấp lên nhau đến mức có thể có khoảng 100 mỗi pixel. Có cách nào đơn giản để loại bỏ dữ liệu quá gần nhau, mà không mất dữ liệu thưa thớt hơn về phía đuôi không?


Tôi nên đã đề cập, tôi thực sự đang so sánh một bộ dữ liệu (quan sát khí hậu) với một tập hợp các bộ dữ liệu có thể so sánh (chạy mô hình). Vì vậy, tôi thực sự so sánh các điểm quan sát 1,2m, với các điểm mô hình 87m, do đó approx()chức năng này được sử dụng trong qqplot()chức năng.
n101 101

Câu trả lời:


12

Cốt truyện QQ được tự động hóa một cách đáng kinh ngạc, ngoại trừ ở phần đuôi. Khi xem xét chúng, người ta tập trung vào hình dạng tổng thể của cốt truyện và hành vi đuôi. Ergo , bạn sẽ làm tốt bằng cách ghép mẫu thô ở trung tâm của các bản phân phối và bao gồm một lượng đuôi đủ.

Dưới đây là mã minh họa cách lấy mẫu trên toàn bộ tập dữ liệu cũng như cách lấy các giá trị cực trị.

quant.subsample <- function(y, m=100, e=1) {
  # m: size of a systematic sample
  # e: number of extreme values at either end to use
  x <- sort(y)
  n <- length(x)
  quants <- (1 + sin(1:m / (m+1) * pi - pi/2))/2
  sort(c(x[1:e], quantile(x, probs=quants), x[(n+1-e):n]))
  # Returns m + 2*e sorted values from the EDF of y
}

Để minh họa, bộ dữ liệu mô phỏng này cho thấy sự khác biệt về cấu trúc giữa hai bộ dữ liệu có khoảng 1,2 triệu giá trị cũng như một lượng "ô nhiễm" rất nhỏ ở một trong số chúng. Ngoài ra, để thực hiện kiểm tra nghiêm ngặt này, một khoảng các giá trị được loại trừ khỏi một trong các bộ dữ liệu hoàn toàn: biểu đồ QQ cần hiển thị ngắt cho các giá trị đó.

set.seed(17)
n.x <- 1.21 * 10^6
n.y <- 1.20 * 10^6
k <- floor(0.0001*n.x)
x <- c(rnorm(n.x-k), rnorm(k, mean=2, sd=2))
x <- x[x <= -3 | x >= -2.5]
y <- rbeta(n.y, 10,13)

Chúng tôi có thể lấy mẫu 0,1% của mỗi tập dữ liệu và bao gồm 0,1% cực trị khác của chúng, cho 2420 điểm vào âm mưu. Tổng thời gian đã trôi qua ít hơn 0,5 giây:

m <- .001 * max(n.x, n.y)
e <- floor(0.0005 * max(n.x, n.y))

system.time(
  plot(quant.subsample(x, m, e), 
       quant.subsample(y, m, e), 
       pch=".", cex=4,
       xlab="x", ylab="y", main="QQ Plot")
  )

Không có thông tin bị mất bất cứ điều gì:

Cốt truyện QQ


Bạn không nên hợp nhất câu trả lời của bạn?
Michael R. Chernick

2
@Michael Vâng, thông thường tôi sẽ chỉnh sửa câu trả lời đầu tiên (câu trả lời hiện tại). Nhưng mỗi câu trả lời dài và họ sử dụng các cách tiếp cận khác nhau đáng kể, với các đặc điểm hiệu suất khác nhau, vì vậy có vẻ tốt nhất để đăng câu thứ hai như một câu trả lời riêng biệt. Trên thực tế, tôi đã cố gắng xóa cái đầu tiên sau cái thứ hai (thích nghi) xảy ra với tôi, nhưng tốc độ tương đối của nó có thể hấp dẫn một số người, vì vậy sẽ không công bằng khi loại bỏ nó hoàn toàn.
whuber

Đây cơ bản là những gì tôi muốn, nhưng lý do đằng sau việc sử dụng là singì? Tôi có đúng rằng một CDF bình thường sẽ là một chức năng tốt hơn, nếu bạn cho rằng x được phân phối bình thường? Bạn vừa chọn tội lỗi vì nó dễ tính toán hơn?
ness101

Đây có phải là dữ liệu giống như câu trả lời khác của bạn không? Nếu vậy, tại sao các lô rất khác nhau? Điều gì đã xảy ra với tất cả dữ liệu cho x> 6?
ness101

(32x)x2

11

Ở những nơi khác trong chủ đề này, tôi đã đề xuất một giải pháp đơn giản nhưng hơi đặc biệt là lấy mẫu các điểm. Nó nhanh, nhưng đòi hỏi một số thử nghiệm để tạo ra những âm mưu lớn. Giải pháp sắp được mô tả là một thứ tự cường độ chậm hơn (mất tới 10 giây cho 1,2 triệu điểm) nhưng là thích ứng và tự động. Đối với các bộ dữ liệu lớn, lần đầu tiên nên cho kết quả tốt và thực hiện nhanh chóng hợp lý.

Dn , độ lệch dọc tối đa từ một đường được trang bị. Theo đó, thuật toán này là:

(x,y)ty

Có một số chi tiết cần quan tâm, đặc biệt là để đối phó với các bộ dữ liệu có độ dài khác nhau. Tôi làm điều này bằng cách thay thế cái ngắn hơn bằng số lượng tử tương ứng với số lượng dài hơn: thực tế, một phép tính gần đúng tuyến tính của EDF của cái ngắn hơn được sử dụng thay cho giá trị dữ liệu thực tế của nó. ("Ngắn hơn" và "dài hơn" có thể được đảo ngược bằng cách cài đặtuse.shortest=TRUE .)

Đây là một Rthực hiện.

qq <- function(x0, y0, t.y=0.0005, use.shortest=FALSE) {
  qq.int <- function(x,y, i.min,i.max) {
    # x, y are sorted and of equal length
    n <-length(y)
    if (n==1) return(c(x=x, y=y, i=i.max))
    if (n==2) return(cbind(x=x, y=y, i=c(i.min,i.max)))
    beta <- ifelse( x[1]==x[n], 0, (y[n] - y[1]) / (x[n] - x[1]))
    alpha <- y[1] - beta*x[1]
    fit <- alpha + x * beta
    i <- median(c(2, n-1, which.max(abs(y-fit))))
    if (abs(y[i]-fit[i]) > thresh) {
      assemble(qq.int(x[1:i], y[1:i], i.min, i.min+i-1), 
               qq.int(x[i:n], y[i:n], i.min+i-1, i.max))
    } else {
      cbind(x=c(x[1],x[n]), y=c(y[1], y[n]), i=c(i.min, i.max))
    }
  }
  assemble <- function(xy1, xy2) {
    rbind(xy1, xy2[-1,])
  }
  #
  # Pre-process the input so that sorting is done once
  # and the most detail is extracted from the data.
  #
  is.reversed <- length(y0) < length(x0)
  if (use.shortest) is.reversed <- !is.reversed
  if (is.reversed) {
    y <- sort(x0)
    n <- length(y)
    x <- quantile(y0, prob=(1:n-1)/(n-1))    
  } else {
    y <- sort(y0)
    n <- length(y)
    x <- quantile(x0, prob=(1:n-1)/(n-1))    
  }
  #
  # Convert the relative threshold t.y into an absolute.
  #
  thresh <- t.y * diff(range(y))
  #
  # Recursively obtain points on the QQ plot.
  #
  xy <- qq.int(x, y, 1, n)
  if (is.reversed) cbind(x=xy[,2], y=xy[,1], i=xy[,3]) else xy
}

Như một ví dụ, tôi sử dụng dữ liệu mô phỏng như trong câu trả lời trước đây của mình (với một ngoại lệ cực cao được ném vào yvà ô nhiễm hơn một chút trong xthời gian này):

set.seed(17)
n.x <- 1.21 * 10^6
n.y <- 1.20 * 10^6
k <- floor(0.01*n.x)
x <- c(rnorm(n.x-k), rnorm(k, mean=2, sd=2))
x <- x[x <= -3 | x >= -2.5]
y <- c(rbeta(n.y, 10,13), 1)

Hãy vẽ một số phiên bản, sử dụng các giá trị nhỏ hơn và nhỏ hơn của ngưỡng. Với giá trị 0,0005 và hiển thị trên màn hình cao 1000 pixel, chúng tôi sẽ đảm bảo sai số không lớn hơn một nửa pixel dọc ở mọi nơi trên lô. Điều này được thể hiện bằng màu xám (chỉ 522 điểm, được nối bởi các đoạn đường); các xấp xỉ thô hơn được vẽ trên đầu của nó: đầu tiên là màu đen, sau đó là màu đỏ (các điểm màu đỏ sẽ là một tập hợp con của các màu đen và overplot chúng), sau đó là màu xanh lam (một lần nữa là một tập hợp con và overplot). Khoảng thời gian từ 6,5 (xanh dương) đến 10 giây (xám). Vì chúng có tỷ lệ rất tốt, người ta có thể sử dụng khoảng một nửa pixel làm mặc định phổ biến cho ngưỡng ( ví dụ: 1/2000 cho màn hình cao 1000 pixel) và được thực hiện với nó.

qq.1 <- qq(x,y)
plot(qq.1, type="l", lwd=1, col="Gray",
     xlab="x", ylab="y", main="Adaptive QQ Plot")
points(qq.1, pch=".", cex=6, col="Gray")
points(qq(x,y, .01), pch=23, col="Black")
points(qq(x,y, .03), pch=22, col="Red")
points(qq(x,y, .1), pch=19, col="Blue")

Cốt truyện QQ

Biên tập

Tôi đã sửa đổi mã gốc qqđể trả về một cột chỉ mục thứ ba thành dài nhất (hoặc ngắn nhất, theo quy định) của hai mảng ban đầu xy, tương ứng với các điểm được chọn. Các chỉ mục này chỉ ra các giá trị "thú vị" của dữ liệu và do đó có thể hữu ích để phân tích thêm.

Tôi cũng đã loại bỏ một lỗi xảy ra với các giá trị lặp lại của x(nguyên nhân betakhông được xác định).


Làm cách nào để tính toán qqcác đối số cho một vectơ đã cho? Ngoài ra, bạn có thể tư vấn về việc sử dụng qqchức năng của bạn với ggplot2gói? Tôi đã suy nghĩ về việc sử dụng ggplot2's stat_functioncho việc này.
Alexanderr Blekh

10

Loại bỏ một số điểm dữ liệu ở giữa sẽ thay đổi phân phối theo kinh nghiệm và do đó là qqplot. Điều này đang được nói, bạn có thể làm như sau và trực tiếp vẽ các lượng tử của phân bố theo kinh nghiệm so với các lượng tử của phân phối lý thuyết:

x <- rnorm(1200000)
mean.x <- mean(x)
sd.x <- sd(x)
quantiles.x <- quantile(x, probs = seq(0,1,b=0.000001))
quantiles.empirical <- qnorm(seq(0,1,by=0.000001),mean.x,sd.x)
plot(quantiles.x~quantiles.empirical) 

Bạn sẽ phải điều chỉnh seq tùy thuộc vào độ sâu bạn muốn vào đuôi. Nếu bạn muốn có được sự thông minh, bạn cũng có thể làm mỏng chuỗi đó ở giữa để tăng tốc độ cốt truyện. Ví dụ: sử dụng

plogis(seq(-17,17,by=.1))

là một khả năng.


Xin lỗi, tôi không có nghĩa là loại bỏ các điểm khỏi bộ dữ liệu, chỉ từ các ô.
ness101

Thậm chí loại bỏ chúng khỏi cốt truyện là một ý tưởng tồi. Nhưng bạn đã thử thay đổi độ trong suốt và / hoặc lấy mẫu ngẫu nhiên từ tập dữ liệu của bạn chưa?
Peter Flom - Tái lập Monica

2
Có vấn đề gì với việc loại bỏ mực thừa khỏi các điểm chồng chéo trong cốt truyện, @Peter?
whuber

1

Bạn có thể làm một hexbinâm mưu.

x <- rnorm(1200000)
mean.x <- mean(x)
sd.x <- sd(x)
quantiles.x <- quantile(x, probs = seq(0,1,b=0.000001))
quantiles.empirical <- qnorm(seq(0,1,by=0.000001),mean.x,sd.x)

library(hexbin)
bin <- hexbin(quantiles.empirical[-c(1,length(quantiles.empirical))],quantiles.x[-c(1,length(quantiles.x))],xbins=100)
plot(bin)

Tôi không biết liệu điều đó có thực sự phù hợp với dữ liệu âm mưu hay không (xem thêm nhận xét của tôi về câu hỏi của tôi về lý do tại sao điều này sẽ không hoạt động cho trường hợp cụ thể của tôi). Điểm thú vị mặc dù. Tôi có thể thấy nếu tôi có thể làm cho nó hoạt động trên các mô hình riêng lẻ so với obs.
ness101

1

Một cách khác là boxplot song song; bạn nói rằng bạn có hai bộ dữ liệu, vì vậy một cái gì đó như:

y <- rnorm(1200000)
x <- rnorm(1200000)
grpx <- cut(y,20)
boxplot(y~grpx)

và bạn có thể điều chỉnh các tùy chọn khác nhau để làm cho nó tốt hơn với dữ liệu của bạn.


Tôi chưa bao giờ là một fan hâm mộ lớn của việc phân tách dữ liệu liên tục, nhưng đó là một ý tưởng thú vị.
ness101
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.