昨天写的[[102-R数据整理12-缺失值的高级处理:用mice进行多重填补]],后台收到了一位朋友有意思的反馈。
经过my_data[sample(153, 10), ]$Wind <- NA
处理过后,整个数据框的结构发生了变化。
不难发现,第一张图中,有许多行的非缺失值部分变得一模一样了。这是为什么呢?是我的取子集操作出了问题吗?亦或是,sample 函数有什么魔法?
一起来探索一下吧。
my_data <- airquality
my_data2 <- my_data
my_data[sample(153, 10), ]$Wind <- NA
> which(my_data2$Ozone %in% NA)
[1] 5 10 22 25 26 27 32 33 34 36 37 39
[13] 42 43 46 52 53 54 55 57 58 59 60 61
[25] 65 72 75 83 84 102 103 107 115 119 150
> which(my_data$Ozone %in% NA)
[1] 5 10 22 25 26 27 32 33 34 36 37 39
[13] 42 43 45 46 52 53 54 55 57 58 59 60
[25] 61 65 72 75 83 84 102 103 107 115 119 150
很奇怪啊,我们对Wind 列做了NA 值处理,可是Ozone 列怎么反倒还少了一个缺失值呢?
再查看一下summary:
> summary(my_data)
Ozone Solar.R Wind
Min. : 1.00 Min. : 7.0 Min. : 1.700
1st Qu.: 18.00 1st Qu.:115.8 1st Qu.: 7.400
Median : 31.50 Median :205.0 Median : 9.700
Mean : 42.13 Mean :185.9 Mean : 9.958
3rd Qu.: 63.25 3rd Qu.:258.8 3rd Qu.:11.500
Max. :168.00 Max. :334.0 Max. :20.700
NA's :37 NA's :7
Temp Month Day
Min. :56.00 Min. :5.000 Min. : 1.0
1st Qu.:72.00 1st Qu.:6.000 1st Qu.: 8.0
Median :79.00 Median :7.000 Median :16.0
Mean :77.88 Mean :6.993 Mean :15.8
3rd Qu.:85.00 3rd Qu.:8.000 3rd Qu.:23.0
Max. :97.00 Max. :9.000 Max. :31.0
> summary(my_data2)
Ozone Solar.R Wind
Min. : 1.00 Min. : 7.0 Min. : 1.700
1st Qu.: 18.00 1st Qu.:100.0 1st Qu.: 7.400
Median : 30.00 Median :194.0 Median : 9.700
Mean : 41.51 Mean :182.3 Mean : 9.892
3rd Qu.: 63.25 3rd Qu.:259.0 3rd Qu.:11.500
Max. :168.00 Max. :334.0 Max. :20.700
NA's :36 NA's :10 NA's :10
Temp Month Day
Min. :56.00 Min. :5.000 Min. : 1.00
1st Qu.:72.00 1st Qu.:6.000 1st Qu.: 8.00
Median :78.00 Median :7.000 Median :16.00
Mean :77.36 Mean :6.928 Mean :15.88
3rd Qu.:84.00 3rd Qu.:8.000 3rd Qu.:23.00
Max. :97.00 Max. :9.000 Max. :31.00
NA's :10
可见不仅仅是Onze,就连Temp, Solar 也受到了迫害,这是怎么了?
那么,会不会是我本身取子集的方式出了问题呢?对小样本的sample 与直接获得sample 指定种子结果,分别测试一下。
> my_data3 <- my_data[1:10,]
> set.seed(1)
> tmp = sample(10,5)
> tmp
[1] 9 4 7 1 2
> my_data5 <- my_data3
> my_data5[tmp,]$Wind <- NA
> set.seed(1)
> my_data4[sample(10,5),]$Wind <- NA
直接来看看数据框好了:
不难发现,下图并没有什么问题,对应的rownames 下的内容的Wind 套上了NA;但是,上图中的sample 还是如前所述般的诡异,好像其他行被施了魔法,全部大变样。
虽然我们设定了种子set.seed(1)
,可最终出的结果确实离谱他奶奶给离谱开门,离谱到家了。
可如果是重复这个过程呢。
> set.seed(1)
> my_data3[sample(10,5),]
Ozone Solar.R Wind Temp Month Day
9 8 19 20.1 61 5 9
4 18 313 11.5 62 5 4
7 23 299 8.6 65 5 7
1 41 190 7.4 67 5 1
2 36 118 8.0 72 5 2
> set.seed(1)
> my_data3[sample(10,5),]$Wind <- NA
> set.seed(1)
> my_data3[sample(10,5),]$Wind
[1] 20.1 11.5 NA NA NA
重复之后,亦是如此,使用rep 也并非赋值长度的问题:
> my_data4 <- my_data3
> set.seed(1)
> my_data4[sample(10,5),]$Wind <- rep(NA,5)
> my_data4[sample(10,5),]$Wind
[1] 20.1 11.5 NA NA NA
仿佛前两个内容被锁定住了似的,即使我们把NA 替换为5:
> my_data4[sample(10,5),]$Wind
[1] 20.1 11.5 5.0 5.0 5.0
虽然sample 并没有听我们的话使用指定的下标赋值,但是,其执行确实存在一定的规律。
同样涉及到随机数的runif:
> set.seed(1)
> my_data4[round(runif(5,1,10)),]$Wind
[1] 12.6 11.5 14.9 20.1 12.6
> set.seed(1)
> my_data4[round(runif(5,1,10)),]$Wind <- NA
> set.seed(1)
> my_data4[round(runif(5,1,10)),]$Wind
[1] 12.6 11.5 14.9 NA 12.6
所以这个结论可以从sample 推广到全部随机数函数吗?
如果并不赋值,直接取子集呢?
> my_data3[sample(10,5),]$Wind
[1] 20.1 11.5 8.6 7.4 8.0
> tmp
[1] 9 4 7 1 2
> set.seed(1)
> my_data3[tmp,]$Wind
[1] 20.1 11.5 8.6 7.4 8.0
而上述奇怪的结果,怀疑和取子集有关:
> my_data4[c(4,4,4),]
Ozone Solar.R Wind Temp Month Day
4 18 313 11.5 62 5 4
4.1 18 313 11.5 62 5 4
4.2 18 313 11.5 62 5 4
可惜我没有证据。
恐怖的一幕:
> set.seed(1)
> my_data4[sample(10,5), ]$Wind
[1] 20.1 11.5 NA NA NA
> my_data4[sample(10,5), ]$Wind
[1] NA NA NA NA NA
> set.seed(1)
> sample(10,5)
[1] 9 4 7 1 2
> sample(10,5)
[1] 7 2 3 8 1
至此我们可以判断,我们实际设定的种子set.seed(1)
,并没有第一步就被数据框进行取子集操作,其使用的实际是该种子的下一批种子。
现在可以解释为什么下标没有对应了。
也就是说,如果需要使用随机数对数据框进行取子集操作,最好还是先将随机结果赋值,防止这样的意外。
那么下一个问题,数据框为什么会被改变呢?这我就不知道了。
欢迎来后台找我讨论。