关于在 R 中同时重新编码多个因子水平的问题
A question about recoding multiple factor levels simultaneously in R
使用 plyr 和 dplyr 等惊人的软件包,数据操作变得轻而易举。重新编码因子水平,这可能被证明是一项艰巨的任务,特别是对于具有多个水平的变量,可以使用这些包轻松完成。但是,对于那些学习数据科学的人来说,了解基本 R 的工作原理很重要。
我向 R 专家寻求有关使用基础 R 重新编码因子的帮助。我的问题是关于为什么一种符号在 R 中有效而另一种符号无效。
我生成了一个包含五个类别和 300 个观测值的向量。我将向量转换为因子并生成以下表格。
x <- sample(c("a", "b", "c", "d", "e", "f"), 300, replace = TRUE)
x <-factor(x)
> table(x)
a b c d e f
57 58 51 45 45 44
> table(as.numeric(x))
1 2 3 4 5 6
57 58 51 45 45 44
请注意,通过使用 as.numeric 选项,我可以看到各个字符符号的内部层次结构。比方说,我想将类别 a 和 f 重新编码为缺失。我可以使用以下代码完成此操作。
x[as.numeric(x) %in% c(1,6)] <- NA
> table(factor(x))
b c d e
58 51 45 45
其中1和6分别对应a和f
请注意,我使用了级别的位置而不是级别本身来将值转换为缺失值。
到目前为止一切顺利。
现在假设我想将类别 a 和 f 转换为成绩。我认为以下代码可以工作,但没有。它 returns 变化多端且错误的答案。
# Recode and a and f as grades
x <- sample(c("a", "b", "c", "d", "e", "f"), 300, replace = TRUE)
x <-factor(x)
table(as.numeric(x))
levels(x)[as.numeric(x) %in% c(1,6)] <- "grades"
table(factor(x))
a b c grades e f
46 46 56 52 42 58
但是,当我明确提及关卡时,脚本会按预期运行。请参阅下面的脚本。
x <- sample(c("a", "b", "c", "d", "e", "f"), 300, replace = TRUE)
x <-factor(x); table(x)
my.list = c("a", "f")
levels(x)[levels(x) %in% my.list] <- "grades"
table(factor(x))
grades b c d e
110 49 40 45 56
那么问题来了,为什么一种方法有效,另一种方法无效?
set.seed(123)
x <- sample(c("a", "b", "c", "d", "e", "f"), 300, replace = TRUE)
x <-factor(x)
table(as.numeric(x))
# 1 2 3 4 5 6
#44 55 56 49 48 48
现在,当您尝试更改 levels
length(as.numeric(x) %in% c(1,6)) #gives
#[1] 300
而
length(levels(x)) #is just
#[1] 6
接下来,当您执行
as.numeric(x) %in% c(1,6) #it returns a vector of length 300
#[1] FALSE FALSE FALSE TRUE TRUE TRUE FALSE TRUE FALSE FALSE TRUE.......
所以现在,当你这样做时
levels(x)[as.numeric(x) %in% c(1,6)]
#[1] "d" "e" "f" NA NA NA NA NA NA NA .....
因为没有更多的 levels
到 select 来自。
所以,
levels(x)[as.numeric(x) %in% c(1,6)] <- "grades"
将 "d"、"e" 和 "f" 更改为 "grades"
table(x)
#x
# a b c grades
#44 55 56 145
但这不是你想要的。
第二次尝试
levels(x)[levels(x) %in% my.list]
之所以有效,是因为
length(levels(x))
#[1] 6
你想达到什么目标?
使用 as.numeric()
操纵因子不是一个好主意,您可能会感到意外。可能最喜欢的方法是尽可能避免因素(例如在创建数据框时使用 stringsAsFactors=FALSE
和 as.is=TRUE
与 read.csv
和 read.table
- as.is
因为相反as.it.is.not
)。与使用因子的任何操作相比,操纵字符向量更直接且更不容易出错,并且当技术上需要一个因子时,在许多情况下分析函数会处理它——或者如果这还不够,创建它通常更容易一个动态的因素(具有水平),具有适当的水平排序和标签,而不是担心与因素相关的所有混淆。
那么..
会发生什么
levels(x)[as.numeric(x) %in% c(1,6)]
levels(x)
是一个长度为 6 的字符向量,as.numeric(x)
是一个长度为 300 的逻辑向量。所以你试图用一个更长的逻辑向量来索引一个短向量。在这样的索引中,索引向量的作用类似于 "switch",TRUE 表示您希望在输出中的这个位置看到一个项目,而 FALSE 表示您不需要。那么您要 levels(x)
的哪些元素? (这将是随机的,如果重要的话,您可以使用 set.seed
使其可重现。)
> which(as.numeric(x) %in% c(1,6))
[1] 4 9 10 12 14 16 24 35 37 44 47 52 54 57 58 61 63 69 79 81 82 83
[23] 84 86 87 89 91 92 99 100 103 109 114 121 124 125 129 134 135 138 140 141 143 147
[45] 154 167 178 179 181 187 188 194 201 212 213 214 217 218 219 220 222 232 235 237 239 245
[67] 254 255 258 260 263 265 266 267 275 278 281 286 294 295 296
如果您想通过引用它们的等效数字来替换某些级别,则根本不需要 as.numeric
:
levels(x)[c(1,6)] <- "grades"
> levels(x)[c(1,6)] <- "grades"
> table(x)
x
grades b c d e
101 45 46 62 46
"a" 和 "f" 已根据需要替换为 "grades"。而上面的"as.numeric",你想到的是第1级和第6级,但实际上只要求更改第4级。 (究竟是哪个级别[s],取决于RNG,而不是直接在你的控制之下)。
使用 plyr 和 dplyr 等惊人的软件包,数据操作变得轻而易举。重新编码因子水平,这可能被证明是一项艰巨的任务,特别是对于具有多个水平的变量,可以使用这些包轻松完成。但是,对于那些学习数据科学的人来说,了解基本 R 的工作原理很重要。
我向 R 专家寻求有关使用基础 R 重新编码因子的帮助。我的问题是关于为什么一种符号在 R 中有效而另一种符号无效。
我生成了一个包含五个类别和 300 个观测值的向量。我将向量转换为因子并生成以下表格。
x <- sample(c("a", "b", "c", "d", "e", "f"), 300, replace = TRUE)
x <-factor(x)
> table(x)
a b c d e f
57 58 51 45 45 44
> table(as.numeric(x))
1 2 3 4 5 6
57 58 51 45 45 44
请注意,通过使用 as.numeric 选项,我可以看到各个字符符号的内部层次结构。比方说,我想将类别 a 和 f 重新编码为缺失。我可以使用以下代码完成此操作。
x[as.numeric(x) %in% c(1,6)] <- NA
> table(factor(x))
b c d e
58 51 45 45
其中1和6分别对应a和f
请注意,我使用了级别的位置而不是级别本身来将值转换为缺失值。
到目前为止一切顺利。
现在假设我想将类别 a 和 f 转换为成绩。我认为以下代码可以工作,但没有。它 returns 变化多端且错误的答案。
# Recode and a and f as grades
x <- sample(c("a", "b", "c", "d", "e", "f"), 300, replace = TRUE)
x <-factor(x)
table(as.numeric(x))
levels(x)[as.numeric(x) %in% c(1,6)] <- "grades"
table(factor(x))
a b c grades e f
46 46 56 52 42 58
但是,当我明确提及关卡时,脚本会按预期运行。请参阅下面的脚本。
x <- sample(c("a", "b", "c", "d", "e", "f"), 300, replace = TRUE)
x <-factor(x); table(x)
my.list = c("a", "f")
levels(x)[levels(x) %in% my.list] <- "grades"
table(factor(x))
grades b c d e
110 49 40 45 56
那么问题来了,为什么一种方法有效,另一种方法无效?
set.seed(123)
x <- sample(c("a", "b", "c", "d", "e", "f"), 300, replace = TRUE)
x <-factor(x)
table(as.numeric(x))
# 1 2 3 4 5 6
#44 55 56 49 48 48
现在,当您尝试更改 levels
length(as.numeric(x) %in% c(1,6)) #gives
#[1] 300
而
length(levels(x)) #is just
#[1] 6
接下来,当您执行
as.numeric(x) %in% c(1,6) #it returns a vector of length 300
#[1] FALSE FALSE FALSE TRUE TRUE TRUE FALSE TRUE FALSE FALSE TRUE.......
所以现在,当你这样做时
levels(x)[as.numeric(x) %in% c(1,6)]
#[1] "d" "e" "f" NA NA NA NA NA NA NA .....
因为没有更多的 levels
到 select 来自。
所以,
levels(x)[as.numeric(x) %in% c(1,6)] <- "grades"
将 "d"、"e" 和 "f" 更改为 "grades"
table(x)
#x
# a b c grades
#44 55 56 145
但这不是你想要的。
第二次尝试
levels(x)[levels(x) %in% my.list]
之所以有效,是因为
length(levels(x))
#[1] 6
你想达到什么目标?
使用 as.numeric()
操纵因子不是一个好主意,您可能会感到意外。可能最喜欢的方法是尽可能避免因素(例如在创建数据框时使用 stringsAsFactors=FALSE
和 as.is=TRUE
与 read.csv
和 read.table
- as.is
因为相反as.it.is.not
)。与使用因子的任何操作相比,操纵字符向量更直接且更不容易出错,并且当技术上需要一个因子时,在许多情况下分析函数会处理它——或者如果这还不够,创建它通常更容易一个动态的因素(具有水平),具有适当的水平排序和标签,而不是担心与因素相关的所有混淆。
那么..
会发生什么 levels(x)[as.numeric(x) %in% c(1,6)]
levels(x)
是一个长度为 6 的字符向量,as.numeric(x)
是一个长度为 300 的逻辑向量。所以你试图用一个更长的逻辑向量来索引一个短向量。在这样的索引中,索引向量的作用类似于 "switch",TRUE 表示您希望在输出中的这个位置看到一个项目,而 FALSE 表示您不需要。那么您要 levels(x)
的哪些元素? (这将是随机的,如果重要的话,您可以使用 set.seed
使其可重现。)
> which(as.numeric(x) %in% c(1,6))
[1] 4 9 10 12 14 16 24 35 37 44 47 52 54 57 58 61 63 69 79 81 82 83
[23] 84 86 87 89 91 92 99 100 103 109 114 121 124 125 129 134 135 138 140 141 143 147
[45] 154 167 178 179 181 187 188 194 201 212 213 214 217 218 219 220 222 232 235 237 239 245
[67] 254 255 258 260 263 265 266 267 275 278 281 286 294 295 296
如果您想通过引用它们的等效数字来替换某些级别,则根本不需要 as.numeric
:
levels(x)[c(1,6)] <- "grades"
> levels(x)[c(1,6)] <- "grades"
> table(x)
x
grades b c d e
101 45 46 62 46
"a" 和 "f" 已根据需要替换为 "grades"。而上面的"as.numeric",你想到的是第1级和第6级,但实际上只要求更改第4级。 (究竟是哪个级别[s],取决于RNG,而不是直接在你的控制之下)。