说明
- 本篇文章所有内容摘自《数据挖掘与R语言》中的第一个实例《预测海藻数量》。
- 部分名词解释来自《工程数学 - 线性代数(第六版)》(同济大学)
观察数据
# 1. 加载程序包
library(DMwR)
# 2. 查看数据表头
head(algae)
# 3. 查看统计特性
summary(algae)
# 4. 查看数值变量分布情况
hist(algae$mxPH, probability = T)
参数说明:
- probability - 布尔类型参数,用于标明直方图是否使用频率来呈现数据
Q-Q图
我们可以使用Q-Q图来查看某一数据对象是否满足正态分布。
# 1. 加载程序包,并设置图像的显示布局
library(car)
par(mfrow = c(1, 2))
# 2. 绘制第一个直方图
hist(algae$mxPH, prob = T, xlab = '', main = 'Histogram of maximum pH value', ylim = 0:1)
# 2.1 给直方图上加上密度线,可以视为平滑版本的直方图
lines(density(algae$mxPH, na.rm = T))
# 2.2 给直方图的x轴下方绘制变量的实际值
rug(jitter(algae$mxPH))
# 3. 绘制Q-Q图
qqPlot(algae$mxPH, main = 'Normal QQ lot of maximum pH')
# 4. 还原图像布局设置
par(mfrow = c(1, 1))
参数说明:
- par() - 设置或检索图像参数
- mfrow - 设置当前图像显示的布局,c(1, 2)表示一行两列
- hist()
- xlab - x轴标题
- main - 设置图像标题
- ylim - y轴范围
- density() - 计算数据对象的分布密度
- rug() - 在x轴附近绘制变量的实际值,从而识别离群点
- jitter() - 对要绘制的原始值略微进行随机排列,避免两个值相等的可能性
利用箱图检查oPO4
箱图能快速提供变量分布的一些关键属性的摘要,它不仅给出了变量的中心趋势,也给出了变量的发散情况和离群值。
箱图框边界代表变量的第一个四分位数和第三个四分位数,而框内的水平线是变量的中位数。
设 r 是变量的四分位距,
- 箱图上方的小横线是小于或等于第三个四分位数加上 1.5 × r 的最大的观测值,
- 箱图下方的小横线是大于或等于第一个四分位数减去 1.5 × r 的最小的观测值。
箱图上方小横线上面或者下方小横线下面的小圆圈表示域其他值相比特别大或者特别小的值,通常认为是离群值。
# 1. 绘制箱图
boxplot(algae$oPO4, ylab = "Orthophosphate (oPO4)")
# 2. 在y轴附近绘制变量的实际值
rug(jitter(algae$oPO4), side = 2)
# 3. 在坐标系中,以平均值为y坐标,绘制水平虚线
abline(h = mean(algae$oPO4, na.rm = T), lty = 2)
注:
- 中位数表示上方的点的个数与下方的点的个数相等。
- 将均值线与箱图内的分位数线进行比较,就可以知道变量的多个离群值使得作为变量中心(及变量的大部分取值)的均值产生了扭曲。
观察离群值
# 1. 绘制散点图
plot(algae$NH4, xlab = "")
# 2. 绘制均线
abline(h = mean(algae$NH4, na.rm = T), lty = 1)
# 3. 绘制均线+一个标准差
abline(h = mean(algae$NH4, na.rm = T) + sd(algae$NH4, na.rm = T), lty = 2)
# 4. 绘制中位线
abline(h = median(algae$NH4, na.rm = T), lty = 3)
# 5. 启动交互,当鼠标点击某个点的附近时,会自动输出这个点的值在点的附近
identify(algae$NH4)
或,输出选取离群值的详细数据
plot(algae$NH4, xlab = "")
clicked.lines <- identify(algae$NH4)
algae[clicked.lines, ]
或,利用逻辑表达式直接检索离群值
algae[algae$NH4 > 19000, ]
algae[!is.na(algae$NH4) & algae$NH4 > 19000, ]
条件绘图
条件绘图是依赖于某个特定因子的图形表示。因子是一个取值为有限集合的名义变量。
对变量Size的每个值绘制a1。
library(lattice)
bwplot(size ~ a1, data = algae, ylab = 'River Size', xlab = 'Algal A1')
分位箱图
分位箱图中的数显分别代表变量的第一个分位数、中位数、第三个分位数,小竖代表数据的真实取值,这些值的分布信息则由分位数图来体现。
library(Hmisc)
bwplot(size ~ a1, data = algae, panel = panel.bpplot, probs = seq(0.1, .49, by = 0.1), datadensity = T, ylab = 'River Size', xlab = 'Algal A1')
- panel.bplot - 分位箱图面板模式
或
library(lattice)
min02 <- equal.count(na.omit(algae$mnO2), number = 4, overlap = 1/5)
stripplot(season ~ a3|min02, data = algae[!is.na(algae$mnO2), ])
- equal.count() - 对连续变量离散化,把该变量转换为因子类型。
- number - 设置区间个数
- overlap - 设置两个区间之间的靠近边界的重合
- stripplot() - 根据'season'变量把变量的实际值绘制到不同的图形中。
- |min02 - 根据'min02'绘制不同的图形。按照从左到右、从下到上的顺序排列。
数据缺失处理
处理数据缺失的常见策略:
- 将含有缺失值的案例剔除
- 根据变量之间的相关关系填补缺失值
- 根据案例之间的相似性填补缺失值
- 使用能够处理缺失值数据的工具
剔除缺失部分
适用于当含有缺失值的记录在总体可用数据中所占比例非常小的时候。
下面的代码会去除在algae中,具有大于20%NA值的观测实例。
library(DMwR)
data(algae)
# 1. 获取所有包含NA值的观测记录,并输出以便观察
algae[!complete.cases(algae), ]
# 2. 获取包含NA值的观测记录条数
nrow(algae[!complete.cases(algae), ])
# 3. 获取每一行观测实例所包含的NA值的个数
apply(algae, 1, function(x) sum(is.na(x)))
# 4. 找出具有大于20%NA值的观测实例
manyNAs(algae, 0.2)
# 5. 去除具有大量NA值的观测实例
algae <- algae[-manyNAs(algae), ]
- complete.cases(algae) - 返回一个布尔值向量,用于指示数据框中,不包含NA值的观测实例
- manyNAs() - 获取包含大于给定概率NA值的观测实例,manyNAs的第二个参数(给定概率)默认为0.2
用高频率值来填补缺失值
填补还有缺失值记录的另一个方法时尝试找到这些缺失值最可能的值,根据数据所呈现的分布情况以及离散情况,应该选择不同的策略进行填补
- 正态分布,因为大部分值围绕在均值附近,所以一般使用均值进行填补。
- 偏态分布或存在离群值,大部分值都处于均值的一侧,或离群值会扭曲平均值,所以,选择中位数进行填充值较好的选择。
PS:不同的数据源、分布情况,选择填充算法外,还需要考虑不同策略对逼近程度和算法复杂度的权衡。
应用步骤如下:
- 找到数据对象各属性的分布情况
- 根据分布情况,选择填充策略
- 应用填充策略到需要的观测实例中
如: mxPH符合正态分布,第48行观测实例使用均值被填充是一种较好的选择。
data(algae)
algae[48, "mxPH"] <- mean(algae$mxPH, na.rm = T)
如: Chla包含几个极端的离群值,且分布偏向于较低的数值,所以使用中位数进行填充是一种相对较好的选额。
data(algae)
algae[is.na(algae$Chla), "Chla"] <- median(algae$Chla, na.rm = T)
使用相关关系填充
给定向量组$$ A: a_1, a_2, a_3, ..., a_m $$,如果存在不全为零的系数$$ k_1, k_2, k_3, ..., k_m $$,使
$$ k_1 a_1 + k_2 a_2 + ... + k_m a_m = 0 $$
则称向量组A是线性相关的,否则称它线性无关。
——《工程数学-线性代数(第六版)》(同济大学)
当两个变量的相关值在1(或-1)周围,表示相应的两个变量之间有强正(或负)线性相关关系。在得到两个变量之间的线性相关关系后,就可以想办法得到变量间线性相关的近似函数形式,以便通过一个变量的值计算出另一个变量的值。
library(DMwR)
data(algae)
cor(algae[, 4:18], use = "complete.obs")
symnum(cor(algae[, 4:18], use = "complete.obs"))
- cor() - 函数可以用来生成变量之间的相关值矩阵
- use = "complete.obs" - 在计算相关值时忽略含有NA的记录。
- symnum() - 函数用来优化变量相关值矩阵的显示
当我们找到两个变量之间的相关关系之后,我们就可以思考如何利用相关性较高的变量来填充NA值。
data(algae)
algae <- algae[-manyNAs(algae), ]
lm(PO4 ~ oPO4, data = algae)
通过计算,我们得出在PO4和oPO4之间的线性函数为:
$$ PO4 = 42.897 + 1.293 oPO4 $$
在得到两个变量之间的线性函数之后,如果不是在同一个观测值上都为NA,那么我们就可以利用这个线性函数来完成填充。
algae[28, "PO4"] <- 42.897 + 1.293 * algae[28, "oPO4"]
我们可以构建一个函数,用来批量处理某一变量的所有缺失值的合理填充。
data(algae)
algae <- algae[-manyNAs(algae), ]
fillPO4 <- function(oP) {
if (is.na(oP))
return(NA)
else
return(42.897 + 1.293 * oP)
}
algae[is.na(algae$PO4), "PO4"] <- sapply(algae[is.na(algae$PO4), "oPO4"], fillPO4)
为了进一步填充缺失值,当无法使用相关函数来处理时,我们可以尝试探索“名义变量”与缺失值变量之间的关系。
algae[is.na(algae$PO4), "PO4"] <- sapply(algae[is.na(algae$PO4), "oPO4"], fillPO4)
algae$season <- factor(algae$season, levels = c("spring", "summer", "autumn", "winter")) # 指定因子式中因子的顺序
histogram(~mxPH | season, data = algae)
histogram(~mxPH | size * speed, data = algae)
stripplot(size ~ mxPH | speed, data = algae, jitter = T)
很多时候,为了部分缺失值的填充,我们需要不断的对各种变量组合的相关关系和填充策略进行分析、测试。这会是一个繁重的工作,但很多时候,却是不可避免的。
通过探测实例实例之间的相似性来填补缺失值
相似性与相关性不同,相关性是指观测实例的变量之间所存在的一种数学关系,而相似性是指观测实例之间所存在的一种实际情况。比如,在同等条件下,不同观测实例之间是否是相似的。
使用相似性填充NA值的步骤:
- 定义“相似性” - 指明用什么样的计算方法,来确定不同观测实例是相似的。
欧式距离
$$ d(x, y) = \sqrt{\sum_{i = 1}^{P} (x_i - y_i)^2} $$
- 一般情况下,我们可以使用相似观测值的“中位数”来进行填充。
- 如果缺失值是“名义变量”,则使用最相似数据中出现四处最多的值(众数)进行填充。
- 还可以使用最相似数据的加权平均值来进行填充。(可以使用“高斯核函数”来从“距离”获得权重。)
高斯核函数
如果相邻个案距待填充值的个案的距离为d,则它的值在加权平均中的权重为:
$$ w(d) = e^{-d} $$
- 根据不同的数据情况,有时会有不同的相关计算函数的变种。如下为一个欧式距离计算函数的变种。
$$ d(x,y) = \sqrt{\sum_{i=1}^{P} \delta_i (x_i, y_i)} $$
$\delta_i ()$ 表示变量$i$的两个值之间的距离,即
$$ \delta_i(v_1, v_2) = \left { \begin{aligned} &1 &当i是名义变量且v_i \ne v_2时 \ &0 &当i是名义变量且v_i = v_2时 \ &(v_1 - v_2)^2 &当i时数值变量时 \end{aligned} \right. $$
- 在应用已经定义好的“距离测算公式”之后,一般情况下,我们需要对数值变量进行标准化,即
$$ y_i = \frac{x_i - \overline{x}}{\sigma_x}\qquad $$
- 利用
DMwR
程序包中的knnImputation()
来执行上面的计算
library(DMwR)
data(algae)
algae <- knnImputation(algae, k = 10) # 使用默认的参数来完成相似数据的填充
algae <- knnImputation(algae, k = 10, meth = "median") # 使用中位数来完成相似数据的填充
书中原文参考
- 《Statistics for Technology》
- 《Introductry Statictics with R》
- 《Visualizing Data》
- 《The Elements of Graphing Data》
- 《Data Visualization》
- 《R Graphics》
- 《Data Preparation for Data Mining》