需要一次迭代 pandas.DataFrame 3 行的数据清理

Data cleanup that requires iterating over pandas.DataFrame 3 rows at a time

我有一些传感器读数的大型数据集,其中偶尔会有一行为 0。启发式非常简单:如果上一行和下一行不为 0,我认为这是传感器故障,我将替换这一行取其周围两者的平均值。

在某些合法情况下,传感器读数可能为 0,因此仅查看 0 不是一种选择。

到目前为止,我想出了以下清理方法:

data["x+1"] = data["x"].shift(1)
data["x+2"] = data["x"].shift(2)

res = data[["x", "x+1", "x+2"]].apply( 
  lambda x : (x[0] + x[2])/2 
             if ((x[0] > 0) and (x[1] <= 0) and (x[2] > 0) ) 
             else x[1], axis=1 )

data[x] = res.shift(-1)

原则上这是可行的,我更喜欢它迭代 3 个压缩和移动的数据帧,如下所示:

for row1, row2, row3 in zip( data.iterrows(), data.shift(1).iterrows(), data.shift(2).iterrows() ):
       ...

然而,这两种方法都需要永恒的时间来处理。我读到 apply 无法矢量化并且内存中存在一些重复(输出)。

我也尝试过以下方法,但它无法正常工作:

data.loc[ data["x"] == 0 , "x" ] = np.NaN
data["x"].fillna( method="ffill", limit=1, inplace=True)
data["x"].fillna( 0 )

这快如闪电,但没有达到我希望它做的效果(它只是停止填充超过第一个 NaN 而我希望它只填充 如果只有一个 NaN)

我不确定如何才能使此解决方案扩展到数 GB 的文件。我目前正在通过文件求助于使用 awk 到 运行 ,但这并不理想,因为代码的可维护性较差,而且已经有很多其他类似的预处理发生在python 程序。

如有任何建议,我们将不胜感激。

您可以使用 where 函数将其向量化:

preV = data['x'].shift(1)
nexT = data['x'].shift(-1)
data['x'] = data['x'].where((data['x'] > 0) | (preV <= 0) | (nexT <= 0), (preV + nexT)/2)

有输入:

data = pd.DataFrame({"x": [1,2,3,0,0,2,3,0,4,2,0,0,0,1]})

给出:

0     1.0
1     2.0
2     3.0
3     0.0
4     0.0
5     2.0
6     3.0
7     3.5              # 0 gets replaced here
8     4.0
9     2.0
10    0.0
11    0.0
12    0.0
13    1.0
Name: x, dtype: float64

或者您可以创建一个逻辑索引来指示应该替换值的位置,并将前后行中的值的平均值分配给它们:

data.loc[(data['x'] <= 0) & (preV > 0) & (nexT > 0), "x"] = (preV + nexT)/2