Действительно, очень полезной концепцией здесь является линейное преобразование вектора v
, выполняемое матрицей A
.Если вы рассматриваете свои точки разброса как кончик векторов, начинающихся с (0,0), то очень легко повернуть их на любой угол theta
.Матрица, которая выполняет такое вращение theta
, будет иметь вид
A = [[cos(theta) -sin(theta]
[sin(theta) cos(theta)]]
Очевидно, что когда тета равна 90 градусам, это приводит к
A = [[ 0 1]
[-1 0]]
И для применения вращения вам потребуется тольковыполнить умножение матриц w = A v
При этом текущая цель состоит в том, чтобы выполнить умножение матриц векторов, сохраненных в m
, с x, y tips равными 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)
И, применяя линейное преобразование с матрицей вращения, вы получаете