I am dropping duplicates from a dataframe based on firstname, lastname, email and saving to a new df called df_unique.
I've converted everything to lower case and removed whitespace so the fields to increase the chances of a match. Note that index 0 and 2 are the same but won't be picked up without converting to lower.
df = pd.DataFrame({'firstname':['foo Bar','Bar Bar','Foo Bar'],'lastname':['Foo Bar','Bar','Foo Bar'],'email':['Foo bar','Bar','Foo Bar']})
df
firstname lastname email
0 foo Bar Foo Bar Foo bar
1 Bar Bar Bar Bar
2 Foo Bar Foo Bar Foo Bar
#remove NAs
#convert to lower
#remove whitespace
#drop dupes
df_unique = (df.dropna(subset=['firstname', 'lastname', 'email'])
.applymap(lambda s:s.lower() if type(s) == str else s)
.applymap(lambda x: x.replace(" ", "") if type(x)==str else x)
.drop_duplicates(subset=['firstname', 'lastname', 'email']))
df_unique
firstname lastname email
0 foobar foobar foobar
1 barbar bar bar
However, the records are permanently lowercase now, and double names like Foo Bar are now foobar.
How can I do this without permanently changing the data?
I've tried using .copy() in the middle of all that but it just got too messy and broke things.
Is there a better way to do this?
edit:
With a bit of tweaking of @shaik moeeds answer below, I managed to get something working.
Here I get the index of unique records:
uniq_indx = (df.dropna(subset=['firstname', 'lastname', 'email'])
.applymap(lambda s:s.lower() if type(s) == str else s)
.applymap(lambda x: x.replace(" ", "") if type(x)==str else x)
.drop_duplicates(subset=['firstname', 'lastname', 'email'])).index
Then use this to index the DF and save the unique records:
df_unique = df.loc[uniq_indx]
I also wanted to keep the duplicate records, so used drop() and the index from above to remove the uniques:
df_duplicates = df.drop(uniq_indx)
This seems to work on checking the outputs, however if there are any mistakes please let me know.