【问题标题】:Replacing Numpy elements with the closest if condition is met如果满足条件,则用最接近的替换 Numpy 元素
【发布时间】:2018-07-13 01:21:03
【问题描述】:

我有一个大型 numpy 数组,我需要对其进行操作,以便每个元素都在一定范围内。

我可以识别无效的元素

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

或更简单地:

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

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

例如

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

【问题讨论】:

  • 一种方法,用 NaN 替换无效值并使用 bfill()/ffill() 方法。
  • 附注:你不需要where,你可以使用v[v&gt;upper_lim]

标签: python arrays numpy boolean


【解决方案1】:

pandas 具有填充能力,这就是您所描述的,但是您必须将数组转换为浮点数,因为 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]

【讨论】:

  • 是的,但您必须编写自己的 fillna 函数。
  • @ErroriSalvo,请参阅仅 numpy 解决方案的更新答案
【解决方案2】:

正如我在 cmets 中建议的那样,

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.])

【讨论】:

  • 如果upper_lim=1e14会怎样?
  • @ErroriSalvo 那么这个解决方案将产生一个巨大的a数组=/
  • 这就是我所指的 :) 同样,迭代它不会很有效
猜你喜欢
  • 2013-11-15
  • 2021-12-22
  • 1970-01-01
  • 2015-11-03
  • 1970-01-01
  • 2018-08-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多