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

Python 根据列条件,放入新列的两行的相似性,python,calculated-columns,cosine-similarity,Python,Calculated Columns,Cosine Similarity,当且仅当另一列满足特定条件时,我正在努力将一系列两行之间的相似性转化为一系列新的列。例如,假设我有一个有四个人的df,他们的朋友身份和他们的社会偏好 preference = {'person': ["Sara","Jordan","Amish","Kimmie"],'game_night':[30,10,50,30], 'movies': [10,10,20,10], 'dinner_out': [20,20,30

当且仅当另一列满足特定条件时,我正在努力将一系列两行之间的相似性转化为一系列新的列。例如,假设我有一个有四个人的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”的新列,这些列将填充
点(person1\u首选项,person2\u首选项)/(norm(person1\u首选项)*norm(person2\u首选项))
在每个人的3个社会偏好和其他偏好之间。例如,添加名为“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)
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.        ]])
为您的操作定义自定义函数:

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([
    array([30, 10, 20]), 
    array([10, 10, 20]), 
    array([50, 20, 30]),
    array([30, 10, 10])
], 
dtype=object)
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合并

谢谢,杰夫,非常感谢。我将不得不花一些时间来消化。很抱歉这么多的编辑,在工作中匆匆忙忙地做了这件事,并且记住了我以后应该做得更好的东西。这让我印象深刻,也让我更加感激
pd.DataFrame(
    out,
    columns=df.person.apply(lambda x: 'sim{}'.format(x)).to_numpy(),
    index=df.person
).reset_index()