1 出現(xiàn)問題
今天在寫一個求眾數(shù)的函數(shù)蹦误,思路很簡單:統(tǒng)計unique數(shù)值芝薇,并計算其頻數(shù)胚嘲,取最大值就是,函數(shù)如下:
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
眾數(shù)值沒有問題洛二,但是此處出現(xiàn)了因子水平levels馋劈,函數(shù)最后一步提取的應(yīng)該是[1,1]位置的數(shù)值才對。怎么出現(xiàn)因子水平呢晾嘶?妓雾??
首先檢驗下眾數(shù)
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出現(xiàn)次數(shù)最大 1371
2 問題關(guān)鍵:table()函數(shù)
問題出現(xiàn)在table函數(shù)上垒迂,table函數(shù)作用就是統(tǒng)計一組向量中unique元素的數(shù)量械姻,具體參數(shù)請參照R幫助文件。R中這樣解釋table函數(shù) , “table uses the cross-classifying factors to build a contingency table of the counts at each combination of factor levels”机断。 因此楷拳,table()返回的結(jié)果是帶有因子水平的绣夺。
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 ...
這時候,當(dāng)然想把因子變量轉(zhuǎn)換成數(shù)值變量欢揖, as.numeric(), 這時候神奇的事情發(fā)生了:
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 因子變量
此處呼叫萬能的網(wǎng)友陶耍,知乎博主[醉一心],CSDN博主[YaoRaoLov]給出了答案她混。參照以下博文:
https://zhuanlan.zhihu.com/p/147799787
https://ask.csdn.net/questions/707550?sort=comments_count
a.因子變量3個重要特征 :
- 因子變量的有序性
- 因子變量本質(zhì)上是由數(shù)值型變量構(gòu)成的
- 因子變量取值的有限性
再來看下table()返回的數(shù)據(jù)框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()函數(shù)的作用下,顯示出真面目:原來就是一個個數(shù)值型變量烈钞。
這也就是為什么對其進行數(shù)值型轉(zhuǎn)化時會得到1,2,3,4等一系列數(shù)值的原因。
它的真實值存儲在Levels里面坤按。
b.因子變量的存儲方式
- 對于非因子向量毯欣,R需要存儲其所有元素的每一個取值。
- 對于因子型變量晋涣,R則存儲其對應(yīng)的水平的次序及有限的幾個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) # 此處顯示的文本內(nèi)容仪媒,但是實際上還是數(shù)值,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 :將因子變量首先轉(zhuǎn)換成字符串變量谢鹊,然后再轉(zhuǎn)換成數(shù)值變量
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中提取數(shù)值變量
as.numeric(levels(e$Var1)[e$Var1]) # 同上
上述眾數(shù)函數(shù)修改為下
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"