【问题标题】:How to weigh the points in a scatter plot for a fit?如何权衡散点图中的点以进行拟合?
【发布时间】:2019-01-05 01:12:12
【问题描述】:

因此,我在 Python 中的 polyfit (numpy.polynomial.polynomial.polyfit) 函数中查找了有关权重参数的信息,它似乎与与各个点相关的错误有关。 (How to include measurement errors in numpy.polyfit)

但是,我想要做的与错误无关,而是与权重有关。我有一个 numpy 数组形式的图像,它指示探测器中沉积的电荷量。我将该图像转换为散点图,然后进行拟合。但是我希望这种拟合能够给沉积更多电荷的点赋予更多的权重,而对电荷较少的点赋予更少的权重。这是 weights 参数的用途吗?

这是一个示例图片: 这是我的代码:

def get_best_fit(image_array, fixedX, fixedY):
    weights = np.array(image_array)
    x = np.where(weights>0)[1]
    y = np.where(weights>0)[0]
    size = len(image_array) * len(image_array[0])
    y = np.zeros((len(image_array), len(image_array[0])))
    for i in range(len(np.where(weights>0)[0])):
        y[np.where(weights>0)[0][i]][np.where(weights>0)[1][i]] = np.where(weights>0)[0][i]
    y = y.reshape(size)
    x = np.array(range(len(image_array)) * len(image_array[0]))
    weights = weights.reshape((size))
    b, m = polyfit(x, y, 1, w=weights)
    angle = math.atan(m) * 180/math.pi
    return b, m, angle

让我给你解释一下代码:

第一行将电荷存放在一个称为权重的变量中。接下来的两行得到沉积电荷大于 0 的点,因此沉积了一些电荷来捕获散点图的坐标。然后我得到整个图像的大小,以便稍后转换为仅用于绘图的一维数组。然后,我浏览图像并尝试获取存在一些电荷沉积的点的坐标(请记住,电荷的数量存储在变量weights 中)。然后我重塑y坐标以获得一维数组并从图像中获取所有相应y坐标的x坐标,然后将权重的形状也更改为一维。

编辑:如果有一种方法可以使用 np.linalg.lstsq 函数执行此操作,那将是理想的,因为我还试图让拟合通过绘图的顶点。我可以重新定位绘图,使顶点为零,然后使用np.linalg.lstsq,但这不允许我使用权重。

【问题讨论】:

  • 您能否查看数据并大致了解绘图应该是什么样子?你的结果合理吗?
  • 我的结果看起来确实合理,但并非适用于所有事件。对于某些图像,它可以完美地拟合角度(如问题中给出的那样),但对于其他图像,则不然。
  • 作为一个小技巧:如果费用是离散的或大小相似,您可以在分配更多费用的地方添加额外的点。也看看这个:en.wikipedia.org/wiki/Weighted_least_squares
  • 你能提供一个可运行的示例,包括一些示例数据吗?
  • @Hiho 我使用的不是同一个数据文件,但是数据格式相同:deeplearnphysics.org/DataChallenge。具体来说,我使用的是名为“test_10k.root”的文件

标签: python numpy data-fitting


【解决方案1】:

所以我可能误解了这个问题,但我只是尝试将一条直线拟合到散点图,然后使用权重参数更改拟合以优先考虑特定点。
我用np.polyfitnp.polynomial.polynomial.polyfit 尝试了这个,我希望它们的行为相同,因为它们都在最小化平方误差(至少这是我的理解)。
然而,拟合是完全不同的,见下文。不太清楚该怎么做。

代码

import numpy as np
import matplotlib.pyplot as plt

def func(p1, p2, x):
    return  p1 * x + p2

y = np.array([1.0, 3.3, 2.2, 4.25, 4.8, 5.1, 6.3, 7.5])
x = np.arange(y.shape[0])

plt.scatter(x, y)

w = np.ones(x.shape[0])
w[1] = 12
# p1, p2 = np.polyfit(x, y, 1, w=w)
p1, p2 = np.polynomial.polynomial.polyfit(x, y, 1, w=w)
print(p1, p2, w)

plt.plot(x, func(p1, p2, x))

plt.show()

np.polyfit

没有权重(或全部设置 1)

第二个点的权重设置为12,其他所有的权重都是1

np.polynomial.polynomial.polyfit

没有权重

第二个点的权重设置为12,其他所有的权重都是1

所以 np.polyfit 的行为符合我的预期,但是我真的不知道 np.polynomial.polynomial.polyfit 发生了什么,即使没有任何权重的拟合对我来说也没有任何意义。
但我认为 np.polyfit 可以满足您的需求吗?更改权重参数显然会赋予更高权重的点更多的权重。

【讨论】:

    【解决方案2】:

    您可以使用sklearn.linear_model.LinearRegression。它允许您不适合拦截(即,线路通过原点,或者与您选择的某个点来看)。它还处理加权数据。

    例如(大多是无耻地从@ hiho的答案中偷走)

    import numpy as np
    import matplotlib.pyplot as plt
    import sklearn.linear_model
    
    y = np.array([1.0, 3.3, 2.2, 4.25, 4.8, 5.1, 6.3, 7.5])
    x = np.arange(y.shape[0]).reshape((-1,1))
    w = np.linspace(1,5,y.shape[0])
    
    model = sklearn.linear_model.LinearRegression(fit_intercept=False)
    model.fit(x, y, sample_weight=w)
    
    line_x = np.linspace(min(x), max(x), 100).reshape((-1,1))
    pred = model.predict(line_x)
    
    plt.scatter(x, y)
    plt.plot(line_x, pred)
    
    plt.show()
    

    【讨论】:

    • 当你说“一些finagling”时,你刚才意味着在我试图强制契合的顶点增加更多的重量吗? span>
    • 没有。您只需提前从所有数据中减去点,然后后向后添加。 IE。对于给定的拟合线性模型Y = AX,您将其更改为(y-y_0)= a(x-x_0):::: y = ax +(y_0 - ax_0)。 span>
    • 其中(x_0,y_0)是您希望模型通过的点。 span>
    • 正如我所说的那样,您需要从您的所有数据中减去那些点,然后在拟合之前fit_intercept=False 987654325 @。y = y - y_0; x = x - x_0
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-20
    • 1970-01-01
    相关资源
    最近更新 更多