工作计划中的异常值

2024-04-25 23:46:32 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图为个人的工作安排寻找异常值(主要是高变化)。试图找出,如果有人来或离开的方式以外的个人(上午8:30至下午5点)或团体正常(上午7点至下午6点)。我试过用标准差,但问题是

  1. 它给了我平均值两边的异常值。如果有些人在工作时间迟到(比如上午10点)或者早退(比如下午4点)。你知道吗
  2. 另一个问题是中庸本身。如果在数据集的开始有一些极端情况,则需要大量观察才能将平均值降到最频繁的次数。例如,一组在下午3点、上午11点、上午10点、上午9点左右的时间很少,但大多数时间在早上6点左右,但平均值需要大量观察才能得到早上6点的平均值。我想到了加权平均数,但这意味着我必须将时间四舍五入到最接近的30分钟左右。但希望避免改变数据点。你知道吗

是否有任何已知的方法来发现工作日程中的异常值?我试图搜索,但我得到的只是时间序列中的异常值。但我在寻找时间本身的异常值。有什么建议吗?你知道吗

注意:我的数据集有PersonID和多次(刷卡)次/day/PersonID。我使用的是Python2.7。你知道吗


Tags: 数据方法方式时间情况序列次数建议
1条回答
网友
1楼 · 发布于 2024-04-25 23:46:32

如果我理解正确的话,你是在寻找那些与他们自己和整体的标准相比出发极早或到达极晚的人。你知道吗

  1. 您遇到的第一个问题似乎与标记晚或早偏离(nx标准偏差)的异常值有关。您应该能够控制是在一侧还是两侧标记异常值。你知道吗
  2. 第二个问题与小样本的偏差或不稳定有关。 除非您提前知道异常值阈值,否则在任何情况下都需要一个健康的样本来识别异常值。如果平均值没有足够快地归零到公共值 你追求共同的价值,用模式代替中庸。你知道吗

另外,我建议把每天到达和离开的时间差作为一个单独的衡量标准。你知道吗

下面我有一个方向性的方法/建议来解决你的问题,python3(抱歉)。
它应该解决你提到的问题,但没有增加我认为你应该包括的每日工作时间。你知道吗

这是您可以预期的输出:

Outlier PersonIDs based on overall data
array([ 1.,  4.,  7.,  8.])
Outlier PersonIDs based on each user's data and overall deviation
array([ 1.,  3.,  4.,  5.,  7.,  8.,  9.])

这是每日到达和离开时间分布: enter image description here

代码如下:

#! /usr/bin/python3

import random
import pandas as pd
import numpy as np
import scipy.stats
import pprint
pp = pprint.PrettyPrinter(indent=4)

# Visualize:
import matplotlib.pyplot as plt

#### Create Sample Data START
# Parameters:
TimeInExpected=8.5 # 8:30am
TimeOutExpected=17 # 5pm
sig=1 # 1 hour variance
Persons=11
# Increasing the ratio between sample size and persons will make more people outliers.
SampleSize=20
Accuracy=1 # Each hour is segmented by hour tenth (6 minutes)

# Generate sample
SampleDF=pd.DataFrame([
    np.random.randint(1,Persons,size=(SampleSize)),
    np.around(np.random.normal(TimeInExpected, sig,size=(SampleSize)),Accuracy),
    np.around(np.random.normal(TimeOutExpected, sig,size=(SampleSize)),Accuracy)
    ]).T
SampleDF.columns = ['PersonID', 'TimeIn','TimeOut']

# Visualize
plt.hist(SampleDF['TimeIn'],rwidth=0.5,range=(0,24))
plt.hist(SampleDF['TimeOut'],rwidth=0.5,range=(0,24))
plt.xticks(np.arange(0,24, 1.0))
plt.xlabel('Hour of day')
plt.ylabel('Arrival / Departure Time Frequency')
plt.show()
#### Create Sample Data END


#### Analyze data 
# Threshold distribution percentile
OutlierSensitivity=0.05 # Will catch extreme events that happen 5% of the time. - one sided! i.e. only late arrivals and early departures.
presetPercentile=scipy.stats.norm.ppf(1-OutlierSensitivity)

# Distribution feature and threshold percentile
argdictOverall={
    "ExpIn":SampleDF['TimeIn'].mode().mean().round(1)
    ,"ExpOut":SampleDF['TimeOut'].mode().mean().round(1)
    ,"sigIn":SampleDF['TimeIn'].var()
    ,"sigOut":SampleDF['TimeOut'].var()
    ,"percentile":presetPercentile
}
OutlierIn=argdictOverall['ExpIn']+argdictOverall['percentile']*argdictOverall['sigIn']
OutlierOut=argdictOverall['ExpOut']-argdictOverall['percentile']*argdictOverall['sigOut']

# Overall
# See all users with outliers - overall
Outliers=SampleDF["PersonID"].loc[(SampleDF['TimeIn']>OutlierIn) | (SampleDF['TimeOut']<OutlierOut)]

# See all observations with outliers - Overall
# pp.pprint(SampleDF.loc[(SampleDF['TimeIn']>OutlierIn) | (SampleDF['TimeOut']<OutlierOut)].sort_values(["PersonID"]))

# Sort and remove NAs
Outliers=np.sort(np.unique(Outliers))
# Show users with overall outliers:
print("Outlier PersonIDs based on overall data")
pp.pprint(Outliers)

# For each
OutliersForEach=[]
for Person in SampleDF['PersonID'].unique():
    # Person specific dataset
    SampleDFCurrent=SampleDF.loc[SampleDF['PersonID']==Person]
    # Distribution feature and threshold percentile
    argdictCurrent={
        "ExpIn":SampleDFCurrent['TimeIn'].mode().mean().round(1)
        ,"ExpOut":SampleDFCurrent['TimeOut'].mode().mean().round(1)
        ,"sigIn":SampleDFCurrent['TimeIn'].var()
        ,"sigOut":SampleDFCurrent['TimeOut'].var()
        ,"percentile":presetPercentile
    }
    OutlierIn=argdictCurrent['ExpIn']+argdictCurrent['percentile']*argdictCurrent['sigIn']
    OutlierOut=argdictCurrent['ExpOut']-argdictCurrent['percentile']*argdictCurrent['sigOut']
    if SampleDFCurrent['TimeIn'].max()>OutlierIn or SampleDFCurrent['TimeOut'].min()<OutlierOut:
        Outliers=np.append(Outliers,Person)

# Sort and get unique values
Outliers=np.sort(np.unique(Outliers))
# Show users with overall outliers:
print("Outlier PersonIDs based on each user's data and overall deviation")
pp.pprint(Outliers)

相关问题 更多 >