How do I change NA in df$x when df$y == 1

Viewed 64

I have a simple data frame read from a csv:

df <- read.csv("test.csv", na.strings = c("", NA))

that gives this (I am using R):

     x  y
1    a  1
2 <NA>  1
3 <NA>  2
4    a  1
5    b  2
6 <NA>  3

I would like to change the NA in df$x to another value based on the value in df$y. Such that, if df$x = NA and df$y = 1, df$x = "p1", if df$x = NA and df$y = 2, df$x = "p2" and so on to look like this:

     x  y
1    a  1
2   p1  1
3   p2  2
4    a  1
5    b  2
6   p3  3

df <- df %>% replace_na(list(x = "p1"))

Lets me change the whole of df$x, but I am unable to find anything that puts a stringent condition on it. It would seem I need to use an ifelse statement but I cannot seem to get the syntax correct.

mutate(df, x = ifelse(is.na(x) && y == 1, x == 'p1', x == 'p2'))

Thanks for any help.

3 Answers

You can use the following solution. It should be noted that those <NA> values your are trying to change or stored as character strings so they are not considered NA values (you can verify that with is.na(df1$x).

library(dplyr)

df1 %>% 
  mutate(x = ifelse(x == "<NA>" & y == 1, "p1", ifelse(x == "<NA>" & y == 2, 
                                                       "p2", ifelse(x == "<NA>" & y == 3,
                                                                    "p3", x))))

   x y
1  a 1
2 p1 1
3 p2 2
4  a 1
5  b 2
6 p3 3

Here is another very concise way for as many replacements as possible:

library(dplyr)
library(stringr)
library(glue)

df1 %>%
  mutate(x = str_replace(x, "<NA>", glue::glue("p{y}")))

   x y
1  a 1
2 p1 1
3 p2 2
4  a 1
5  b 2
6 p3 3

You can try the code below using replace + is.na

transform(
  df,
  x = replace(x, is.na(x), paste0("p", y[is.na(x)]))
)

which gives

   x y
1  a 1
2 p1 1
3 p2 2
4  a 1
5  b 2
6 p3 3

Data

> dput(df)
structure(list(x = c("a", NA, NA, "a", "b", NA), y = c(1L, 1L, 
2L, 1L, 2L, 3L)), class = "data.frame", row.names = c("1", "2",
"3", "4", "5", "6"))

In base R you can use a simple one-liner

df$x <- ifelse(is.na(df$x), paste0('p', df$y), df$x)
#    x y
# 1  1 1
# 2 p1 1
# 3 p2 2
# 4  1 1
# 5  2 2
# 6 p3 3
Related