Pandas:如何在数据框中检测峰值点(异常值)?

4

我有一个包含多个速度值的pandas数据框,这些值是连续移动的,但它们是传感器数据,所以我们经常会在中间出现错误,一些点的移动平均似乎也无法帮助解决问题。那么我应该使用什么方法来去除数据中的异常值或峰值点呢?

例如:

data points = {0.5,0.5,0.7,0.6,0.5,0.7,0.5,0.4,0.6,4,0.5,0.5,4,5,6,0.4,0.7,0.8,0.9}

在这个数据中,如果我看到4、4、5、6这几个点完全是异常值,在此之前我使用了5分钟的滚动平均窗口来平滑这些值,但仍然会得到许多这样的异常点,我想要去除它们,有人能建议我任何技术来摆脱这些点吗?
我有一张更清晰的数据图像:enter image description here
如果您在这里看到数据如何显示一些异常点,我必须去除它们。有什么办法可以摆脱这些点吗?

你可以计算所有点的z分数,并拒绝超过某个阈值的点。 - ALollz
@ALollz,如果您的正态分布在两侧都有值,那么这种方法是可行的,但在这种情况下,我不会有任何小于零的值,或者速度永远不会变为负数,那么在这种情况下使用z-score是否正确呢...??? - id101112
哦,好观点,那些数据不会是正常的。你有没有感性地了解底层分布应该是什么? - ALollz
这里是一个可能有用的链接:偏斜分布的离群值检测 - ALollz
2个回答

3

我认为使用scipy.stats.zscore()的z-score方法是解决这个问题的途径。在这篇文章中,他们关注的是在删除潜在异常值之前要使用哪种方法。在我看来,你面临的挑战有点简单,因为根据提供的数据,很容易识别潜在的异常值,而不必转换数据。下面是一个代码片段,可以做到这一点。但请记住,什么看起来像异常值和什么不是完全取决于您的数据集。在删除了一些异常值之后,以前没有看起来像异常值的数据可能会突然变成异常值。请看:

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from scipy import stats

# your data (as a list)
data = [0.5,0.5,0.7,0.6,0.5,0.7,0.5,0.4,0.6,4,0.5,0.5,4,5,6,0.4,0.7,0.8,0.9]

# initial plot
df1 = pd.DataFrame(data = data)
df1.columns = ['data']
df1.plot(style = 'o')

# Function to identify and remove outliers
def outliers(df, level):

    # 1. temporary dataframe
    df = df1.copy(deep = True)

    # 2. Select a level for a Z-score to identify and remove outliers
    df_Z = df[(np.abs(stats.zscore(df)) < level).all(axis=1)]
    ix_keep = df_Z.index

    # 3. Subset the raw dataframe with the indexes you'd like to keep
    df_keep = df.loc[ix_keep]

    return(df_keep)

原始数据:

enter image description here

测试运行1: Z得分=4:

enter image description here

如您所见,因为设置的水平过高,没有删除任何数据。

测试运行2: Z得分=2:

enter image description here

现在我们有所进展。已删除两个异常值,但仍有一些可疑数据。

测试运行3: Z得分=1.2:

enter image description here

这看起来非常好。剩下的数据现在似乎比以前更均匀分布。但是,原始数据点突出的数据点现在开始看起来有点像潜在的异常值。那么何时停止呢?这将完全取决于您!

编辑:以下是整个内容,供简单复制粘贴:

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from scipy import stats

# your data (as a list)
data = [0.5,0.5,0.7,0.6,0.5,0.7,0.5,0.4,0.6,4,0.5,0.5,4,5,6,0.4,0.7,0.8,0.9]

# initial plot
df1 = pd.DataFrame(data = data)
df1.columns = ['data']
df1.plot(style = 'o')

# Function to identify and remove outliers
def outliers(df, level):

    # 1. temporary dataframe
    df = df1.copy(deep = True)

    # 2. Select a level for a Z-score to identify and remove outliers
    df_Z = df[(np.abs(stats.zscore(df)) < level).all(axis=1)]
    ix_keep = df_Z.index

    # 3. Subset the raw dataframe with the indexes you'd like to keep
    df_keep = df.loc[ix_keep]

    return(df_keep)

# remove outliers
level = 1.2
print("df_clean = outliers(df = df1, level = " + str(level)+')')
df_clean = outliers(df = df1, level = level)

# final plot
df_clean.plot(style = 'o')

@id101112 这解决了你的问题吗?如果还没有,请告诉我,我会再次查看它。 - vestland
抱歉回复晚了,我确实使用了zscore方法,但是我采用了一些不同的方式。非常感谢您的回复。 - id101112

1
你可以按照以下方式裁剪超过某个分位数的值:
import numpy as np
clean_data=np.array(data_points)[(data_points<=np.percentile(data_points, 95))]

在pandas中,您可以使用df.quantile函数,您可以在这里找到它。

或者您可以使用Q3+1.5*IQR方法来排除异常值,就像您通过箱线图做的那样。


我之前使用了这两种技术,但似乎对我的数据无效,所以我仍在努力找出其他好的方法来仅提取那些最高点。我使用了z-score和IQR方法来去除这些点。 - id101112

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接