1.什么是线性回归?

线性回归是试图在一堆数据中训练得到自变量x和因变量y中一组线性关系,如。例如把人脚底板长度作为自变量,身高作为因变量,那么在这两种数据之间就可以做一个简单线性回归,可以得到脚底板长度和身高的关系式。

维基百科:线性回归
在统计学中,线性回归是利用称为线性回归方程的最小二乘函数对一个或多个自变量和因变量之间关系进行建模的一种回归分析。

周志华:机器学习
基于均方误差最小化来进行模型求解的方法称为“最小二乘法”,线性回归中最小二乘法就是试图找到一条直线,使所有样本到直线上的欧氏距离之和最小。

2. 线性回归的目标函数

要想求得这组线性关系,即求得相应的回归系数的值。那么先讲解一下线性回归的目标函数。

假设一堆数据中因变量为y,自变量为,对其进行线性回归,求得结果会如下所示:

其中w0是x0=1的系数,表示为全局偏移量,在平面直线中的具体意义为截距,也作为自变量的一个维度,其中w就是我们需要求得的。那么怎么去求得这个w呢?假设一共有m个样本,对于第i个数据,有

对于一个样本来说,为一个样本存在的误差。显然求得需要的w的方法,就是找出使误差最小的w,然而使用这个误差的简单累加将使得正差值和复差值抵消,所以我们采用均方误差,那么对于全部的m个样本来说,总误差为

均方误差是回归任务中最常用的性能度量,有非常好的几何意义,它对应了常用的欧几里得距离或简称“欧氏距离”

显然我们需要这个总误差的值为最小,所以取目标函数为

求这个目标函数最小值时的w,就是我们需要的w了。

3. 求目标函数得回归系数

3.1 梯度下降算法

对于求最小值的问题,我们能想到的第一个应该是梯度下降算法。在实验过程中发现,在对上述的目标函数进行梯度下降时,需要把步长设置的很小很小才行,为此我们先将目标函数改为如下形式

之后我们使用梯度下降算法来求这个目标函数的最小值。该目标函数的梯度为



所以使用梯度算法迭代的公式为

然而对于迭代过程中使用的训练集数量不同,会有不同细分的梯度下降算法,但是都是梯度下降算法,核心没有变。

  • 批量梯度下降算法

    使用所有的数据集,存在的问题是每次下降都要对整个数据集进行遍历运算,当数据集很大时,他的计算机会出现溢出,或者计算时间非常长。然而随机梯度下降就可以解决这些问题。

  • 随机梯度下降算法

    每次迭代使用的是一组数据。然而随机梯度下降算法由于每次只是用了一组数据,因为他受噪声/离群点/异常值的影响非常大,由此有了一种折中的方法,那就是小批量梯度下降。

  • 小批量梯度下降算法

    每次迭代时使用一批数据,这批数据可以自行选择也可以随机产生,大小也可自由定,越大就越接近批量梯度下降,越小就越接近随机梯度下降。

下面是上述三种算法的Python代码实现,可以参考一下:

'''
批量梯度下降算法
'''
def BGD(xArr, yArr, alpha, theta, times):m = len(xArr)for k in range(times):# 一次迭代for j in range(len(theta)):sum = 0.0# 进行求和for xi, yi in zip(xArr, yArr):sum += ((theta * xi).sum() - yi) * xi[j]# 更新theta[j] = theta[j] - (alpha * sum) / m  # 不除以m的话,得把步长设置的很小很小return theta'''
随机梯度下降算法
'''
def SGD(xArr, yArr, alpha, theta, times):m = len(xArr)for k in range(times * 10):t = random.randint(0, m - 1)# 一次迭代for j in range(len(theta)):sum = ((theta * xArr[t]).sum() - yArr[t]) * xArr[t][j]# 更新theta[j] = theta[j] - (alpha * sum) / mreturn theta'''
小批量梯度下降算法
'''
def MBGD(xArr, yArr, alpha, theta, times):m = len(xArr)n = 5  # 小批量数据的数量for k in range(times):# 随机产生小批量的数据train_set = []for t in range(n):train_set.append(random.randint(0, m - 1))# 一次迭代for j in range(len(theta)):sum = 0.0for i in train_set:sum += ((theta * xArr[i]).sum() - yArr[i]) * xArr[i][j]# 更新theta[j] = theta[j] - (alpha * sum) / mreturn theta

3.2 矩阵求导

针对这个最小值的求法我们还可以使用的矩阵的方法,上述的目标函数

可以用矩阵表示为,

其中X表示m个n维样本,每一行表示一个样本,即X为mxn阶矩阵。之后求向量w的导数

令上式为0,求得

这个w就是我们需要的回归系数。但是需要注意的是,在求该式的时候涉及到了矩阵逆的计算,因此这个方程只能在逆矩阵存在的时候适用

矩阵求导方式的核心代码实现

'''
矩阵的方法求参数值
'''
def mat(xArr, yArr):xMat = np.mat(xArr)  # x矩阵xMatT = xMat.T  # x的转置矩阵yMat = np.mat(yArr).T  # y矩阵xTx = xMatT * xMatif (np.linalg.det(xTx) != 0):theta = xTx.I * xMatT * yMatreturn thetareturn None

4. 简单线性回归的Python实现

下面我们模拟出分布在某个函数周围的数据,然后使用上述四种方法进行线性回归,全部代码如下

import numpy as np
import math
import random
import matplotlib.pyplot as plt'''
批量梯度下降算法
'''
def BGD(xArr, yArr, alpha, theta, times):m = len(xArr)for k in range(times):# 一次迭代for j in range(len(theta)):sum = 0.0# 进行求和for xi, yi in zip(xArr, yArr):sum += ((theta * xi).sum() - yi) * xi[j]# 更新theta[j] = theta[j] - (alpha * sum) / m  # 不除以m的话,得把步长设置的很小很小return theta'''
随机梯度下降算法
'''
def SGD(xArr, yArr, alpha, theta, times):m = len(xArr)for k in range(times * 10):t = random.randint(0, m - 1)# 一次迭代for j in range(len(theta)):sum = ((theta * xArr[t]).sum() - yArr[t]) * xArr[t][j]# 更新theta[j] = theta[j] - (alpha * sum) / mreturn theta'''
小批量梯度下降算法
'''
def MBGD(xArr, yArr, alpha, theta, times):m = len(xArr)n = 5  # 小批量数据的数量for k in range(times):# 随机产生小批量的数据trainSet = []for t in range(n):trainSet.append(random.randint(0, m - 1))# 一次迭代for j in range(len(theta)):sum = 0.0for i in trainSet:sum += ((theta * xArr[i]).sum() - yArr[i]) * xArr[i][j]# 更新theta[j] = theta[j] - (alpha * sum) / mreturn theta'''
矩阵的方法求参数值
'''
def mat(xArr, yArr):xMat = np.mat(xArr)  # x矩阵xMatT = xMat.T  # x的转置矩阵yMat = np.mat(yArr).T  # y矩阵xTx = xMatT * xMatif (np.linalg.det(xTx) != 0):theta = xTx.I * xMatT * yMatreturn thetareturn None'''
画图
'''
def draw_line(xArr, theta):y = []for i in xArr:y.append((theta * i).sum())plt.plot(xArr[:, 1], np.array(y), 'r', lw=2)def main():x = np.arange(0, 25, 0.5)xArr = []yArr = []# 产生用于训练的数据for xi in x:xArr.append([1, xi])yArr.append(0.5 * xi + 3 + random.uniform(0, 1) * math.sin(xi))xArr = np.array(xArr)yArr = np.array(yArr)alpha = 0.005  # 步长theta = np.array([0.0, 0.0])  # 回归系数times = 10000  # 迭代次数theta_re = BGD(xArr, yArr, alpha, theta, times)print("批量梯度下降算法下求的theta值 ", theta_re)print("批量梯度下降算法求得相关系数为
",  # 计算相关系数np.corrcoef(yArr, np.array(np.mat(xArr) * np.mat(theta_re).T)[:,0]))draw_line(xArr, theta_re)theta_re = SGD(xArr, yArr, alpha, theta, times)print("随机梯度下降算法下求的theta值", theta_re)print("随机梯度下降算法求得相关系数为
",  # 计算相关系数np.corrcoef(yArr, np.array(np.mat(xArr) * np.mat(theta_re).T)[:, 0]))draw_line(xArr, theta_re)theta_re = MBGD(xArr, yArr, alpha, theta, times)print("小批量梯度下降算法下求的theta值", theta_re)print("小批量梯度下降算法求得相关系数为
",np.corrcoef(yArr, np.array(np.mat(xArr) * np.mat(theta_re).T)[:, 0]))draw_line(xArr, theta_re)theta_re = mat(xArr, yArr)print("矩阵求逆法求得的theta值", np.array(theta_re)[:, 0])print("小批量梯度下降算法求得相关系数为
",np.corrcoef(yArr, np.array(np.mat(xArr) * theta_re)[:, 0]))draw_line(xArr, np.array(theta_re)[:, 0])plt.scatter(x, yArr, 60)plt.show()if __name__ == "__main__":main()

上述的梯度下降算法中,没有加上对函数值变换很小时的判断

控制台的输出结果如下所示

批量梯度下降算法下求的theta值  [3.15890008 0.48804966]
批量梯度下降算法求得相关系数为[[1.         0.99426138][0.99426138 1.        ]]
随机梯度下降算法下求的theta值 [3.15560184 0.49059031]
随机梯度下降算法求得相关系数为[[1.         0.99426138][0.99426138 1.        ]]
小批量梯度下降算法下求的theta值 [3.16014486 0.48668596]
小批量梯度下降算法求得相关系数为[[1.         0.99426138][0.99426138 1.        ]]
矩阵求逆法求得的theta值 [3.15890797 0.48804918]
小批量梯度下降算法求得相关系数为[[1.         0.99426138][0.99426138 1.        ]]
  • 可以通过相关系数来判断预测值和真实值之间的匹配程度,以此来比较效果好坏。

  • Numpy库提供了相关系数的计算方法corrcoef(),返回的矩阵包含所有两两组合的相关系数。

批量梯度下降算法的图形效果如下:

随机梯度下降算法的效果如下

小批量效果如下

矩阵求逆的效果如下

5. 局部加权线性回归

线性回归的一个问题是很可能出现欠拟合的现象,因为它求的是具有最小均方误差的无偏估计。然而有时候模型会出现欠拟合的情况,那么这种情况下将不能取得很好的预测效果。所以有些方法允许在估计中引入一些偏差,来降低预测的均方误差。其中一个方法就是局部加权线性回归(LWLR)

依旧使用前面使用过的那个目标函数,只是现在是进行加权之后的,如下所示

其中w(i)是权重,根据要预测的点与数据集中的点的距离来为数据集中的点赋权值。某点离要预测的点越远,其权重越小,否则越大。LWLR使用“核”来对附近的点赋予更高的权重,最常用的核实高斯核,高斯核对应的权重如下:

上述公式中包含一个需要用户指定的参数k,它决定了对附近的点赋予多大的权重,这也是使用LWLR时唯一需要考虑的参数。然后对上式进行求解,解得回归系数如下

W是权重矩阵,其中

根据上述公式,编写相应的Python代码,通过改变K值来调节回归效果,代码如下

import numpy as np
import random
import matplotlib.pyplot as plt
import math'''
针对一个点的局部线性回归
'''
def lwlr(testPoint, xArr, yArr, k=1.0):xMat = np.mat(xArr)yMat = np.mat(yArr).Tm = np.shape(xMat)[0]weight = np.mat(np.eye(m))  # 对角都是1的矩阵for i in range(m):diffMat = testPoint - xMat[i, :]weight[i, i] = np.exp((diffMat * diffMat.T) / (-2 * k ** 2))xTx = xMat.T * weight * xMatif np.linalg.det(xTx) != 0:theta = xTx.I * xMat.T * weight * yMatreturn thetareturn Nonedef lwlrAll(testArr, xArr, yArr, k=1.0):m = np.shape(testArr)[0]yHat = np.zeros(m)for i in range(m):thetaRe = lwlr(testArr[i], xArr, yArr, k)yHat[i] = testArr[i] * thetaRereturn yHatdef main():# 产生用于训练的数据x = np.arange(0, 25, 0.5)xArr = []yArr = []for xi in x:xArr.append([1, xi])yArr.append(0.5 * xi + 3 + random.uniform(0, 1) * math.sin(xi))xArr = np.array(xArr)yArr = np.array(yArr)# 对所有样本依次进行局部线性回归,并画图plt.figure(1)yHat = lwlrAll(xArr, xArr, yArr, 1.0)plt.scatter(xArr[:, 1], yArr, 60)plt.plot(xArr[:, 1], yHat, 'r', lw=2)plt.figure(2)yHat = lwlrAll(xArr, xArr, yArr, 0.3)plt.scatter(xArr[:, 1], yArr, 60)plt.plot(xArr[:, 1], yHat, 'r', lw=2)plt.figure(3)yHat = lwlrAll(xArr, xArr, yArr, 0.1)plt.scatter(xArr[:, 1], yArr, 60)plt.plot(xArr[:, 1], yHat, 'r', lw=2)plt.show()if __name__ == "__main__":main()

上述代码的效果如下,第一张图是K=1.0的,拟合的效果较好;第二张图是K=0.3的;第三张图是K=0.1,考虑太多噪声,有点过拟合了。

最后说一下局部线性回归存在的问题,局部线性回归增加一定的计算量,因为它对每个点做预测时都必须使用整个数据集。从上述图中K=0.1的情况中可以看出,大多数据点的权重都接近零,如果避免这些计算将可以减少程序运行时间,从而缓解计算机量增加带来的问题。

6. 示例:预测鲍鱼的年龄

这个示例是机器学习实战这本书上的一个示例,将局部线性回归知识用于真实数据。使用的是来自UCI数据集合的数据,数据集大概情况如下:

1    0.455   0.365   0.095   0.514   0.2245  0.101   0.15    15
1    0.35    0.265   0.09    0.2255  0.0995  0.0485  0.07    7
-1    0.53    0.42    0.135   0.677   0.2565  0.1415  0.21    9
1    0.44    0.365   0.125   0.516   0.2155  0.114   0.155   10
0    0.33    0.255   0.08    0.205   0.0895  0.0395  0.055   7
0    0.425   0.3     0.095   0.3515  0.141   0.0775  0.12    8
-1    0.53    0.415   0.15    0.7775  0.237   0.1415  0.33    20
-1    0.545   0.425   0.125   0.768   0.294   0.1495  0.26    16
1    0.475   0.37    0.125   0.5095  0.2165  0.1125  0.165   9
-1    0.55    0.44    0.15    0.8945  0.3145  0.151   0.32    19
-1    0.525   0.38    0.14    0.6065  0.194   0.1475  0.21    14
1    0.43    0.35    0.11    0.406   0.1675  0.081   0.135   10
1    0.49    0.38    0.135   0.5415  0.2175  0.095   0.19    11
-1    0.535   0.405   0.145   0.6845  0.2725  0.171   0.205   10
-1    0.47    0.355   0.1     0.4755  0.1675  0.0805  0.185   10
1    0.5     0.4     0.13    0.6645  0.258   0.133   0.24    12
0    0.355   0.28    0.085   0.2905  0.095   0.0395  0.115   7
-1    0.44    0.34    0.1     0.451   0.188   0.087   0.13    10
1    0.365   0.295   0.08    0.2555  0.097   0.043   0.1     7

从数据集可以看到,数据集是多维的,最后一列代表鲍鱼的真实年龄,前面几列的数据是一些鲍鱼的特征,例如鲍鱼壳的层数等,基于的推论是鲍鱼的真实年龄可由鲍鱼壳的层数等鲍鱼的特征推算而出。下面我们不对数据进行处理,直接测试局部加权回归的效果:

import numpy as npdef loadDataSet(filePath):f = open(filePath)numFeat = len(f.readline().split("   ")) - 1  # 获取一行特征的数量dataList = []labelList = []f.seek(0)  # 文件指针回到初始位置for line in f.readlines():lineArr = []curLine = line.strip().split("    ")  # strip去掉for i in range(numFeat):lineArr.append(float(curLine[i]))dataList.append(lineArr)labelList.append(float(curLine[-1]))return dataList, labelListdef lwlr(testPoint, xArr, yArr, k=1.0):xMat = np.mat(xArr)yMat = np.mat(yArr).Tm = np.shape(xMat)[0]weight = np.mat(np.eye(m))for i in range(m):diffMat = testPoint - xMat[i, :]weight[i, i] = np.exp((diffMat * diffMat.T) / (-2.0 * k ** 2))xTx = xMat.T * (weight * xMat)if np.linalg.det(xTx) != 0.0:theta = xTx.I * (xMat.T * (weight * yMat))return testPoint * thetareturn Nonedef lwlrAll(testArr, xArr, yArr, k=1.0):m = np.shape(testArr)[0]yHat = np.zeros(m)for i in range(m):yHat[i] = lwlr(testArr[i], xArr, yArr, k)return yHatdef standRegres(xArr, yArr):xMat = np.mat(xArr)yMat = np.mat(yArr).TxTx = xMat.T * xMatif np.linalg.det(xTx) != 0.0:theta = xTx.I * (xMat.T * yMat)return thetareturn Nonedef rssError(yArr, yHatArr):return ((yArr - yHatArr) ** 2).sum()if __name__ == '__main__':abaloneX, abaloneY = loadDataSet("abalone.txt")yHat01 = lwlrAll(abaloneX[0:99], abaloneX[0:99], abaloneY[0:99], 0.1)yHat1 = lwlrAll(abaloneX[0:99], abaloneX[0:99], abaloneY[0:99], 1)yHat10 = lwlrAll(abaloneX[0:99], abaloneX[0:99], abaloneY[0:99], 10)print("k=0.1时,训练集上的误差为:", rssError(abaloneY[0:99], yHat01))print("k=1时,训练集上的误差为:", rssError(abaloneY[0:99], yHat1))print("k=10时,训练集上的误差为:", rssError(abaloneY[0:99], yHat10))yHat01 = lwlrAll(abaloneX[100:199], abaloneX[0:99], abaloneY[0:99], 0.1)yHat1 = lwlrAll(abaloneX[100:199], abaloneX[0:99], abaloneY[0:99], 1)yHat10 = lwlrAll(abaloneX[100:199], abaloneX[0:99], abaloneY[0:99], 10)print("k=0.1时,测试集上的误差为:", rssError(abaloneY[100:199], yHat01))print("k=1时,测试集上的误差为:", rssError(abaloneY[100:199], yHat1))print("k=10时,测试集上的误差为:", rssError(abaloneY[100:199], yHat10))theta = standRegres(abaloneX[0:99],abaloneY[0:99])yHat = np.mat(abaloneX[100:199])*thetaprint("简单线性回归时的误差为:", rssError(abaloneY[100:199], yHat.T.A))

输出结果如下:

k=0.1时,训练集上的误差为:56.78868743050092
k=1时,训练集上的误差为:429.89056187038
k=10时,训练集上的误差为:549.1181708827924
k=0.1时,测试集上的误差为:57913.51550155911
k=1时,测试集上的误差为:573.5261441895982
k=10时,测试集上的误差为:517.5711905381903
简单线性回归时的误差为:518.6363153245542

从输出结果可以看出,当核k=10的时候,训练集上的误差是最大的,但是测试集上的误差是最小的,同时它效果和简单线性回归的效果类似。所以在所有数据集上都使用最小的核的话,将会造成过拟合,在新数据上不一定能达到最好的预测效果。

注意:
1.在局部加权线性回归中,过小的核可能导致过拟合现象,即在训练集上表现良好,但在测试集上表现就不行了;
2.训练的模型要在测试集上比较他们的效果,而不是训练集;

7.如何用线性回归模型拟合非线性关系

线性模型也可以拟合自变量和因变量之间的非线性关系,只是需要对样本数据进行修改。比如有一些样本,只有一个特征,我们把特征和结果作图以后发现,可能是这个样子的:

从样本特征和结果关系走势来看,这不是一个直线,看起来挺像二阶曲线的,那么我们可以把一个特征“变成”两个,如

那么在添加“新的特征”之后的样本集上去训练这个函数

那么得到回归系数之后代回函数

那么就相当于拟合了一个二阶多项式了。这种操作以此类推都可以,比如三阶、四阶、对数都行。

1. 预测鲍鱼的年龄的数据集地址:

https://github.com/DawnGuoDev/MachineLearningInActionSourceCode/blob/master/Ch08/abalone.txt

参考内容

  1. 机器学习,周志华

  2. 机器学习实战,[美]Peter Harrington

  3. CSDN_线性回归及其Python实现(最大似然法)

  4. CSDN_Python实现批量梯度下降 随机梯度下降 小批量梯度下降 代码

  5. CSDN_【机器学习】局部加权线性回归

不甘于「本该如此」,值得关注

快来加入一起学习啊!

线性回归模型(简单线性回归、局部线性回归、非线性关系)从理论到Python实现.整理...相关推荐

  1. 一般线性模型和线性回归模型_您的线性回归模型指南

    一般线性模型和线性回归模型 Interpretability is one of the biggest challenges in machine learning. A model has mor ...

  2. 时间序列预测——深度好文,ARIMA是最难用的(数据预处理过程不适合工业应用),线性回归模型简单适用,预测趋势很不错,xgboost的话,不太适合趋势预测,如果数据平稳也可以使用。...

    补充:https://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-15-276 如果用arima的话,还不如使用随机森 ...

  3. 二、简单线性回归模型(计量经济学学习笔记)

    研究经济变量之间相互数量关系最基本的方法之一是回归分析. ①回归分析与回归函数 1.1相关分析与回归分析 1.1.1函数关系与相关关系 经济变量之间的相互依存关系有两种:1.确定性的函数关系 2.不确 ...

  4. 回归方程的拟合优度检验_计量经济学第四讲(多元线性回归模型:基本假定,参数估计,统计检验)...

    第三章.经典单方程计量经济学模型:多元线性回归模型 3.1多元线性回归模型及其基本假定 3.1.1多元回归模型及其表示 解释变量至少有两个的线性回归模型,一般形式为 如果不作说明, 是不包括常数项的解 ...

  5. python多元线性回归模型案例_Python 实战多元线性回归模型,附带原理+代码

    原标题:Python 实战多元线性回归模型,附带原理+代码 作者 | 萝卜 来源 | 早起Python( ID:zaoqi-python ) 「多元线性回归模型」非常常见,是大多数人入门机器学习的第一 ...

  6. 《计量经济学》学习笔记之多元线性回归模型

    导航 上一章:一元线性回归模型 下一章:放宽基本假定的模型 文章目录 导航 3.1多元线性回归模型 一.多元线性回归模型 二.多元线性回归的基本假设 3.2多元线性回归模型的参数估计 四.参数统计量的 ...

  7. python 线性回归模型_如何在Python中建立和训练线性和逻辑回归ML模型

    python 线性回归模型 Linear regression and logistic regression are two of the most popular machine learning ...

  8. 深度学习:线性回归模型

    ​     在机器学习领域中的大多数任务通常都与预测有关. 当我们想预测一个数值时,就会涉及到回归问题. 常见的例子包括:预测价格(房屋.股票等).预测住院时间(针对住院病人等). 预测需求(零售销量 ...

  9. 小福利,带你快速了解数据分析之一元线性回归模型和多元线性回归模型

    大家好,我是天空之城,今天给大家带来小福利,带你快速了解一元线性回归方程模拟和多元线性回归方程模拟 主要用来进行数据的相关性分析 之前在研究生阶段用过一个叫origin的数据处理软件,只要是科研数据都 ...

最新文章

  1. How to protect video content (Flash Media Server)
  2. java阅读doc文件格式_java – 正确区分.xls和.doc文件的方法?
  3. android 代码 日历 重复事件设置,日历重复/重复事件 - 最佳存储方法
  4. NAB 2019见闻:CAE视频编码与QoE
  5. 写java代码时的注意事项_从方法返回Java 8的可选项时的注意事项
  6. 30个类仿真手写spring框架V2.0版本
  7. qt5以后正常显示中文(windows下 vs编译器)
  8. 第三章 3.3 DI自动装配 --《跟我学Spring》笔记 张开涛
  9. Setting up a EDK II build environment on Windows and Linux:搭建Windows和Linux开发环境[2.2]
  10. Bat脚本 -(一)- echo/ echo off/ echo on/ @ / start / pause / rem
  11. 永中office属于职称计算机吗,职称计算机考核永中Office辅导之文字处理.docx
  12. 义帝熊心--秦末汉初
  13. 怎么搜索百度网盘的资源
  14. TransModeler 交通仿真软件
  15. 第 270 场力扣周赛
  16. MacOS下qt签名与公证
  17. 直流无刷电机和霍尔传感器
  18. 123网盘无法下载问题解决
  19. org.eclipse.wst.validation has been removed
  20. 计算机网络专业学校实践经验,学校实习计算机网络心得体会3篇

热门文章

  1. 2020美赛D题翻译
  2. 微型计算机课程总结,《微机原理与接口技术》课程总结
  3. 实习面经--小米 java后台开发 v1
  4. 脚本之家 前端jQuery js 学习 网站
  5. 谁能推荐几款免费的配音软件
  6. SIP系统怎么禁用?Mac上 sip系统完整性关闭方法,怎么看sip是否关闭
  7. 对话 CTO | 健身新物种,超级猩猩带来了哪些改变?
  8. 文明4 玩家原创全面攻略
  9. div里的元素相对于该div水平居中和垂直居中
  10. 自热食品赛道不缺新品牌,莫小仙靠“性价比”难建护城河?