2016-10-06 37 views
6

У меня есть 350 баллов документов, которые, когда я сюжет их, имеют такую ​​форму:2D Ортогональные проекции вектора на линии с NumPy дает неправильный результат

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)] 

Я разместил полный спектр here на pastebin (это соответствует список dataPoints на код ниже).

Score distribution

Теперь я первоначально нужно найти elbow point этой L-shape кривой, которую я нашел благодаря this post.

Теперь, на следующем графике, красный вектор p представляет точку локтя. Я хотел бы найти точку x=(?,?) (желтая звезда) на векторе b, что соответствует ортогональному выступу p на b.

enter image description here

Красная точка на графике является один я получаю (что, очевидно, неверно). Я получаю это делает следующее:

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 

Теперь, если проекция p на b определяется его начальной и конечной точки, а именно s и x (желтая звезда), то отсюда следует, что proj_p_onto_b = x - s, поэтому x = proj_p_onto_b + s ?

Я сделал ошибку здесь?

EDIT: В ответ на @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 

EDIT: Вот код для сюжета:

>>> 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')'. Если оси не имеют одинаковых масштабов, углы между линиями искажаются на графике. –

+0

Вау, я думаю, что это трюк ...позвольте мне попробовать быстро –

+0

@WarrenWeckesser Ну, это была вещь, я чувствую себя немой. Большое спасибо за указание на это, можете ли вы написать его как ответ, чтобы я мог его принять? –

ответ

3

Если вы используете график, чтобы визуально определить, правильно ли оно выглядит, вы должны построить данные с использованием той же шкалы на каждой оси, то есть использовать plt.axis('equal'). Если оси не имеют одинаковых масштабов, углы между линиями искажаются на графике.

1

Прежде всего, это точка в ~ (50, 37) p или s+p? Если p, это может быть ваша проблема прямо там! Если Y-компонент вашей переменной p положителен, вы не получите ожидаемых результатов, когда будете делать точечный продукт.

Если предположить, что дело в том, s+p, если немного Post-It писанины является правильным,

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. Надеюсь это поможет.

+0

Привет! Спасибо за Ваш ответ. Я думаю, что проблема действительно связана с 'p', поскольку я использовал POINT' p' для создания точечного продукта вместо VECTOR 'p' (который является' s + p')! Я попробую ваше предложение и вернусь к вам, когда я получу результат :) –

+0

Aaah, проигнорируйте последний комментарий, вектор 'p' получается путем выполнения' p (50, 37) - s (0,60) ', это не верно ? –

+0

Используя ваш код, я получаю тот же самый «red_point», который я получил ранее. странно, используя 'p' или' p + s' оба дают мне ту же красную точку :( –