1 出现问题
今天在写一个求众数的函数,思路很简单:统计unique数值,并计算其频数,取最大值就是,函数如下:
head(ani, 10)
X0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
10 0
getmode = function(v) {
a = data.frame(table(v))
b = max(a$Freq)
c = a[which(a$Freq == b),]
return(c[1,1])
}
getmode(ani$X0)
[1] 0
6163 Levels: 0 0.029 0.03 0.032 0.033 0.036 0.044 0.045 0.048 0.054 0.057 0.058 0.06 0.064 0.065 0.068 ... 42.386
众数值没有问题,但是此处出现了因子水平levels,函数最后一步提取的应该是[1,1]位置的数值才对。怎么出现因子水平呢???
首先检验下众数
table(ani$X0)
0 0.029 0.03 0.032 0.033 0.036 0.044 0.045 0.048 0.054 0.057 0.058 0.06 0.064 0.065 0.068 0.072 0.073 0.077
1371 4 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 3
0.081 0.082 0.083 0.084 0.085 0.086 0.087 0.088 0.089 0.09 0.091 0.092 0.093 0.094 0.095 0.097 0.098 0.1 0.101
2 1 2 1 1 3 1 1 2 3 5 2 3 3 6 11 5 5 2
0.102 0.103 0.105 0.107 0.11 0.114 0.116 0.117 0.118 0.119 0.12 0.121 0.122 0.125 0.128 0.129 0.13 0.132 0.134
1 1 1 3 1 2 1 2 1 1 3 2 1 1 2 3 1 1 1
0.135 0.136 0.14 0.145 0.147 0.15 0.151 0.152 0.153 0.154 0.155 0.156 0.157 0.158 0.159 0.16 0.162 0.163 0.164
1 1 2 2 1 1 1 1 1 7 1 2 3 2 1 2 1 2 1
0.165 0.166 0.167 0.168 0.169 0.17 0.171 0.172 0.173 0.174 0.175 0.176 0.177 0.178 0.18 0.181 0.183 0.184 0.185
1 1 1 3 1 3 2 2 3 2 2 2 2 1 1 1 2 3 1
0.186 0.187 0.188 0.189 0.19 0.191 0.192 0.193 0.194 0.195 0.196 0.197 0.198 0.199 0.2 0.201 0.202 0.203 0.204
...
[ reached getOption("max.print") -- omitted 5163 entries ]
max( table(ani$X0))
[1] 1371 # 0出现次数最大 1371
2 问题关键:table()函数
问题出现在table函数上,table函数作用就是统计一组向量中unique元素的数量,具体参数请参照R帮助文件。R中这样解释table函数 , “table uses the cross-classifying factors to build a contingency table of the counts at each combination of factor levels”。 因此,table()返回的结果是带有因子水平的。
e = data.frame(table(ani$X0))
str(e) # 注意变量Var1
'data.frame': 6163 obs. of 2 variables:
$ Var1: Factor w/ 6163 levels "0","0.029","0.03",..: 1 2 3 4 5 6 7 8 9 10 ...
$ Freq: int 1371 4 1 1 1 1 1 1 1 1 ...
这时候,当然想把因子变量转换成数值变量, as.numeric(), 这时候神奇的事情发生了:
head(as.numeric(e$Var1), 100)
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
[28] 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
[55] 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
[82] 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
head(as.integer(e$Var1), 100)
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
[28] 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
[55] 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
[82] 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
# 这完全不是原始值
table(ani$X0)
3 因子变量
此处呼叫万能的网友,知乎博主[醉一心],CSDN博主[YaoRaoLov]给出了答案。参照以下博文:
https://zhuanlan.zhihu.com/p/147799787
https://ask.csdn.net/questions/707550?sort=comments_count
a.因子变量3个重要特征 :
- 因子变量的有序性
- 因子变量本质上是由数值型变量构成的
- 因子变量取值的有限性
再来看下table()返回的数据框e
unclass(e$Var1[1:30])
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
attr(,"levels")
[1] "0" "0.029" "0.03" "0.032" "0.033" "0.036" "0.044" "0.045" "0.048" "0.054" "0.057" "0.058" "0.06"
[14] "0.064" "0.065" "0.068" "0.072" "0.073" "0.077" "0.081" "0.082" "0.083" "0.084" "0.085" "0.086" "0.087"
[27] "0.088" "0.089" "0.09" "0.091" "0.092" "0.093" "0.094" "0.095" "0.097" "0.098" "0.1" "0.101" "0.102"
[40] "0.103" "0.105" "0.107" "0.11" "0.114" "0.116" "0.117" "0.118" "0.119" "0.12" "0.121" "0.122" "0.125"
...
[ reached getOption("max.print") -- omitted 5163 entries ]
因子型变量在unclass()函数的作用下,显示出真面目:原来就是一个个数值型变量。
这也就是为什么对其进行数值型转化时会得到1,2,3,4等一系列数值的原因。
它的真实值存储在Levels里面。
b.因子变量的存储方式
- 对于非因子向量,R需要存储其所有元素的每一个取值。
- 对于因子型变量,R则存储其对应的水平的次序及有限的几个levels取值
x = sample(c("Apple", "Orange", "melon"), 100000, replace = TRUE)
head(x, 50)
[1] "Apple" "Orange" "Orange" "melon" "Apple" "Orange" "melon" "melon" "Orange" "melon" "Apple" "Orange"
[13] "melon" "Apple" "melon" "Apple" "Apple" "Orange" "Orange" "melon" "Orange" "melon" "melon" "Apple"
[25] "Apple" "Orange" "melon" "melon" "Orange" "melon" "Orange" "Orange" "Orange" "Apple" "Orange" "Apple"
[37] "Apple" "Orange" "Apple" "Orange" "Orange" "melon" "Apple" "Orange" "melon" "melon" "Apple" "melon"
[49] "Apple" "melon"
y = as.factor(x)
head(y,50) # 此处显示的文本内容,但是实际上还是数值,unclass()查看
[1] Apple Orange Orange melon Apple Orange melon melon Orange melon Apple Orange melon Apple melon
[16] Apple Apple Orange Orange melon Orange melon melon Apple Apple Orange melon melon Orange melon
[31] Orange Orange Orange Apple Orange Apple Apple Orange Apple Orange Orange melon Apple Orange melon
[46] melon Apple melon Apple melon
Levels: Apple melon Orange
# 减少了一半的存储空间
pryr::object_size(x)
800,216 B
pryr::object_size(y)
400,632 B
4 解决方法
- method1 :将因子变量首先转换成字符串变量,然后再转换成数值变量
as.numeric(as.character(e$Var1))
head(as.numeric(as.character(e$Var1)) , 50)
[1] 0.000 0.029 0.030 0.032 0.033 0.036 0.044 0.045 0.048 0.054 0.057 0.058 0.060 0.064 0.065 0.068 0.072 0.073
[19] 0.077 0.081 0.082 0.083 0.084 0.085 0.086 0.087 0.088 0.089 0.090 0.091 0.092 0.093 0.094 0.095 0.097 0.098
[37] 0.100 0.101 0.102 0.103 0.105 0.107 0.110 0.114 0.116 0.117 0.118 0.119 0.120 0.121
- method2: 直接从Levels中提取数值变量
as.numeric(levels(e$Var1)[e$Var1]) # 同上
上述众数函数修改为下
getmode = function(v) {
a = data.frame(table(v))
b = max(a$Freq)
c = a[which(a$Freq == b),]
return(as.numeric(as.character(c[1,1])))
}
getmode(ani$X0)
[1] 0
class(getmode(ani$X0))
[1] "numeric"