Một thuật toán tốt để ước tính trung vị của một tập dữ liệu đọc một lần rất lớn là gì?


48

Tôi đang tìm kiếm một thuật toán tốt (có nghĩa là tính toán tối thiểu, yêu cầu lưu trữ tối thiểu) để ước tính trung vị của một tập dữ liệu quá lớn để lưu trữ, sao cho mỗi giá trị chỉ có thể được đọc một lần (trừ khi bạn lưu trữ rõ ràng giá trị đó). Không có giới hạn về dữ liệu có thể được giả định.

Xấp xỉ là tốt, miễn là độ chính xác được biết đến.

Bất kỳ con trỏ?


4
Có lẽ, hỏi về Stackoverflow có thể nhận được câu trả lời tốt hơn.

2
@Srikant:> đó là một lĩnh vực nghiên cứu thống kê khá tích cực :) Giải pháp gần với giới hạn lý thuyết thấp hơn về mặt lưu trữ cũng liên quan đến một số cấu trúc xác suất khá thông minh. Tất cả trong tất cả tôi đã ngạc nhiên khi lần đầu tiên tôi nhìn nó một vài tháng trước; có nhiều chỉ số ở đây hơn là bắt mắt.
user603

Câu trả lời:


6

Bạn có thể nhóm tập dữ liệu thành các tập dữ liệu nhỏ hơn nhiều không (giả sử 100 hoặc 1000 hoặc 10.000 điểm dữ liệu) Nếu sau đó bạn tính trung bình của từng nhóm. Nếu bạn đã làm điều này với đủ bộ dữ liệu, bạn có thể vẽ một cái gì đó như trung bình kết quả của từng bộ nhỏ hơn và con woul này, bằng cách chạy đủ bộ dữ liệu nhỏ hơn hội tụ đến một giải pháp 'trung bình'.


Điều này thật thú vị, và nơi mà một số lời khuyên thống kê có thể đến! Giả sử trong tổng số tôi đã có (nói) 500.000 điểm iid và tôi xem xét các nhóm (nói) 1.000 trong số đó, và tính trung bình của mỗi nhóm. Bây giờ tôi đã có 500 trung vị. Có lý thuyết nào có thể cho phép tôi tính khoảng tin cậy cho trung bình tổng thể dựa trên 500 trung vị này không?
PeterR

4
Vì vậy, theo một đồng nghiệp đã mất từ ​​lâu, apropoach tốt nhất dường như là Chiranjeeb Buragohain và Subhash Suri. Số lượng trên luồng. cs.ucsb.edu/~suri/:54ir/ency.pdf Tôi cũng thích cách tiếp cận của Ian, vì các trung vị của các tập dữ liệu nhỏ hơn này sẽ hội tụ thành một phân phối bình thường và vì vậy tôi có thể tạo các khoảng conf cho các trung vị.
PeterR

10

Làm thế nào về một cái gì đó như một thủ tục binning? Giả sử (cho mục đích minh họa) mà bạn biết rằng các giá trị nằm trong khoảng từ 1 đến 1 triệu. Thiết lập N thùng, có kích thước S. Vì vậy, nếu S = 10000, bạn sẽ có 100 thùng, tương ứng với các giá trị [1: 10000, 10001: 20000, ..., 990001: 1000000]

Sau đó, bước qua các giá trị. Thay vì lưu trữ từng giá trị, chỉ cần tăng bộ đếm trong thùng thích hợp. Sử dụng trung điểm của mỗi thùng làm ước tính, bạn có thể đưa ra xấp xỉ hợp lý của trung vị. Bạn có thể chia tỷ lệ này thành độ phân giải mịn hoặc thô như bạn muốn bằng cách thay đổi kích thước của các thùng. Bạn chỉ bị giới hạn bởi bao nhiêu bộ nhớ.

Vì bạn không biết giá trị của mình có thể lớn đến mức nào, chỉ cần chọn kích thước thùng đủ lớn để bạn không bị hết bộ nhớ, sử dụng một số tính toán ngược nhanh chóng. Bạn cũng có thể lưu trữ các thùng một cách thưa thớt, sao cho bạn chỉ thêm một thùng nếu nó chứa một giá trị.

Biên tập:

Liên kết ryfm cung cấp một ví dụ về việc này, với bước bổ sung là sử dụng tỷ lệ phần trăm tích lũy để ước tính chính xác hơn điểm trong thùng trung vị, thay vì chỉ sử dụng điểm giữa. Đây là một cải tiến tốt đẹp.


Vấn đề với cách tiếp cận binning là chúng ta không có giới hạn trên tốt cho dữ liệu, và vì vậy điểm giữa của thùng lớn nhất sẽ phải rất lớn. Vì vậy, chúng ta cần một số lượng lớn các thùng (không đủ bộ nhớ cho việc đó) hoặc có các thùng khá rộng (sau đó sẽ dẫn đến một câu trả lời khá không chính xác.) Và dữ liệu không phải là rất thưa thớt.
PeterR

Vì bạn chỉ quan tâm đến trung vị, tại sao bạn không thể làm cho các thùng rộng hơn với giá trị cao hơn của biến của bạn?
russellpierce

drknexus - bởi vì chúng ta không biết thùng lớn nhất nên là gì.
PeterR

Bạn có bất kỳ trực giác nào về phạm vi sẽ là gì không? Nếu bạn khá chắc chắn rằng hơn một nửa số câu trả lời sẽ ở dưới số N, thì bạn có thể làm cho thùng cuối cùng của mình lớn như bạn muốn. Có thể thùng cuối cùng của bạn là tất cả các con số lớn hơn 1 nghìn tỷ - điều đó có đủ cao không? Với dung lượng bộ nhớ trong các hệ thống hiện đại, bạn có thể lưu trữ RẤT NHIỀU thùng và đạt được độ phân giải khá cao. Về mặt cấu trúc dữ liệu, chúng tôi không nói bất cứ điều gì lạ mắt và bộ nhớ chuyên sâu ở đây.
chrisamiller

Có trực giác nào không? Đúng. Và cách tiếp cận của bạn có thể làm việc nói chung. Tuy nhiên, trong trường hợp này chúng ta không thể có nhiều bộ nhớ / tính toán. Đó là trong một ứng dụng mạng, nơi thiết bị có thể nhìn thấy hàng chục ngàn mục mỗi giây và có RẤT ít xử lý cho mục đích này. Không phải kịch bản lý tưởng / điển hình, tôi biết, nhưng đó là điều làm cho nó thú vị!
PeterR


8

Các thuật toán Rivest-Tarjan-Selection (đôi khi còn được gọi là trung bình-of-trung vị thuật toán) sẽ cho phép bạn tính toán các yếu tố trung bình trong thời gian tuyến tính mà không cần bất kỳ phân loại. Đối với các tập dữ liệu lớn, việc này có thể nhanh hơn một chút so với sắp xếp theo tuyến tính. Tuy nhiên, nó sẽ không giải quyết vấn đề lưu trữ bộ nhớ của bạn.



2

Tôi chưa bao giờ phải làm điều này, vì vậy đây chỉ là một gợi ý.

Tôi thấy hai khả năng (khác).

Một nửa dữ liệu

  1. Tải một nửa dữ liệu và sắp xếp
  2. Tiếp theo đọc các giá trị còn lại và so sánh với danh sách đã sắp xếp của bạn.
    1. Nếu giá trị mới lớn hơn, loại bỏ nó.
    2. khác đặt giá trị trong danh sách được sắp xếp và loại bỏ giá trị lớn nhất khỏi danh sách đó.

Phân phối lấy mẫu

Tùy chọn khác, là sử dụng một xấp xỉ liên quan đến phân phối lấy mẫu. Nếu dữ liệu của bạn là Bình thường, thì lỗi tiêu chuẩn cho n vừa phải là:

1,253 * sd / sqrt (n)

Để xác định kích thước của n mà bạn sẽ hài lòng, tôi đã chạy mô phỏng Monte-Carlo nhanh trong R

n = 10000
outside.ci.uni = 0
outside.ci.nor = 0
N=1000
for(i in 1:N){
  #Theoretical median is 0
  uni = runif(n, -10, 10)
  nor  = rnorm(n, 0, 10)

  if(abs(median(uni)) > 1.96*1.253*sd(uni)/sqrt(n))
    outside.ci.uni = outside.ci.uni + 1

  if(abs(median(nor)) > 1.96*1.253*sd(nor)/sqrt(n))
    outside.ci.nor = outside.ci.nor + 1
}

outside.ci.uni/N
outside.ci.nor/N

Với n = 10000, 15% ước tính trung bình thống nhất nằm ngoài CI.


3
Bộ dữ liệu có khả năng quá lớn để đọc được một nửa ... trong bối cảnh mạng nơi thiết bị xử lý có thể thấy hàng chục nghìn mục mỗi giây và có thể có đủ bộ nhớ để lưu trữ chỉ vài trăm. Ngoài ra dữ liệu chắc chắn không phải là Gaussian. Trong thực tế, nó không phù hợp với bất kỳ phân phối phổ biến nào.
PeterR


1

Đây là câu trả lời cho câu hỏi được hỏi về stackoverflow: https://stackoverflow.com/questions/1058813/on-line-iterator-alerskyms-for-estimating-statistic-median-mode-skewness/2144754#2144754

Bản cập nhật lặp lại trung vị + = eta * sgn (mẫu - trung vị) nghe có vẻ là một cách để đi.


1
Nhưng sau đó làm thế nào để chọn eta, và những gì doe sthis có nghĩa là thống kê? tức là làm thế nào để hình thành khoảng tin cậy cho trung vị từ kết quả này?
PeterR

@PeterR, hey, giải pháp cuối cùng bạn đã sử dụng là gì?
Aakash Goel

1

Các Remedian Algorithm (PDF) đưa ra một một vượt qua ước tính trung bình với nhu cầu lưu trữ thấp và độ chính xác được xác định rõ.

Người sửa chữa với cơ sở b tiến hành bằng cách tính toán trung vị của các nhóm quan sát b, và sau đó là trung vị của các trung vị này, cho đến khi chỉ còn một ước tính duy nhất. Phương pháp này chỉ cần k mảng có kích thước b (trong đó n = b ^ k) ...


1

Nếu các giá trị bạn đang sử dụng nằm trong một phạm vi nhất định, giả sử từ 1 đến 100000, bạn có thể tính toán trung bình một cách hiệu quả số lượng giá trị cực lớn (giả sử là hàng nghìn tỷ mục), với một số nguyên (mã này được lấy từ BSD được cấp phép -utils / sam-stats.cpp)

class ibucket {
public:
    int tot;
    vector<int> dat;
    ibucket(int max) {dat.resize(max+1);tot=0;}
    int size() const {return tot;};

    int operator[] (int n) const {
        assert(n < size());
        int i;
        for (i=0;i<dat.size();++i) {
            if (n < dat[i]) {
                return i;
            }
            n-=dat[i];
        }
    }

    void push(int v) {
        assert(v<dat.size());
        ++dat[v];
        ++tot;
    }
};


template <class vtype>
double quantile(const vtype &vec, double p) {
        int l = vec.size();
        if (!l) return 0;
        double t = ((double)l-1)*p;
        int it = (int) t;
        int v=vec[it];
        if (t > (double)it) {
                return (v + (t-it) * (vec[it+1] - v));
        } else {
                return v;
        }
}

Ngoài ra, điều này có thể được mở rộng để sử dụng số lượng thùng hữu hạn cho trung bình thời gian thực, v.v.
Erik Aronesty
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.