Phương pháp thống kê để vẽ dữ liệu hiệu quả hơn khi có hàng triệu điểm?


31

Tôi thấy R có thể mất nhiều thời gian để tạo ra các ô khi có hàng triệu điểm - không có gì ngạc nhiên khi các điểm được vẽ riêng lẻ. Hơn nữa, các lô như vậy thường quá lộn xộn và dày đặc là không hữu ích. Nhiều điểm trùng nhau và tạo thành một khối màu đen và rất nhiều thời gian được dành để vẽ nhiều điểm hơn vào khối đó.

Có bất kỳ sự thay thế thống kê nào để thể hiện dữ liệu lớn trong một biểu đồ phân tán tiêu chuẩn không? Tôi đã xem xét một âm mưu mật độ, nhưng có những lựa chọn thay thế khác là gì?n


1
Đối với một số giải pháp với các ô tuyến tính, hãy xem stats.stackexchange.com/questions/35220/ .
whuber

Câu trả lời:


13

Đây là một nhiệm vụ khó khăn với không có giải pháp sẵn sàng (điều này là tất nhiên vì cốt truyện mật độ là một dự phòng hấp dẫn hơn là không ai thực sự quan tâm). Vậy, bạn có thể làm gì?

Nếu chúng thực sự trùng nhau (nghĩa là có cùng tọa độ X & Y) và bạn không sử dụng alpha, ý tưởng tốt nhất sẽ là giảm sự trùng lặp bằng cách sử dụng unique(với alpha, nó có thể được tóm tắt qua các nhóm như vậy).

Nếu không, bạn có thể làm tròn các tọa độ theo cách thủ công đến các pixel gần nhất và sử dụng phương pháp trước đó (tuy nhiên đây là một giải pháp bẩn).

Cuối cùng, bạn có thể tạo một biểu đồ mật độ chỉ để sử dụng nó để lấy mẫu các điểm trong các khu vực dày đặc nhất. Mặt khác, điều này sẽ không tạo ra cốt truyện giống hệt nhau và có thể giới thiệu các tạo tác nếu không được điều chỉnh chính xác.


5
Giảm sự chồng chéo với uniquehoặc bằng cách làm tròn có thể dẫn đến các âm mưu (lừa đảo) sai lệch. Điều quan trọng là bằng cách nào đó chỉ ra số lượng chồng lấp thông qua một số phương tiện đồ họa như độ sáng hoặc với các ô hướng dương.
whuber

44

Nhìn vào gói hexbin thực hiện giấy / phương pháp của Dan Carr. Các họa tiết pdf có nhiều chi tiết hơn mà tôi trích dẫn dưới đây:

1. Sơ lượt

Hexagon binning là một dạng biểu đồ bivariate hữu ích để hiển thị cấu trúc trong các bộ dữ liệu với n lớn. Khái niệm cơ bản của hexning binning là cực kỳ đơn giản;

  1. mặt phẳng xy trên tập hợp (phạm vi (x), phạm vi (y)) được chia thành một lưới các hình lục giác thông thường.
  2. số lượng điểm rơi trong mỗi hình lục giác được tính và lưu trữ trong cấu trúc dữ liệu
  3. n106

Nếu kích thước của lưới và các vết cắt trong đoạn màu được chọn theo kiểu thông minh hơn cấu trúc vốn có trong dữ liệu sẽ xuất hiện trong các ô được tô màu. Những cảnh báo tương tự áp dụng cho việc tạo hình lục giác như áp dụng cho biểu đồ và cần thận trọng trong việc chọn tham số tạo thùng


4
Đó là một trong những tốt đẹp. Chỉ cần những gì bác sĩ đã ra lệnh.
Roman Luštrik

13
(+1) Cũng được quan tâm, smoothScatter {RColorBrewer}densCols {grDevices}. Tôi có thể xác nhận nó hoạt động khá tốt với hàng ngàn đến hàng triệu điểm từ dữ liệu di truyền.
chl

2
Nếu có dữ liệu 3D thì sao? (quá nhiều cho scatterplot3d)
skan

Để tiết kiệm thời gian cho người khác - tôi đã tìm thấy smoothScatter, như đã đề xuất 2 bình luận, để có mặc định / hoạt động tốt hơn nhiều.
Charlie

16

Tôi phải thừa nhận rằng tôi không hiểu đầy đủ đoạn cuối của bạn:

"Tôi không tìm kiếm một âm mưu mật độ (mặc dù chúng thường hữu ích), tôi sẽ muốn đầu ra giống như một cuộc gọi cốt truyện đơn giản nhưng nhanh hơn nhiều so với hàng triệu overplots nếu có thể."

Nó cũng không rõ loại cốt truyện (chức năng) bạn đang tìm kiếm.

Cho rằng bạn có các biến số, bạn có thể tìm thấy các ô hình lục giác hoặc các ô hướng dương hữu ích. Để tham khảo thêm, xem


6

Một câu trả lời trực tiếp khác cho câu hỏi là gói rgl, có thể vẽ hàng triệu điểm bằng OpenGL. Ngoài ra, chỉ định kích thước điểm (ví dụ 3) và thu nhỏ để xem các tâm khối này là các khối nguyên khối hoặc phóng to và xem cấu trúc của những gì từng là nguyên khối - kích thước điểm không đổi nhưng khoảng cách giữa chúng trên màn hình phụ thuộc vào việc phóng to. Mức độ Alpha cũng có thể được sử dụng.


5

Đây là một tập tin tôi gọi bigplotfix.R. Nếu bạn lấy nó, nó sẽ xác định một trình bao bọc để plot.xy"nén" dữ liệu cốt truyện khi nó rất lớn. Trình bao bọc không làm gì nếu đầu vào nhỏ, nhưng nếu đầu vào lớn thì nó sẽ chia nó thành các khối và chỉ vẽ các giá trị x và y tối đa và tối thiểu cho mỗi khối. Tìm nguồn cung ứng bigplotfix.Rcũng phản hồi graphics::plot.xyđể trỏ đến trình bao bọc (tìm nguồn cung ứng nhiều lần là OK).

Lưu ý rằng plot.xylà "ngựa thồ" chức năng cho các phương pháp âm mưu tiêu chuẩn như plot(), lines(), và points(). Do đó, bạn có thể tiếp tục sử dụng các hàm này trong mã của mình mà không cần sửa đổi và các ô lớn của bạn sẽ được tự động nén.

Đây là một số ví dụ đầu ra. Về cơ bản plot(runif(1e5)), với các điểm và đường thẳng, và có và không có "nén" được triển khai ở đây. Biểu đồ "điểm nén" bỏ lỡ vùng giữa do tính chất của nén, nhưng biểu đồ "đường nén" trông gần giống với bản gốc không nén hơn. Thời gian dành cho png()thiết bị; vì một số lý do, điểm trên pngthiết bị nhanh hơn nhiều so với trong X11thiết bị, nhưng tốc độ tăng tốc X11tương đương ( X11(type="cairo")chậm hơn so với X11(type="Xlib")trong thí nghiệm của tôi).

Đầu ra thử nghiệm "bigplotfix.R"

Lý do tôi viết điều này là vì tôi cảm thấy mệt mỏi vì chạy một plot()cách tình cờ trên một tập dữ liệu lớn (ví dụ: tệp WAV). Trong những trường hợp như vậy, tôi sẽ phải chọn giữa chờ vài phút để âm mưu kết thúc và chấm dứt phiên R của tôi bằng một tín hiệu (do đó làm mất lịch sử lệnh và các biến gần đây của tôi). Bây giờ nếu tôi có thể nhớ tải tệp này trước mỗi phiên, tôi thực sự có thể có được một âm mưu hữu ích trong những trường hợp này. Một thông báo cảnh báo nhỏ cho biết khi dữ liệu lô đã được "nén".

# bigplotfix.R
# 28 Nov 2016

# This file defines a wrapper for plot.xy which checks if the input
# data is longer than a certain maximum limit. If it is, it is
# downsampled before plotting. For 3 million input points, I got
# speed-ups of 10-100x. Note that if you want the output to look the
# same as the "uncompressed" version, you should be drawing lines,
# because the compression involves taking maximum and minimum values
# of blocks of points (try running test_bigplotfix() for a visual
# explanation). Also, no sorting is done on the input points, so
# things could get weird if they are out of order.
test_bigplotfix = function() {
  oldpar=par();
  par(mfrow=c(2,2))
  n=1e5;
  r=runif(n)
  bigplotfix_verbose<<-T
  mytitle=function(t,m) { title(main=sprintf("%s; elapsed=%0.4f s",m,t["elapsed"])) }
  mytime=function(m,e) { t=system.time(e); mytitle(t,m); }

  oldbigplotfix_maxlen = bigplotfix_maxlen
  bigplotfix_maxlen <<- 1e3;

  mytime("Compressed, points",plot(r));
  mytime("Compressed, lines",plot(r,type="l"));
  bigplotfix_maxlen <<- n
  mytime("Uncompressed, points",plot(r));
  mytime("Uncompressed, lines",plot(r,type="l"));
  par(oldpar);
  bigplotfix_maxlen <<- oldbigplotfix_maxlen
  bigplotfix_verbose <<- F
}

bigplotfix_verbose=F

downsample_xy = function(xy, n, xlog=F) {
  msg=if(bigplotfix_verbose) { message } else { function(...) { NULL } }
  msg("Finding range");
  r=range(xy$x);
  msg("Finding breaks");
  if(xlog) {
    breaks=exp(seq(from=log(r[1]),to=log(r[2]),length.out=n))
  } else {
    breaks=seq(from=r[1],to=r[2],length.out=n)
  }
  msg("Calling findInterval");
  ## cuts=cut(xy$x,breaks);
  # findInterval is much faster than cuts!
  cuts = findInterval(xy$x,breaks);
  if(0) {
    msg("In aggregate 1");
    dmax = aggregate(list(x=xy$x, y=xy$y), by=list(cuts=cuts), max)
    dmax$cuts = NULL;
    msg("In aggregate 2");
    dmin = aggregate(list(x=xy$x, y=xy$y), by=list(cuts=cuts), min)
    dmin$cuts = NULL;
  } else { # use data.table for MUCH faster aggregates
    # (see http://stackoverflow.com/questions/7722493/how-does-one-aggregate-and-summarize-data-quickly)
    suppressMessages(library(data.table))
    msg("In data.table");
    dt = data.table(x=xy$x,y=xy$y,cuts=cuts)
    msg("In data.table aggregate 1");
    dmax = dt[,list(x=max(x),y=max(y)),keyby="cuts"]
    dmax$cuts=NULL;
    msg("In data.table aggregate 2");
    dmin = dt[,list(x=min(x),y=min(y)),keyby="cuts"]
    dmin$cuts=NULL;
    #  ans = data_t[,list(A = sum(count), B = mean(count)), by = 'PID,Time,Site']
  }
  msg("In rep, rbind");
  # interleave rows (copied from a SO answer)
  s <- rep(1:n, each = 2) + (0:1) * n
  xy = rbind(dmin,dmax)[s,];
  xy
}

library(graphics);
# make sure we don't create infinite recursion if someone sources
# this file twice
if(!exists("old_plot.xy")) {
  old_plot.xy = graphics::plot.xy
}

bigplotfix_maxlen = 1e4

# formals copied from graphics::plot.xy
my_plot.xy = function(xy, type, pch = par("pch"), lty = par("lty"),
  col = par("col"), bg = NA, cex = 1, lwd = par("lwd"),
  ...) {

  if(bigplotfix_verbose) {
    message("In bigplotfix's plot.xy\n");
  }

  mycall=match.call();
  len=length(xy$x)
  if(len>bigplotfix_maxlen) {
    warning("bigplotfix.R (plot.xy): too many points (",len,"), compressing to ",bigplotfix_maxlen,"\n");
    xy = downsample_xy(xy, bigplotfix_maxlen, xlog=par("xlog"));
    mycall$xy=xy
  }
  mycall[[1]]=as.symbol("old_plot.xy");

  eval(mycall,envir=parent.frame());
}

# new binding solution adapted from Henrik Bengtsson
# https://stat.ethz.ch/pipermail/r-help/2008-August/171217.html
rebindPackageVar = function(pkg, name, new) {
  # assignInNamespace() no longer works here, thanks nannies
  ns=asNamespace(pkg)
  unlockBinding(name,ns)
  assign(name,new,envir=asNamespace(pkg),inherits=F)
  assign(name,new,envir=globalenv())
  lockBinding(name,ns)
}
rebindPackageVar("graphics", "plot.xy", my_plot.xy);

0

Có lẽ tôi sẽ xa lánh phương pháp của mình, những ký ức tồi tệ về một trong những nghiên cứu của tôi đã la hét mọi người vì đã vứt bỏ dữ liệu tốt bằng cách dịch chúng thành các danh mục (tất nhiên, tôi đồng ý bây giờ là một ngày lol), không biết. Dù sao, nếu bạn đang nói về một scatterplot, thì tôi cũng gặp vấn đề tương tự. Bây giờ, khi tôi có dữ liệu số, tôi không có ý nghĩa gì để phân loại nó để phân tích. Nhưng hình dung là một câu chuyện khác. Những gì tôi đã thấy phù hợp nhất với tôi là trước tiên (1) chia biến độc lập của bạn thành các nhóm bằng cách sử dụng hàm cắt. Bạn có thể chơi xung quanh với số lượng nhóm, và sau đó (2) chỉ đơn giản là âm mưu DV so với phiên bản cắt của IV. R sẽ tạo ra các ô hộp thay vì âm mưu phân tán kinh tởm đó. Tôi khuyên bạn nên loại bỏ các ngoại lệ tạo thành cốt truyện (sử dụng tùy chọn phác thảo = FALSE trong lệnh vẽ). Một lần nữa, tôi KHÔNG BAO GIỜ lãng phí dữ liệu số hoàn toàn tốt bằng cách phân loại và sau đó phân tích. Quá nhiều vấn đề làm điều đó. Mặc dù tôi biết đó là một chủ đề tranh luận sôi nổi. Nhưng làm điều đó đặc biệt cho mục tiêu ít nhất là làm cho một số ý nghĩa trực quan ra khỏi dữ liệu, không có nhiều tác hại tôi đã thấy từ nó. Tôi đã vẽ dữ liệu lớn tới 10 triệu và vẫn có thể hiểu được từ phương pháp này. Mong rằng sẽ giúp! Trân trọng! đã nhìn thấy từ nó. Tôi đã vẽ dữ liệu lớn tới 10 triệu và vẫn có thể hiểu được từ phương pháp này. Mong rằng sẽ giúp! Trân trọng! đã nhìn thấy từ nó. Tôi đã vẽ dữ liệu lớn tới 10 triệu và vẫn có thể hiểu được từ phương pháp này. Mong rằng sẽ giúp! Trân trọng!


0

Đối với chuỗi thời gian lớn, tôi đã yêu thích smoothScatter (một phần của cơ sở R không hơn không kém). Tôi thường phải đưa vào một số dữ liệu bổ sung và việc bảo tồn API cốt truyện cơ bản thực sự hữu ích:

set.seed(1)
ra <- rnorm(n = 100000, sd = 1, mean = 0)
smoothScatter(ra)
abline(v=25000, col=2)
text(25000, 0, "Event 1", col=2)

Cung cấp cho bạn (nếu bạn tha thứ cho thiết kế):

ví dụ phân tán

Nó luôn có sẵn và hoạt động tốt với các bộ dữ liệu khổng lồ, vì vậy, ít nhất hãy xem những gì bạn có.

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.