根据列条件,放入新列的两行的相似性

问题描述

当且仅当另一列满足特定条件时,我才努力将两行之间的相似性转换为新的列。例如,假设我有一个有四个人,他们的朋友身份和他们的社会偏好的df。

preference = {'person': ["Sara","Jordan","Amish","Kimmie"],'game_night':[30,10,50,30],'movies': [10,20,10],'dinner_out': [20,30,10] }
near = {'person': ["Sara",'friendSara':[0,1,0],'friendJordan': [1,1],'friendamish': [0,'friendKimmie': [0,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,array([50,20,30]),array([30,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.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合并