在 Python 中找到共同好友的数量
Find the number of mutual friends in Python
我有一个用户及其朋友的数据框,如下所示:
user_id | friend_id
1 3
1 4
2 3
2 5
3 4
我想在 python
中编写一个函数来计算每对的共同朋友的数量:
user_id | friend_id | num_mutual
1 3 1
1 4 1
2 3 0
2 5 0
3 4 1
目前我有:
def find_mutual(df):
num_mutual = []
for i in range(len(df)):
user, friend = df.loc[i, 'user_id'], df.loc[i, 'friend_id']
user_list = df[df.user_id == user].friend_id.tolist() + df[df.friend_id == user].user_id.tolist()
friend_list = df[df.user_id == friend].friend_id.tolist() + df[df.friend_id == friend].user_id.tolist()
mutual = len(list(set(user_list) & set(friend_list)))
num_mutual.append(mutual)
return num_mutual
它适用于小型数据集,但我运行将其用于具有数百万行的数据集。 运行 一切都需要永远。我知道这不是找到伯爵的理想方法。 Python有没有更好的算法?提前致谢!
[丑陋]的想法是构建一个以user_id
开始并以相同的user_id
结束的4点路径。如果存在这样一条路径,则2个起点有共同的朋友。
我们从:
开始
df
user_id friend_id
0 1 3
1 1 4
2 2 3
3 2 5
4 3 4
那么你可以这样做:
dff = df.append(df.rename(columns={"user_id":"friend_id","friend_id":"user_id"}))
df_new = dff.merge(dff, on="friend_id", how="outer")
df_new = df_new[df_new["user_id_x"]!= df_new["user_id_y"]]
df_new = df_new.merge(dff, left_on= "user_id_y", right_on="user_id")
df_new = df_new[df_new["user_id_x"]==df_new["friend_id_y"]]
df_out = df.merge(df_new, left_on=["user_id","friend_id"], right_on=["user_id_x","friend_id_x"], how="left",suffixes=("__","_"))
df_out["count"] = (~df_out["user_id_x"].isnull()).astype(int)
df_out[["user_id__","friend_id","count"]]
user_id__ friend_id count
0 1 3 1
1 1 4 1
2 2 3 0
3 2 5 0
4 3 4 1
使用图形方法的更优雅、更直接的方法
import networkx as nx
g = nx.from_pandas_edgelist(df, "user_id","friend_id")
nx.draw_networkx(g)
然后您可以将共同朋友的数量识别为存在 3 节点路径的 2 个相邻节点(2 个朋友)的路径数:
from networkx.algorithms.simple_paths import all_simple_paths
for row in df.itertuples():
df.at[row[0],"count"] = sum([len(l)==3 for l in list(all_simple_paths(g, row[1], row[2]))])
print(df)
user_id friend_id count
0 1 3 1.0
1 1 4 1.0
2 2 3 0.0
3 2 5 0.0
4 3 4 1.0
我有一个用户及其朋友的数据框,如下所示:
user_id | friend_id
1 3
1 4
2 3
2 5
3 4
我想在 python
中编写一个函数来计算每对的共同朋友的数量:
user_id | friend_id | num_mutual
1 3 1
1 4 1
2 3 0
2 5 0
3 4 1
目前我有:
def find_mutual(df):
num_mutual = []
for i in range(len(df)):
user, friend = df.loc[i, 'user_id'], df.loc[i, 'friend_id']
user_list = df[df.user_id == user].friend_id.tolist() + df[df.friend_id == user].user_id.tolist()
friend_list = df[df.user_id == friend].friend_id.tolist() + df[df.friend_id == friend].user_id.tolist()
mutual = len(list(set(user_list) & set(friend_list)))
num_mutual.append(mutual)
return num_mutual
它适用于小型数据集,但我运行将其用于具有数百万行的数据集。 运行 一切都需要永远。我知道这不是找到伯爵的理想方法。 Python有没有更好的算法?提前致谢!
[丑陋]的想法是构建一个以user_id
开始并以相同的user_id
结束的4点路径。如果存在这样一条路径,则2个起点有共同的朋友。
我们从:
开始df
user_id friend_id
0 1 3
1 1 4
2 2 3
3 2 5
4 3 4
那么你可以这样做:
dff = df.append(df.rename(columns={"user_id":"friend_id","friend_id":"user_id"}))
df_new = dff.merge(dff, on="friend_id", how="outer")
df_new = df_new[df_new["user_id_x"]!= df_new["user_id_y"]]
df_new = df_new.merge(dff, left_on= "user_id_y", right_on="user_id")
df_new = df_new[df_new["user_id_x"]==df_new["friend_id_y"]]
df_out = df.merge(df_new, left_on=["user_id","friend_id"], right_on=["user_id_x","friend_id_x"], how="left",suffixes=("__","_"))
df_out["count"] = (~df_out["user_id_x"].isnull()).astype(int)
df_out[["user_id__","friend_id","count"]]
user_id__ friend_id count
0 1 3 1
1 1 4 1
2 2 3 0
3 2 5 0
4 3 4 1
使用图形方法的更优雅、更直接的方法
import networkx as nx
g = nx.from_pandas_edgelist(df, "user_id","friend_id")
nx.draw_networkx(g)
然后您可以将共同朋友的数量识别为存在 3 节点路径的 2 个相邻节点(2 个朋友)的路径数:
from networkx.algorithms.simple_paths import all_simple_paths
for row in df.itertuples():
df.at[row[0],"count"] = sum([len(l)==3 for l in list(all_simple_paths(g, row[1], row[2]))])
print(df)
user_id friend_id count
0 1 3 1.0
1 1 4 1.0
2 2 3 0.0
3 2 5 0.0
4 3 4 1.0