Поиск общих значений в строках информационного кадра с ограничением на основе значений в другом столбце - PullRequest
0 голосов
/ 01 марта 2019

В приведенном ниже примере данных, как найти пользователей в одном месте, которые имеют одинаковый интерес?Данные -

userid   interest    location
 1       [A, B]          Z
 2       [A, C, B]       Y
 3       [B, D]          Z
 4       [A, C]          Y
 5       [A, B, D]       Z

Выходные данные должны быть -

userid    relativeid  common interest  location
  1          3           [B]              Z
  1          5           [A, B]           Z
  2          4           [A,C]            Y

До сих пор я создавал отдельные кадры данных для каждого местоположения, как показано ниже -

userid   interest    location
 1       [A, B]          Z
 3       [B, D]          Z
 5       [A, B, D]       Z

код-

dictionary = df.set_index('userid')['interest'].map(set).to_dict()
dictionary

out = pd.DataFrame(list(itertools.combinations(df.userid, 2)), columns=['userid', 'relative_id']) 
out['common_interest'] = [list(dictionary[x] & dictionary[y]) for x, y in out.values]
out

но это дает мне вывод без столбца местоположения.

userid    relativeid  common interest 
  1          3           [B]              
  1          5           [A, B]

Вопросы: 1) как изменить этот код, чтобы получить столбец местоположения в выводе?2) Есть ли способ сделать это без разделения исходного фрейма данных на несколько фреймов данных в зависимости от местоположения?

Ответы [ 2 ]

0 голосов
/ 06 марта 2019

Вот мое решение, без необходимости создавать субкадры данных.Это выглядит довольно тяжело, хотя.Кредиты идут в @AlexK для инициации кадра.

import pandas as pd
import itertools

df = pd.DataFrame({'userid':[1,2,3,4,5],'interest':[['A','B'],['A','C','B'],['B','D'],['A','C'],['A','B','D']],
                        'location':['Z','Y','Z','Y','Z']})
# Builds a dictionary of location as key and a list of index of users in df as value
idxlocation = df.groupby('location').apply(lambda x: x.index.values).to_dict()

new_frame = []
for k, v  in idxlocation.items():
    for i in itertools.combinations(v, 2):
        userid = df.loc[i[0], 'userid']
        relativeid = df.loc[i[1], 'userid']
        new_frame.append((userid, relativeid, [j for j in set(df.loc[i[0], 'interest']).intersection(set(df.loc[i[1], 'interest']))], k))

out = pd.DataFrame(new_frame)
out.columns = ['userid', 'relative_id', 'common_interest', 'location']

>>>out
   userid  relative_id common_interest location
0       2            4          [A, C]        Y
1       1            3             [B]        Z
2       1            5          [A, B]        Z
3       3            5          [D, B]        Z
0 голосов
/ 06 марта 2019

Вот одно из возможных решений.Я отметил добавленный код.Существует только дополнительный словарь, созданный для хранения информации о местоположении для каждого идентификатора пользователя, функция, которая удаляет комбинации пользователей, если у них нет общего местоположения, и строка в конце, которая использует этот же словарь местоположений для создания столбца местоположения вокончательный фрейм данных.

import itertools

users_df = pd.DataFrame({'userid':[1,2,3,4,5],'interest':[['A','B'],['A','C','B'],['B','D'],['A','C'],['A','B','D']],
                        'location':['Z','Y','Z','Y','Z']})

#new code: location dictionary
loc_dict = users_df.set_index('userid')['location'].to_dict()

#new code: function that removes userid combinations when locations are different
def restrict_users(all_combs):
    return [comb for comb in all_combs if loc_dict[comb[0]] == loc_dict[comb[1]]]

dictionary = users_df.set_index('userid')['interest'].map(set).to_dict()

#new function applied below
out = pd.DataFrame(restrict_users(list(itertools.combinations(users_df.userid, 2))), columns=['userid', 'relative_id']) 
out['common_interest'] = [list(dictionary[x] & dictionary[y]) for x, y in out.values]
#location column added to the dataframe
out['location'] = out['userid'].map(loc_dict)

out

Output

...