Python 如何旋转一组二维点以最小化numpy中的垂直跨度?

Python 如何旋转一组二维点以最小化numpy中的垂直跨度?,python,numpy,rotation,coordinates,Python,Numpy,Rotation,Coordinates,我有一个2D点的集合,我想旋转它们,以便在最小垂直高度上显示它们。有没有一种不用优化就能找到角度的方法 作为简要说明: 将numpy导入为np #一些初始点垂直展开 xy=np.random.randn(2100) xy[1,:]*=2 def旋转(xy,θ): “”“返回一组旋转的点。 """ s=np.sin(θ) c=np.cos(θ) xyr=np.empty_-like(xy) xyr[0,:]=c*xy[0,:]-s*xy[1,:] xyr[1,:]=s*xy[0,:]+c*xy[1

我有一个2D点的集合,我想旋转它们,以便在最小垂直高度上显示它们。有没有一种不用优化就能找到角度的方法

作为简要说明:

将numpy导入为np
#一些初始点垂直展开
xy=np.random.randn(2100)
xy[1,:]*=2
def旋转(xy,θ):
“”“返回一组旋转的点。
"""
s=np.sin(θ)
c=np.cos(θ)
xyr=np.empty_-like(xy)
xyr[0,:]=c*xy[0,:]-s*xy[1,:]
xyr[1,:]=s*xy[0,:]+c*xy[1,:]
返回xyr
def量程(xy):
“”“返回点的垂直跨度。
"""
返回xy[1,:].max()-xy[1,:].min()
def绘图(xy):
“”“具有固定纵横比的二维绘图。”。
"""
将matplotlib.pyplot作为plt导入
图,ax=plt.子批次(图尺寸=(3,3))
最大散射(*xy,α=0.3)
ax.set_方面(1)
plt.show()
plt.show()
请看一下原始要点:

>span(xy)
11.503342270923472
>>>绘图(xy)

查看一些旋转点:

xyr=rotate(xy,np.pi/2) >>>跨度(xyr) 4.594620173868735 >>>绘图(xyr)

通过调用
scipy
,很容易找到最佳答案(这里应该是pi/2左右):

从scipy.optimize import最小化标量 >>>最小化标量(λθ:跨度(旋转(xy,θ))) 乐趣:4.5231883127276214 nfev:38 nit:34 成功:真的 x:1.590391370976612
但肯定有一种更简单的方法不需要scipy和38函数评估

这可能不一定是最优的,但一个足够简单的解决方案可能是获取数据的主要成分并旋转数据,以使最大的主要成分与水平轴对齐

将numpy导入为np
#发布代码。。。
#求特征值最大的特征向量
c=(xy@xy.T)/(xy.shape[1]-1)
评估,evecs=np.linalg.eig(c)
imax=np.abs(evals).argmax()
v=evecs[:,imax]
#校正角与矢量角相反
θ=-np.arctan2(v[1],v[0])
#轮换
xy2=旋转(xy,θ)
#密谋
绘图(xy2)
输出:


使用xyr=np。转置(xx)我不认为您能够摆脱优化。但是,如果点的数量较大(例如,代码>10000 < /代码>而不是<代码> 100 < /代码>),则可能需要首先考虑凸壳<代码> >赫尔=XY[]、SimP.Salet。ConvexHull(XY.TrSPOSO())、顶点[< /代码>,然后对该子集进行优化,而不是应用于整个数据集。这一定会得到同样的结果。这绝对是有用的,也是我一直在寻找的东西!虽然对于一些具有多个“大方向”的数据(例如,正方形
xy=np.random.uniform(大小=(2,1000)
),它会产生一个非常接近最大值的垂直跨距。@jawknee是的,这是真的,这主要适用于“圆角”数据或多或少是紧凑的。我也不知道它对于数据的多模态分布是如何工作的。