将旋转矩阵应用于 xy 坐标
Apply a rotation matrix to xy coordinates
我有 xy
坐标表示给定 space 上的主题。它是从另一个点引用的,因此 偏离中心 。由于 longitudinal
axes
未沿 x-axis
.
对齐
下面随机生成的 ellipse
说明了这一点:
import numpy as np
from matplotlib.pyplot import scatter
xx = np.array([-0.51, 51.2])
yy = np.array([0.33, 51.6])
means = [xx.mean(), yy.mean()]
stds = [xx.std() / 3, yy.std() / 3]
corr = 0.8 # correlation
covs = [[stds[0]**2 , stds[0]*stds[1]*corr],
[stds[0]*stds[1]*corr, stds[1]**2]]
m = np.random.multivariate_normal(means, covs, 1000).T
scatter(m[0], m[1])
要拉直 我正在考虑将矢量应用于 rotation matrix
的坐标。
这样的东西行得通吗?
angle = 65.
theta = (angle/180.) * np.pi
rotMatrix = np.array([[np.cos(theta), -np.sin(theta)],
[np.sin(theta), np.cos(theta)]])
这似乎也是一个愚蠢的问题,但有没有办法确定 xy
坐标的结果 vector
是否垂直?或者你只需要玩玩 rotation angle
?
如果两条线的斜率相乘等于-1,则说明它们是垂直的。
另一种情况是正确的,即一个斜率为 0 而另一个未定义(一条完美的水平线和一条完美的垂直线)。
您可以使用 sklearn.decomposition.PCA
(主成分分析)和 n_components=2
来提取旋转点云所需的最小角度,使其主轴水平。
可运行示例
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
np.random.seed(1)
xx = np.array([-0.51, 51.2])
yy = np.array([0.33, 51.6])
means = [xx.mean(), yy.mean()]
stds = [xx.std() / 3, yy.std() / 3]
corr = 0.8 # correlation
covs = [[stds[0]**2, stds[0]*stds[1]*corr],
[stds[0]*stds[1]*corr, stds[1]**2]]
m = np.random.multivariate_normal(means, covs, 1000)
pca = PCA(2)
# This was in my first answer attempt: fit_transform works fine, but it randomly
# flips (mirrors) points across one of the principal axes.
# m2 = pca.fit_transform(m)
# Workaround: get the rotation angle from the PCA components and manually
# build the rotation matrix.
# Fit the PCA object, but do not transform the data
pca.fit(m)
# pca.components_ : array, shape (n_components, n_features)
# cos theta
ct = pca.components_[0, 0]
# sin theta
st = pca.components_[0, 1]
# One possible value of theta that lies in [0, pi]
t = np.arccos(ct)
# If t is in quadrant 1, rotate CLOCKwise by t
if ct > 0 and st > 0:
t *= -1
# If t is in Q2, rotate COUNTERclockwise by the complement of theta
elif ct < 0 and st > 0:
t = np.pi - t
# If t is in Q3, rotate CLOCKwise by the complement of theta
elif ct < 0 and st < 0:
t = -(np.pi - t)
# If t is in Q4, rotate COUNTERclockwise by theta, i.e., do nothing
elif ct > 0 and st < 0:
pass
# Manually build the ccw rotation matrix
rotmat = np.array([[np.cos(t), -np.sin(t)],
[np.sin(t), np.cos(t)]])
# Apply rotation to each row of m
m2 = (rotmat @ m.T).T
# Center the rotated point cloud at (0, 0)
m2 -= m2.mean(axis=0)
fig, ax = plt.subplots()
plot_kws = {'alpha': '0.75',
'edgecolor': 'white',
'linewidths': 0.75}
ax.scatter(m[:, 0], m[:, 1], **plot_kws)
ax.scatter(m2[:, 0], m2[:, 1], **plot_kws)
输出
警告:pca.fit_transform()
有时会翻转(镜像)点云
主成分可以随机显示为正数或负数。在某些情况下,您的点云可能看起来上下颠倒,甚至在其主轴之一上镜像。 (要对此进行测试,请更改随机种子并重新 运行 代码,直到您观察到翻转。)有一个深入的讨论 here(基于 R,但数学是相关的)。要更正此问题,您必须将 fit_transform
行替换为手动翻转一个或两个组件的符号,然后将符号翻转后的组件矩阵乘以点云数组。
这里确实有一个非常有用的概念,它是由矩阵 A
执行的向量 v
的线性变换。如果您将散点视为源自 (0,0) 的向量的尖端,则很容易将它们旋转任意角度 theta
。执行这种 theta
旋转的矩阵将是
A = [[cos(theta) -sin(theta]
[sin(theta) cos(theta)]]
显然,当 theta 为 90 度时,结果为
A = [[ 0 1]
[-1 0]]
要应用旋转,您只需执行矩阵乘法 w = A v
有了这个,当前的目标是对存储在 m
中的向量执行矩阵乘法,x,y 提示为 m[0],m[1]
。旋转后的矢量将存储在 m2
中。下面是这样做的相关代码。请注意,我已转置 m
以便更轻松地计算矩阵乘法(使用 @
执行)并且旋转角度逆时针旋转 90 度。
import numpy as np
import matplotlib.pyplot as plt
xx = np.array([-0.51, 51.2])
yy = np.array([0.33, 51.6])
means = [xx.mean(), yy.mean()]
stds = [xx.std() / 3, yy.std() / 3]
corr = 0.8 # correlation
covs = [[stds[0]**2 , stds[0]*stds[1]*corr],
[stds[0]*stds[1]*corr, stds[1]**2]]
m = np.random.multivariate_normal(means, covs, 1000).T
plt.scatter(m[0], m[1])
theta_deg = 90
theta_rad = np.deg2rad(theta_deg)
A = np.matrix([[np.cos(theta_rad), -np.sin(theta_rad)],
[np.sin(theta_rad), np.cos(theta_rad)]])
m2 = np.zeros(m.T.shape)
for i,v in enumerate(m.T):
w = A @ v.T
m2[i] = w
m2 = m2.T
plt.scatter(m2[0], m2[1])
这导致了旋转的散点图:
你可以确定旋转后的版本通过线性变换正好逆时针旋转90度。
编辑
要找到您需要应用的旋转角度以使散点图与 x 轴对齐,一个好的方法是使用 numpy.polyfit
找到散点数据的线性近似值。这通过提供 slope
和 y 轴的截距 b
产生线性函数。然后用斜率的 arctan
函数得到旋转角度,并像以前一样计算变换矩阵。您可以通过将以下部分添加到代码中来完成此操作
slope, b = np.polyfit(m[1], m[0], 1)
x = np.arange(min(m[0]), max(m[0]), 1)
y_line = slope*x + b
plt.plot(x, y_line, color='r')
theta_rad = -np.arctan(slope)
以及您正在寻找的情节的结果
编辑 2
因为@Peter Leimbigler 指出 numpy.polyfit
没有找到正确的分散数据的全局方向,我认为你可以通过对 x
和 y
部分数据。这是为了找到另一个斜率,称为 slope2
(现在用绿色表示)来应用旋转。如此简单,
slope, b = np.polyfit(m[1], m[0], 1)
x = np.arange(min(m[0]), max(m[0]), 1)
y_line = slope*x + b
slope2 = np.mean(m[1])/np.mean(m[0])
y_line2 = slope2*x + b
plt.plot(x, y_line, color='r')
plt.plot(x, y_line2, color='g')
theta_rad = -np.arctan(slope2)
通过对旋转矩阵应用线性变换,你得到
我有 xy
坐标表示给定 space 上的主题。它是从另一个点引用的,因此 偏离中心 。由于 longitudinal
axes
未沿 x-axis
.
下面随机生成的 ellipse
说明了这一点:
import numpy as np
from matplotlib.pyplot import scatter
xx = np.array([-0.51, 51.2])
yy = np.array([0.33, 51.6])
means = [xx.mean(), yy.mean()]
stds = [xx.std() / 3, yy.std() / 3]
corr = 0.8 # correlation
covs = [[stds[0]**2 , stds[0]*stds[1]*corr],
[stds[0]*stds[1]*corr, stds[1]**2]]
m = np.random.multivariate_normal(means, covs, 1000).T
scatter(m[0], m[1])
要拉直 我正在考虑将矢量应用于 rotation matrix
的坐标。
这样的东西行得通吗?
angle = 65.
theta = (angle/180.) * np.pi
rotMatrix = np.array([[np.cos(theta), -np.sin(theta)],
[np.sin(theta), np.cos(theta)]])
这似乎也是一个愚蠢的问题,但有没有办法确定 xy
坐标的结果 vector
是否垂直?或者你只需要玩玩 rotation angle
?
如果两条线的斜率相乘等于-1,则说明它们是垂直的。 另一种情况是正确的,即一个斜率为 0 而另一个未定义(一条完美的水平线和一条完美的垂直线)。
您可以使用 sklearn.decomposition.PCA
(主成分分析)和 n_components=2
来提取旋转点云所需的最小角度,使其主轴水平。
可运行示例
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
np.random.seed(1)
xx = np.array([-0.51, 51.2])
yy = np.array([0.33, 51.6])
means = [xx.mean(), yy.mean()]
stds = [xx.std() / 3, yy.std() / 3]
corr = 0.8 # correlation
covs = [[stds[0]**2, stds[0]*stds[1]*corr],
[stds[0]*stds[1]*corr, stds[1]**2]]
m = np.random.multivariate_normal(means, covs, 1000)
pca = PCA(2)
# This was in my first answer attempt: fit_transform works fine, but it randomly
# flips (mirrors) points across one of the principal axes.
# m2 = pca.fit_transform(m)
# Workaround: get the rotation angle from the PCA components and manually
# build the rotation matrix.
# Fit the PCA object, but do not transform the data
pca.fit(m)
# pca.components_ : array, shape (n_components, n_features)
# cos theta
ct = pca.components_[0, 0]
# sin theta
st = pca.components_[0, 1]
# One possible value of theta that lies in [0, pi]
t = np.arccos(ct)
# If t is in quadrant 1, rotate CLOCKwise by t
if ct > 0 and st > 0:
t *= -1
# If t is in Q2, rotate COUNTERclockwise by the complement of theta
elif ct < 0 and st > 0:
t = np.pi - t
# If t is in Q3, rotate CLOCKwise by the complement of theta
elif ct < 0 and st < 0:
t = -(np.pi - t)
# If t is in Q4, rotate COUNTERclockwise by theta, i.e., do nothing
elif ct > 0 and st < 0:
pass
# Manually build the ccw rotation matrix
rotmat = np.array([[np.cos(t), -np.sin(t)],
[np.sin(t), np.cos(t)]])
# Apply rotation to each row of m
m2 = (rotmat @ m.T).T
# Center the rotated point cloud at (0, 0)
m2 -= m2.mean(axis=0)
fig, ax = plt.subplots()
plot_kws = {'alpha': '0.75',
'edgecolor': 'white',
'linewidths': 0.75}
ax.scatter(m[:, 0], m[:, 1], **plot_kws)
ax.scatter(m2[:, 0], m2[:, 1], **plot_kws)
输出
警告:pca.fit_transform()
有时会翻转(镜像)点云
主成分可以随机显示为正数或负数。在某些情况下,您的点云可能看起来上下颠倒,甚至在其主轴之一上镜像。 (要对此进行测试,请更改随机种子并重新 运行 代码,直到您观察到翻转。)有一个深入的讨论 here(基于 R,但数学是相关的)。要更正此问题,您必须将 fit_transform
行替换为手动翻转一个或两个组件的符号,然后将符号翻转后的组件矩阵乘以点云数组。
这里确实有一个非常有用的概念,它是由矩阵 A
执行的向量 v
的线性变换。如果您将散点视为源自 (0,0) 的向量的尖端,则很容易将它们旋转任意角度 theta
。执行这种 theta
旋转的矩阵将是
A = [[cos(theta) -sin(theta]
[sin(theta) cos(theta)]]
显然,当 theta 为 90 度时,结果为
A = [[ 0 1]
[-1 0]]
要应用旋转,您只需执行矩阵乘法 w = A v
有了这个,当前的目标是对存储在 m
中的向量执行矩阵乘法,x,y 提示为 m[0],m[1]
。旋转后的矢量将存储在 m2
中。下面是这样做的相关代码。请注意,我已转置 m
以便更轻松地计算矩阵乘法(使用 @
执行)并且旋转角度逆时针旋转 90 度。
import numpy as np
import matplotlib.pyplot as plt
xx = np.array([-0.51, 51.2])
yy = np.array([0.33, 51.6])
means = [xx.mean(), yy.mean()]
stds = [xx.std() / 3, yy.std() / 3]
corr = 0.8 # correlation
covs = [[stds[0]**2 , stds[0]*stds[1]*corr],
[stds[0]*stds[1]*corr, stds[1]**2]]
m = np.random.multivariate_normal(means, covs, 1000).T
plt.scatter(m[0], m[1])
theta_deg = 90
theta_rad = np.deg2rad(theta_deg)
A = np.matrix([[np.cos(theta_rad), -np.sin(theta_rad)],
[np.sin(theta_rad), np.cos(theta_rad)]])
m2 = np.zeros(m.T.shape)
for i,v in enumerate(m.T):
w = A @ v.T
m2[i] = w
m2 = m2.T
plt.scatter(m2[0], m2[1])
这导致了旋转的散点图:
编辑
要找到您需要应用的旋转角度以使散点图与 x 轴对齐,一个好的方法是使用 numpy.polyfit
找到散点数据的线性近似值。这通过提供 slope
和 y 轴的截距 b
产生线性函数。然后用斜率的 arctan
函数得到旋转角度,并像以前一样计算变换矩阵。您可以通过将以下部分添加到代码中来完成此操作
slope, b = np.polyfit(m[1], m[0], 1)
x = np.arange(min(m[0]), max(m[0]), 1)
y_line = slope*x + b
plt.plot(x, y_line, color='r')
theta_rad = -np.arctan(slope)
以及您正在寻找的情节的结果
编辑 2
因为@Peter Leimbigler 指出 numpy.polyfit
没有找到正确的分散数据的全局方向,我认为你可以通过对 x
和 y
部分数据。这是为了找到另一个斜率,称为 slope2
(现在用绿色表示)来应用旋转。如此简单,
slope, b = np.polyfit(m[1], m[0], 1)
x = np.arange(min(m[0]), max(m[0]), 1)
y_line = slope*x + b
slope2 = np.mean(m[1])/np.mean(m[0])
y_line2 = slope2*x + b
plt.plot(x, y_line, color='r')
plt.plot(x, y_line2, color='g')
theta_rad = -np.arctan(slope2)
通过对旋转矩阵应用线性变换,你得到