2012-12-18 93 views
6

Tôi có 1 dữ liệu chiều thiết lập với một số không có giá trị dữ liệu được thiết lập như là 9999. Dưới đây là một trích vì nó là khá dài:Python: Thay thế các giá trị trong một mảng

this_array = [ 4, 4, 1, 9999, 9999, 9999, -5, -4, ... ] 

Tôi muốn thay thế không có giá trị dữ liệu nào với giá trị trung bình gần nhất ở hai bên, tuy nhiên vì một số giá trị dữ liệu không có giá trị gần nhất cũng như không có giá trị dữ liệu, thay thế chúng khó hơn một chút. tức là tôi muốn ba giá trị dữ liệu không được thay thế bằng -2. Tôi đã tạo ra một vòng lặp để đi qua từng vô hướng trong mảng và thử nghiệm mà không có dữ liệu:

for k in this_array: 
    if k == 9999: 
     temp = np.where(k == 9999, (abs(this_array[k-1]-this_array[k+1])/2), this_array[k]) 
    else: 
     pass 
this_array[k] = temp 

Tuy nhiên tôi cần phải thêm vào một nếu chức năng hoặc cách để có những giá trị trước k-1 hoặc sau khi k +1 nếu điều đó cũng bằng 9999 ví dụ:

if np.logical_or(k+1 == 9999, k-1 == 9999): 
    temp = np.where(k == 9999, (abs(this_array[k-2]-this_array[k+2])/2), this_array[k]) 

Như bạn có thể nói, mã này có thể kết thúc với giá trị sai hoặc kết thúc bằng vô số chức năng lồng nhau. Có ai biết một cách sạch hơn để thực hiện điều này vì nó khá biến trong suốt tập dữ liệu?

Theo yêu cầu: Nếu điểm đầu tiên và/hoặc cuối cùng không có dữ liệu, tốt nhất nên thay thế bằng điểm dữ liệu gần nhất.

+3

Điều gì xảy ra nếu phần tử cuối cùng trong danh sách là '9999'? Bạn muốn thay thế giá trị nào? – Cameron

+0

@Cameron Xin lỗi, nếu phần tử cuối cùng là '9999' thì nó có thể được thay thế bằng phần tử cuối cùng thứ hai. Cảm ơn. – AJEnvMap

Trả lời

3

Có thể có một cách efficeint hơn để làm điều này với các chức năng NumPy, nhưng đây là một giải pháp sử dụng itertools module:

from itertools import groupby 

for k, g in groupby(range(len(this_array)), lambda i: this_array[i] == 9999): 
    if k: 
     indices = list(g) 
     new_v = (this_array[indices[0]-1] + this_array[indices[-1]+1])/2 
     this_array[indices[0]:indices[-1]+1].fill(new_v) 

Nếu yếu tố cuối cùng hoặc yếu tố đầu tiên có thể 9999, bạn sử dụng như sau:

from itertools import groupby 

for k, g in groupby(range(len(this_array)), lambda i: this_array[i] == 9999): 
    if k: 
     indices = list(g) 
     prev_i, next_i = indices[0]-1, indices[-1]+1 
     before = this_array[prev_i] if prev_i != -1 else this_array[next_i] 
     after = this_array[next_i] if next_i != len(this_array) else before 
     this_array[indices[0]:next_i].fill((before + after)/2) 

Ví dụ sử dụng phiên bản thứ hai:

>>> from itertools import groupby 
>>> this_array = np.array([9999, 4, 1, 9999, 9999, 9999, -5, -4, 9999]) 
>>> for k, g in groupby(range(len(this_array)), lambda i: this_array[i] == 9999): 
...  if k: 
...   indices = list(g) 
...   prev_i, next_i = indices[0]-1, indices[-1]+1 
...   before = this_array[prev_i] if prev_i != -1 else this_array[next_i] 
...   after = this_array[next_i] if next_i != len(this_array) else before 
...   this_array[indices[0]:next_i].fill((before + after)/2) 
... 
>>> this_array 
array([ 4, 4, 1, -2, -2, -2, -5, -4, -4]) 
1

Tôi sẽ làm điều gì đó theo các dòng sau:

import numpy as np 

def fill(arr, fwd_fill): 
    out = arr.copy() 
    if fwd_fill: 
    start, end, step = 0, len(out), 1 
    else: 
    start, end, step = len(out)-1, -1, -1 
    cur = out[start] 
    for i in range(start, end, step): 
    if np.isnan(out[i]): 
     out[i] = cur 
    else: 
     cur = out[i] 
    return out 

def avg(arr): 
    fwd = fill(arr, True) 
    back = fill(arr, False) 
    return (fwd[:-2] + back[2:])/2. 

arr = np.array([ 4, 4, 1, np.nan, np.nan, np.nan, -5, -4]) 
print arr 
print avg(arr) 

Chức năng đầu tiên có thể thực hiện chuyển tiếp hoặc điền lùi, thay thế mọi NaN bằng NaN không gần nhất.

Khi bạn có điều đó, tính toán mức trung bình là không đáng kể và được thực hiện bởi hàm thứ hai.

Bạn không nói cách bạn muốn phần tử đầu tiên và phần tử cuối cùng được xử lý, do đó, mã chỉ cắt xén chúng. Cuối cùng, cần lưu ý rằng hàm có thể trả về NaN nếu đầu tiên hoặc phần tử cuối cùng của mảng đầu vào bị thiếu (trong trường hợp này không có dữ liệu để tính toán một số giá trị trung bình).

0

Đây là giải pháp đệ quy nơi đầu tiên và cuối cùng không phải là 9999. Bạn có thể làm sạch nó bằng máy phát khi đệ quy có thể bị sâu. Đó là một sự khởi đầu hợp lý

def a(list, first, depth):  
    if ([] == list): 
    return [] 
    car = list[0] 
    cdr = list[1:] 
    if (9999 == car):   
     return a(cdr, first, depth+1) 
    if (depth != 0): 
     avg = [((first + car) /2)] * depth 
     return avg + [car] + a(cdr, car, 0) 
    else: 
     return [car] + a(cdr, car, 0) 



print a([1,2,9999, 4, 9999,9999, 12],0,0) 
# => [1, 2, 3, 4, 8, 8, 12] 
0

Ok, tôi sợ tôi phải viết bản thân mình, bạn có thể sử dụng np.interp hoặc tương đương (có thể phần nào đẹp hơn và nhiều tính năng hơn) chức năng scipy bạn có thể tìm thấy trong scipy.interpolate.

Ok, đọc lại ... Tôi đoán bạn không muốn nội suy tuyến tính?Trong trường hợp này tất nhiên điều này không làm việc ... Mặc dù tôi chắc chắn có một số phương pháp vectorized.

imort numpy as np 
# data is the given array. 
data = data.astype(float) # I cast to float, if you don't want that badly... 
valid = data != 9999 
x = np.nonzero(valid)[0] 
replace = np.nonzero(~valid)[0] 
valid_data = data[x] 

# using np.interp, but I think you will find better things in scipy.interpolate 
# if you don't mind using scipy. 
data[replace] = np.interp(replace, x, valid_data, 
            left=valid_data[0], right=valid_data[-1]) 
Các vấn đề liên quan