使用numpy进行线性投影的二维正交向量结果错误

7

我有350个文档分数,当我将它们绘制出来时,形状如下:

docScores = [(0, 68.62998962), (1, 60.21374512), (2, 54.72480392), 
             (3, 50.71389389), (4, 49.39723969), ...,  
             (345, 28.3756237), (346, 28.37126923), 
             (347, 28.36397934), (348, 28.35762787), (349, 28.34219933)]

我在pastebin上发布了完整的数组,链接在这里(它对应于以下代码中的dataPoints列表)。

评分分布

现在,我最初需要找到这个L-shape曲线的拐点,感谢这篇文章,我找到了。

在下面的图中,红色向量p表示弯曲点。 我想要找到向量b上对应于p正交投影的点x=(?,?)(即黄色星形)。

输入图像描述

图中的红点是我得到的点(显然是错误的)。 我通过以下方式获得它:

b_hat = b / np.linalg.norm(b)    #unit vector of b
proj_p_onto_b = p.dot(b_hat)*b_hat
red_point = proj_p_onto_b + s

现在,如果将pb上的投影定义为它的起点和终点,即sx(黄色星形),则有proj_p_onto_b = x - s,因此x = proj_p_onto_b + s?这里有错误吗?
编辑:回答@cxw,下面是计算拐点的代码:
def findElbowPoint(self, rawDocScores):
    dataPoints = zip(range(0, len(rawDocScores)), rawDocScores)
    s = np.array(dataPoints[0])
    l = np.array(dataPoints[len(dataPoints)-1])
    b_vect = l-s
    b_hat = b_vect/np.linalg.norm(b_vect)
    distances = []
    for scoreVec in dataPoints[1:]:
        p = np.array(scoreVec) - s
        proj = p.dot(b_hat)*b_hat
        d = abs(np.linalg.norm(p - proj)) # orthgonal distance between b and the L-curve
        distances.append((scoreVec[0], scoreVec[1], proj, d))

    elbow_x = max(distances, key=itemgetter(3))[0]
    elbow_y = max(distances, key=itemgetter(3))[1]
    proj = max(distances, key=itemgetter(3))[2]
    max_distance = max(distances, key=itemgetter(3))[3]

    red_point = proj + s

编辑:这是图形的代码:

>>> l_curve_x_values = [x[0] for x in docScores]
>>> l_curve_y_values = [x[1] for x in docScores]
>>> b_line_x_values = [x[0] for x in docScores]
>>> b_line_y_values = np.linspace(s[1], l[1], len(docScores))
>>> p_line_x_values = l_curve_x_values[:elbow_x]
>>> p_line_y_values = np.linspace(s[1], elbow_y, elbow_x)
>>> plt.plot(l_curve_x_values, l_curve_y_values, b_line_x_values, b_line_y_values, p_line_x_values, p_line_y_values)
>>> red_point = proj + s
>>> plt.plot(red_point[0], red_point[1], 'ro')
>>> plt.show()

1
如果您使用绘图来直观地确定解决方案是否正确,则必须在每个轴上使用相同的比例尺来绘制数据,即使用 plt.axis('equal')。如果轴没有相等的比例尺,则图中线之间的角度会发生扭曲。 - Warren Weckesser
哇,我觉得这就是诀窍...让我快速尝试一下。 - Floran Gmehlin
@WarrenWeckesser 嗯,这就是问题所在,我感觉很蠢。非常感谢您指出来,您能否将其写成答案,以便我可以接受它? - Floran Gmehlin
好的,答案已提交。 - Warren Weckesser
2个回答

4

如果您使用图表来直观地确定解决方案是否正确,则必须在每个轴上使用相同的比例尺来绘制数据,即使用plt.axis('equal')。如果轴没有相等的比例尺,则图表中的线之间的角度会失真。


谢谢你,我一直在尝试寻找这个投影已经一个小时了。我以为方程式是错的,检查了十多次。最终,问题出在matplotlib上,你的答案帮助我找到了问题所在。谢谢! - Ahmed Tarawneh

1
首先,点位于(50,37)处的是p还是s+p?如果是p,那么你的问题可能就出在这里!如果p变量的Y分量为正数,则在进行点积运算时将无法得到预期结果。
假设该点位于s+p,如果一些便签上的涂鸦是正确的,
p_len = np.linalg.norm(p)
p_hat = p / p_len
red_len = p_hat.dot(b_hat) * p_len   # red_len = |x-s|
    # because p_hat . b_hat = 1 * 1 * cos(angle) = |x-s| / |p|
red_point = s + red_len * b_hat

未经测试!效果因人而异。希望能对您有所帮助。

嗨!谢谢你的回答。我认为问题确实出在 p 上,因为我使用点 p 来进行点积,而不是向量 p(即 s+p)!我会尝试你的建议,并在得到结果后再联系你 :) - Floran Gmehlin
啊,忽略上一个评论,向量p是通过执行p(50, 37) - s(0,60)获得的,这不正确吗? - Floran Gmehlin
使用您的代码,我得到了之前相同的“red_point”。奇怪的是,使用“p”或“p+s”都会给我相同的红点:( - Floran Gmehlin
我已经在问题中编辑了代码,如果你需要完整的数据,请让我知道,我会把它粘贴到pastebin上。 - Floran Gmehlin
1
@FloranGmehlin 谢谢你再次!由于红点出现在错误的位置,你能否也加上绘制红点的代码?我已经详细查看了发布的代码,但找不到错误(这既是好消息也是坏消息 :))。非常感谢! - cxw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接