【问题标题】:r: when to use if else loops vs. functionsr:何时使用 if else 循环与函数
【发布时间】:2026-02-18 09:55:01
【问题描述】:

需要您的帮助来解决循环问题;

示例数据:

data2 <- structure(list(a = c(101, 102, 103, 104, 105, 106, 107, 108,109,110), 
                         b = c(1,1,1,1,2,2,3,4,4,4),
                         c = c(4, 4, 4, 4, 2, 2, 1, 3,3,3)), 
          .Names = c("ID", "Band", "Group_qty"), row.names = c(NA, 10L), class = "data.frame")

所需输出示例:

Output <- structure(list(a = c(101, 102, 103, 104, 105, 106, 107, 108, 109, 110), 
                          b = c(1,1,1,1,2,2,3,4,4,4),
                          c = c(4,4,4,4,2,2,1,3,3,3),
                          d = c(102,103,104,103,"Class B","Class B","Class A",109,110,109)), 
                     .Names = c("ID", "Band", "Group_qty","NewID"), row.names = c(NA, 10L), class = "data.frame")

if else 语句草稿: 注意:这不起作用。

data2$NewID <- 
  for(i in 1:length(data2$ID))
  {
    ifelse(data2$[i,3] == 1, "Class A", ifelse(data2[i,3] == 2, "Class B", ifelse(data2[i,2] == data2[i+1,2], data2[i+1,1], data2[i-1,1])))
  }

问题:

如何创建可以与 dplyr 一起使用的工作循环或函数。 规则:

  1. 如果 Group_qty = 1;输出 = A 类

  2. 如果 Group_qty = 2;输出 = B 类

  3. 否则,请检查 Band 是否与下一行的 Band 匹配。

    • 如果是,输出 = 下一行的 ID
    • 如果否,输出 = 上一行的 ID
  4. 一旦我们到达循环的最后一行 - 我们将没有行+1。在这种情况下:输出 = 上一行的 ID。

  5. 可以使用 dplyr & mutate 解决这个问题吗?如果是的话,很乐意将其作为可能的答案。

谢谢,

【问题讨论】:

  • 我从字面上改变了关于您的循环的两件事 1) sapply 以返回结果和 2) %in% 而不是 == 以更好地处理 NA,绝对没有理由引入这一项任务的包sapply(1:length(data2$ID), function(i) ifelse(data2[i,3] %in% 1, "Class A", ifelse(data2[i,3] %in% 2, "Class B", ifelse(data2[i,2] %in% data2[i+1,2], data2[i+1,1], data2[i-1,1]))))
  • @rawr - 你也可以在没有循环或包的情况下做到这一点,尽管不是很漂亮:data2$NewID &lt;- NA;tband &lt;- c(tail(data2$Band,-1),NA);lband &lt;- data2$Band == tband;data2$NewID[which(lband)] &lt;- c(tail(data2$ID,-1),NA)[which(lband)];data2$NewID[which(!lband)] &lt;- c(NA,head(data2$ID,-1))[which(!lband)];data2$NewID[length(data2$NewID)] &lt;- tail(data2$ID,2)[1];data2$NewID[data2$Group_qty == 1] &lt;- "Class A";data2$NewID[data2$Group_qty == 2] &lt;- "Class B"
  • @thelatemail 纯洁造就了它的美丽
  • @rawr - 谢谢你们。我确实玩过 sapply & rapply,但无法让它工作。谢谢你告诉我怎么做。 :)
  • @J1975 抱歉,不知道我从来没有做过那种事。听起来像来自here,您可以发送一个请求,每个请求最多 100 个条目。但也可以将&amp;paginationInput.pageNumber=n 添加到您的网址末尾并获取特定的页码,n。然后你可以遍历页码,直到没有更多结果,将列表组合成一个结果,然后进行聚合

标签: r if-statement for-loop dplyr


【解决方案1】:

我们可以使用data.table。将'data.frame'转换为'data.table'(setDT(data2)),按'Band'分组,if组内元素个数大于1(.N &gt;1),我们使用shift使用type='lead' 获取每个组的后续“ID”或else 保留“ID”以创建“NewID”列。然后,根据条件,我们用ifelse替换'NewID'中'Group_qty' 2 为'Class B' 和1 为'Class_A'的值。

library(data.table) 
setDT(data2)[, NewID:=if(.N>1) shift(ID, type='lead', 
                       fill = ID[.N-1]) else ID , by = .(Band)]
 data2[, NewID:= ifelse(Group_qty==2, 'Class B', 
                 ifelse(Group_qty==1, 'Class A', NewID))]
data2
#     ID Band Group_qty   NewID
# 1: 101    1         4     102
# 2: 102    1         4     103
# 3: 103    1         4     104
# 4: 104    1         4     103
# 5: 105    2         2 Class B
# 6: 106    2         2 Class B
# 7: 107    3         1 Class A
# 8: 108    4         3     109
# 9: 109    4         3     110
#10: 110    4         3     109

我们可以使用与dplyr类似的方法

library(dplyr)
data2 %>%
    group_by(Band) %>% 
    mutate(NewID = if(n()==1) ID else dplyr::lead(ID, 
                         default= ID[n()-1]), 
           NewID= ifelse(Group_qty==2, 'Class B', 
                  ifelse(Group_qty==1, 'Class A', 
                        as.character(NewID))))
#     ID  Band Group_qty   NewID
#   (dbl) (dbl)     (dbl)   (chr)
#1    101     1         4     102
#2    102     1         4     103
#3    103     1         4     104
#4    104     1         4     103
#5    105     2         2 Class B
#6    106     2         2 Class B
#7    107     3         1 Class A
#8    108     4         3     109
#9    109     4         3     110
#10   110     4         3     109

【讨论】:

  • 非常感谢阿克伦。你能解释一下“shift”&type='lead'&fill吗?
  • 复杂但“精彩”。因此,对于 Group by 子句,Group_qty 列基本上是多余的。问题:分组是哪个部分 - 是 .(Band)?
  • 也希望将其与 dplyr 解决方案进行比较。不是在系统时间方面,而是在帮助我学习的实际代码方面。提前致谢。
  • @Jun1975 是by = .(Band)
  • @Jun1975 更新了 dplyr 选项。