Python 如何删除Pandas中连续的坏数据点
我有一个熊猫数据框,看起来像:Python 如何删除Pandas中连续的坏数据点,python,pandas,time-series,sensors,Python,Pandas,Time Series,Sensors,我有一个熊猫数据框,看起来像: import pandas as pd import numpy as np df = pd.DataFrame({"Dummy_Var": [1]*12, "B": [6, 143.3, 143.3, 143.3, 3, 4, 93.9, 93.9, 93.9, 2, 2, 7], "C": [4.1, 23.2, 23.2, 23.2, 4.3, 2.5, 7.8, 7.8, 2,
import pandas as pd
import numpy as np
df = pd.DataFrame({"Dummy_Var": [1]*12,
"B": [6, 143.3, 143.3, 143.3, 3, 4, 93.9, 93.9, 93.9, 2, 2, 7],
"C": [4.1, 23.2, 23.2, 23.2, 4.3, 2.5, 7.8, 7.8, 2, 7, 7, 7]})
B C Dummy_Var
0 6.0 4.1 1
1 143.3 23.2 1
2 143.3 23.2 1
3 143.3 23.2 1
4 3.0 4.3 1
5 4.0 2.5 1
6 93.9 7.8 1
7 93.9 7.8 1
8 93.9 2.0 1
9 2.0 7.0 1
10 2.0 7.0 1
11 7.0 7.0 1
当同一数字连续出现三次或更多次时,该数据应替换为NAN
。因此,结果应该是:
B C Dummy_Var
0 6.0 4.1 1
1 NaN NaN 1
2 NaN NaN 1
3 NaN NaN 1
4 3.0 4.3 1
5 4.0 2.5 1
6 NaN 7.8 1
7 NaN 7.8 1
8 NaN 2.0 1
9 2.0 NaN 1
10 2.0 NaN 1
11 7.0 NaN 1
我编写了一个函数,它可以:
def non_sense_remover(df, examined_columns, allowed_repeating):
def count_each_group(grp, column):
grp['Count'] = grp[column].count()
return grp
for col in examined_columns:
sel = df.groupby((df[col] != df[col].shift(1)).cumsum()).apply(count_each_group, column=col)["Count"] > allowed_repeating
df.loc[sel, col] = np.nan
return df
df = non_sense_remover(df, ["B", "C"], 2)
然而,我真正的数据帧有2M行和18列!在2M行上运行此功能非常慢。有没有更有效的方法?我错过什么了吗?提前感谢。我们正在使用
groupby
+mask
m=df[['B','C']]
df[['B','C']]=m.mask(m.apply(lambda x : x.groupby(x.diff().ne(0).cumsum()).transform('count'))>2)
df
Out[1245]:
B C Dummy_Var
0 6.0 4.1 1
1 NaN NaN 1
2 NaN NaN 1
3 NaN NaN 1
4 3.0 4.3 1
5 4.0 2.5 1
6 NaN 7.8 1
7 NaN 7.8 1
8 NaN 2.0 1
9 2.0 NaN 1
10 2.0 NaN 1
11 7.0 NaN 1
由此看来,使用apply/transform(在您的例子中是apply)是造成最大瓶颈的原因。我引用的链接更详细地介绍了这是为什么以及如何解决它在这种情况下构建布尔掩码将比基于
apply()
的解决方案更有效,特别是对于大型数据集。以下是一种方法:
cols = df[['B', 'C']]
mask = (cols.shift(-1) == cols) & (cols.shift(1) == cols)
df[mask | mask.shift(1).fillna(False) | mask.shift(-1).fillna(False)] = np.nan
编辑: 对于更一般的方法,将长度为
N
的序列替换为NaN
,您可以执行以下操作:
from functools import reduce
from operator import or_, and_
def replace_sequential_duplicates_with_nan(df, N):
mask = reduce(and_, [cols.shift(i) == cols.shift(i + 1)
for i in range(N - 1)])
full_mask = reduce(or_, [mask.shift(-i).fillna(False)
for i in range(N)])
df[full_mask] = np.nan
这是一个迅速的解决办法。如果接受的限制是9,怎么办?i、 e.一行中有9个连续点是可以的,但只要有10个或更多点,我们就给它们分配
NaN
。我们能推广这种方法吗?谢谢你的编辑。这种方法花了22秒在我的2M行数据帧上完成任务,数据帧有18列。它非常优雅,我从中学到了很多东西。这种方法花了7秒钟在我的2M行数据框上完成任务,数据框有18列。如果您能在回答中详细说明为什么我的初始函数如此之慢,那就太好了。@ahoosh for loop是一个耗费时间的函数,如果您正在使用pandas,请尝试在这里不使用for loop