独立线性度 最佳直线

找到的散点线性拟合方法都是基于最小二乘法的(numpy.polyfit()scipy.optimize())

以下是根据 GB/T 18459-2001中附录 A2 提供的独立线性度拟合方法,求得的最佳拟合直线

# !/usr/bin/env python3
# -*- coding: utf-8 -*-

def find_line(x0, y0):
    '''
    根据散点求得端基直线k,b,并得到每点对端基直线的偏差dy
    :param x0: x坐标数组
    :param y0: y坐标数组
    :return: 每点的偏差dy
    '''
    # 求得端基直线的k,b
    k = (y0[-1] - y0[0]) / (x0[-1] - x0[0])
    d = y0[0] - (k * x0[0])

    # 根据端基直线的k,b,求得每点对端基直线的偏差dy
    dy = [(y0[i] - ((k * x0[i]) + d)) for i in range(len(x0))]

    return dy


def find_poly(x_lst, y_lst):
    '''
    找到凸多边形,可以包含全部偏差点dy
    :param x_lst:x数组
    :param y_lst:偏差点dy数组
    :return:最佳凸多边形各个点
    '''
    g_x = []
    g_y = []

    # 从起始点开始,向右(x增大方向),找到最大斜率点,再从最大斜率点开始,向右继续寻找
    x_tmp = x_lst
    y_tmp = y_lst
    while len(x_tmp) > 1:
        k_lst = [((y_tmp[i] - y_tmp[0]) / (x_tmp[i] - x_tmp[0])) for i in range(0 + 1, len(x_tmp))]
        max_k_index = k_lst.index(max(k_lst)) + 1
        g_x.append(x_tmp[max_k_index])
        g_y.append(y_tmp[max_k_index])
        x_tmp = x_tmp[max_k_index:]
        y_tmp = y_tmp[max_k_index:]

    # 从最末点开始,向左(x减小方向),也找到最大斜率点(有人说找最小斜率点,但是结果算出来不对),再从最大斜率点开始,向左继续寻找
    x_tmp = x_lst[::-1]
    y_tmp = y_lst[::-1]
    while len(x_tmp) > 1:
        k_lst = [((y_tmp[i] - y_tmp[0]) / (x_tmp[i] - x_tmp[0])) for i in range(0 + 1, len(x_tmp))]
        # max_k_index = k_lst.index(min(k_lst)) + 1  # 算出来不对
        max_k_index = k_lst.index(max(k_lst)) + 1
        g_x.append(x_tmp[max_k_index])
        g_y.append(y_tmp[max_k_index])
        x_tmp = x_tmp[max_k_index:]
        y_tmp = y_tmp[max_k_index:]

    return g_x, g_y


def find_cross(p1, p2, p3):
    '''
    根据一个点p1和一条直线(p2和p3的连线),
    求得该点对直线的铅垂线(平行于纵轴坐标的直线)和直线的交点
    :param p1: 点
    :param p2: 线上一点
    :param p3: 线上另一点
    :return: 铅垂线与线(p2-p3)的交点
    '''
    k = (p2[1] - p3[1]) / (p2[0] - p3[0])
    b = p2[1] - k * p2[0]
    p4 = (p1[0], (k * p1[0]) + b)
    return p4


def find_perfect_line(a, b, x0, y0):
    '''
        根据凸多边形的每个点,找到凸多边形内最长的一根铅垂线,
    与最长垂线相交的直线l1的斜率就是最佳直线的斜率
    过最长铅垂线的中点作直线l2平行于直线l1,直线l2为最佳直线
    :param a:凸多边形的x轴数组
    :param b:凸多边形的y轴数组
    :param x0: 实际x轴数组
    :param y0: 实际y轴数组
    :return:最佳直线的斜率k, 截距b
    '''
    p = []
    l = []
    k_lst = []
    b_lst = []
    for i in range(len(a)):
        p1 = (a[i], b[i])
        rp1 = (x0[x0.index(p1[0])], y0[x0.index(p1[0])])

        for j in range(len(a)):
            p2 = (a[j], b[j])
            rp2 = (x0[x0.index(p2[0])], y0[x0.index(p2[0])])
            if j == len(a) - 1:
                p3 = (a[0], b[0])
            else:
                p3 = (a[j + 1], b[j + 1])
            rp3 = (x0[x0.index(p3[0])], y0[x0.index(p3[0])])
            s = find_cross(p1, p2, p3)
            if s[0] >= min(a) and s[0] <= max(a) and s[1] >= min(b) and s[1] <= max(b):
                p.append(s)
                l.append(abs(p1[1] - s[1]))
                # 点和直线两端点中点连线的斜率
                k = (((rp1[1] + rp2[1]) / 2) - ((rp1[1] + rp3[1]) / 2)) / (
                        ((rp1[0] + rp2[0]) / 2) - ((rp1[0] + rp3[0]) / 2))
                k_lst.append(k)
                b_lst.append(((rp1[1] + rp2[1]) / 2) - (k * ((rp1[0] + rp2[0]) / 2)))
    per_index = l.index(max(l))
    k = k_lst[per_index]
    b = b_lst[per_index]
    return k, b


if __name__ == '__main__':
    x0 = [1.00, 2.00, 3.00, 4.00, 5.00, 6.00]
    y0 = [2.02, 4.00, 5.98, 7.90, 10.10, 12.05]

    dy = find_line(x0, y0)
    a, b = find_poly(x0, dy)
    print(find_perfect_line(a, b, x0, y0))

猜你喜欢

转载自www.cnblogs.com/sunqim16/p/9121011.html