需要一次迭代 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
我有一些传感器读数的大型数据集,其中偶尔会有一行为 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