我想根据取决于采用数字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 ,因此任何有关如何更有效或更紧凑地编写它的帮助将不胜感激。
答案 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
如所怀疑的,假设上述逻辑是正确的,则有一个更简单的解决方案。我们使用findInterval
并将参数rightmost.closed
和left.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