<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>可视化 on 格物堂</title><link>https://gewutang.cn/categories/%E5%8F%AF%E8%A7%86%E5%8C%96/</link><description>Recent content in 可视化 on 格物堂</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Wed, 24 Mar 2010 00:00:00 +0000</lastBuildDate><atom:link href="https://gewutang.cn/categories/%E5%8F%AF%E8%A7%86%E5%8C%96/index.xml" rel="self" type="application/rss+xml"/><item><title>布袋图与异常值检测</title><link>https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/</link><pubDate>Wed, 24 Mar 2010 00:00:00 +0000</pubDate><guid>https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/</guid><description>&lt;p&gt;这两天在R软件中发现了一种趣味横生的检测异常值的可视化方法叫bagplot，我翻译为“布袋图”。它首先定义一个二维数据的中心,然后，将与中心较为疏离的点定义为野值。&lt;/p&gt;&#10;&lt;p&gt;以经典的car数据为例演示下布袋图的用法：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;library(aplpack);&#10;library(rpart);&#10;cardata&amp;lt;-car.test.frame[,6:7];&#10;par(mfrow=c(1,1))&#10;bagplot(cardata,verbose=F,factor=3,show.baghull=T,&#10; dkmethod=2,show.loophull=T,precision=1)&#10;title(&amp;quot;car data Chambers/Hastie 1992&amp;quot;)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;img src="https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/index_files/figure-html/unnamed-chunk-1-1.png" width="672" /&gt;&#10;&lt;p&gt;可以看到图形右上角有一些偏离中心较远的点被染成了血红色，那就是布袋图眼中的野值。&lt;/p&gt;&#10;&lt;p&gt;如果随机生成一个正态数据，对应的布袋图会是什么样子？&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;seed=222;&#10;set.seed(seed);&#10;n=200;&#10;data=rnorm(n,mean=0);&#10;datan&amp;lt;-cbind(data,c(rnorm(n-2,mean=20),10,30));&#10;datan[,2]&amp;lt;-datan[,2]*300;&#10;bagplot(datan,factor=3,create.plot=T,approx.limit=300,&#10; show.outlier=T,show.looppoints=T,&#10; show.bagpoints=T,dkmethod=2,&#10; show.whiskers=T,show.loophull=T,&#10; show.baghull=T,verbose=F)&#10;title(paste(&amp;quot;seed: &amp;quot;,seed,&amp;quot;/ n: &amp;quot;,n));&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;img src="https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/index_files/figure-html/unnamed-chunk-2-1.png" width="672" /&gt;&#10;&lt;p&gt;我们增加数据规模看看会是什么效果。&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;seed &amp;lt;- 194&#10;n &amp;lt;- 3000&#10;set.seed(seed)&#10;data &amp;lt;- rnorm(n)&#10;datan&amp;lt;-cbind(data,c(rnorm(n-2,mean=76,sd=20),105,50));&#10;datan[,2]&amp;lt;-datan[,2]*300&#10;bagplot(datan,factor=3,create.plot=T,approx.limit=300,&#10; show.outlier=T,show.looppoints=T,&#10; show.bagpoints=T,dkmethod=2,&#10; show.whiskers=T,show.loophull=T,&#10; show.baghull=T,verbose=F)&#10;title(paste(&amp;quot;seed: &amp;quot;,seed,&amp;quot;/ n: &amp;quot;,n))&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;img src="https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/index_files/figure-html/unnamed-chunk-3-1.png" width="672" /&gt;&#10;&lt;p&gt;像一颗海胆。&lt;/p&gt;&#10;&lt;h1 id="其他异常值检测方法"&gt;&lt;a href="#%e5%85%b6%e4%bb%96%e5%bc%82%e5%b8%b8%e5%80%bc%e6%a3%80%e6%b5%8b%e6%96%b9%e6%b3%95" class="header-anchor"&gt;&lt;/a&gt;其他异常值检测方法&#10;&lt;/h1&gt;&lt;p&gt;除了布袋图之外，还有很多异常值的识别方法，这些方法大致可以分为可视化方法、模型方法和经验方法三类。&lt;/p&gt;&#10;&lt;h2 id="可视化方法"&gt;&lt;a href="#%e5%8f%af%e8%a7%86%e5%8c%96%e6%96%b9%e6%b3%95" class="header-anchor"&gt;&lt;/a&gt;可视化方法&#10;&lt;/h2&gt;&lt;p&gt;可视化方法识别异常值是最直观的一种方法了。常用的图形主要包括箱线图、QQ图、直方图、密度图、小提琴图、布袋图、散点图、热力图以及局部离群因子（LOF）得分图。&lt;/p&gt;&#10;&lt;h3 id="箱线图"&gt;&lt;a href="#%e7%ae%b1%e7%ba%bf%e5%9b%be" class="header-anchor"&gt;&lt;/a&gt;箱线图&#10;&lt;/h3&gt;&lt;pre&gt;&lt;code class="language-r"&gt;# 箱线图&#10;boxplot(data, main = &amp;quot;Boxplot for Outlier Detection&amp;quot;, col = &amp;quot;lightblue&amp;quot;)&#10;# 添加异常值标记&#10;outliers &amp;lt;- boxplot.stats(data)$out&#10;points(rep(1, length(outliers)), outliers, col = &amp;quot;red&amp;quot;, pch = 19)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;img src="https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/index_files/figure-html/unnamed-chunk-4-1.png" width="672" /&gt;&#10;&lt;h3 id="qq图"&gt;&lt;a href="#qq%e5%9b%be" class="header-anchor"&gt;&lt;/a&gt;QQ图&#10;&lt;/h3&gt;&lt;pre&gt;&lt;code class="language-r"&gt;qqnorm(data, main = &amp;quot;Q-Q Plot for Normality Check&amp;quot;)&#10;qqline(data, col = &amp;quot;red&amp;quot;)&#10;# 标出异常值&#10;qq_outliers &amp;lt;- data[abs(scale(data)) &amp;gt; 3]&#10;points(which(data %in% qq_outliers), qq_outliers, col = &amp;quot;red&amp;quot;, pch = 19)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;img src="https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/index_files/figure-html/unnamed-chunk-5-1.png" width="672" /&gt;&#10;&lt;h3 id="直方图"&gt;&lt;a href="#%e7%9b%b4%e6%96%b9%e5%9b%be" class="header-anchor"&gt;&lt;/a&gt;直方图&#10;&lt;/h3&gt;&lt;pre&gt;&lt;code class="language-r"&gt;hist(data, breaks = 30, col = &amp;quot;skyblue&amp;quot;, main = &amp;quot;Histogram with Outliers&amp;quot;)&#10;abline(v = outliers, col = &amp;quot;red&amp;quot;, lwd = 2)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;img src="https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/index_files/figure-html/unnamed-chunk-6-1.png" width="672" /&gt;&#10;&lt;h3 id="密度图"&gt;&lt;a href="#%e5%af%86%e5%ba%a6%e5%9b%be" class="header-anchor"&gt;&lt;/a&gt;密度图&#10;&lt;/h3&gt;&lt;pre&gt;&lt;code class="language-r"&gt;# 密度图&#10;plot(density(data), main = &amp;quot;Density Plot with Outliers&amp;quot;)&#10;rug(data, col = &amp;quot;blue&amp;quot;)&#10;rug(outliers, col = &amp;quot;red&amp;quot;, lwd = 2)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;img src="https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/index_files/figure-html/unnamed-chunk-7-1.png" width="672" /&gt;&#10;&lt;h3 id="小提琴图"&gt;&lt;a href="#%e5%b0%8f%e6%8f%90%e7%90%b4%e5%9b%be" class="header-anchor"&gt;&lt;/a&gt;小提琴图&#10;&lt;/h3&gt;&lt;pre&gt;&lt;code class="language-r"&gt;# 使用ggplot2&#10;library(ggplot2)&#10;ggplot(data.frame(value = data), aes(x = &amp;quot;&amp;quot;, y = value)) +&#10; geom_violin(fill = &amp;quot;lightgreen&amp;quot;) +&#10; geom_boxplot(width = 0.1, fill = &amp;quot;orange&amp;quot;) +&#10; ggtitle(&amp;quot;Violin Plot with Boxplot&amp;quot;)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;img src="https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/index_files/figure-html/unnamed-chunk-8-1.png" width="672" /&gt;&#10;&lt;h3 id="布袋图"&gt;&lt;a href="#%e5%b8%83%e8%a2%8b%e5%9b%be" class="header-anchor"&gt;&lt;/a&gt;布袋图&#10;&lt;/h3&gt;&lt;p&gt;见本文开篇内容，不赘述。&lt;/p&gt;&#10;&lt;h3 id="散点图分布图"&gt;&lt;a href="#%e6%95%a3%e7%82%b9%e5%9b%be%e5%88%86%e5%b8%83%e5%9b%be" class="header-anchor"&gt;&lt;/a&gt;散点图/分布图&#10;&lt;/h3&gt;&lt;pre&gt;&lt;code class="language-r"&gt;# 生成含异常值的双变量数据&#10;set.seed(123)&#10;x &amp;lt;- rnorm(100)&#10;y &amp;lt;- x + rnorm(100, sd = 0.5)&#10;x[101:102] &amp;lt;- c(4, -3) # 插入异常值&#10;y[101:102] &amp;lt;- c(5, -4)&#10;&#10;# 基础散点图&#10;plot(x, y, pch = 19, col = &amp;quot;blue&amp;quot;, main = &amp;quot;Scatter Plot with Outliers&amp;quot;)&#10;outliers &amp;lt;- data.frame(x = x[101:102], y = y[101:102])&#10;points(outliers$x, outliers$y, col = &amp;quot;red&amp;quot;, pch = 19)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;img src="https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/index_files/figure-html/unnamed-chunk-9-1.png" width="672" /&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;# 使用ggplot2&#10;df &amp;lt;- data.frame(x, y)&#10;ggplot(df, aes(x, y)) +&#10; geom_point(color = ifelse(1:nrow(df) %in% 101:102, &amp;quot;red&amp;quot;, &amp;quot;blue&amp;quot;)) +&#10; ggtitle(&amp;quot;Outliers in Scatter Plot&amp;quot;)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;img src="https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/index_files/figure-html/unnamed-chunk-9-2.png" width="672" /&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;# 使用GGally包&#10;library(GGally)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code&gt;## Registered S3 method overwritten by 'GGally':&#10;## method from &#10;## +.gg ggplot2&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;df &amp;lt;- data.frame(x = rnorm(100), y = rnorm(100), z = rnorm(100))&#10;df[101:102, ] &amp;lt;- c(5, 5, 5) # 插入异常值&#10;ggpairs(df) + &#10;theme_bw() +&#10;ggtitle(&amp;quot;Matrix Scatter Plot for Multivariate Outliers&amp;quot;)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;img src="https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/index_files/figure-html/unnamed-chunk-9-3.png" width="672" /&gt;&#10;&lt;h3 id="热力图"&gt;&lt;a href="#%e7%83%ad%e5%8a%9b%e5%9b%be" class="header-anchor"&gt;&lt;/a&gt;热力图&#10;&lt;/h3&gt;&lt;pre&gt;&lt;code class="language-r"&gt;# 生成含异常值的矩阵数据&#10;mat &amp;lt;- matrix(rnorm(100), nrow = 10)&#10;mat[3, 5] &amp;lt;- 10 # 插入异常值&#10;heatmap(mat, Colv = NA, Rowv = NA, col = heat.colors(256), &#10; main = &amp;quot;Heatmap with Outlier (Bright Spot)&amp;quot;)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;img src="https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/index_files/figure-html/unnamed-chunk-10-1.png" width="672" /&gt;&#10;&lt;h3 id="局部离群因子lof得分图"&gt;&lt;a href="#%e5%b1%80%e9%83%a8%e7%a6%bb%e7%be%a4%e5%9b%a0%e5%ad%90lof%e5%be%97%e5%88%86%e5%9b%be" class="header-anchor"&gt;&lt;/a&gt;局部离群因子（LOF）得分图&#10;&lt;/h3&gt;&lt;pre&gt;&lt;code class="language-r"&gt;# 使用DMwR2包&#10;library(DMwR2)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code&gt;## Registered S3 method overwritten by 'quantmod':&#10;## method from&#10;## as.zoo.data.frame zoo&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;lof_scores &amp;lt;- lofactor(data, k = 5) # 计算LOF得分&#10;plot(data, col = ifelse(lof_scores &amp;gt; 1.5, &amp;quot;red&amp;quot;, &amp;quot;blue&amp;quot;), &#10; pch = 19, main = &amp;quot;LOF Outlier Scores&amp;quot;)&#10;legend(&amp;quot;topright&amp;quot;, legend = c(&amp;quot;Outlier&amp;quot;, &amp;quot;Normal&amp;quot;), &#10; col = c(&amp;quot;red&amp;quot;, &amp;quot;blue&amp;quot;), pch = 19)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;img src="https://gewutang.cn/2010/03/24/bagplot-and-extreme-value-detection/index_files/figure-html/unnamed-chunk-11-1.png" width="672" /&gt;&#10;&lt;h2 id="模型方法"&gt;&lt;a href="#%e6%a8%a1%e5%9e%8b%e6%96%b9%e6%b3%95" class="header-anchor"&gt;&lt;/a&gt;模型方法&#10;&lt;/h2&gt;&lt;p&gt;模型方法主要包括统计分析方法和机器学习方法。统计分析方法主要是利用一些常见的统计量作为指标来生成一些正常值的甄别标准，以此标准来甄别异常值。&lt;/p&gt;&#10;&lt;h3 id="统计分析法"&gt;&lt;a href="#%e7%bb%9f%e8%ae%a1%e5%88%86%e6%9e%90%e6%b3%95" class="header-anchor"&gt;&lt;/a&gt;统计分析法&#10;&lt;/h3&gt;&lt;p&gt;常用的统计分析方法主要包括$3\sigma$方法和四分位距。&lt;/p&gt;&#10;&lt;h4 id="3西格玛准则"&gt;&lt;a href="#3%e8%a5%bf%e6%a0%bc%e7%8e%9b%e5%87%86%e5%88%99" class="header-anchor"&gt;&lt;/a&gt;3西格玛准则&#10;&lt;/h4&gt;&lt;p&gt;&lt;code&gt;\(3\sigma\)&lt;/code&gt; 准则的应用十分简明，即将超过均值三个标准差的数据全都视为异常值。下面看一个例子：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;# 生成示例数据&#10;set.seed(123)&#10;data &amp;lt;- rnorm(100)&#10;data[20] &amp;lt;- 10 # 插入异常值&#10;&#10;# 3西格玛准则识别&#10;mean_val &amp;lt;- mean(data)&#10;sd_val &amp;lt;- sd(data)&#10;outliers_3sigma &amp;lt;- data[abs(data - mean_val) &amp;gt; 3*sd_val]&#10;cat(&amp;quot;3西格玛准则识别的异常值：&amp;quot;, outliers_3sigma, &amp;quot;\n&amp;quot;)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code&gt;## 3西格玛准则识别的异常值： 10&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;h4 id="四分位距"&gt;&lt;a href="#%e5%9b%9b%e5%88%86%e4%bd%8d%e8%b7%9d" class="header-anchor"&gt;&lt;/a&gt;四分位距&#10;&lt;/h4&gt;&lt;p&gt;四分位距方法是根据上四分之一分位数和下四分之一分位数生成一个正常域，把超出正常域的数值视为异常值，具体算法见代码：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-r"&gt;# IQR法识别&#10;Q1 &amp;lt;- quantile(data, 0.25)&#10;Q3 &amp;lt;- quantile(data, 0.75)&#10;IQR_val &amp;lt;- Q3 - Q1&#10;lower_bound &amp;lt;- Q1 - 1.5 * IQR_val&#10;upper_bound &amp;lt;- Q3 + 1.5 * IQR_val&#10;outliers_iqr &amp;lt;- data[data &amp;lt; lower_bound | data &amp;gt; upper_bound]&#10;cat(&amp;quot;IQR法识别的异常值：&amp;quot;, outliers_iqr)&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;pre&gt;&lt;code&gt;## IQR法识别的异常值： 10&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;h3 id="机器学习方法"&gt;&lt;a href="#%e6%9c%ba%e5%99%a8%e5%ad%a6%e4%b9%a0%e6%96%b9%e6%b3%95" class="header-anchor"&gt;&lt;/a&gt;机器学习方法&#10;&lt;/h3&gt;&lt;p&gt;最常用的甄别异常值的机器学习方法是聚类分析。&lt;/p&gt;&#10;&lt;h4 id="聚类分析"&gt;&lt;a href="#%e8%81%9a%e7%b1%bb%e5%88%86%e6%9e%90" class="header-anchor"&gt;&lt;/a&gt;聚类分析&#10;&lt;/h4&gt;&lt;pre&gt;&lt;code class="language-r"&gt;# K-means聚类识别异常值&#10;data(USArrests)&#10;data &amp;lt;- USArrests&#10;kmeans_model &amp;lt;- kmeans(data, centers = 2)&#10;cluster_centers &amp;lt;- kmeans_model$centers&#10;distances &amp;lt;- sqrt(rowSums((data - cluster_centers[kmeans_model$cluster])^2))&#10;outliers_cluster &amp;lt;- data[distances &amp;gt; quantile(distances, 0.95),]&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;h1 id="异常值的意义和处理"&gt;&lt;a href="#%e5%bc%82%e5%b8%b8%e5%80%bc%e7%9a%84%e6%84%8f%e4%b9%89%e5%92%8c%e5%a4%84%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;异常值的意义和处理&#10;&lt;/h1&gt;&lt;p&gt;识别异常值只是万里长征第一步。更重要的是找到异常值出现的原因，到底是录入错误还是背后有深刻的原因。如果是录入错误可以重新补正或者干脆删除了之，当然也可以进行插值处理。值得注意的是背后有驱动原因的异常值。譬如，对于上市公司的股票价格而言，每一个异常的股票价格背后可能都对应了一个值得研究学习的事件，而类似的事件如果经常发生的话，就可以利用它构建一个事件驱动策略。&lt;/p&gt;&#10;</description></item></channel></rss>