Python:替换数组中的值
我有一个一维数据集,其中一些无数据值设置为9999。这是一段很长的摘录:Python:替换数组中的值,python,arrays,numpy,interpolation,median,Python,Arrays,Numpy,Interpolation,Median,我有一个一维数据集,其中一些无数据值设置为9999。这是一段很长的摘录: this_array = [ 4, 4, 1, 9999, 9999, 9999, -5, -4, ... ] 我想用两边最接近的值的平均值替换无数据值,但是,由于一些无数据值也有最接近的值,因此替换它们有点困难。 i、 e.我希望将三个无数据值替换为-2。我创建了一个循环来遍历数组中的每个标量,并测试是否没有数据: for k in this_array: if k == 9999:
this_array = [ 4, 4, 1, 9999, 9999, 9999, -5, -4, ... ]
我想用两边最接近的值的平均值替换无数据值,但是,由于一些无数据值也有最接近的值,因此替换它们有点困难。
i、 e.我希望将三个无数据值替换为-2。我创建了一个循环来遍历数组中的每个标量,并测试是否没有数据:
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
但是,如果k-1之前或k+1之后的值也等于9999,我需要添加一个if函数或方法来获取该值,例如:
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])
可以看出,这段代码会变得很混乱,因为最终可能会使用错误的值或加载嵌套的if函数。
有没有人知道一种更干净的方法来实现这一点,因为它在整个数据集中都是可变的
根据要求:如果第一个和/或最后一个点没有数据,最好用最近的数据点替换它们。可能有一种更有效的方法使用numpy函数来实现这一点,但这里有一个解决方案,使用: 如果最后一个元素或第一个元素可以是
9999
,则使用以下选项:
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)
使用第二个版本的示例:
>>> 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])
我会按照以下思路做一些事情:
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)
第一个函数可以向前或向后填充,用最近的非NaN替换每个NaN
一旦你有了它,计算平均值就很简单了,并且是由第二个函数完成的
您没有说明希望如何处理第一个和最后一个元素,因此代码只是将它们切掉
最后,值得注意的是,如果输入数组的第一个或最后一个元素丢失(在这种情况下,没有数据来计算某些平均值),函数可以返回NaN。这里有一个递归解决方案,其中第一个和最后一个元素不是9999。您可能可以使用生成器来清理它,因为递归可能会变得有点深。这是一个合理的开始
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]
好的,恐怕我必须自己编写,您可以使用
np.interp
或类似的(可能更好、功能更强大)scipy函数,您可以在scipy.interpolate
中找到
好的,重读。。。我猜你不想要线性插值?在这种情况下,这当然不太管用。。。虽然我确信有一些矢量化的方法
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])
如果列表中的最后一个元素是
9999
,该怎么办?您希望用什么值替换它?@Cameron表示歉意,如果最后一个元素是9999
,则可以用最后第二个元素替换它。谢谢
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])