matplotlib:在绘图时忽略异常值

Ric*_*son 29 python plot matplotlib outliers percentile

我正在绘制各种测试的一些数据.有时在测试中我碰巧有一个异常值(比如说0.1),而所有其他值都小三个数量级.

使用matplotlib,我会对范围进行绘图 [0, max_data_value]

我怎样才能放大我的数据而不显示异常值,这会弄乱我的情节中的x轴?

我应该简单地采用95%并且[0, 95_percentile] 在x轴上具有范围吗?

Joe*_*ton 58

对于异常值,没有单一的"最佳"测试.理想情况下,您应该合并先验信息(例如,"因为等等,此参数不应超过x").

大多数异常值测试使用中位数绝对偏差,而不是第95百分位数或其他一些基于方差的测量.否则,计算出的方差/ stddev将严重偏离异常值.

这是一个实现一个更常见的异常值测试的函数.

def is_outlier(points, thresh=3.5):
    """
    Returns a boolean array with True if points are outliers and False 
    otherwise.

    Parameters:
    -----------
        points : An numobservations by numdimensions array of observations
        thresh : The modified z-score to use as a threshold. Observations with
            a modified z-score (based on the median absolute deviation) greater
            than this value will be classified as outliers.

    Returns:
    --------
        mask : A numobservations-length boolean array.

    References:
    ----------
        Boris Iglewicz and David Hoaglin (1993), "Volume 16: How to Detect and
        Handle Outliers", The ASQC Basic References in Quality Control:
        Statistical Techniques, Edward F. Mykytka, Ph.D., Editor. 
    """
    if len(points.shape) == 1:
        points = points[:,None]
    median = np.median(points, axis=0)
    diff = np.sum((points - median)**2, axis=-1)
    diff = np.sqrt(diff)
    med_abs_deviation = np.median(diff)

    modified_z_score = 0.6745 * diff / med_abs_deviation

    return modified_z_score > thresh
Run Code Online (Sandbox Code Playgroud)

作为使用它的示例,您可以执行以下操作:

import numpy as np
import matplotlib.pyplot as plt

# The function above... In my case it's in a local utilities module
from sci_utilities import is_outlier

# Generate some data
x = np.random.random(100)

# Append a few "bad" points
x = np.r_[x, -3, -10, 100]

# Keep only the "good" points
# "~" operates as a logical not operator on boolean numpy arrays
filtered = x[~is_outlier(x)]

# Plot the results
fig, (ax1, ax2) = plt.subplots(nrows=2)

ax1.hist(x)
ax1.set_title('Original')

ax2.hist(filtered)
ax2.set_title('Without Outliers')

plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 当中位数偏差为零时,这会中断。当我天真地加载一个包含超过50%零的数据集时,这发生了。 (2认同)

Jdo*_*dog 9

如果您不喜欢拒绝Joe提到的异常值,并且这样做纯粹是美学原因,您可以设置绘图的x轴限制:

plt.xlim(min_x_data_value,max_x_data_value)
Run Code Online (Sandbox Code Playgroud)

值是您希望显示的限制值.

plt.ylim(min,max) 也适用于设置y轴的限制.

  • 但是,对于直方图,OP还需要重新计算箱.Matplotlib使用固定的bin边缘.放大时它不会"重新绑定". (2认同)

Zst*_*ack 8

我认为使用熊猫分位数很有用,而且更加灵活。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)

pd_series = pd.Series(np.random.normal(size=300)) 
pd_series_adjusted = pd_series[pd_series.between(pd_series.quantile(.05), pd_series.quantile(.95))] 

ax1.boxplot(pd_series)
ax1.set_title('Original')

ax2.boxplot(pd_series_adjusted)
ax2.set_title('Adjusted')

plt.show()
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明


Jor*_*ona 7

我通常通过函数传递数据np.clip,如果您对数据的最大值和最小值有一些合理的估计,只需使用它。如果您没有合理的估计,裁剪数据的直方图将向您显示尾部的大小,如果异常值真的只是异常值,则尾部应该很小。

我运行的是这样的:

import numpy as np
import matplotlib.pyplot as plt

data = np.random.normal(3, size=100000)
plt.hist(np.clip(data, -15, 8), bins=333, density=True)
Run Code Online (Sandbox Code Playgroud)

如果更改裁剪函数中的最小值和最大值,则可以比较结果,直到为数据找到正确的值。

例子

在此示例中,您可以立即看到最大值 8 不好,因为您正在删除大量有意义的信息。-15 的最小值应该没问题,因为尾部甚至不可见。

您可能会编写一些基于此的代码,找到一些良好的边界,根据一些容差最小化尾部的大小。