Объедините 2 кадра данных и создайте список значений относительно нескольких столбцов. - PullRequest
1 голос
/ 11 апреля 2020

Учитывая два кадра данных (которые могут содержать несколько строк с одинаковым идентификатором):

import pandas as pd
from io import StringIO
df1 = pd.read_csv(StringIO("""
userid,a,b,c,email_work
1,0,0,0,a@a.com
2,0,0,0,b@b.com
3,0,0,0,c@c.com
4,0,0,0,d@d.com
4,0,0,0,e@e.com"""))

df2 = pd.read_csv(StringIO("""
id,A,B,email_personal,email_other
2,0,0,b@b.com,f@f.com
4,0,0,g@g.com"""))

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

userid,emails
1,[a@a.com]
2,[b@b.com, f@f.com]
3,[c@c.com]
4,[d@d.com, e@e.com, g@g.com]

(Я пробовал разные вещи с merge, join, concatenate, но без успеха у меня нет четкого представления о решении pythoni c.)

Как объединить 2 кадра данных и создать список / набор значений относительно нескольких столбцов (здесь email_work, email_personal, email_other)?

Ответы [ 3 ]

2 голосов
/ 11 апреля 2020

Можно переименовать id в userid, чтобы сделать столбец идентификатора пользователя тем же именем, а затем сложить столбцы, имеющие работу email, используя df.filter и df.stack и назовите их email_work, затем concat с внутренним объединением и групповым + агрегированием, как установлено для удаления повторяющихся значений

m = (df2.set_index('id').filter(like='email').rename_axis('userid')
        .stack().reset_index(name='email_work'))

out = (pd.concat((df1,m),join='inner').groupby('userid')['email_work'].agg(set)
      .reset_index())

print(out)

   userid                   email_work
0       1                    {a@a.com}
1       2           {b@b.com, f@f.com}
2       3                    {c@c.com}
3       4  {d@d.com, g@g.com, e@e.com}

print(m)

   userid         level_1 email_work
0       2  email_personal    b@b.com
1       2     email_other    f@f.com
2       4  email_personal    g@g.com
2 голосов
/ 11 апреля 2020

Идея состоит в том, чтобы создать Series с id для индекса в обоих DataFrame с - сначала в DataFrame.set_index, а во втором необходимо выбрать только все email столбцы в DataFrame.filter, затем измените форму на DataFrame.stack и удалите второй уровень на Series.reset_index с помощью drop=True:

s1 = df1.set_index('userid')['email_work']
s2 = df2.set_index('id').filter(like='email').stack().reset_index(level=1, drop=True)

Последнее соединение togehter на concat и агрегирование по индексу (уровень = 0) ожидается set с, последнее преобразование Series в 2 columns DataFrame на Series.rename_axis и Series.reset_index:

df = (pd.concat([s1, s2])
        .groupby(level=0)
        .agg(set)
        .rename_axis('userid')
        .reset_index(name='emails'))
print (df)
   userid                       emails
0       1                    {a@a.com}
1       2           {b@b.com, f@f.com}
2       3                    {c@c.com}
3       4  {g@g.com, d@d.com, e@e.com}
0 голосов
/ 11 апреля 2020

Просто дополнение, помогающее понять различные этапы решения @ jezrael:

s1 = df1.set_index('userid')['email_work']
print("s1::\n", s1)
print("df2::\n", df2)
print("filter::\n",     df2.set_index('id').filter(like='email'))
print("stack::\n",      df2.set_index('id').filter(like='email').stack())
print("resetindex::\n", df2.set_index('id').filter(like='email').stack().reset_index(level=1))
s2 =                    df2.set_index('id').filter(like='email').stack().reset_index(level=1, drop=True)
print('drop=True::\n', s2)
print('agg::\n',        pd.concat([s1, s2]).groupby(level=0).agg(set))
print('renameaxis::\n', pd.concat([s1, s2]).groupby(level=0).agg(set).rename_axis('userid'))                             # Set the name of the axis for the index or columns.
print('resetindex::\n', pd.concat([s1, s2]).groupby(level=0).agg(set).rename_axis('userid').reset_index(name='emails'))  # This is useful when the index needs to be treated as a column, or when the index is meaningless and needs to be reset to the default before another operation.

То же, что и ответ @ anky:

print('renameaxis::\n', df2.set_index('id').filter(like='email').rename_axis('userid'))
print('stack::\n',      df2.set_index('id').filter(like='email').rename_axis('userid').stack())
m =   df2.set_index('id').filter(like='email').rename_axis('userid').stack().reset_index(name='email_work')
print('resetindex::\n', m)
print('concat::\n',     pd.concat((df1, m), join='inner'))
print('agg::\n',        pd.concat((df1, m), join='inner').groupby('userid')['email_work'].agg(set))
print('resetindex::\n', pd.concat((df1, m), join='inner').groupby('userid')['email_work'].agg(set).reset_index())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...