我试图为给定的(x,y)数据点绘制最佳拟合线。
这里显示数据点(红色像素)和估计线(绿色),我使用以下库获得。
import numpy as np
m, c = np.linalg.lstsq(A, y)[0]
的文档
我们可以看到数据点大致对称分布。问题是为什么这条线通过数据点没有类似于长对称轴的梯度?能否解释一下这个结果是否正确?那么,它如何给出最小的误差? (使用lstsq
方法返回的渐变正确绘制线条)。谢谢。
修改
以下是我尝试的代码。输入图像可以从here下载。在这段代码中,我没有强迫线穿过像素分布的中心。 (注意:此处我使用polyfit
代替lstsq
。两者都给出相同的结果)
import numpy as np
import cv2
import math
img = cv2.imread('points.jpg',1);
h, w = img.shape[:2]
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
points = np.argwhere(gray>10) # get (x,y) pairs where red pixels exist
y = points[:,0]
x = points[:,1]
m, c = np.polyfit(x, y, 1) # calculate least square fit line
# calculate two cordinates (x1,y1),(x2,y2) on the line
angle = np.arctan(m)
x1, y1, length = 0, int(c), 500
x2 = int(round(math.ceil(x1 + length * np.cos(angle)),0))
y2 = int(round(math.ceil(y1 + length * np.sin(angle)),0))
# draw line on the color image
cv2.line(img, (x1, y1), (x2, y2), (0,255,0), 1, cv2.LINE_8)
# show output the image
cv2.namedWindow("Display window", cv2.WINDOW_AUTOSIZE);
cv2.imshow("Display window", img);
cv2.waitKey(0);
cv2.destroyAllWindows()
如何让线穿过像素分布的最长对称轴?我可以使用主成分分析吗?
答案 0 :(得分:3)
很难说为什么会出现这种情况。最重要的是,我无法看到您正在使用的数据,而且我无法查看您正在使用的数据的计算斜率和y截距。
以下是一些可以解释我们所看到的内容的事情: (1)数据点的密度实际上与偶然看起来完全不同,一切都正常。 (2)您向最小二乘函数发送了错误的参数,并且您已经获得了GIGO情况。 (我还没有使用numpy的最小二乘算法,所以我无法检查这个。) (3)散点图和线图不同意轴的比例。 (4)破坏了所讨论的最小二乘函数。 (5)您没有将相同的数据传递给最小二乘算法,因为您正在传递给绘图程序。 (6)数据格式很时髦,因此散点图和最小二乘例程以不同方式解释数据。
我无法知道这些问题中的哪一个,除非是(3),否则我希望我们需要更多的数据才能区分这些可能性。
如果我是你,那么我将如何继续:(1)创建一个位于一条线上的小型人工数据集,并将其传递给最小二乘函数,看看它是否向右吐出数字。看看它们在绘制时是否正确。 (2)如果看起来没问题,记录最小二乘算法的输出,看看你是否能找到另一个最小二乘程序来计算斜率和y截距并进行比较。如果它们相同,那可能不是常规,它可能与绘图有关。
如果你做到这一点并且仍然是一个谜,请告诉我们你发现了什么,也许我们可以提出另一个建议。
祝你好运。答案 1 :(得分:1)
如果红点真正代表您的数据,您可能会以强制线穿过原点的方式应用线性回归函数。我怎么知道?当对两个变量x和y使用线性回归时,该线将截取几个特定点。例如,x的平均值和y的平均值。此外,根据您的规格,计算或指定y轴的截距。如果x和y的所有变量都是正数,那么如果强制通过原点,那么你将有一条看起来像你的线。在提供可重现的数据和代码之前,不能说更多。
修改强> 我提供的可重复样本没有太多运气,所以我用随机数建立了一个例子来详细说明我的原始答案。我认为statsmodels是一个适合线性回归分析的库。首先,我将解决之前的评论:
如果x和y的所有变量都是正数,那么如果强行穿过原点,你将有一条看起来像你的线。
你会看到越来越多的效果,你的数字越大(你的数字离原点越远)。将sm.OLS(y,sm.add_constant(x)).fit()
和sm.OLS(y,x).fit()
用于两组不同的数字将准确显示我的意思。首先,我将对下面的数据集进行回归,而不是一个估计的常量(该行经过原点)。这将给我们一个类似于你原始情节的情节:
# Libraries
import statsmodels.api as sm
import numpy as np
import matplotlib.pyplot as plt
# Data
np.random.seed(123)
x = np.random.normal(size=2500) + 100
y = x * 2 + np.random.normal(size=2500) + 100
# Regression
results1 = sm.OLS(y,x).fit()
regLine_origin = x*results1.params[0]
# PLot
fig, ax = plt.subplots()
ax.scatter(x, y, c='red', s=4)
ax.scatter(x, regLine_origin, c = 'green', s = 1)
ax.patch.set_facecolor('black')
plt.show()
接下来,我将在回归中包含一个常量。现在,黄线将代表我认为您在问题中所追求的内容:
# Libraries
import statsmodels.api as sm
import numpy as np
import matplotlib.pyplot as plt
# Data
np.random.seed(123)
x = np.random.normal(size=2500) + 100
y = x * 2 + np.random.normal(size=2500) + 100
# Regression
results1 = sm.OLS(y,x).fit()
results2 = sm.OLS(y,sm.add_constant(x)).fit()
regLine_origin = x*results1.params[0]
regLine_constant = results2.params[0] + x*results2.params[1]
# PLot
fig, ax = plt.subplots()
ax.scatter(x, y, c='red', s=4)
ax.scatter(x, regLine_origin, c = 'green', s = 1)
ax.scatter(x, regLine_constant, c = 'yellow', s = 1)
ax.patch.set_facecolor('black')
plt.show()
最后,我们可以看看当数字更接近原点时会发生什么。可以这么说。在这里,我将在生成数字时删除+100部分:
# The following is changed in the snippet above:
# Data
x = np.random.normal(size=2500)
y = x * 2 + np.random.normal(size=2500)
这就是为什么我认为您的原始回归线设置为通过原点。看一下statsmodels包。在这里,您可以运行print(results2.summary())
:
正如您在上面的代码段中所见,您可以使用results2.params
直接访问回归系数。
编辑2:我的解释仍然不是100%有效。 x和y值的大小必须略有不同才能看到这种效果。无论数字的大小如何,你肯定会发现线路穿过原点的情况。 看看不同的x标签,你会明白我的意思。