4

I’m trying to come up with a cleaner way (less typing) to replace values in lists in a large tibble. From looking around online, it seems common to use subsetting rather than $ to replace values, like this:

mtcars["cyl"][mtcars["cyl"] == 4] <- 6

I would like to do this with less code because I need to do it manually (with different replacements) 2-3 times for over 200 columns in this tibble. My tibble name and column names are also pretty long, making this cumbersome.

I tried to write my own function that did the same thing, but I couldn’t get it to work:

val_set <- function(df, column, old_value, replace) {
  df[column][df[column] == old_value] <- replace
}

Then I learned about the replace function, but I can only make it work with $ and not []. And when I go to check on the change with View(), the values remain unchanged. Does that have to do with using $ vs []?

replace(mtcars$cyl, mtcars$cyl == 4, 6)

What is the safest and fastest way to do this?

M--
  • 25,431
  • 8
  • 61
  • 93
ajt10
  • 45
  • 3

3 Answers3

3

It is just that we need to assign it back to the object

val_set <- function(df, column, old_value, replace) {
  df[[column]][df[[column]] == old_value] <- replace
  df
}
mtcars <- val_set(mtcars, 'cyl', 4, 6)

Now, check the 'mtcars' 'cyl' column

mtcars$cyl
 [1] 6 6 6 6 8 6 8 6 6 6 6 8 8 8 8 8 8 6 6 6 6 8 8 8 8 6 6 6 8 6 8 6
akrun
  • 874,273
  • 37
  • 540
  • 662
  • 1
    with a little tweak, we can pass the column name as a variable instead of a character string. But this is already very close to what OP needs. – M-- Jul 21 '21 at 16:48
  • Thank you both for this answer! If you don't mind, @M--, could you describe what that tweak would be for my own knowledge? – ajt10 Jul 21 '21 at 18:56
  • 2
    @ajt10 Just add this line at the beginning of the function: ```column <- deparse(substitute(column))``` and then you can run it like this: ```mtcars <- val_set(mtcars, cyl, 4, 6)```. – M-- Jul 26 '21 at 15:03
2

You can use within and avoid making your own custom function. That makes the code cleaner and more legible.

within(mtcars, cyl[cyl == 4] <- 6)
M--
  • 25,431
  • 8
  • 61
  • 93
0

As you mentioned in the second part of your question on using replace I think you should treat column names as characters. Change your code to this:

replace(mtcars["cyl"], mtcars["cyl"] == 4, 6)
ETeddy
  • 115
  • 5