【问题标题】:2D Orthogonal projection of vector onto line with numpy yields wrong result使用 numpy 将向量二维正交投影到线上会产生错误的结果
【发布时间】:2017-02-15 03:49:51
【问题描述】:

我有 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 上发布了完整的数组here(它对应于下面代码中的dataPoints 列表)。

现在,我最初需要找到这条L-shape 曲线的elbow point,感谢this post

现在,在下图中,红色矢量p 表示肘点。我想在向量b 上找到点x=(?,?)(黄色星),它对应于pb 的正交投影。

情节上的红点是我得到的(这显然是错误的)。我通过以下方式获得它:

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,因此@987654343 @?

我这里是不是搞错了?

编辑:回答@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()

【问题讨论】:

  • 如果您使用绘图来直观地确定解决方案是否正确,则必须在每个轴上使用相同的比例绘制数据,即使用plt.axis('equal')。如果坐标轴的比例不同,则线之间的角度会在图中扭曲。
  • 哇,我觉得这就是诀窍……让我快点试试
  • @WarrenWeckesser 好吧,这就是事情,我觉得很愚蠢。非常感谢您指出这一点,您能否将其写为答案以便我接受?
  • 好的,答案已提交。

标签: python numpy plot linear-algebra orthogonal


【解决方案1】:

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

【讨论】:

  • 谢谢你,我一直在努力寻找投影 1 小时。我以为方程式是错误的,我检查了10多次。最终,问题出在 matplotlib 上,您的回答帮助我解决了这个问题。谢谢!
【解决方案2】:

首先,点是在 ~(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

未经测试! YMMV。希望这会有所帮助。

【讨论】:

  • 嗨!感谢您的回答。我认为问题确实在于p,因为我使用POINT p 来制作点积而不是矢量p(即s+p)!我会尝试你的建议,当我得到结果时会回复你:)
  • 啊啊,忽略最后一条评论,向量p是通过p(50, 37) - s(0,60)得到的,是不是不正确?
  • 使用您的代码,我得到了与以前相同的red_point。奇怪的是,使用pp+s 都给了我相同的红点:(
  • 我用代码编辑了问题,如果您需要完整的数据,请告诉我,我会粘贴它
  • @FloranGmehlin 再次感谢您!由于红点是出现在错误位置的那个,请您也添加绘制红点的代码吗?我已经详细查看了发布的代码,但找不到错误(这既是好消息,也是坏消息 :))。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-05
  • 2019-08-11
相关资源
最近更新 更多