在箱图中标注离群值-Python

时间:2020-05-11 16:15:09

标签: python label seaborn boxplot

我正在分析极端天气事件。我的数据框称为df,如下所示:

|    Date    |      Qm      |
|------------|--------------|                                              
| 1993-01-01 |  4881.977061 |
| 1993-02-01 |  4024.396839 |
| 1993-03-01 |  3833.664650 |
| 1993-04-01 |  4981.192526 |
| 1993-05-01 |  6286.879798 |  
| 1993-06-01 |  6939.726070 |
| 1993-07-01 |  6492.936065 |
|    ...     |      ...     |

我想知道极端事件是否在同一年发生,以异常值衡量。因此,我使用seaborn进行箱形图绘制:

# Qm boxplot analysis

boxplot = sns.boxplot(x=df.index.month,y=df['Qm'])
plt.show()

Boxplot obtained

现在,我想在同一图中显示离群值所对应的年份。因此,用日期标记它们。

我已经检查了多个包含箱线图的库,但是没有如何标记它们的线索。

PD:我在本例中使用seaborn,但是任何可以帮助您的库都会受到高度赞赏

谢谢!

2 个答案:

答案 0 :(得分:5)

您可以遍历数据框,并将每个值与异常值的限制进行比较。默认情况下,这些限制为1.5 timesIQR超出低四分位数和高四分位数的范围。对于超出该范围的每个值,您都可以在其旁边绘制年份。如果您希望显示更多或更少的年份,请随意修改此定义。

这里有一些代码来说明这个想法。在代码中,离群值的位置旁边显示了年份的最后两位数字。

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

Y = 26
df = pd.DataFrame({'Date': pd.date_range('1993-01-01', periods=12 * Y, freq='M'),
                   'Qm': np.random.normal(np.tile(5000 + 1000 * np.sin(np.linspace(0, 2 * np.pi, 12)), Y), 1000)})
df.set_index('Date', inplace=True)
boxplot = sns.boxplot(x=df.index.month, y=df['Qm'])
month_q1 = df.groupby(df.index.month).quantile(0.25)['Qm'].to_numpy()
month_q3 = df.groupby(df.index.month).quantile(0.75)['Qm'].to_numpy()
outlier_top_lim = month_q3 + 1.5 * (month_q3 - month_q1)
outlier_bottom_lim = month_q1 - 1.5 * (month_q3 - month_q1)

for row in df.itertuples():
    month = row[0].month - 1
    val = row.Qm
    if val > outlier_top_lim[month] or val < outlier_bottom_lim[month]:
        plt.text(month, val, f' {row[0].year % 100:02d}', ha='left', va='center')
plt.xlabel('Month')
plt.tight_layout()
plt.show()

sample plot

答案 1 :(得分:0)

我不知道将标签与数据一起交给seaborn.boxplotpandas.DataFrame.boxplot的方法。解决方法是,您可以使用matplotlib's annotate function手动注释绘图。

这里是一个例子:

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

np.random.seed(42)
df = pd.DataFrame( np.random.randn(50, 2), columns=['Col1', 'Col2'])
boxplot = df.boxplot(
    column=['Col1', 'Col2'],
    flierprops=dict(markerfacecolor='r', marker='s', label='not shown'))
boxplot.annotate(
    '1993',
    (1, -2.65),
    xytext=(0.3, 0.15),
    textcoords='axes fraction',
    arrowprops=dict(facecolor='black', arrowstyle='wedge'),
    fontsize=11)
plt.show()

结果图:

<code>annotate</code> example