Podano przykład Dataframe poniżej, jak znaleźć użytkowników w tej samej lokalizacji, która mają takie same zainteresowanie? Dane są

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

Wyjście powinno być

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

Do tej pory stworzyłem oddzielne dane Dataframe dla każdej lokalizacji, jak poniżej

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

Kod-

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

Ale to daje mi wyjście bez kolumny lokalizacji.

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

Pytania: 1) Jak zmodyfikować ten kod, aby uzyskać kolumnę lokalizacji w wyjściu? 2) Czy istnieje sposób, aby zrobić to bez podziału oryginalnych ramek do wielu ramek opartych na lokalizacji?

2
user11133276 1 marzec 2019, 01:40

2 odpowiedzi

Najlepsza odpowiedź

Oto jedno możliwe rozwiązanie. Zauważyłem dodany kod. Wystąpił dodatkowy słownik, aby zachować informacje o lokalizacji dla każdego użytkownika, funkcję, która usuwa kombinacje użytkowników, jeśli nie udostępniają tej samej lokalizacji i linii na końcu, który używa tego samego Słownik lokalizacji, aby utworzyć kolumnę lokalizacji na stronie Final Dataframe.

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

0
AlexK 6 marzec 2019, 02:49

Oto moje rozwiązanie, bez konieczności tworzenia ram do danych. Wygląda jednak na ciężką ciężką. Kredyty idą do @alexk dla iniczej ramy.

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
kerwei 6 marzec 2019, 09:15