基于列条件将两行放入新列的相似性

Similarity of two rows placed into new column, based on column condition

当且仅当另一列满足特定条件时,我正在努力将一系列两行之间的相似性转化为一系列新的列。例如,假设我有四个人的 df,他们的朋友状态和他们的社交偏好。

preference = {'person': ["Sara","Jordan","Amish","Kimmie"],'game_night':[30,10,50,30], 'movies': [10,10,20,10], 'dinner_out': [20,20,30,10] }
near = {'person': ["Sara","Jordan","Amish","Kimmie"], 'friendSara':[0,1,0,0], 'friendJordan': [1,0,1,1], 'friendAmish': [0,1,0,1], 'friendKimmie': [0,1,1,0]}

df = pd.DataFrame(data=preference)
near_df = pd.DataFrame(data=near)

如果您觉得有更好的方法来组织 df 或解决问题,请挑战我,但我希望在本示例中创建一系列名为 'simSara' 的新列, 'simJordan',等等,填充每个人的3个社交偏好与其他人之间的dot(person1_preferences, person2_preferences)/(norm(person1_preferences)*norm(person2_preferences))。例如,添加的第一列名为 'simSara' 的第二行将填充 0.873(因为 Jordan 和 Sara 是朋友)

创建一个 numpy 数组,将每个人的偏好汇总为一个向量,每个向量也是一个 np.array

prefVec = df.apply(lambda x: np.array([x.game_night,x.movies,x.dinner_out]),axis=1).to_numpy()

应该是这样的:

array([
    array([30, 10, 20]), 
    array([10, 10, 20]), 
    array([50, 20, 30]),
    array([30, 10, 10])
], 
dtype=object)

为您的操作定义自定义函数:

def getVal(v1,v2):
    return np.sum(v1*v2)/(np.sqrt((v1**2).sum())*np.sqrt((v2**2).sum()))

现在我们基本上需要使用我们之前定义的函数来做一个自定义的内积。 np.frompyfunc 采用我们的自定义函数和指定自定义函数输入和输出数量的整数。通过将 prefVec 垂直和水平传递给此 customFunc,我们广播操作。这意味着我们的水平 prefVec 被“拉伸”成一个矩阵,然后我们将让它通过我们的自定义内积与我们的列 prefVec:

customFunc = np.frompyfunc(getVal,2,1)
out = customFunc(prefVec.reshape(-1,1),prefVec)
#                  ^column prefVec       ^horizontal prefVec

out 应该是这样的:

array([[1.        , 0.87287156, 0.99717646, 0.96698756],
       [0.87287156, 1.        , 0.86094603, 0.73854895],
       [0.99717646, 0.86094603, 1.        , 0.97823198],
       [0.96698756, 0.73854895, 0.97823198, 1.        ]])

通过获取原始 df.person 列中的人员列表将其转换为数据框

pd.DataFrame(
    out,
    columns=df.person.apply(lambda x: 'sim{}'.format(x)).to_numpy(),
    index=df.person
).reset_index()

输出:

    person  simSara simJordan   simAmish    simKimmie
0   Sara    1.000000    0.872872    0.997176    0.966988
1   Jordan  0.872872    1.000000    0.860946    0.738549
2   Amish   0.997176    0.860946    1.000000    0.978232
3   Kimmie  0.966988    0.738549    0.978232    1.000000

如果您希望它们都在同一个数据框中,请将上述输出与 person 列上的原始 df 合并