R中嵌套的if-else循环

R中嵌套的if-else循环,r,if-statement,R,If Statement,我有一个名为“犯罪”的数据框架,其中包含一个“pre_rate”列,表示某项法律实施前的犯罪率。我想使用嵌套的if-else循环将每个速率放在“rate\u category”列中。我有以下代码: crimes$rate_category = with(crimes, ifelse(pre_rate > 0.26 && pre_rate < 0.87, 1, ifelse(pre_rate > 1.04 && pre_rate &l

我有一个名为“犯罪”的数据框架,其中包含一个“pre_rate”列,表示某项法律实施前的犯罪率。我想使用嵌套的if-else循环将每个速率放在“rate\u category”列中。我有以下代码:

crimes$rate_category = 
  with(crimes, ifelse(pre_rate > 0.26 && pre_rate < 0.87, 1,
    ifelse(pre_rate > 1.04 && pre_rate < 1.94, 2, 
      ifelse(pre_rate > 2.03 && pre_rate < 2.96, 3, 
        ifelse(pre_rate > 3.10 && pre_rate < 3.82, 4, 
          ifelse(pre_rate > 4.20 && pre_rate < 11.00, 5, "NA"))))))
crimes

但是,当我使用原始数据帧运行循环时,“rate_category”列中的所有级别都被错误地设置为1。上面的循环似乎有什么问题?

我建议在时使用
case\u,而不是嵌套ifelse语句。它更容易阅读/理解。但是正如@Marius提到的,您的问题是
&
而不是使用
&

library(tidyverse)
crimes <- data.frame(pre_rate = c(0.27, 1.91, 2.81, 3.21, 4.80))

crimes %>% 
  mutate(rate_category = case_when(pre_rate > 0.26 & pre_rate < 0.87 ~ 1,
                                   pre_rate > 1.04 & pre_rate < 1.94 ~ 2,
                                   pre_rate > 2.03 & pre_rate < 2.96 ~ 3,
                                   pre_rate > 3.10 & pre_rate < 3.82 ~ 4,
                                   pre_rate > 4.20 & pre_rate < 11.00 ~ 5))
库(tidyverse)
犯罪率%
当(预处理率>0.26和预处理率<0.87~1,
前置率>1.04,前置率<1.94~2,
前置率>2.03,前置率<2.96~3,
前置率>3.10,前置率<3.82~4,
预制率>4.20,预制率<11.00~5)

为什么不在两个向量中定义下界和上界,然后依靠索引?使用此方法,无需多次写入
pre_rate>num1和pre_rate

lowB <- c(0.26, 1.04, 2.03, 3.10, 4.2)
uppB <- c(0.87, 1.94, 2.96, 3.82, 11)

myCategory <- 1:5 ## this can be whatever categories you'd like

crimes$rate_category <- with(crimes, myCategory[pre_rate > lowB & pre_rate < uppB])

lowB您可以使用代数方法来解决您的问题,它应该比ifelse更快:

pre_rate = c(0.27, 1.91, 2.81, 3.21, 4.80) 
crimes = data.frame(pre_rate)   
crimes$rate = (pre_rate > 0.26 & pre_rate < 0.87)*1 + 
  (pre_rate > 1.04 & pre_rate < 1.94)* 2 + 
  (pre_rate > 2.03 & pre_rate < 2.96)* 3 + 
  (pre_rate > 3.10 & pre_rate < 3.82)* 4 + 
  (pre_rate > 4.20 & pre_rate < 11.00)* 5

如果您的数据不包含间隙,并且您只需要索引,则可以使用
。bincode

crimes$rate_category <- .bincode(crimes$pre_rate,
                                 breaks = c(-Inf, 1, 2, 3, 4, Inf))
但是,在您的情况下,您可能只需要
上限
(即将
预付款利率的值四舍五入,并将其上限设置为5:

crimes$rate_category <- pmin(ceiling(crimes$pre_rate), 5)

#>   pre_rate rate_category
#> 1     0.27             1
#> 2     1.91             2
#> 3     2.81             3
#> 4     3.21             4
#> 5     4.80             5
犯罪$rate\u类别pre\u rate\u类别
#> 1     0.27             1
#> 2     1.91             2
#> 3     2.81             3
#> 4     3.21             4
#> 5     4.80             5

可以使用非相等联接和联接时更新,而不是多个嵌套的
ifelse()

# OP's sample data set with one out-of-bounds value appended
crimes = data.frame(pre_rate = c(0.27, 1.91, 2.81, 3.21, 4.80, 1.0))   

library(data.table)
# specify categories, lower, and upper bounds
bounds <- data.table(
  cat = 1:5,
  lower = c(0.26, 1.04, 2.03, 3.10, 4.2),
  upper = c(0.87, 1.94, 2.96, 3.82, 11)
)
# non-equi join and update on join
setDT(crimes)[bounds, on = .(pre_rate > lower, pre_rate < upper), rate_category := cat][]

请注意,
pre-rate
任何给定间隔之外的值都会自动获得一个
NA
rate\u类别

使用
&&
时要小心:它只比较向量的第一个元素。
&
进行元素级比较,这可能是您想要的。我认为g a字符
“NA”
在你的期末考试中,
ifelse
会将列转换为字符,从而弄乱列。只需使用
NA
,不加引号。你的目标真的是要有差距吗?例如,你想让预设的2为NA吗?@Hugh所有的比率都是8位小数,所以我只是将它们四舍五入到第一百位。会有差距,但不会有差距在任何相关数据中,.between()在这里可能有用。@Hugh根据帮助页面,
?dplyr::between
x>=left&x Correct的快捷方式。但是,从OP的评论来看,这种区别似乎无关紧要。您也可以只包括

library(magrittr)
library(data.table)

rate_category_by_pre_rate <- 
  data.table(rate_category = c("foo", "bar", "foobar", "baz", "foobie"),
             pre_rate = c(1, 2, 3, 4, 11)) %>%
  setkey(pre_rate)

crimes %>%
  as.data.table %>%
  setkey(pre_rate) %>%
  rate_category_by_pre_rate[., roll = -Inf]

#>    rate_category pre_rate
#> 1:           foo     0.27
#> 2:           bar     1.91
#> 3:        foobar     2.81
#> 4:           baz     3.21
#> 5:        foobie     4.80
crimes$rate_category <- pmin(ceiling(crimes$pre_rate), 5)

#>   pre_rate rate_category
#> 1     0.27             1
#> 2     1.91             2
#> 3     2.81             3
#> 4     3.21             4
#> 5     4.80             5
# OP's sample data set with one out-of-bounds value appended
crimes = data.frame(pre_rate = c(0.27, 1.91, 2.81, 3.21, 4.80, 1.0))   

library(data.table)
# specify categories, lower, and upper bounds
bounds <- data.table(
  cat = 1:5,
  lower = c(0.26, 1.04, 2.03, 3.10, 4.2),
  upper = c(0.87, 1.94, 2.96, 3.82, 11)
)
# non-equi join and update on join
setDT(crimes)[bounds, on = .(pre_rate > lower, pre_rate < upper), rate_category := cat][]
   pre_rate rate_category
1:     0.27             1
2:     1.91             2
3:     2.81             3
4:     3.21             4
5:     4.80             5
6:     1.00            NA