1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
| import argparse from math import sqrt,log,pi import numpy as np from IPython import embed import matplotlib.pyplot as plt from TINV import TINV
xNames = ["谐频次数$\mathcal{n}$(个)", "弦长倒数$\ \mathcal{L}^{-1}(\mathcal{m}$$^{-1}$)", "拉力对数$\ln\mathcal{T}}$", "线密度对数$\ \lnρ$", "振动次数 n", "振幅平方$A^2(rad^2$)"]
yNames = ["共振频率$\mathcal{f}\ \mathcal{(Hz)}$", "共振频率$\mathcal{f}\ \mathcal{(Hz)}$", "基频对数$\ln\mathcal{f}}$", "基频对数$\ln\mathcal{f}}$", "振幅($\mathrm{rad}$)的对数 $\mathrm{ln}\ θ$", "周期$T(s)$"]
xName = xNames[-1] yName = yNames[-1]
def getInput():
parser = argparse.ArgumentParser(description = 'Version: v1.0. Draw the regression line for the Physics Report,' 'coefficient 0 means the intercept is 0, ' '1 means the intercept is not 1, ' '01 means the intercept is 0 and save the figure, ' '11 means the intercept is not 0 and save the figure.' '\nFor example, python LinearRegression.py 0') parser.add_argument('crossOrigin', help = 'Whether the intercept of the line is 0 or 1. ' 'Besides, if want to save the figure, just add 1. ') args = parser.parse_args() return args.crossOrigin
class regression:
def __init__(self, x, y): self.x = x self.y = y self.length = len(x) self.k = 0.0 self.b = 0.0 self.R_2 = 0.0 self.Sk = 0.0 self.Uk = 0.0 self.Sb = 0.0 self.Ub = 0.0 def expression(self): lineExpression = "$\hat{y}=" + str(round(self.k, 6)) + "x" R2Expression = '$r^2=' + str(self.R_2) + "$" if self.b == 0.0: b = "" elif self.b > 0: b = "+" + str(round(self.b, 6)) else: b = str(round(self.b, 6)) lineExpression += (b + "$") return lineExpression, R2Expression
def drawLineAndPoints(self): xdraw = np.linspace(min(self.x), max(self.x), 50) ydraw = self.k * xdraw + self.b plt.plot(xdraw, ydraw, '-' , color = 'b', linewidth = 0.5) plt.plot(self.x, self.y, 'ro')
def addTwoExpressions(self): addLimx = (max(self.x) - min(self.x)) / 10 addLimy = (max(self.y) - min(self.y)) / 10 plt.xlim(min(self.x) - addLimx, max(self.x) + addLimx) plt.ylim(min(self.y) - addLimy, max(self.y) + addLimy)
deltaY = max(self.y ) - min(self.y) + 2 * addLimy deltaX = max(self.x) - min(self.x) + 2 * addLimx middleX = (max(self.x) + min(self.x)) / 2 middleY = (max(self.y) + min(self.y)) / 2
if self.k < 0: lineY1 = middleY + deltaY * 0.24 lineY2 = middleY + deltaY * 0.16 lineX1 = middleX - deltaX * 0.088 lineX2 = middleX - deltaX * 0.088 else: lineY1 = middleY - deltaY * 0.16 lineY2 = middleY - deltaY * 0.24 lineX1 = middleX - deltaX * 0.088 lineX2 = middleX - deltaX * 0.088
lineExpression, R2Expression = self.expression() plt.text(lineX1, lineY1, lineExpression, fontsize = 12) plt.text(lineX2, lineY2, R2Expression, fontsize = 12)
def addLabels(self): plt.rcParams['font.sans-serif'] = 'Kaiti' plt.xlabel(xName, fontsize = 12) plt.ylabel(yName, fontsize = 12)
def drawGraph(self): plt.rcParams['axes.unicode_minus'] = False plt.rcParams['font.sans-serif'] ='Times New Roman' self.drawLineAndPoints() self.addTwoExpressions() self.addLabels() self.addLabels()
def dataOutput(self): print("\quad \quad \quad 线性拟合斜率$k=", round(self.k, 10), end = "$") print("\quad \quad 调用Excel中TINV函数", "$t_{0.95,", str(self.length - 1) + "}=", round(float(TINV[self.length - 1]), 10), "$\par") print("\quad \quad \quad 斜率标准偏差$s_k=", round(self.Sk, 10), end = "$") print("\quad \quad 斜率不确定度为$U_k=", round(self.Uk, 10), "$\par")
if(self.Sb != 0.0): print("\quad \quad \quad 线性拟合截距$b=", round(self.b, 10), end = "$") print("\quad \quad 线性回归相关系数", "$R^2=", round(self.R_2, 10), "$\par") print("\quad \quad \quad 截距标准偏差$s_b=", round(self.Sb, 10), end = "$") print("\quad \quad 截距不确定度为$U_b=", round(self.Ub,10), "$\par")
def output(self): self.dataOutput() self.drawGraph() plt.show()
def save(self, saveName): self.dataOutput() self.drawGraph() plt.savefig(saveName) plt.show()
class notCrossOrigin(regression):
def __init__(self, x, y): regression.__init__(self, x, y) self.k, self.b = self.regressK_b() self.R_2 = self.getR_2() self.Sk = sqrt((1 / self.R_2 - 1) / (self.length - 2)) * self.k self.Uk = self.Sk * TINV[self.length - 1] self.Sb = sqrt((1 - self.R_2) / (self.length - 2)) * self.b self.Ub = self.Sb * TINV[self.length - 1]
def regressK_b(self): coef = np.polyfit(self.x, self.y, 1) return coef[0], coef[1] def getR_2(self): coeffs = np.polyfit(self.x, self.y, 1) p = np.poly1d(coeffs) yhat = p(self.x) ybar = np.sum(self.y) / len(self.y) ssreg = np.sum((yhat - ybar) ** 2) sstot = np.sum((self.y - ybar) ** 2) return ssreg / sstot
class crossOrigin(regression):
def __init__(self, x, y): regression.__init__(self, x, y) self.k = np.dot(x, y) / np.dot(x, x) self.R_2, self.Sk= self.getR_2AndS_k() self.Uk = self.Sk * TINV[self.length - 1] def getR_2AndS_k(self): yhat = [self.k * self.x[i] for i in range(self.length)] deltay = [self.y[i] - yhat[i] for i in range(self.length)] ybar = np.sum(self.y) / self.length newReg = np.dot(deltay, deltay) sstot = np.dot(self.y - ybar, yhat - ybar) sy = sqrt(newReg / (len(self.y) - 1)) xrms = sqrt(np.dot(self.x, self.x)) return (1 - newReg / sstot), sy / xrms
if __name__ == '__main__':
x = range(1,7,1) y = [31.2,62.9,95.5,128.4,161.0,194.3]
cross = getInput()
if cross == "0": crossOrigin(x, y).output() elif cross == "1": notCrossOrigin(x, y).output()
elif cross == "01": crossOrigin(x, y).save("crossOrigin.png") elif cross == "11": notCrossOrigin(x, y).save("notCrossOrigin.png")
|