问题描述
当且仅当另一列满足特定条件时,我才努力将两行之间的相似性转换为新的列。例如,假设我有一个有四个人,他们的朋友身份和他们的社会偏好的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合并