结合ifelse语句和for循环R

时间:2019-11-12 18:12:48

标签: r for-loop if-statement

我有关于某人是否被某所学校(1到35)录取以及他们对这些学校有偏好的数据。我的数据集最终将有更多的学生和学校,但这是一个模拟数据集,可以用来做一些跟踪工作。数据看起来像这样,但还将有更多的学校:

> head(Schools)
     ID              S1_AR S1_Rank              S2_AR S2_Rank
1 ID001 Provisional Accept       1 Provisional Accept       2
2 ID002 Provisional Accept       1     No Application      NA
3 ID003 Provisional Reject       1 Provisional Accept       2
4 ID004 Provisional Reject       2 Provisional Accept       1
5 ID005 Provisional Accept       3 Provisional Accept       1

每个人最多只能上一所学校,因此,如果他们被多于一所学校临时录取,则他们的择优排名最低的学校将被视为不接受。这意味着他们的位置可以供其他学生使用。

我已经编写了代码,用于识别已被学校1和2录取的学生,比较其排名,并更新其录取状态,如下所示。但是,这仅适用于一对学校,而我将需要为35所不同学校中的每对学校这样做。是否可以使用for循环针对不同的学校对自动执行此过程?

此外,我知道我的代码目前很笨拙,但这是我目前使用它的唯一方法。使用嵌套的ifelse()是否有助于使此代码在for循环中更易于管理?

Schools$Match <-ifelse(Schools$S1_AR == "Provisional Accept" & Schools$S2_AR == "Provisional Accept", 1, 0)
Schools$Preference<- ifelse(Schools$S1_Rank<Schools$S2_Rank, 1,2)
Schools$S2_AR[Schools$Match == 1 & Schools$Preference == 1]<- "Accepted Elsewhere"
Schools$S1_AR[Schools$Match == 1 & Schools$Preference == 2]<- "Accepted Elsewhere"


head(Schools)

     ID              S1_AR S1_Rank              S2_AR S2_Rank Match Preference
1 ID001 Provisional Accept       1 Accepted Elsewhere       2     1          1
2 ID002 Provisional Accept       1     No Application      NA     0         NA
3 ID003 Provisional Reject       1 Provisional Accept       2     0          1
4 ID004 Provisional Reject       2 Provisional Accept       1     0          2
5 ID005 Accepted Elsewhere       3 Provisional Accept       1     1          2

1 个答案:

答案 0 :(得分:0)

这是一个真正的hacky功能,但是只要数据集看起来像您提供的那样,它就可以为任意数量的学校使用。基本上,它执行以下操作:

  1. 制作一个临时数据集,并添加一个变量,以检查学生是否已在多所学校“接受”,这意味着需要根据选择的等级做出决定(根据您的描述,如果我理解是对的)。

  2. 接下来,它生成2个索引向量。这些索引将用于提取由于默认(无选择)而选择或由于排名而选择的列名或学校。

  3. 根据逻辑检查生成学校名称的向量。如果需要做出选择,则等级最低的学校名称将添加到学生所在位置的向量中,如果不需要做出决定,则将添加学生接受的学校。我这样做的目的是,在任何情况下都有学生接受不是首选的学校(请参阅示例数据中的第6行)。

就像@ slava-kohut指出的那样,可能有一种更优雅的方法来完成所有这些工作,如果可以的话,值得研究。

这是函数。我希望这会有所帮助:

## data set
df <- data.frame("ID" = 1:6,
             "S1_AR" = c("PA", "PA", "PR", "PR", "PA", "PA"),
             "S1_Rank" = c(1, 1, 1, 2, 3, 2),
             "S2_AR" = c("PA", "NA", "PA", "PA", "PA", "PR"),
             "S2_Rank" = c(2, NA, 2, 1, 1, 1))
my_fun <- function(data){
  ## generate tmp data and ready data for downstream classification
  tmp <- data %>%
    mutate(ck_1 = rowSums(. == "PA"), 
           ck_2 = ifelse(ck_1 > 1, TRUE, FALSE),
           ck_2 = ifelse(is.na(ck_2), FALSE, ck_2))
  ## generate rank table
  tmp.rank <- tmp %>%
    dplyr::select(contains("_Rank"))
  ## generate choice table
  tmp.ar <- tmp %>%
    dplyr::select(contains("_AR"))
  ## generate index of highest ranked school choice
  index_choose <- apply(tmp[, which(colnames(tmp) %in% colnames(tmp.rank))], 1, 
function(x){
    which.min(x)
  })
  ## generate index for school accepted when no choice needs to be made
  index_nochoose <- sapply(apply(tmp[, which(colnames(tmp) %in% 
  colnames(tmp.ar))], 1, function(x){
    which(x == "PA")
  }), function(a) a[[1]])
  ## Generate decision vector
  decision <- c()
  for(i in 1:nrow(df)){
    ifelse(tmp$ck_2[i] == TRUE, decision[i] <- colnames(tmp.rank) 
    [index_choose[i]],
           decision[i] <- colnames(tmp.ar)[index_nochoose[i]]) 
  }
  decision <- sapply(strsplit(decision, split = "_", fixed = TRUE),  
  function(x) 
    x[1])
  ## add vector and output result
  tmp$decision <- decision
  return(tmp)
}

my_fun(df)


  ID S1_AR S1_Rank S2_AR S2_Rank ck_1  ck_2 decision
1  1    PA       1    PA       2    2  TRUE       S1
2  2    PA       1    NA      NA   NA FALSE       S1
3  3    PR       1    PA       2    1 FALSE       S2
4  4    PR       2    PA       1    1 FALSE       S2
5  5    PA       3    PA       1    2  TRUE       S2
6  6    PA       2    PR       1    1 FALSE       S1