0

I am very much a novice to R and currently struggling to learn the language. What I am trying to do is create a new variable with three levels (if that makes sense). I am trying to show growth <=0%,<1%, and >=1% all in the same new variable (let me know if that is even possible).

So far I have tried this:

pincome$perctchng<- ifelse(pincome$perctchng<=0,ifelse(pincome$perctchng<1,
              ifelse(pincome$perctchng>=1,"level 1","level 2","level 3")))

This is the code that I attempted. I know that it is wrong, but any advice is the right direction is welcomed.

Thanks!

Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
fletchr
  • 646
  • 2
  • 8
  • 25
  • Try `pincome$perctchng<- ifelse(pincome$perctchng<=0, "level 1", ifelse(pincome$perctchng<1,"level 2","level 3"))` – Ronak Shah Sep 26 '16 at 04:07
  • 1
    Possible duplicate of [Nested ifelse statement in R](http://stackoverflow.com/questions/18012222/nested-ifelse-statement-in-r) – Ronak Shah Sep 26 '16 at 04:09
  • I find it is infinitely easier to understand these sort of nested statements (especially ifelse statements!) if proper indenting is used. You have the right idea, you just tripped up with the parenthesis order. – Chrisss Sep 26 '16 at 04:13
  • Are you really sure you want levels with <=0%,<1%, and >=1% which is a mix of right closed and right open intervals? If you were asking for consistently right closed intervals, i.e., <=0%,<=1%, and >1% you could use the `cut` function as shown in @jdobres's answer. – Uwe Sep 26 '16 at 06:38

3 Answers3

4

Nested ifelse statements are almost never the right answer. They're hard to read and fragile. Your goal is to transform a continuous value (the numeric values in perctchng) into a categorical value ('level 1', etc). R's cut function is perfect for this:

pincome <- data.frame(perctchng = c(-2, -1, 0, 1, 2, 5))

  perctchng
1        -2
2        -1
3         0
4         1
5         2
6         5

pincome$level <- cut(pincome$perctchng, c(-Inf, 0, 1, Inf), c('level 1', 'level 2', 'level 3'))

  perctchng   level
1        -2 level 1
2        -1 level 1
3         0 level 1
4         1 level 2
5         2 level 3
6         5 level 3
jdobres
  • 11,339
  • 1
  • 17
  • 37
  • 1
    Unfortunately, using `cut` here does not do what the OP asked for. By default, `cut` uses left open, right closed intervals, Thus, the levels are <=0%,<=1%, and >1% while the OP asked for <=0%,<1%, and >=1%. So, `1` would belong to `level 3` and not `level 2` as in this answer. – Uwe Sep 26 '16 at 06:45
  • 1
    There is an argument to `cut` `includeLowest` which controls this behaviour. – JDL Sep 26 '16 at 08:10
1

Your solution is almost good your syntax is just not right :

library(dplyr)

pincome <- data.frame(perctchng = c(-2, -1, 0, 1, 2, 5))

pincome %>%
  mutate(perctchng_level = ifelse(perctchng <= 0, "level 1",
                            ifelse(perctchng < 1, "level 2",
                                   ifelse(perctchng >= 1, "level 3", NA))))

results :

  perctchng perctchng_level
1        -2         level 1
2        -1         level 1
3         0         level 1
4         1         level 3
5         2         level 3
6         5         level 3
Menelith
  • 521
  • 2
  • 4
  • 13
1

A tidyverse solution:

pincome$perctchng<- ifelse(pincome$perctchng<=0,ifelse(pincome$perctchng<1, ifelse(pincome$perctchng>=1,"level 1","level 2","level 3")))

library(tidyverse)
pincome <- pincome %>%
           mutate(perctchng = case_when(perctchng <= 0 ~ "level 1",
                                        perctchng < 1 ~ "level 2",
                                        perctchng >= 1 ~ "level 3",
                                        TRUE ~ NA_character_)
jsv
  • 740
  • 3
  • 5