У меня большой фреймворк, и я хочу создать «уникальный идентификатор» для каждого отдельного человека. Соответствующий столбец - это столбец «электронная почта», но он усложняется форматированием: у каждого человека может быть несколько электронных писем. Пример кадра ниже:
Name of person ||| E-mail Address
'John Doe' ||| '[email protected]'
'Bob Jones' ||| '[email protected];[email protected]'
'Robert Jones' ||| '[email protected];[email protected]'
'Clara Bit' ||| '[email protected]'
'John Doe' ||| '[email protected];[email protected]'
Я хочу иметь поле, чтобы различать людей как личности на основе электронных писем:
Name of person ||| person ID
'John Doe' 1
'Bob Jones' 2
'Robert Jones' 2
'Clara Bit' 3
'John Doe' 4
Мой мозг как бы взрывается, пытаясь понять, как это сделать с помощью циклов for, поэтому я надеюсь, что есть более простой способ (плюс, я много повторяю df.index, что, как мне сказали, является плохим тоном и невероятно медленно, несмотря ни на что). Есть ли функция, которая могла бы что-то сделать, если бы я сделал несколько столбцов электронной почты с отдельными элементами электронной почты?
Спасибо!
Обновлено: извиняюсь за опечатку в третьей строке электронных писем, она исправлена.
Непонятно, как вы сгруппировали Bob Jones
с Robert Jones
, ни одно из полей в их столбце email
не совпало.
предположительно отсутствие буквы "j" в последнем электронном письме aboy.net является опечаткой
Я бы использовал dict, который сопоставляет адреса электронной почты с UID. Проверка того, входит ли электронное письмо в число ключей словаря, выполняется быстро и тривиально.
Предполагая, что в общей электронной почте есть опечатка, это проблема с несколькими шагами, которая включает библиотеки pandas и networkx, это проблема сети, и я черпал вдохновение из этих двух вопросов проблемы с сетью и проблема с разделением списка:
(1) Добавляйте электронные письма в списки
(2) Расширить столбец электронной почты
(3) Создайте крайние списки пользователей с одинаковыми адресами электронной почты
(4) Создайте сеть с этим edgelist
.
(5) Извлеките различные подграфы сети, которые будут представлять ваш уникальный идентификатор
.
(6) Назначьте эти уникальные идентификаторы оригинальным людям.
(1) Добавляйте электронные письма в списки
import pandas as pd
df = pd.DataFrame({'name':['John','Bob', 'Rob', 'Clara', 'John'], 'email':['[email protected]','[email protected];[email protected]','[email protected];[email protected]','[email protected]','[email protected];[email protected]']})
df['email_list'] = df['email'].str.split(';').tolist()
(2) Расширить столбец электронной почты
df_emails = df['email_list'].apply(pd.Series).reset_index().melt(id_vars='index',value_name='email').dropna()[['index', 'email']].set_index('index')
(3) Создавайте крайние списки пользователей с одинаковыми адресами электронной почты.
df_emails['email_id'] = df_emails.groupby('email').ngroup()
df_emails = df_emails.reset_index()
network = df_emails.merge(df_emails, on='email_id').drop(columns=['email_id', 'email_x', 'email_y'])
(4) Создайте сеть с этим списком.
import networkx as nx
G = nx.from_pandas_edgelist(network, source='index_x', target='index_y')
(5) Извлеките различные подграфы сети, которые будут представлять ваш уникальный идентификатор.
l = [list(x.nodes()) for x in nx.connected_component_subgraphs(G)]
(6) Назначьте эти уникальные идентификаторы оригинальным людям.
d = dict((k, i) for i in range(len(l)) for k in l[i])
df['unique_id'] = df.index.map(d)
Конечный результат:
name email email_list unique_id
0 John [email protected] [[email protected]] 0
1 Bob [email protected];[email protected] [[email protected], [email protected]] 1
2 Rob [email protected];[email protected] [[email protected], [email protected]] 1
3 Clara [email protected] [[email protected]] 2
4 John [email protected];[email protected] [[email protected], [email protected]] 3
Замечательный ответ, большое вам спасибо! Проверено, работает, теперь мне просто нужно сесть и разобраться, почему: P
в вашем текущем примере, Боб и Роберт Джонс не обмениваются электронным письмом, один из Роберта должен быть
[email protected]
?