机器学习回归的局限性?

Limitations of Regression in Machine Learning?

我最近一直在学习 ML 的一些核心概念,并使用 Sklearn 库编写代码。经过一些基本练习后,我尝试了来自 kaggle 的 AirBnb NYC 数据集(大约有 40000 个样本)- https://www.kaggle.com/dgomonov/new-york-city-airbnb-open-data#New_York_City_.png

我试图建立一个模型,可以根据数据集的各种特征预测 room/apt 的价格。我意识到这是一个回归问题并使用这个 sklearn cheat-sheet,我开始尝试各种回归模型。

我使用 sklearn.linear_model.Ridge 作为我的基线,在做了一些基本的数据清理之后,我在我的测试集上得到了一个糟糕的 R^2 分数 0.12。然后我想,也许线性模型太简单了,所以我尝试了适用于回归的 'kernel trick' 方法 (sklearn.kernel_ridge.Kernel_Ridge),但它们需要太多时间来拟合 (>1hr)!为了解决这个问题,我使用 sklearn.kernel_approximation.Nystroem 函数来近似内核映射,在训练之前将转换应用于特征,然后使用简单的线性回归模型。然而,如果我增加 n_components 参数,即使这样也需要花费大量时间来转换和适应,我必须这样做才能使准确性有任何有意义的提高。

所以我现在在想,当你想对一个巨大的数据集进行回归时会发生什么?内核技巧在计算上非常昂贵,而线性回归模型过于简单,因为真实数据很少是线性的。那么神经网络是唯一的答案还是我缺少一些聪明的解决方案?

P.S。我刚刚开始使用 Overflow,所以请让我知道我可以做些什么来改善我的问题!

这是一个很好的问题,但由于它经常发生,复杂的问题没有简单的答案。回归并不像经常出现的那样简单。它涉及许多假设,并且不限于线性最小二乘模型。需要几门大学课程才能完全理解它。下面我将写一个关于回归的快速(但远非完整)备忘录:

  • 没有什么能代替正确的分析。这可能涉及专家访谈以了解您的数据集的局限性。
  • 您的模型(任何模型,不限于回归)仅与您的特征一样好。如果房价取决于当地税率或学校评级,如果没有这些功能,即使是完美的模型也不会表现良好。
  • 某些特征无法包含在模型中,所以不要指望在现实世界中获得满分。例如,几乎不可能考虑到杂货店、餐馆、俱乐部等的访问权限。其中许多功能也是移动目标,因为它们往往会随着时间而改变。如果人类专家的表现更差,即使是 0.12 R2 也可能很棒。
  • 模型有它们的假设。线性回归期望因变量(价格)与独立变量(例如 属性 尺寸)线性相关。通过探索残差,您可以观察到一些非线性并用非线性特征覆盖它们。然而,有些模式很难发现,但仍可通过其他模型解决,例如非参数回归和神经网络。

那么,为什么人们仍然使用(线性)回归?

  • 这是最简单、最快的模型。对实时系统和统计分析有很多影响,所以它很重要
  • 通常它被用作基线模型。在尝试花哨的神经网络架构之前,了解与朴素方法相比我们改进了多少会很有帮助。
  • 有时回归被用来检验某些假设,例如效应的线性度和变量之间的关系

总而言之,回归在大多数情况下绝对不是最终工具,但这通常是最先尝试的最便宜的解决方案

UPD, 来说明关于非线性的观点。

构建回归后,您计算残差,即回归误差 predicted_value - true_value。然后,为每个特征绘制一个散点图,其中横轴是特征值,纵轴是误差值。理想情况下,残差具有正态分布并且不依赖于特征值。基本上,错误往往是小而不是大,并且在整个情节中都是相似的。

它应该是这样的:

这仍然是正常的 - 它只反映了样本密度的差异,但误差具有相同的分布:

这是一个非线性的例子(周期性模式,添加 sin(x+b) 作为特征):

非线性的另一个例子(添加平方特征应该有所帮助):

以上两个例子可以描述为不同的残差均值取决于特征值。其他问题包括但不限于:

  • 不同的方差取决于特征值
  • 残差的非正态分布(误差为 +1 或 -1、簇等)

以上部分图片取自此处:

http://www.contrib.andrew.cmu.edu/~achoulde/94842/homework/regression_diagnostics.html

对于初学者来说,这是一本关于回归诊断的好书。

我会试试这个。看我嵌入代码的notes/comments。请记住,这只是我测试过的一些想法。您可以尝试各种其他方法(获取更多数据、测试不同模型等)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
#%matplotlib inline
import sklearn
from sklearn.linear_model import RidgeCV, LassoCV, Ridge, Lasso
from sklearn.datasets import load_boston
#boston = load_boston()

# Predicting Continuous Target Variables with Regression Analysis
df = pd.read_csv('C:\your_path_here\AB_NYC_2019.csv')
df

# get only 2 fields and convert non-numerics to numerics
df_new = df[['neighbourhood']]
df_new = pd.get_dummies(df_new)
# print(df_new.columns.values)

# df_new.shape
# df.shape

# let's use a feature selection technique so we can see which features (independent variables) have the highest statistical influence on the target (dependent variable).
from sklearn.ensemble import RandomForestClassifier
features = df_new.columns.values
clf = RandomForestClassifier()
clf.fit(df_new[features], df['price'])

# from the calculated importances, order them from most to least important
# and make a barplot so we can visualize what is/isn't important
importances = clf.feature_importances_
sorted_idx = np.argsort(importances)

# what kind of object is this
# type(sorted_idx)
padding = np.arange(len(features)) + 0.5
plt.barh(padding, importances[sorted_idx], align='center')
plt.yticks(padding, features[sorted_idx])
plt.xlabel("Relative Importance")
plt.title("Variable Importance")
plt.show()

X = df_new[features]
y = df['price']


reg = LassoCV()
reg.fit(X, y)
print("Best alpha using built-in LassoCV: %f" % reg.alpha_)
print("Best score using built-in LassoCV: %f" %reg.score(X,y))
coef = pd.Series(reg.coef_, index = X.columns)

print("Lasso picked " + str(sum(coef != 0)) + " variables and eliminated the other " +  str(sum(coef == 0)) + " variables")

结果:

Best alpha using built-in LassoCV: 0.040582
Best score using built-in LassoCV: 0.103947
Lasso picked 78 variables and eliminated the other 146 variables

下一步...

imp_coef = coef.sort_values()
import matplotlib
matplotlib.rcParams['figure.figsize'] = (8.0, 10.0)
imp_coef.plot(kind = "barh")
plt.title("Feature importance using Lasso Model")


# get the top 25; plotting fewer features so we can actually read the chart
type(imp_coef)
imp_coef = imp_coef.tail(25)
matplotlib.rcParams['figure.figsize'] = (8.0, 10.0)
imp_coef.plot(kind = "barh")
plt.title("Feature importance using Lasso Model")

X = df_new
y = df['price']


from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 10)

# Training the Model
# We will now train our model using the LinearRegression function from the sklearn library.

from sklearn.linear_model import LinearRegression
lm = LinearRegression()
lm.fit(X_train, y_train)

# Prediction
# We will now make prediction on the test data using the LinearRegression function and plot a scatterplot between the test data and the predicted value.
prediction = lm.predict(X_test)
plt.scatter(y_test, prediction)


from sklearn import metrics
from sklearn.metrics import r2_score
print('MAE', metrics.mean_absolute_error(y_test, prediction))
print('MSE', metrics.mean_squared_error(y_test, prediction))
print('RMSE', np.sqrt(metrics.mean_squared_error(y_test, prediction)))
print('R squared error', r2_score(y_test, prediction))

结果:

MAE 1004799260.0756996
MSE 9.87308783180938e+21
RMSE 99363412943.64531
R squared error -2.603867717517002e+17

这太可怕了!好吧,我们知道这行不通。让我们试试别的。我们仍然需要使用数字数据进行 rowk,所以让我们尝试使用 lng 和 lat 坐标。

X = df[['longitude','latitude']]
y = df['price']

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 10)

# Training the Model
# We will now train our model using the LinearRegression function from the sklearn library.

from sklearn.linear_model import LinearRegression
lm = LinearRegression()
lm.fit(X_train, y_train)

# Prediction
# We will now make prediction on the test data using the LinearRegression function and plot a scatterplot between the test data and the predicted value.
prediction = lm.predict(X_test)
plt.scatter(y_test, prediction)

df1 = pd.DataFrame({'Actual': y_test, 'Predicted':prediction})
df2 = df1.head(10)
df2
df2.plot(kind = 'bar')

from sklearn import metrics
from sklearn.metrics import r2_score
print('MAE', metrics.mean_absolute_error(y_test, prediction))
print('MSE', metrics.mean_squared_error(y_test, prediction))
print('RMSE', np.sqrt(metrics.mean_squared_error(y_test, prediction)))
print('R squared error', r2_score(y_test, prediction))
# better but not awesome

结果:

MAE 85.35438165291622
MSE 36552.6244271195
RMSE 191.18740655994972
R squared error 0.03598346983552425

我们来看看OLS:

import statsmodels.api as sm
model = sm.OLS(y, X).fit()


# run the model and interpret the predictions
predictions = model.predict(X)
# Print out the statistics
model.summary()

我假设如下:

一个热编码正在做它应该做的事情,但它并不能帮助你得到你想要的结果。使用 lng/lat 的效果稍好一些,但这也无法帮助您获得想要的结果。如您所知,您必须使用数字数据来解决回归问题,但是 none 的特征可以帮助您预测价格,至少不是很好。当然,我可能在某个地方犯了错误。如果我做错了,请告诉我!

查看下面的链接,了解使用各种特征预测房价的好例子。注意:所有变量都是数字,结果相当不错(大约 70%,给予或接受,但仍然比我们在 Air BNB 数据集上看到的要好得多)。

https://bigdata-madesimple.com/how-to-run-linear-regression-in-python-scikit-learn/

https://towardsdatascience.com/linear-regression-on-boston-housing-dataset-f409b7e4a155