【问题标题】:detecting outliers on wide data frame检测宽数据框上的异常值
【发布时间】:2012-10-15 01:30:43
【问题描述】:

x

Team Date       Score
A    1-1-2012   80
A    1-2-2012   90
A    1-3-2012   50
A    1-4-2012   40   
B    1-1-2012   100
B    1-2-2012   60
B    1-3-2012   30
B    1-4-2012   70
etc

我需要并且可以将此数据框转换为宽数据框,为每个团队设置一行,并将所有观察结果和日期作为标题:

xx

Team 1-1-2012 1-2-2012  1-3-2012 1-4-2012
A    80       90        50        40
B    100     60         30        70  

我需要计算每一行的平均值和标准差,我可以这样做:

xx

Team 1-1-2012 1-2-2012  1-3-2012 1-4-2012  mean   sd
A    80       90        50        40       75    20
B    100     60         30        70       55    10 

考虑到我在数据框 xx 中有数千行。我想对每个单元格进行计算:

如果 abs(xx-Mean) > 3*SD,创建一个计数器列名并增加值。这个想法是将每个观察值与平均值和 sd 进行比较,如果给定团队的每个观察值都与此匹配 - abs(xx-Mean) > 3*SD,则增加计数器。检查每个单元格后,我想查看每个团队的每个计数器,并获得计数器值最高的前十名高团队。基本上我正在尝试检测最多的异常值。获得前 10 名团队名称后,我想在数据框 x 上绘制他们的时间序列数据。

我希望我没有让这变得比应该的更复杂。不确定,R 已经具有对每个单元格进行计算的功能。任何想法如何实现这一点表示赞赏?

【问题讨论】:

    标签: r


    【解决方案1】:

    我会将您的数据保留为长格式并使用plyrdata.table 或任何其他拆分-应用-组合工具来计算您的统计信息。以下是我将如何使用 plyr 来完成任务:

    #Your data
    dat <- read.table(text = "Team Date       Score
    A    1-1-2012   80
    A    1-2-2012   90
    A    1-3-2012   50
    A    1-4-2012   40   
    B    1-1-2012   100
    B    1-2-2012   60
    B    1-3-2012   30
    B    1-4-2012   70", header = TRUE)
    
    library(plyr)
    
    #Compute mean and sd by team
    dat <- ddply(dat, .(Team), transform, mean = mean(Score), sd = sd(Score))
    #Your outlier threshold
    dat <- transform(dat, outlier = abs(Score - mean) > 3*sd)
    #Cumulative sum by team
    dat <- ddply(dat, .(Team), transform, cumsumOutlier = cumsum(outlier))
    

    将此作为输出(与您的示例不匹配,但可能是您的真实数据):

     Team     Date Score mean       sd outlier cumsumOutlier
    1    A 1-1-2012    80   65 23.80476   FALSE             0
    2    A 1-2-2012    90   65 23.80476   FALSE             0
    3    A 1-3-2012    50   65 23.80476   FALSE             0
    4    A 1-4-2012    40   65 23.80476   FALSE             0
    5    B 1-1-2012   100   65 28.86751   FALSE             0
    6    B 1-2-2012    60   65 28.86751   FALSE             0
    7    B 1-3-2012    30   65 28.86751   FALSE             0
    8    B 1-4-2012    70   65 28.86751   FALSE             0
    

    【讨论】:

    • 提示某人提供一些计时结果...data.table 将赢得这场战斗,这里有一些 proof
    • 我很好奇您将如何使用 cumsumOutlier 列。我猜它会记录每个团队中发现的异常值的数量。您将如何将这些信息用于实际用途?
    【解决方案2】:

    long-formatdata.table 方法

    DT <- read.table( 'clipboard', header = T)
    library(data.table)
    DT <- as.data.table(DT)
    DT[, mean.score := mean(Score), by = Team]
    ##    Team     Date Score mean.score
    ## 1:    A 1-1-2012    80         65
    ## 2:    A 1-2-2012    90         65
    ## 3:    A 1-3-2012    50         65
    ## 4:    A 1-4-2012    40         65
    ## 5:    B 1-1-2012   100         65
    ## 6:    B 1-2-2012    60         65
    ## 7:    B 1-3-2012    30         65
    ## 8:    B 1-4-2012    70         65
    DT[, sd.score := sd(Score), by = Team]
    ##    Team     Date Score mean.score sd.score
    ## 1:    A 1-1-2012    80         65 23.80476
    ## 2:    A 1-2-2012    90         65 23.80476
    ## 3:    A 1-3-2012    50         65 23.80476
    ## 4:    A 1-4-2012    40         65 23.80476
    ## 5:    B 1-1-2012   100         65 28.86751
    ## 6:    B 1-2-2012    60         65 28.86751
    ## 7:    B 1-3-2012    30         65 28.86751
    ## 8:    B 1-4-2012    70         65 28.86751
    DT[, outlier := abs(Score-mean.score) > 3 * sd.score, by = Team]
    ##    Team     Date Score mean.score sd.score outlier
    ## 1:    A 1-1-2012    80         65 23.80476   FALSE
    ## 2:    A 1-2-2012    90         65 23.80476   FALSE
    ## 3:    A 1-3-2012    50         65 23.80476   FALSE
    ## 4:    A 1-4-2012    40         65 23.80476   FALSE
    ## 5:    B 1-1-2012   100         65 28.86751   FALSE
    ## 6:    B 1-2-2012    60         65 28.86751   FALSE
    ## 7:    B 1-3-2012    30         65 28.86751   FALSE
    ## 8:    B 1-4-2012    70         65 28.86751   FALSE
    

    或者,一步完成

    DT[, outlier := abs(Score-mean(Score)) > 3 *  sd(Score), by = Team]
    

    添加异常值的数量(逻辑变量的总和将强制为 0,1)

    DT[, sum.outlier := sum(outlier), by = Team]
    

    【讨论】:

    • 非常感谢。明天早上我会先试试这个。我认为这会奏效。我可以给它一个整数而不是真假,而不是 pefrom aggregate(outlier~Team, sum, DT) 并获取每个团队的总和值,然后绘制前十名。
    • @user - 在大多数情况下,R 会将 TRUE/FALSE 分别视为 1/0。
    • @mnel,我执行此操作,它在苯酚速率下的性能优于 plyr。
    • @mnel,我有一个问题。而不是看 abs,我只对这个计算的正值感兴趣:离群值:= abs(Score-mean(Score)) > 3 * sd(Score),by=Team。有没有简单的方法可以做到这一点?
    猜你喜欢
    • 2018-03-04
    • 2013-10-09
    • 2021-11-13
    • 1970-01-01
    • 2018-12-03
    • 1970-01-01
    • 1970-01-01
    • 2011-08-26
    • 2015-11-22
    相关资源
    最近更新 更多