多个不同的条件以及循环内的语句

时间:2017-12-08 16:33:51

标签: r for-loop if-statement

我想根据取决于采用数字A:U的不同列的某些条件,将1:99中的不同字母分配给新的列向量。

我提出了以下解决方案,但我想更有效地编写它。

for (i in 1:99){

  if (i %in% 1:3 == T  ){
    id<-which(H07_NACE$NACE2.Code==i)
    H07_NACE$NACE2.Sectors[id]<-"A"
  }


   .............         

    if (i %in% 45:60 == T  ){
      id<-which(H07_NACE$NACE2.Code==i)
      H07_NACE$NACE2.Sectors[id]<-"D"
    }
      .....................


     if (i == 99  ){
id<-which(H07_NACE$NACE2.Code==i)
H07_NACE$NACE2.Sectors[id]<-"U"
  }

}

在前面的代码中,我跳过了多个基本上做同样事情的其他行。请注意,我创建的此循环中的条件一直在变化,并且是两个类型。一个是类型i %in% 45:60 == T,另一个是类型&#39; i == 99&#39;

我的原始代码在此循环中有多个这样的 ifs ,因此任何有关如何更有效或更紧凑地编写它的帮助将不胜感激。

3 个答案:

答案 0 :(得分:4)

用户已要求根据他在许多H07_NACE$NACE2.Code条款中硬编码的规则,将"A"中给出的数字映射到"U"if的字母。

更灵活的方法(代码更简单)是使用查找表(或约束向量,如Joseph Wood称之为in his answer)。

使用data.table,我们可以使用滚动连接非equi更新连接来进行映射。

要映射的样本数据

set.seed(1)
H07_NACE <- data.frame(NACE2.Code = sample(99, 10, replace = TRUE))

滚动加入

对于滚动连接,我们通过连续平铺数字范围1:99并指定每个图块的起始编号来指定映射规则。

library(data.table)
# set up lookup table
lookup <- data.table(Code = c(1, 4, 21, 45, 61:75, 98, 99),
                     Sector = LETTERS[1:21])
lookup
    Code Sector
 1:    1      A
 2:    4      B
 3:   21      C
 4:   45      D
 5:   61      E
 6:   62      F
 7:   63      G
 8:   64      H
 9:   65      I
10:   66      J
11:   67      K
12:   68      L
13:   69      M
14:   70      N
15:   71      O
16:   72      P
17:   73      Q
18:   74      R
19:   75      S
20:   98      T
21:   99      U
    Code Sector
# map Code to Sector 
lookup[setDT(H07_NACE), on = .(Code = NACE2.Code), roll = TRUE]
    Code Sector
 1:   27      C
 2:   37      C
 3:   57      D
 4:   90      S
 5:   20      B
 6:   89      S
 7:   94      S
 8:   66      J
 9:   63      G
10:    7      B

如果要更新H07_NACE,我们可以通过

添加新列
setDT(H07_NACE)[, NACE2.Sector := lookup[H07_NACE, on = .(Code = NACE2.Code), 
  roll = TRUE, Sector]][]
    NACE2.Code NACE2.Sector
 1:         27            C
 2:         37            C
 3:         57            D
 4:         90            S
 5:         20            B
 6:         89            S
 7:         94            S
 8:         66            J
 9:         63            G
10:          7            B

非平等更新加入

对于非equi更新连接,我们通过给出下限和上限来指定映射规则。这可以从lookup

派生
lookup2 <- lookup[, .(Sector, lower = Code, 
                      upper = shift(Code - 1L, type = "lead", fill = max(Code)))]
lookup2
    Sector lower upper
 1:      A     1     3
 2:      B     4    20
 3:      C    21    44
 4:      D    45    60
 5:      E    61    61
 6:      F    62    62
 7:      G    63    63
 8:      H    64    64
 9:      I    65    65
10:      J    66    66
11:      K    67    67
12:      L    68    68
13:      M    69    69
14:      N    70    70
15:      O    71    71
16:      P    72    72
17:      Q    73    73
18:      R    74    74
19:      S    75    97
20:      T    98    98
21:      U    99    99
    Sector lower upper

新列由

创建
setDT(H07_NACE)[lookup2, on = .(NACE2.Code >= lower, NACE2.Code <= upper), 
                NACE2.Sector := Sector][]
    NACE2.Code NACE2.Sector
 1:         27            C
 2:         37            C
 3:         57            D
 4:         90            S
 5:         20            B
 6:         89            S
 7:         94            S
 8:         66            J
 9:         63            G
10:          7            B

答案 1 :(得分:3)

这是一个快速而肮脏的解决方案,应该完成这项工作(我确信有更高效/更优雅的方式来做到这一点)。我们可以设置一个约束向量,并从那里使用索引来产生所需的结果。

## Here is some random data that resembles the OP's
set.seed(3)
H07_NACE <- data.frame(NACE2.Code = sample(99, replace = TRUE))

## "T" is the 20th element... we need to gurantee
## that the number corresponding to "U" 
## corresponds to max(NACE2.Code)
maxCode <- max(H07_NACE$NACE2.Code)
constraintVec <- sort(sample(maxCode - 1, 20))
constraintVec <- c(constraintVec, maxCode)

H07_NACE$NACE2.Sector <- LETTERS[vapply(H07_NACE$NACE2.Code, function(x) {
                                            which(constraintVec >= x)[1]
                                    }, 1L)]

## Add optional check column to ensure we are mapping the 
## Code to the correct Sector
H07_NACE$NACE2.Check <- constraintVec[vapply(H07_NACE$NACE2.Code, function(x) {
    which(constraintVec >= x)[1]
}, 1L)]

head(H07_NACE)
  NACE2.Code NACE2.Sector NACE2.Check
1         17            E          18
2         80            R          85
3         39            K          54
4         33            J          37
5         60            N          66
6         60            N          66

更新@Frank提供

如所怀疑的,假设上述逻辑是正确的,则有一个更简单的解决方案。我们使用findInterval并将参数rightmost.closedleft.open设置为TRUE(我们还必须将1L添加到结果向量中):

H07_NACE$NACE2.Sector2 <- LETTERS[findInterval(H07_NACE$NACE2.Code, constraintVec,
                                    rightmost.closed = TRUE, , left.open = TRUE) + 1L]

head(H07_NACE)
  NACE2.Code NACE2.Sector NACE2.Check NACE2.Sector2
1         17            E          18             E
2         80            R          85             R
3         39            K          54             K
4         33            J          37             J
5         60            N          66             N
6         60            N          66             N

identical(H07_NACE$NACE2.Sector, H07_NACE$NACE2.Sector2)
[1] TRUE

答案 2 :(得分:1)

以下是两个tidyverse示例,但我并不完全确定原始海报的真正要求。

library(tidyverse)

data.frame(NACE2.Code = sample(99, replace = TRUE)) %>% 
  mutate(Sectors = ifelse(NACE2.Code %in% 1:3, "A", 
                          ifelse(NACE2.Code %in% 45:60, "D",
                                 ifelse(NACE2.Code ==99, "U", NA))))

data.frame(NACE2.Code = sample(99, replace = TRUE)) %>% 
  mutate(Sectors = case_when(NACE2.Code %in% 1:3 ~ "A", 
                             NACE2.Code %in% 45:60 ~ "D",
                             NACE2.Code ==99 ~ "U")) %>% 
  drop_na