Я удаляю дубликаты из фрейма данных на основе имени, фамилии, адреса электронной почты и сохраняю их в новый файл под названием df_unique.

Я преобразовал все в нижний регистр и удалил пробелы, чтобы поля могли увеличить шансы на совпадение. Обратите внимание, что индексы 0 и 2 одинаковы, но не будут получены без преобразования в нижнее значение.

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


Тем не менее, записи теперь постоянно записываются в нижнем регистре, а теперь двойные имена, такие как Foo Bar, теперь foobar.

Как я могу сделать это без постоянного изменения данных?

Я пытался использовать .copy () в середине всего этого, но он стал слишком грязным и сломал вещи.

Есть лучший способ сделать это?

Редактировать:

Немного подправив ответ @shaik moeeds ниже, мне удалось получить что-то работающее.

Здесь я получаю индекс уникальных записей:

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

Затем используйте это, чтобы проиндексировать DF и сохранить уникальные записи:

df_unique = df.loc[uniq_indx]

Я также хотел сохранить дубликаты записей, поэтому использовал drop () и индекс сверху для удаления уникальных:

df_duplicates = df.drop(uniq_indx)

Это похоже на проверку выходных данных, однако, если есть какие-либо ошибки, пожалуйста, дайте мне знать.

2
SCool 2 Июл 2019 в 12:22

3 ответа

Лучший ответ

Вы можете продолжить с вашим кодом, с небольшими изменениями. Используйте значения .index дубликатов, чтобы получить оригинальный формат.

Как это,

>>> df = pd.DataFrame({'firstname':['Foo Bar','Foo Bar','Bar Bar','Foo Bar'],
                       'lastname' :['Foo Bar','Foo Bar', 'Bar','Foo Bar'],
                       'email'    :['Foo Bar','Foo Bar', 'Bar','Foo Bar']})

>>> df.iloc[(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]

< Сильный > Вывод :

  firstname lastname    email
0   Foo Bar  Foo Bar  Foo Bar
2   Bar Bar      Bar      Bar
1
shaik moeed 2 Июл 2019 в 09:46

Ищите значения индекса ваших дубликатов и отбрасывайте строки.

df.drop(
    index=(
        pd.concat(
            g for _, g in 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)
            .groupby(["firstname", "lastname", "email"])
            if len(g) > 1
        )
    ).index
)

Выход:

  firstname lastname email
1   Bar Bar      Bar   Bar
0
Kyle 2 Июл 2019 в 11:13

Попробуй это:

df_unique = df[df.applymap(str).applymap(str.lower).applymap(str.strip).duplicated() == False]
0
Ron Kalian 2 Июл 2019 в 13:16