R语言 将一个变量有条件地赋值给另外两个变量中的一个的值

brvekthn  于 2023-05-04  发布在  其他
关注(0)|答案(2)|浏览(298)

我想创建一个新变量,它的值等于另外两个变量中的一个,条件是其他变量的值。这里有一个假数据的玩具例子。
数据框的每一行代表一个学生。每个学生最多可以学习两个科目(subj1subj2),并且可以在每个科目中攻读学位(“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,则不能使用向量化赋值。
我觉得我一定是错过了一些基本的东西在这里,但上面的代码似乎是显而易见的事情要做,我还没有能够拿出一个替代品。

euoag5mw

euoag5mw1#

你原来的赋值方法失败了,至少有两个原因。
1)下标赋值df$major[df$degree1 == "BA"] <-的问题。使用==会产生NA,这就是导致错误的原因。从?"[<-":“当替换时(即在赋值的lhs上使用索引),NA不选择任何要替换的元素。由于是否应该使用rhs的元素存在歧义,因此只有当rhs值的长度为1时才允许使用(因此两种解释将具有相同的结果)。有很多方法可以解决这个问题,但我更喜欢使用which

df$major[which(df$degree1 == "BA")] <-

不同之处在于==返回TRUEFALSENA,而which返回的对象索引为TRUE

> df$degree1 == "BA"
 [1] FALSE    NA  TRUE  TRUE  TRUE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE

> which(df$degree1 == "BA")
 [1]  3  4  5  8  9 10 11 12 13 14 15 16 17 18 19 20

2)当你执行下标赋值时,右边需要合理地适应左手(这是我的想法)。这可能意味着左手边和右手边的长度相等,这就是你的例子似乎暗示的。因此,您还需要对赋值的右侧进行子集化:

df$major[which(df$degree1 == "BA")] <- df$subj1[which(df$degree1 == "BA")]

我希望这能解释为什么你最初的尝试会产生错误。
使用ifelse,正如@DavidRobinson所建议的那样,是进行这种类型赋值的好方法。我对它的看法:

df$major2 <- ifelse(df$degree1 == "BA", df$subj1, ifelse(df$degree2 == "BA",
  df$subj2,NA))

这相当于

df$major[which(df$degree1 == "BA")] <- df$subj1[which(df$degree1 == "BA")]
df$major[which(df$degree1 != "BA" & df$degree2 == "BA")] <- 
  df$subj2[which(df$degree1 != "BA" & df$degree2 == "BA")]

根据嵌套ifelse语句的深度,另一种方法可能更适合真实的数据。

编辑:

我本来打算写第三个原始代码失败的原因(即df$major还没有被赋值),但它对我来说是有效的,不必这样做。这是一个问题,我记得在过去。你运行的是哪个版本的R?2.15.0我的)如果使用ifelse()方法,则不需要此步骤。您的解决方案在使用[时很好,尽管我会选择

df$major <- NA

要获取主题的字符值,而不是因子水平索引,请使用as.character()(对于因子,它等效于并调用levels(x)[x]):

df$major[which(df$degree1 == "BA")] <- as.character(df$subj1)[which(df$degree1 == "BA")]
df$major[which(df$degree1 != "BA" & df$degree2 == "BA")] <- 
  as.character(df$subj2)[which(df$degree1 != "BA" & df$degree2 == "BA")]

ifelse()方式相同:

df$major2 <- ifelse(df$degree1 == "BA", as.character(df$subj1),
  ifelse(df$degree2 == "BA", as.character(df$subj2), NA))
mjqavswn

mjqavswn2#

一般来说,ifelse函数是这些情况的正确选择,例如:

df$major = ifelse((!is.na(df$degree1) & df$degree1 == "BA") & (is.na(df$degree2) | df$degree1 != "BA"), df$subj1, df$subj2)

但是,它的确切用法取决于如果df$degree1df$degree2都是“BA”,您将执行什么操作。

相关问题