【问题标题】:How to predict y=1/x values in Python? [closed]如何在 Python 中预测 y=1/x 值? [关闭]
【发布时间】:2020-07-17 08:32:42
【问题描述】:

我有一个名为df的数据框:

import pandas as pd

df = pd.DataFrame({'p': [15-x for x in range(14)]
                  , 'x': [x for x in range(14)]})

df['y'] = 1000 * (10 / df['p'])

x 仅用于绘图目的。 我试图根据p 值预测y 值。我正在使用SVR from sklearn:

from sklearn.svm import SVR

nlm = SVR(kernel='poly').fit(df[['p']], df['y'])
df['nml'] = nlm.predict(df[['p']])

我已经尝试了所有内核,但仍然无法正常工作。

     p   x            y          nml
0   15   0   666.666667   524.669572
1   14   1   714.285714   713.042459
2   13   2   769.230769   876.338765
3   12   3   833.333333  1016.349674

您知道我应该使用哪个 sklearn 模型或其他库来更好地拟合模型吗?

【问题讨论】:

  • 欢迎来到 stackoverflow,你能把更多的注意力放在这些问题上吗?
  • 感谢您的建议,我已经添加了一个具体问题。

标签: python scikit-learn non-linear-regression


【解决方案1】:

您错过了基本步骤“规范化数据”

修复

df = pd.DataFrame({'p': [15-x for x in range(14)]
                  , 'x': [x for x in range(14)]})

df['y'] = 1000 * (10 / df['p'])

# Normalize the data (x - mean(x))/std(x)
s_p = np.std(df['p'])
m_p = np.mean(df['p'])

s_y = np.std(df['y'])
m_y = np.mean(df['y'])
                        
df['p_'] = (df['p'] - s_p)/m_p
df['y_'] = (df['y'] - s_y)/m_y

# Fit and make prediction
nlm = SVR(kernel='rbf').fit(df[['p_']], df['y_'])
df['nml'] = nlm.predict(df[['p_']])

# Plot
plt.plot(df['p_'], df['y_'], 'r')
plt.plot(df['p_'], df['nml'], 'g')
plt.show()

# Rescale back and plot
plt.plot(df['p_']*s_p+m_p, df['y_']*s_y+m_y, 'r')
plt.plot(df['p_']*s_p+m_p, df['nml']*s_y+m_y, 'g')
plt.show()

【讨论】:

  • 非常感谢您的回答。在使用线性回归时我是否也应该对数据进行归一化?
  • 是的,对于任何 ML 模型,您都应该规范化数据,除非基于树的模型不需要它。不过,如果您也对基于树的模型进行归一化,也没有什么坏处。
【解决方案2】:

正如@mujjiga 所指出的,缩放是该过程的重要组成部分。

我想提请您注意另外两个关键点:

  • 模型选择决定了您解决一类问题的能力;
  • 新的scklearn API,可帮助您标准化解决方案开发。

让我们从您的数据集开始:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

x = np.arange(14)
df = pd.DataFrame({'x': x, 'p': 15-x})
df['y'] = 1e4/df['p']

然后我们导入一些sklearn感兴趣的API对象:

from sklearn.svm import SVR
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler, RobustScaler, FunctionTransformer

首先我们为目标值创建一个缩放函数:

ysc = StandardScaler()

注意我们可以使用不同的scalers,或者构建一个custom transformation

# Scaler robust against outliers:
ysc = RobustScaler()

# Logarithmic Transformation:
ysc = FunctionTransformer(func=np.log, inverse_func=np.exp, check_inverse=True)

我们使用我们选择的缩放器缩放目标:

ysc.fit(df[['y']])
df['yn'] = ysc.transform(df[['y']])

我们还构建了一个pipeline,带有特征标准化器和选定的模型(我们调整了参数以提高拟合度)。我们使用管道将其拟合到您的数据集:

reg = make_pipeline(StandardScaler(), SVR(kernel='rbf', C=1e3, epsilon=1e-3))
reg.fit(df[['p']], df['yn'])

此时我们可以预测值并将它们转换回原始比例:

df['ynhat'] = reg.predict(df[['p']])
df['yhat'] = ysc.inverse_transform(df[['ynhat']])

我们检查拟合分数:

reg.score(df[['p']], df['yn']) # 0.9999646718755011

我们还可以计算每个点的绝对误差和相对误差:

df['yaerr'] = df['yhat'] - df['y']
df['yrerr'] = df['yaerr']/df['y']

最终结果是:

     x   p            y        yn     ynhat         yhat      yaerr     yrerr
0    0  15   666.666667 -0.834823 -0.833633   668.077018   1.410352  0.002116
1    1  14   714.285714 -0.794636 -0.795247   713.562403  -0.723312 -0.001013
2    2  13   769.230769 -0.748267 -0.749627   767.619013  -1.611756 -0.002095
3    3  12   833.333333 -0.694169 -0.693498   834.128425   0.795091  0.000954
4    4  11   909.090909 -0.630235 -0.629048   910.497550   1.406641  0.001547
5    5  10  1000.000000 -0.553514 -0.555029   998.204445  -1.795555 -0.001796
6    6   9  1111.111111 -0.459744 -0.460002  1110.805275  -0.305836 -0.000275
7    7   8  1250.000000 -0.342532 -0.341099  1251.697707   1.697707  0.001358
8    8   7  1428.571429 -0.191830 -0.193295  1426.835676  -1.735753 -0.001215
9    9   6  1666.666667  0.009105  0.010458  1668.269984   1.603317  0.000962
10  10   5  2000.000000  0.290414  0.291060  2000.764717   0.764717  0.000382
11  11   4  2500.000000  0.712379  0.690511  2474.088446 -25.911554 -0.010365
12  12   3  3333.333333  1.415652  1.416874  3334.780642   1.447309  0.000434
13  13   2  5000.000000  2.822199  2.821420  4999.076799  -0.923201 -0.000185

图形化地导致:

fig, axe = plt.subplots()
axe.plot(df['p'], df['y'], label='$y(p)$')
axe.plot(df['p'], df['yhat'], 'o', label='$\hat{y}(p)$')
axe.set_title(r"SVR Fit for $y(x) = \frac{k}{x-a}$")
axe.set_xlabel('$p = x-a$')
axe.set_ylabel('$y, \hat{y}$')
axe.legend()
axe.grid()

线性化

在上面的示例中,我们不能使用poly 内核,而必须使用rbf 内核。这是因为如果我们的目标是使用多项式拟合有理函数,我们最好先转换数据,然后再使用p = x/(x-b) 替换进行拟合。在这种情况下,它只会归结为执行线性回归。下面的例子表明它是有效的:

缩放器和转换也可以组成一个管道。我们定义了一个可以线性化和扩展问题的管道:

# Rational Fraction Substitution with consecutive Standardization
ysc = make_pipeline(
          FunctionTransformer(func=lambda x: x/(x+1),
                              inverse_func=lambda x: x/(1-x),
                              check_inverse=True),
          StandardScaler()
)

然后我们可以使用经典 OLS 对数据进行回归:

reg = make_pipeline(StandardScaler(), LinearRegression())
reg.fit(df[['p']], df['yn'])

提供正确结果:

reg.score(df[['p']], df['yn']) # 0.9999998722172933

第二种解决方案利用了已知的线性化,因此无需对模型进行参数化。

【讨论】:

    猜你喜欢
    • 2012-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-03
    • 2021-07-24
    • 2019-05-08
    • 1970-01-01
    • 2020-11-13
    相关资源
    最近更新 更多