3

I understand to replace a string in a column would simply be:

df['surf'].replace(to_replace='Grass', value='Turf')

This replaces all the values of 'Grass' with 'Turf' in my column. But I want the opposite of that. I've tried to look up using != or ~, but haven't gotten that to work.

What if I want all the values NOT 'Grass' to be replaced with 'Turf'

Edit: I should add, I can do it with:

df.loc[df['surf'] != 'Grass', 'surf'] = 'Turf'

but was wondering if there was a way with the .replace

chitown88
  • 27,527
  • 4
  • 30
  • 59
  • 2
    According to [the docs](https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.replace.html), `to_replace` can be a regex. – glibdud Nov 21 '17 at 20:41

2 Answers2

4

you can use a negative lookahead and regex mode to do what you want:

df['surf'] = df['surf'].replace(to_replace=r"^(.(?<!Grass))*?$", value='Turf',regex=True)

(matching everything but the word trick took from How to negate specific word in regex?)


Alternatively, use str.replace, which performs regex-based replacement by default:

df['surf'] = df['surf'].str.replace(r"^(.(?<!Grass))*?$", "Turf")
cs95
  • 379,657
  • 97
  • 704
  • 746
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • @COLDSPEED thanks, excellent edit. Wouldn't setting `inplace=True,` be better than assigning back to `df['surf']` ? (not the pandas expert, you tell me). Also, raw prefix is not needed here, there are no backslashes in the regex. – Jean-François Fabre Nov 21 '17 at 21:49
  • No problem. Also, setting `inplace=True` works if it's with respect to the entire dataframe. When you're slicing columns, things become iffy (it may or may not work depending on whether slicing returns a view or a copy - I am not sure of the exact instances when each one happens, but you get the point). So, it's better to just play safe and assign back. I should mention here that, even if it works, `inplace=True` does not offer any performance gains. A copy is still made, but assigned back to the original, so you don't have to explicitly state reassignment. A convenience feature of sorts. – cs95 Nov 21 '17 at 21:54
  • (Psst, I didn't get your ping, you'll need to use @cᴏʟᴅsᴘᴇᴇᴅ :p) – cs95 Nov 21 '17 at 21:54
  • 1
    I thought so. But hard to do those lowercase uppercase stuff. thanks for the precisions. As I said, not a `pandas` expert, I almost _never_ answer `pandas` question but that one was hanging low in front of me so... – Jean-François Fabre Nov 21 '17 at 21:55
  • The `c` is pure ascii, so you could type "@c" and then tab complete the rest of my name! (I think it should work) – cs95 Nov 21 '17 at 21:57
  • Most of the pandas questions are low hanging fruit, that's why I like answering them. :p Passed you an upvote, good answer for a non-stalwart. – cs95 Nov 21 '17 at 21:57
  • it completes only if you're commenting. Otherwise (edit, dupehammer to close) it doesn't. thanks for the UV. – Jean-François Fabre Nov 21 '17 at 22:02
1

@crenbaerry93, tried to answer in the comments, but might be easier to read here than in the comments:

I think its the same idea, but you'd just add a second .replace()

>>>words = ['Grass', 'abc', 'xyz'] 
['Grass', 'abc', 'xyz'] 

>>>replaced = [w.replace('Grass', 'Turf').replace('abc', 'Turf') for w in words]
['Turf', 'Turf', 'xyz']
chitown88
  • 27,527
  • 4
  • 30
  • 59