在for循环中嵌套ifelse语句

时间:2019-01-10 20:42:36

标签: r loops for-loop if-statement nested

我正在尝试在for循环中使用嵌套的ifelse语句来创建一个新变量,其值基于因子变量(邮政编码列表)的出现频率。

新变量应根据邮政编码的频率(频率范围在1到4之间)返回预定义的数字系列。这些数字系列中的每个数字都必须以800结尾,并以200为增量递增,其起始点取决于每个邮政编码的频率:频率越高,起始增量200越低。

为此,我定义了一个for循环,在该循环中,我首先测量每个邮政编码的频率,然后测量一个嵌套的ifelse语句,并根据频率指定要分配给NewVar的每个数字序列。

这里写了一个我想要实现的直观小示例,我想将此示例应用于包含数百万个邮政编码的数据框。

所需结果:

Postcode  NewVar
AA        600
AA        800
BB        400
BB        600
BB        800
CC        800
DD        200
DD        400
DD        600
DD        800

代码:

DF$NewVar <- 0

DF$NewVar <- for (i in levels(DF$Postcode[i]))
ifelse((table(DF$Postcode[i]) == 4), DF$NewVar[i] <- c(200,400,600,800),
  (ifelse ((table(DF$Postcode[i]) == 3), DF$NewVar[i] <- c(400,600,800),
    (ifelse ((table(DF$Postcode[i]) == 2), DF$NewVar[i] <- c(600,800), 
      DF$NewVar[i] <- c(800))))))

问题1:

首先,在运行整个代码时,我收到一条错误消息,指出替换中的行数与数据中的行数不匹配,而在手动检查时,情况并非如此(不匹配总是仅限1行)。

Error in `$<-.data.frame`(`*tmp*`, NewVar, value = c("0", "0", "0",  : 
replacement has 11 rows, data has 10.

问题2:

如果无法正常工作,请进行测试(超出范围):

当验证ifelse子句是否可以单独工作时(在循环外部),我看到NewVar的每一行仅复制了200的开始增量,因此它不会增加到800。这不是我的意思想要实现以下任何一个目标:

一次测试代码:

DF$NewVar[1:2] <- ifelse((sum(table(DF$Postcode)) == 2),                       
  DF$NewVar[1:2] <- c(600,800), "NA")

结果(不需要):

Postcode  NewVar
AA        200
AA        200

所需结果:

Postcode  NewVar
AA        200
AA        400

注意:在尝试分配变量之前,我预定义了NewVar列,并且我已经检查了NA是否存在。

提前感谢您的时间。

2 个答案:

答案 0 :(得分:1)

如果您愿意使用 dplyr 的一种方法:

library(dplyr)
DF <- structure(list(Postcode = c("AA", "AA", "BB", "BB", "BB", "CC", 
"DD", "DD", "DD", "DD")), class = "data.frame", row.names = c(NA, 
-10L))

vals <- c(200,400,600,800)
DF %>% group_by(Postcode) %>% mutate(NewVar = tail(vals,n()))

答案 1 :(得分:0)

为了完整起见,这是使用ave()函数的基本R解决方案。

我们假设Postcode是随机顺序的邮政编码的 vector

Postcode
 [1] "BB" "CC" "CC" "BB" "BB" "AA" "CC" "BB" "AA" "DD"

下面的代码创建一个包含PostcodeNewVar的data.frame:

data.frame(
  Postcode, 
  NewVar = ave(Postcode, Postcode, 
               FUN = function(x) seq(to = 800, by = 200, length.out = length(x)))
)
   Postcode NewVar
1        BB    200
2        CC    400
3        CC    600
4        BB    400
5        BB    600
6        AA    600
7        CC    800
8        BB    800
9        AA    800
10       DD    800

数据

# create data
library(magrittr)   # only used to improve readability
n_codes <- 4L
set.seed(1L)
Postcode <- 
  stringr::str_dup(LETTERS[1:n_codes], 2L) %>% # create codes
  rep(times = sample(n_codes)) %>%             # replicate randomly
  sample()                                     # re-order randomly