R语言:异常数据处理
前言
??在數據處理中,尤其在作函數擬合時,異常點的出現不僅會很大程度的改變函數擬合的效果,而且有時還會使得函數的梯度出現奇異梯度,這就導致算法的終止,從而影響研究變量之間的函數關系。為了有效的避免這些異常點造成的損失,我們需要采取一定的方法對其進行處理,而處理的第一步便是找到異常點在數據中的位置。
??什么是異常值?如何檢測異常值?
目錄
?1. 單變量異常值檢測
?2. 使用LOF(local outlier factor,局部異常因子)進行異常檢測
?3. 通過聚類的方法檢驗異常值
?4. 檢驗時間序列數據里面的異常值
?5. 討論
主要程序包
install.packages(c("DMwR","dprep"))library(DMwR)library(dprep)1. 單變量異常值檢測
??使用函數boxplot.stats()實現單變量檢測,該函數根據返回的統計數據生成箱線圖。在上述函數的返回結果中,有一個參數out,它是由異常值組成的列表。更明確的說就是里面列出了箱線圖中箱須線外面的數據點。其中參數coef可以控制箱須線從箱線盒上延伸出來的長度,關于該函數的更多細節可以通過輸入‘?boxplot.ststs’查看。
??畫箱線圖:
set.seed(3147) x <- rnorm(100) #產生100個服從正態分布的數據 summary(x) boxplot.stats(x)$out #輸出異常值 boxplot(x) #繪制箱線圖? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
??如上的單變量異常檢測可以用來發現多元數據中的異常值,通過簡單搭配的方式。在下例中,我們首先產生一個數據框df,它有兩列x和y。之后,異常值分別從x和y檢測出來。然后,我們獲取兩列都是異常值的數據作為異常數據。
x <- rnorm(100)y <- rnorm(100)# 生成一個包含列名分別為x與y的數據框dfdf <- data.frame(x, y)rm(x,y)head(df)# 連接數據框dfattach(df)(a <- which(x %in% boxplot.stats(x)$out)) # 輸出x中的異常值(b <- which(y %in% boxplot.stats(y)$out)) # 輸出y中的異常值# 斷開與數據框的連接detach(df)# (1) 輸出x,y相同的異常值(outlier.list1 <- intersect(a,b)) plot(df)points(df[outlier.list1,], col="red", pch="+", cex=2.5) # 標注異常點# (2) x或y中的異常值(outlier.list2 <- union(a, b))plot(df)points(df[outlier.list2,], col="blue", pch="x", cex=2)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
??當有三個以上的變量時,最終的異常值需要考慮單變量異常檢測結果的多數表決。當選擇最佳方式在真實應用中進行搭配時,需要涉及領域知識。
?
2. 使用LOF(local outlier factor,局部異常因子)進行異常檢測
??LOF(局部異常因子)是一種基于密度識別異常值的算法。算法實現是:將一個點的局部密度與分布在它周圍的點的密度相比較,如果前者明顯的比后者小,那么這個點相對于周圍的點來說就處于一個相對比較稀疏的區域,這就表明該點事一個異常值。(使用LOF,一個點的局部密度會與它的鄰居進行比較。如果前者明顯低于后者(有一個大于1 的LOF值),該點位于一個稀疏區域,對于它的鄰居而言,這就表明,該點是一個異常值。)LOF算法的缺點是它只對數值型數據有效。
??lofactor()函數使用LOF算法計算局部異常因子,并且它在DMwR和dprep包中是可用的。下面將介紹一個使用LOF進行異常檢測的例子,k是用于計算局部異常因子的鄰居數量。下圖呈現了一個異常值得分的密度圖。
> library(DMwR)> # 移除“Species”這個鳶尾花類別列數據> iris2 <- iris[,1:4]> # k是計算局部異常因子所需要判斷異常點周圍的點的個數> outlier.scores <- lofactor(iris2, k=5)> # 繪制異常值得分的密度分布圖> plot(density(outlier.scores))> # 挑出得分排前五的數據作為異常值> outliers <- order(outlier.scores, decreasing = T)[1:5]> # 輸出異常值> print(outliers)[1] 42 107 23 110 63? ? ? ? ? ? ? ? ? ? ? ?
??接下來對鳶尾花數據進行主成分分析,并利用產生的前兩個主成分繪制成雙標圖來顯示異常值。
> n <- nrow(iris2)> labels <- 1:n> # 除了異常值以外所有的數據用"."標注> labels[-outliers] <- "."> biplot(prcomp(iris2), cex=.8, xlabs=labels)? ? ? ? ? ? ? ?
??上面的代碼中,prcomp()實現對數據集iris2的主成分分析,biplot()取主成分分析結果的前兩列數據也就是前兩個主成分繪制雙標圖。上圖中,x軸和y軸分別代表第一、二主成分,箭頭指向了原始變量名,其中5個異常值分別用對應的行號標注。
??我們也可以通過pairs()函數繪制散點圖矩陣來顯示異常值,其中異常值用紅色的'+'標注:
> # 使用rep()生成n個"."> pch <- rep(".", n)> pch[outliers] <- "+"> col <- rep("black", n)> col[outliers] <- "red"> pairs(iris2, pch=pch, col=col)? ? ? ? ? ? ? ??
??Rlof包,對LOF算法的并行實現。它的用法與lofactor()相似,但是lof()有兩個附加的特性,即支持k的多元值和距離度量的幾種選擇。如下是lof()的一個例子。在計算異常值得分后,異常值可以通過選擇前幾個檢測出來。注意,目前包Rlof的版本在MacOS X和Linux環境下工作,但并不在windows環境下工作,因為它要依賴multicore包用于并行計算。
library(Rlof)outlier.scores <- lof(iris2, k=5)# 嘗試使用不同的k值# try with different number of neighbors (k=5,6,7,8,9 and 10)outlier.scores <- lof(iris2, k=c(5:10))3. 通過聚類的方法檢驗異常值
??另外一種異常檢測的方法是聚類。通過把數據聚成類,將那些不屬于任務一類的數據作為異常值。比如,使用基于密度的聚類DBSCAN,如果對象在稠密區域緊密相連,它們將被分組到一類。因此,那些不會被分到任何一類的對象就是異常值。
??我們也可以使用k-means算法來檢測異常。使用k-means算法,數據被分成k組,通過把它們分配到最近的聚類中心。然后,我們能夠計算每個對象到聚類中心的距離(或相似性),并且選擇最大的距離作為異常值。
#####################################iris2 <- iris[,1:4]kmeans.result <- kmeans(iris2, centers=3)#class(kmeans.result)# 輸出簇中心kmeans.result$centers#length(kmeans.result$centers)# 分類結果kmeans.result$cluster#mode(kmeans.result$cluster)# 計算數據對象與簇中心的距離centers <- kmeans.result$centers[kmeans.result$cluster, ]#class(centers)distances <- sqrt(rowSums((iris2 - centers)^2))# 挑選出前5個最大距離outliers <- order(distances, decreasing = T)[1:5]# 輸出異常值print(outliers)print(iris2[outliers,])# 畫出聚類結果plot(iris2[,c("Sepal.Length", "Sepal.Width")], pch="o", col=kmeans.result$cluster, cex=0.3)# 繪制類(簇)中心,用"*"標記points(kmeans.result$centers[,c("Sepal.Length", "Sepal.Width")], col=1:3, pch=8, cex=1.5)# 畫出異常值,用"+"標記points(iris2[outliers,c("Sepal.Length", "Sepal.Width")], pch="+", col=4, cex=1.5)##########################################################################> iris2 <- iris[,1:4]> kmeans.result <- kmeans(iris2, centers=3)> #class(kmeans.result)> # 輸出簇中心> kmeans.result$centersSepal.Length Sepal.Width Petal.Length Petal.Width1 6.314583 2.895833 4.973958 1.70312502 5.175758 3.624242 1.472727 0.27272733 4.738095 2.904762 1.790476 0.3523810> #length(kmeans.result$centers)> # 分類結果> kmeans.result$cluster[1] 2 3 3 3 2 2 2 2 3 3 2 2 3 3 2 2 2 2 2 2 2 2 2 2 3 3 2 2 2 3 3 2[33] 2 2 3 2 2 2 3 2 2 3 3 2 2 3 2 3 2 2 1 1 1 1 1 1 1 3 1 1 3 1 1 1[65] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 1[97] 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1[129] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1> #mode(kmeans.result$cluster)> # 計算數據對象與簇中心的距離> centers <- kmeans.result$centers[kmeans.result$cluster, ]> #class(centers)> distances <- sqrt(rowSums((iris2 - centers)^2))> # 挑選出前5個最大距離> outliers <- order(distances, decreasing = T)[1:5]> # 輸出異常值> print(outliers)[1] 119 118 132 123 106> print(iris2[outliers,])Sepal.Length Sepal.Width Petal.Length Petal.Width119 7.7 2.6 6.9 2.3118 7.7 3.8 6.7 2.2132 7.9 3.8 6.4 2.0123 7.7 2.8 6.7 2.0106 7.6 3.0 6.6 2.1> # 畫出聚類結果> plot(iris2[,c("Sepal.Length", "Sepal.Width")], pch="o", col=kmeans.result$cluster, cex=0.3)> # 繪制類(簇)中心,用"*"標記> points(kmeans.result$centers[,c("Sepal.Length", "Sepal.Width")], col=1:3, pch=8, cex=1.5)> # 畫出異常值,用"+"標記> points(iris2[outliers,c("Sepal.Length", "Sepal.Width")], pch="+", col=4, cex=1.5)#####################################? ? ? ? ? ? ? ? ? ?
??在上圖中,聚類中心被標記為星號,異常值標記為'+'
4. 檢驗時間序列數據里面的異常值
??本部分講述一個對時間序列數據進行異常檢測的例子。在本例中,時間序列數據首次使用stl()進行穩健回歸分解,然后識別異常值。
######################################### 使用穩健回歸擬合f <- stl(AirPassengers, "periodic", robust=TRUE)(outliers <- which(f$weights < 1e-8))# 繪圖布局op <- par(mar=c(0, 4, 0, 3), oma=c(5, 0, 4, 0), mfcol=c(4, 1))plot(f, set.pars=NULL)sts <- f$time.series# 畫出異常值,用紅色"x"標記points(time(sts)[outliers], 0.8*sts[,"remainder"][outliers], pch="x", col="red")par(op)########################################> # 使用穩健回歸擬合> f <- stl(AirPassengers, "periodic", robust=TRUE)> (outliers <- which(f$weights < 1e-8))[1] 79 91 92 102 103 104 114 115 116 126 127 128 138 139 140> # 繪圖布局> op <- par(mar=c(0, 4, 0, 3), oma=c(5, 0, 4, 0), mfcol=c(4, 1))> plot(f, set.pars=NULL)> sts <- f$time.series> # 畫出異常值,用紅色"x"標記> points(time(sts)[outliers], 0.8*sts[,"remainder"][outliers], pch="x", col="red")> par(op)########################################? ? ? ? ? ? ? ? ? ? ? ? ??
??在上圖中,異常值用紅色標記為'x'
5. 討論
??LOF算法擅長檢測局部異常值,但是它只對數值數據有效。Rlof包依賴multicore包,在Windows環境下失效。對于分類數據的一個快速穩定的異常檢測的策略是AVF(Attribute Value Frequency)算法。
??一些用于異常檢測的R包包括:
??extremevalues包:單變量異常檢測
??mvoutlier包:基于穩定方法的多元變量異常檢測
??outliers包:對異常值進行測驗
?
轉載自:https://www.cnblogs.com/cloudtj/articles/5519964.html
總結
以上是生活随笔為你收集整理的R语言:异常数据处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TensorFlow入门:计算图
- 下一篇: R语言:ts() 时间序列的建立