2009-06-21 44 views
5

Cho một bàn nơi cột đầu tiên là giây đã qua một điểm tham chiếu nhất định và điều thứ hai là một đo lường tùy ý:làm mịn dữ liệu thời gian đột xuất lấy mẫu

6 0.738158581 
21 0.801697222 
39 1.797224596 
49 2.77920469 
54 2.839757536 
79 3.832232283 
91 4.676794376 
97 5.18244704 
100 5.521878863 
118 6.316630137 
131 6.778507504 
147 7.020395216 
157 7.331607129 
176 7.637492223 
202 7.848079136 
223 7.989456499 
251 8.76853608 
278 9.092367123 
    ... 

Như bạn thấy, các phép đo được lấy mẫu tại các thời điểm bất thường . Tôi cần phải làm mịn dữ liệu bằng cách tính trung bình số đọc lên đến 100 giây trước mỗi phép đo (bằng Python). Vì bảng dữ liệu là rất lớn, nên một phương thức dựa trên trình vòng lặp thực sự được ưu tiên. Thật không may, sau hai giờ mã hóa tôi không thể tìm ra giải pháp hiệu quả và thanh lịch.

Có ai có thể giúp tôi không?

EDIT s

  1. Tôi muốn một đọc vuốt cho từng đọc nguyên, và việc đọc vuốt là trở thành trung bình cộng của việc đọc liệu và bất kỳ những người khác trong vòng 100 (đồng bằng) giây trước . (John, bạn là đúng)

  2. lớn ~ 1e6 - dòng 10e6 + cần phải làm việc với RAM chặt chẽ

  3. Dữ liệu được xấp xỉ ngẫu nhiên đi bộ

  4. Dữ liệu được sắp xếp

GIẢI PHÁP

Tôi đã thử nghiệm các giải pháp được đề xuất bởi J Machin và yairchu. Cả hai đều cho cùng một kết quả, tuy nhiên, trên tập dữ liệu của tôi, phiên bản của J Machin thực hiện theo cấp số nhân, trong khi đó yairchu là tuyến tính. Sau đây là thời gian thực hiện được đo bằng IPython của % timeit (ms):

data size J Machin yairchu 
10  90.2  55.6 
50   930   258 
100   3080  514 
500   64700  2660 
1000  253000  5390 
2000  952000  11500 

Cảm ơn tất cả các bạn đã giúp đỡ.

+1

có quá lớn để được xử lý trong các mảng có nhiều mảng không? Bạn có bao nhiêu món đồ? –

+0

Là nội suy tuyến tính này để tìm các điểm bội số của 100? –

+0

Nếu bạn có yêu cầu làm mịn, hãy xây dựng thêm một chút. Tôi đã thử một vài lần nhưng tôi không thể phân tích cú pháp mô tả này của bạn: "Tôi cần phải làm mịn dữ liệu bằng cách lấy trung bình số đọc lên đến 100 giây trước mỗi phép đo". – rix0rrr

Trả lời

2

Tôi đang sử dụng kết quả tổng hợp mà tôi đang thêm thành viên mới và trừ các thành viên cũ. Tuy nhiên theo cách này người ta có thể bị tích lũy điểm không chính xác nổi.

Vì vậy, tôi thực hiện "Deque" với danh sách. Và bất cứ khi nào Deque của tôi phân bổ lại thành một kích thước nhỏ hơn. Tôi tính toán lại số tiền trong cùng một dịp.

Tôi cũng tính điểm trung bình đến điểm x bao gồm điểm x sao cho có ít nhất một điểm mẫu đến mức trung bình.

def getAvgValues(data, avgSampleTime): 
    lastTime = 0 
    prevValsBuf = [] 
    prevValsStart = 0 
    tot = 0 
    for t, v in data: 
    avgStart = t - avgSampleTime 
    # remove too old values 
    while prevValsStart < len(prevValsBuf): 
     pt, pv = prevValsBuf[prevValsStart] 
     if pt > avgStart: 
     break 
     tot -= pv 
     prevValsStart += 1 
    # add new item 
    tot += v 
    prevValsBuf.append((t, v)) 
    # yield result 
    numItems = len(prevValsBuf) - prevValsStart 
    yield (t, tot/numItems) 
    # clean prevVals if it's time 
    if prevValsStart * 2 > len(prevValsBuf): 
     prevValsBuf = prevValsBuf[prevValsStart:] 
     prevValsStart = 0 
     # recalculate tot for not accumulating float precision error 
     tot = sum(v for (t, v) in prevValsBuf) 
+0

(1) Đó là một thực hiện rất thú vị của một deque. (2) Tôi nghi ngờ rằng OP rất lo lắng về các lỗi làm tròn điểm trôi nổi tích luỹ; họ chắc chắn sẽ bị cắt rất nhỏ so với những thay đổi nghiêm trọng của việc làm mịn ... nhưng nếu anh ta, sử dụng một người bổ sung Kahan để duy trì tổng số chạy có thể được xem xét. –

+0

Lưu ý rằng việc này rất tốn kém tính toán so với mức trung bình di động theo hàm mũ (http://stackoverflow.com/questions/1023860/exponential-moving-average-sampled-at-varying-times/1024008). Trừ khi bạn đặc biệt cần đảm bảo rằng tất cả các mẫu trong phạm vi thời gian đóng góp như nhau, và những cái cũ không đóng góp gì cả, tôi sẽ đi với EMA hiệu quả hơn nhiều. –

+0

@Curt Sampson: OP đặc biệt được yêu cầu cho số này – yairchu

-1

điều gì đó về điều này, giữ giá trị lưu trữ cho đến khi chênh lệch thời gian với thời gian qua là> 100, trung bình và mang lại giá trị như vậy ví dụ:

def getAvgValues(data): 
    lastTime = 0 
    prevValues = [] 
    avgSampleTime=100 

    for t, v in data: 
     if t - lastTime < avgSampleTime: 
      prevValues.append(v) 
     else: 
      avgV = sum(prevValues)/len(prevValues) 
      lastTime = t 
      prevValues = [v] 
      yield (t,avgV) 

for v in getAvgValues(data): 
    print v 
+0

ông yêu cầu trung bình 100 giây trước đó cho tất cả các lần đo ban đầu. bạn chỉ đưa ra 2 kết quả cho ví dụ của mình – yairchu

+0

hmm tôi hiểu nhầm nó, bất kỳ cách nào giống như bạn sửa đổi nó cho giải pháp đúng –

+0

Tôi đã không sửa đổi nó thực sự. Tôi chỉ sử dụng tên biến của bạn. – yairchu

2

Bạn chưa nói chính xác khi nào bạn muốn xuất. Tôi giả định rằng bạn muốn một đọc trơn tru cho mỗi đọc thô, và đọc trơn tru là là trung bình số học của đọc nguyên và bất kỳ người nào khác trong 100 giây (đồng bằng) trước đó.

Câu trả lời ngắn: sử dụng collection.deque ... nó sẽ không bao giờ chứa nhiều hơn "delta" số lần đọc. Cách tôi đã thiết lập nó, bạn có thể điều trị deque giống như một danh sách, và dễ dàng tính toán trung bình hoặc một số gizmoid ưa thích mà cung cấp cho trọng lượng hơn để đọc gần đây.

Long trả lời:

>>> the_data = [tuple(map(float, x.split())) for x in """\ 
... 6  0.738158581 
... 21  0.801697222 
[snip] 
... 251  8.76853608 
... 278  9.092367123""".splitlines()] 
>>> import collections 
>>> delta = 100.0 
>>> q = collections.deque() 
>>> for t, v in the_data: 
...  while q and q[0][0] <= t - delta: 
...   # jettison outdated readings 
...   _unused = q.popleft() 
...  q.append((t, v)) 
...  count = len(q) 
...  print t, sum(item[1] for item in q)/count, count 
... 
... 
6.0 0.738158581 1 
21.0 0.7699279015 2 
39.0 1.112360133 3 
49.0 1.52907127225 4 
54.0 1.791208525 5 
79.0 2.13137915133 6 
91.0 2.49500989771 7 
97.0 2.8309395405 8 
100.0 3.12993279856 9 
118.0 3.74976297144 9 
131.0 4.41385300278 9 
147.0 4.99420529389 9 
157.0 5.8325615685 8 
176.0 6.033109419 9 
202.0 7.15545189083 6 
223.0 7.4342562845 6 
251.0 7.9150342134 5 
278.0 8.4246097095 4 
>>> 

Sửa

một cửa: có được ưa thích của bạn gizmoid đây.Dưới đây là các mã:

numerator = sum(item[1] * upsilon ** (t - item[0]) for item in q) 
denominator = sum(upsilon ** (t - item[0]) for item in q) 
gizmoid = numerator/denominator 

nơi upsilon nên ít hơn một chút so với phiên bản 1.0 (< = zero là bất hợp pháp, ngay trên zero không ít mịn, một giúp bạn số học có nghĩa là cộng thêm thời gian CPU lãng phí, và lớn hơn một cho nghịch đảo của mục đích của bạn).

+0

Dường như với tôi một danh sách thông thường sẽ hoạt động ở đây, sử dụng .pop (0) thay vì .popleft(). Lợi thế của collections.deque là gì? – Paul

+2

popping bên trái của một danh sách Python là O (N); popping bên trái của deque là O (1) –

0

Dữ liệu của bạn có vẻ là khoảng tuyến tính:

Plot of your data http://rix0r.nl/~rix0r/share/shot-20090621.144851.gif

Những loại mịn bạn đang tìm kiếm? Một hình vuông nhỏ nhất phù hợp với một dòng cho tập dữ liệu này? Một số loại bộ lọc thông thấp? Hay cái gì khác?

Vui lòng cho chúng tôi biết đơn đăng ký để chúng tôi có thể tư vấn cho bạn tốt hơn một chút.

EDIT: Ví dụ, tùy thuộc vào ứng dụng, nội suy một dòng giữa điểm đầu tiên và điểm cuối có thể đủ tốt cho mục đích của bạn.

+0

Lần này nó có thể là tuyến tính. – Nosredna

0

một này làm cho nó tuyến tính:

def process_data(datafile): 
    previous_n = 0 
    previous_t = 0 
    for line in datafile: 
     t, number = line.strip().split() 
     t = int(t) 
     number = float(number) 
     delta_n = number - previous_n 
     delta_t = t - previous_t 
     n_per_t = delta_n/delta_t 
     for t0 in xrange(delta_t): 
      yield previous_t + t0, previous_n + (n_per_t * t0) 
     previous_n = n 
     previous_t = t 

f = open('datafile.dat') 

for sample in process_data(f): 
    print sample 
+0

(1) .strip() là dư thừa. (2) Bạn dường như đã quên cập nhật previous_ * mỗi lần xung quanh (3) Thậm chí sau đó, nó không rõ ràng những gì này có nghĩa là để làm ... nó sẽ xuất hiện để làm một nội suy tuyến tính giữa đọc trước và đọc hiện tại, tại một khoảng thời gian thứ hai - một giải thích thú vị về các yêu cầu của OP. (3) Tôi nghĩ bạn có nghĩa là 'cho t0 trong xrange (1, delta_t + 1)' –

-2

Âm thanh như bạn cần một công thức làm tròn đơn giản. Làm tròn số bất kỳ để một khoảng thời gian tùy ý:

tròn (num/interval) * khoảng

Bạn có thể thay thế tròn với sàn hoặc trần cho "dẫn đến" hoặc "từ" ảnh hưởng. Nó có thể làm việc trong bất kỳ ngôn ngữ nào, bao gồm cả SQL.

0

O (1) bộ nhớ trong trường hợp bạn có thể lặp lại đầu vào nhiều lần - bạn có thể sử dụng một trình lặp cho "bên trái" và một cho "bên phải".

def getAvgValues(makeIter, avgSampleTime): 
    leftIter = makeIter() 
    leftT, leftV = leftIter.next() 
    tot = 0 
    count = 0 
    for rightT, rightV in makeIter(): 
    tot += rightV 
    count += 1 
    while leftT <= rightT - avgSampleTime: 
     tot -= leftV 
     count -= 1 
     leftT, leftV = leftIter.next() 
    yield rightT, tot/count 
+1

Tôi đoán OP muốn hiển thị giá trị trơn tru trong thời gian thực ... nghĩ theo dõi nhịp tim trong khu chăm sóc đặc biệt. –

0

Trong khi nó mang lại cho trung bình theo cấp số nhân mục nát, chứ không phải là trung bình tổng, tôi nghĩ bạn có thể muốn những gì tôi gọi là exponential moving average with varying alpha, mà thực sự là một đơn cực bộ lọc thông thấp. Bây giờ có một giải pháp cho câu hỏi đó, và nó chạy theo thời gian tuyến tính đến số lượng các điểm dữ liệu. Xem nếu nó làm việc cho bạn.

Các vấn đề liên quan