用最接近的if条件替换Numpy元素

时间:2018-02-02 14:06:34

标签: python arrays numpy boolean

我需要操作一个大的numpy数组,以便每个元素都在一定的范围内。

我可以识别无效的元素

v[np.where(v>upper_lim)]
v[np.where(v<lower_lim)]

或更简单地通过:

v[v>upper_lim]
v[v<lower_lim]

现在我想用符合条件的最接近(早期)样本替换满足此条件的每个元素。

e.g。

upper_lim=10
lower_lim=1
v=[1,-77,3,4,5,13213,6,7,8,1024]

应该给出

v=[1,1,3,4,5,5,6,7,8,8]

当没有元素可用之前无效值时,我需要替换为下一个有效元素

所以

upper_lim=10
lower_lim=1
v=[-7,1,2,3,-77]

应该给出

v=[1,1,2,3,3]

使用pandas的可能解决方案:

import pandas as pd
v=pd.DataFrame(v)
v[v>ul]=np.nan
v[v<ll]=np.nan
v=v.fillna(method='ffill').fillna(method='bfill')
v=v.flatten()

但使用pandas不是我的选择

2 个答案:

答案 0 :(得分:3)

pandas具有填充功能,这是你所描述的,但是你必须将你的数组转换为float,因为numpy int数组不能保存np.nan值。

import pandas as pd
import numpy as np

upper = 10
lower = 1
v=np.array([1,-77,3,4,5,13213,6,7,8,1024])
s = pd.Series(v)
s[~((s>lower) & (s<upper))] = np.nan
s = s.fillna(method='pad')
# at this point the series is padded but the values are floats instead of 
# ints,  you can cast back to an int array if you wish

v2 = s.values.astype(int)
v2
# outputs:
array([1, 1, 3, 4, 5, 5, 6, 7, 8, 8])

更新

一个只有numpy的解决方案

# first we identify elements that are out of bounds and need to be filled from the data
mask = (v<lower) | (v>upper)
oob = np.where(mask)[0]

# for each oob value, we calculate the index that provides the fill-value using a forward fill or backward fill
def fillidx(i, mask_oob):
    try:
        if i == 0 or np.all(mask_oob[:i]): 
        # all elements from start are oob
            raise IndexError()
        n = -1 * (1 + np.argmin(mask_oob[:i][::-1]))
    except (IndexError):
        n = 1 + np.argmin(mask_oob[i+1:])
    return i + n


fill = [fillidx(i, mask) for i in oob]
v[mask] = v[fill]
print(v)

使用第一个测试数组v = np.array([1,-77,3,4,5,13213,6,7,8,1024]),输出如下:

[1 1 3 4 5 5 6 7 8 8]

使用第二个测试数组v = np.array([-7,1,2,3,-77])输出以下内容:

[1 1 2 3 3]

有一个数组,其中连续值超出界限,前几个元素也超出界限,即v = np.array([-200,20,1,-77,3,4,5,13213,-200,6,7,8,1024])我们得到以下输出:

[1 1 1 1 3 4 5 5 5 6 7 8 8]

答案 1 :(得分:0)

正如我在评论中所建议的那样,

v=[1,-77,3,4,5,13213,6,7,8,1024]
df=pd.DataFrame(v)

df[df>ul]=np.nan
df[df<ll]=np.nan
df=df.fillna(method='ffill')
v=np.array(df[0])

输出:

array([ 1.,  1.,  3.,  4.,  5.,  5.,  6.,  7.,  8.,  8.])