2016-10-06 10 views
6

私はそれをプロットし、350のドキュメントのスコアを有していて、この形状を有している:ラインにベクターの2次元直交投影を

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のリストを参照してください)。

Score distribution

今、私はもともと私がthis postに感謝を発見し、このL-shape曲線のelbow point見つける必要がありました。

ここで、次のプロットでは、赤いベクトルpがエルボーポイントを表します。ベクトルb上の点x=(?,?)(黄色の星)が、bpの正射影に対応することを確認したいと思います。

enter image description here

プロット上の赤い点は、(明らかに間違っている)私は得るものです。それは以下を実行得る:bpの突起は、その始点と終点、すなわちsx(黄色の星)によって定義されている場合、今

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 

を、したがって、そのproj_p_onto_b = x - sx = 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、それはあなたの問題があるかもしれません! 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。お役に立てれば。

+0

こんにちは!ご回答有難うございます。私はVECTOR 'p'(' s + p')の代わりにドットプロダクトを作るためにPOINT 'p'を使ったので、実際に' p'に問題があると思います! –

+0

Aaah、最後のコメントを無視して、 'p'は' p(50,37)-s(0,60) 'を実行して得られたものです正しくありません ? –

+0

あなたのコードを使って、私は以前に取得したのと同じ 'red_point'を取得します。奇妙なことに、 'p'または' p + s'を使って私に同じ赤い点を与えます:( –

関連する問題