我想创建一个新变量,它的值等于另外两个变量中的一个,条件是其他变量的值。这里有一个假数据的玩具例子。
数据框的每一行代表一个学生。每个学生最多可以学习两个科目(subj1
和subj2
),并且可以在每个科目中攻读学位(“BA”)或辅修(“MN”)。我的真实的数据包括数千名学生,几种类型的学位,大约50个科目,学生最多可以有五个专业/辅修专业。
df <- data.frame(
ID = 1:20,
subj1 = factor(c(
"SCI", NA, "BUS", "ENG", "ENG", "SCI", "ENG", "BUS", "ENG",
"ENG", "BUS", "ENG", "BUS", "BUS", "BUS", "SCI", "SCI", "BUS",
"ENG", "BUS"
)),
degree1 = factor(rep(c("MN", NA, "BA", "MN", "BA"), c(1L, 1L, 3L, 2L, 13L))),
subj2 = factor(c(
"BUS", "ENG", NA, NA, "BUS", NA, "SCI", "ENG", NA, "ENG", "ENG",
"BUS", "SCI", NA, "ENG", "BUS", "BUS", NA, "ENG", "ENG"
)),
degree2 = factor(c(
"MN", "MN", NA, NA, "MN", NA, "BA", "MN", NA, "MN", "BA", "BA",
"MN", NA, "BA", "MN", "MN", NA, "BA", "MN"
))
)
df
#> ID subj1 degree1 subj2 degree2
#> 1 1 SCI MN BUS MN
#> 2 2 <NA> <NA> ENG MN
#> 3 3 BUS BA <NA> <NA>
#> 4 4 ENG BA <NA> <NA>
#> 5 5 ENG BA BUS MN
#> 6 6 SCI MN <NA> <NA>
#> 7 7 ENG MN SCI BA
#> 8 8 BUS BA ENG MN
#> 9 9 ENG BA <NA> <NA>
#> 10 10 ENG BA ENG MN
#> 11 11 BUS BA ENG BA
#> 12 12 ENG BA BUS BA
#> 13 13 BUS BA SCI MN
#> 14 14 BUS BA <NA> <NA>
#> 15 15 BUS BA ENG BA
#> 16 16 SCI BA BUS MN
#> 17 17 SCI BA BUS MN
#> 18 18 BUS BA <NA> <NA>
#> 19 19 ENG BA ENG BA
#> 20 20 BUS BA ENG MN
现在我想创建第六个变量df$major
,如果subj1
是学生的主要专业,则该变量等于subj1
的值,如果subj2
是主要专业,则该变量等于subj2
的值。主要专业是第一个学位等于“BA”的学科。我尝试了以下代码:
df$major[df$degree1 == "BA"] = df$subj1
df$major[df$degree1 != "BA" & df$degree2 == "BA"] = df$subj2
不幸的是,我得到了一个错误消息:
> df$major[df$degree1 == "BA"] = df$subj1
Error in df$major[df$degree1 == "BA"] = df$subj1 :
NAs are not allowed in subscripted assignments
我假设这意味着如果赋值至少有一行的计算结果为NA,则不能使用向量化赋值。
我觉得我一定是错过了一些基本的东西在这里,但上面的代码似乎是显而易见的事情要做,我还没有能够拿出一个替代品。
2条答案
按热度按时间euoag5mw1#
你原来的赋值方法失败了,至少有两个原因。
1)下标赋值
df$major[df$degree1 == "BA"] <-
的问题。使用==
会产生NA
,这就是导致错误的原因。从?"[<-"
:“当替换时(即在赋值的lhs上使用索引),NA不选择任何要替换的元素。由于是否应该使用rhs的元素存在歧义,因此只有当rhs值的长度为1时才允许使用(因此两种解释将具有相同的结果)。有很多方法可以解决这个问题,但我更喜欢使用which
:不同之处在于
==
返回TRUE
、FALSE
和NA
,而which
返回的对象索引为TRUE2)当你执行下标赋值时,右边需要合理地适应左手(这是我的想法)。这可能意味着左手边和右手边的长度相等,这就是你的例子似乎暗示的。因此,您还需要对赋值的右侧进行子集化:
我希望这能解释为什么你最初的尝试会产生错误。
使用
ifelse
,正如@DavidRobinson所建议的那样,是进行这种类型赋值的好方法。我对它的看法:这相当于
根据嵌套
ifelse
语句的深度,另一种方法可能更适合真实的数据。编辑:
我本来打算写第三个原始代码失败的原因(即
df$major
还没有被赋值),但它对我来说是有效的,不必这样做。这是一个问题,我记得在过去。你运行的是哪个版本的R?2.15.0我的)如果使用ifelse()
方法,则不需要此步骤。您的解决方案在使用[
时很好,尽管我会选择要获取主题的字符值,而不是因子水平索引,请使用
as.character()
(对于因子,它等效于并调用levels(x)[x]
):ifelse()
方式相同:mjqavswn2#
一般来说,ifelse函数是这些情况的正确选择,例如:
但是,它的确切用法取决于如果
df$degree1
和df$degree2
都是“BA”,您将执行什么操作。