使用机器学习预测和防止高价值客户流失
** 简短的代码片段和可视化将在这篇文章中分享,但该项目的所有代码都可以在这个Github Repo中找到。
公司非常重视获取客户,这是理所当然的:公司需要客户。然而,客户获取成本通常相当高,公司有时过于关注获取,而对保留关注不够。一家公司可能有很高的收购率,但是,如果你也有很高的流失率,你基本上是在浪费这些收购成本。这个项目的目标是演示如何使用机器学习来识别可能在未来几个月流失的客户。如果可以及早识别出高流失风险的客户,就可以采取干预措施来留住该客户。
什么是流失?
如果一个客户取消了他们在你公司的服务,这被认为是一个客户流失案例。
信用:Unsplash.com
数据
对于这个项目,我选择使用来自移动电话运营商的数据集。该数据集包含 3,100 名随机选择的客户的信息。清理后,数据集如下所示…
移动运营商数据集快照(图片由作者提供)
每行代表一个客户,每个客户有 12 个相关联的属性以及第 13 个属性(“客户流失”),该属性描述该客户是否取消了他们的服务。除了流失之外,每个属性都是 9 个月数据(第 1-9 个月)的聚合。客户流失记录了该客户在第 9 个月到第 12 个月期间是否取消了服务。
如果已经有一个客户流失列,为什么我们还需要预测客户流失?
我们只有一个客户流失列,因为这是过去的数据。我们将使用这些过去的数据来建立一个模型,然后可以在当前数据上使用该模型来预测客户流失。
可视化数据
属性与客户流失的关系(0 =非客户流失,1 =客户流失)。(图片由作者提供)
正如我们所看到的,流失组和非流失组之间的许多变量存在显著差异,因此该数据集可能包含大量有用的信息。
培训和测试数据
与所有机器学习模型一样,我们将数据集分成两部分:训练和测试。我们将使用训练数据建立模型,然后在测试数据上评估该模型的性能(该模型从未见过)。我们将在训练过程中为模型提供流失值,然后在测试过程中,我们将保留流失值并让模型预测它们。这就是我们如何模拟该模型在部署和使用当前数据预测客户流失时的表现。
不平衡的班级
我们试图解决的问题是一个分类问题:我们试图将每个客户分为非流失类(表示为 0)或流失类(表示为 1)。
每当我们遇到分类问题时,注意我们观察数据集中每个类的频率是很重要的。在我们的案例中,非客户流失案例明显多于客户流失案例,我们希望任何企业都是如此。
对于每个客户流失案例,我们看到大约 5.5 个非客户流失案例(图片由作者提供)
记录类别不平衡对于评估建模准确性结果很重要。
例如,如果我告诉你,我建立的模型对 84%的案例进行了正确分类,这可能看起来相当不错。但在这种情况下,非流失案例代表了 84%的数据,因此,理论上,该模型可以将所有内容分类为非流失,并获得 84%的准确率。
因此**,**当我们用不平衡数据集评估模型性能时,我们希望主要根据它在少数类上的表现来判断模型。
建模结果
和往常一样,在进入建模过程之前,我将直接跳到最终模型的结果,这样那些对整个过程不太感兴趣的人可以了解最终的结果及其含义。
通过对训练数据使用合成少数过采样来对流失类进行过采样,我能够构建一个随机森林分类器,其总体准确率为 96%。这意味着在看不见的数据(测试数据)上,该模型以 96%的准确率准确预测了客户在未来 3 个月内是否会流失。
然而,正如我们刚刚讨论的,整体准确性并不能说明全部情况!
因为我们有不平衡的类别(84%:16%),我们希望更多地关注模型在客户流失案例(少数类别)中的表现。
下面的分类报告为我们提供了这些信息…
流失类性能下划线(图片由作者提供)
让我们稍微分析一下这些结果…
召回
0.91 的流失类别召回意味着模型能够捕获 91%的实际流失案例。这是我们真正关心的衡量标准,因为我们希望尽可能少地遗漏真正的客户流失案例。
Precision
流失类的 Precision 衡量模型捕获实际流失案例的频率,同时还考虑了将非流失案例错误分类为流失案例的频率。在这种情况下,0.84 的流失精度不是问题,因为当客户没有流失风险时,将客户识别为流失风险不会产生重大后果。
F1 得分
F1 得分是精确度和召回率的调和平均值。这有助于我们对模型在客户流失类上的表现有一个平衡的了解。在这种情况下,0.87 的客户流失等级 F1 分数相当不错。通常在精确度和召回率之间有一个折衷。我本来可以调整模型的概率阈值,使流失类别召回率达到 97%,但流失类别的精确度会下降,因为模型会将一堆实际的非流失案例归类为流失案例。F1 分数有助于我们保持诚实。
我们可以用流失类的精确召回曲线来形象化这种关系…
流失类的精确召回曲线(图片由作者提供)
曲线越向右弓出,模型越好,所以这个模型做的很好!
解释最终模型
对于那些对使用 SMOTE 的随机森林分类器有兴趣的人…
合成少数过采样
SMOTE 是一种处理阶级不平衡问题的方法。因为我们的数据中每 5.5 个客户流失案例中只有 1 个案例,所以模型没有发现足够多的客户流失案例,因此在对这些案例进行分类时表现不佳。
有了 SMOTE,我们可以综合少数类的例子,让类变得更加平衡。现在,需要注意的是,我们仅对定型数据执行此操作,以便模型可以看到少数民族类的更多示例。我们不以任何方式操纵测试数据,这是我们用来评估模型性能的数据。
SMOTE 如何凭空创造新的数据点?
SMOTE 在 12 维空间中绘制了少数民族类的每个示例,因为每个客户有 12 个属性。它从 12D 空间中随机选取一个点,画一条线到该点最近的邻居,然后在该线的正中间绘制一个新点。它一遍又一遍地这样做,直到达到你一开始要求的等级比率。
在这种情况下,我对训练数据使用 SMOTE 来生成足够的流失类样本,这样每 2 个非流失案例中就有 1 个流失案例。这有助于大大提高性能。
随机森林分类器
这是用于分类的实际模型。随机森林是单个决策树的集合,它的工作方式非常酷!
我们大多数人都熟悉决策树的概念,即使我们并不知道自己是。决策树搜索可用的特征并挑选特征,通过基于该特征的值分割数据,将产生彼此尽可能不同的结果组。一张图会提供更清楚的解释…
简单的决策树示例(图片由作者提供)
随机森林是数百个不同决策树的集合。每个单独的决策树都会产生一个分类,哪个分类获得的“票数”最多,哪个就获胜。
投票过程的可视化(图片由作者提供)
如果每棵决策树都在最有效的特征上分裂,那么森林中的每棵决策树不应该是完全相同的吗?
随机森林以这种方式引入了随机性:每当一棵树决定分割哪个特征时,它必须从随机的特征子集而不是整个特征集中进行选择。因此,森林中的每一棵树都是独一无二的!
以下是如何用 SMOTE 实现和评估随机森林分类器的代码…
运行中的模型
精确度很高,但是这个模型如何用于现实生活呢?
使用随机森林模型,我们实际上可以为每一类预测生成概率。因此,我们基本上可以让模型为每个客户提供一个概率,即模型认为该客户在未来三个月内流失的可能性有多大。
例如,我们可以返回一个所有有超过 65%的翻盘机会的客户的列表。因为我们只关心高价值的客户,所以我们可以使列表只包含那些高于平均客户价值的客户。
通过这样做,我们能够生成一个对公司具有高价值并且具有高流失风险的客户列表。这些客户是公司希望以某种方式干预以留住他们的客户。
当在测试数据上运行时,这样的列表看起来像这样(索引是客户 ID)…
我们所有的高风险、高价值客户(图片由作者提供)
下面是像上面那样拟合模型后生成这样一个列表的代码…
了解每个特性如何导致客户流失
能够预测那些可能流失的客户是很好的,但是,如果这是我的公司,我也想知道每个功能是如何造成流失的。
就像我们在可视化数据部分所做的那样,通过可视化数据,我们可以看到每个单独的特征是如何与客户流失相关联的。不幸的是,仅仅基于可视化很难比较每个变量的影响。
我们实际上可以使用另一种机器学习技术,称为逻辑回归,来比较每个特征的影响。逻辑回归也是一种分类模型。在我们的例子中,它没有给我们提供像 Random Forest 一样好的预测性能,但它确实给了我们关于每个特征如何影响流失的好的、可解释的信息。
逻辑回归系数如下所示…
逻辑回归系数(图片由作者提供)
具有正系数的特征意味着该特征的增加导致该观察成为流失情况的机会增加。
具有负系数的特征意味着该特征的增加导致该观察成为流失情况的机会减少。
因此,记录的客户通话失败次数越多,该客户就越有可能成为客户流失案例。客户发送的短信越多(“短信频率”),客户流失的可能性就越小。
以下是计算和绘制这些系数的代码…
建模迭代
和往常一样,在用 SMOTE 选择随机森林之前,我尝试了多种不同的模型和过采样技术。
尝试的模型:
-逻辑回归
-随机森林
-梯度推进分类器
-Ada 推进分类器
尝试过采样技术:
-无过采样(不平衡类)
-SMOTE w/ 0.25、0.5、0.75 和 1 作为类比率
-ADASYN w/ 0.25、0.5、0.75 和 1 类比率
为了比较这些模型,我尝试了每种模型和每种采样策略。我将所有结果添加到一个数据帧中,如下所示…
建模迭代的总结(图片由作者提供)
此数据框架与以下两个代码块放在一起(逻辑回归模型除外,因为需要调整 X 变量,所以必须单独计算)…
用每种采样技术生成集合模型
这就是你如何使用机器学习来预测和防止高价值客户流失的方法。概括地说,我们能够使用机器学习完成两件主要的事情,这是我们用基于“传统”可视化的分析无法完成的。我们能够:
1)生成一个模型,能够在客户流失案例发生之前识别 90%的案例
2)对每个因素对客户流失概率的影响进行排序。
感谢阅读!!
预测动画电影表现的数据管道
实施线性回归预测动画电影表现的技术演示。
这是 METIS 正在进行的五个数据科学项目中的第二个,涉及虚构的客户端。这篇文章基于第 1 部分:客户演示。
项目焦点
这个项目的目的是使用新获得的数据科学工具来解决一个虚构客户的问题领域。我选择看动画电影是因为我个人对媒体的兴趣,并将这个项目视为帮助动画电影制片人和电影制作人增加投资回报的一种方式。我试图梳理出让动画电影更有利可图的众所周知的特征,从而帮助整个行业。帖子中的技术解释可能过于详细,但我在一个数据科学项目的典型帖子中从未见过如此详细的内容,所以我认为这将是对万维网的一个很好的贡献。
技术工具
这是我使用技术工具的顺序,但是,项目的重点以粗体显示。
- 数据刮痧:美汤
- 数据清理和合并:熊猫
- 探索性数据分析:Seaborn,Statsmodel
- 线性回归:SKlearn
- 正规化:拉索和山脊,拉斯
数据抓取
利用美人汤,我从“the-numbers.com”上刮出了有史以来 423 部动画电影的排行榜。从主页上,我调出了每部电影的票房收入,包括国内、国际票房收入、上映年份以及每部电影的网址。下面是初始数据帧的头部,以及生成它的代码。
from bs4 import BeautifulSoup
import requests
import time#store url of page to be scraped
movies_html = “[https://www.the-numbers.com/box-office-records/domestic/all-movies/cumulative/all-time-animated](https://www.the-numbers.com/box-office-records/domestic/all-movies/cumulative/all-time-animated)"
movies_htmls = [movies_html, movies_html + “/101”, movies_html + “/201”, movies_html + “/301”, movies_html+ “401”]#iterate through url pages
movies = {}
for movies_html in movies_htmls:#retrieve page’s html
response = requests.get(movies_html)
response.status_code#store response
page = response.text#parse page with “lxml” parser
soup = BeautifulSoup(page, “lxml”)#gather movie data
table = soup.find(‘table’)
type(table)#find all rows: tr tag is for rows
rows = [row for row in table.find_all(‘tr’)]#get movies info
for row in rows[1:100]:
items = row.find_all(‘td’)
url_1 = “[https://www.the-numbers.com](https://www.the-numbers.com)”
link = items[2].find(‘a’)
title, url = link.text, url_1 + link[‘href’]
movies[title] = [url] + [i.text for i in items]
time.sleep(2)```
然后,我提取每部电影的数据和预处理信息,例如,在提取美元金额时,我删除了逗号和美元符号,以获得一个纯粹的数字。这个过程与上面的非常相似,但是我从 the-numbers.com 的 HTML 中提取的信息是基于关键字的,而不是来自表格。下面是单个电影页面抓取的结果数据帧。
我想给这个项目一个更广阔的视角,所以我结合了 GDP 数据,以及从现有数据集中提取的 IMDB 元得分数据。与使用美国 GDP 数据一致,我决定使用国内票房表现,而不是国际。回想起来,我认为虚构的客户使用国际票房收入会更有用,因为钱就是钱,正如你在上面的前 5 部电影中看到的,国内份额不到 50%。此外,通过合并有限的现有数据集,其中没有太多的动画电影,我不得不将数据集削减到 166 部电影。如果时间允许的话,如果我没有削减数据集的话,可能会产生一个更好的模型。元分数在我的模型中很有影响力,但它可能是一个很好的实验,以检查是否有更多的数据来训练或有元分数会产生更好的模型。
我对数据集进行了一些清理,将其与其他数据集合并,并在数值数据类型中包含数值数据。
#convert datatypes to numeric / date
df["Avg. Run"] = pd.to_numeric(df["Avg. Run"], errors='coerce')
df["Runtime"] = pd.to_numeric(df["Runtime"], errors='coerce')
df["Release Date"] = pd.to_datetime(df["Release Date"], format = "%Y-%m-%d" )#make a column of lowercase + no punctuation titles
df["title_formatted"] = df["Title"].str.lower()
df["title_formatted"] = df["title_formatted"].str.replace('[^\w\s]','')
df["title_formatted"] = df["title_formatted"].str.replace(' ','')
我对要合并的数据集做了类似的清理和重新格式化,然后合并。
mergedStuff = pd.merge(df, df_imdb, on=['title_formatted'], how='inner')
我还从我收集的信息中生成了一些数字数据,尽可能地为模型提供最有意义的数字数据。例如,当我把发行语言转换成语言的数量,把标题转换成标题的长度,把续集转换成 0 和 1。
#find how many languages the film is in
gdp_movie_df['Language'] = gdp_movie_df['Language'].str.split()
gdp_movie_df['# of Languages'] = [len(x) for x in gdp_movie_df['Language']]
我最终使用以下数据集来进行 EDA 和模型训练,它由 15 个数字特征和 7 个分类特征组成。
我做了一个快速总结,看看是否一切都像预期的那样,没有不太可能的异常值。
X_y_df.describe()
一切似乎都井井有条,我确实决定保留票房表现高端的异常值,以便更好地理解它们。回过头来看,去掉它们以产生一个更精确的模型可能是明智的。
探索性数据分析
在我收集了所有的数据之后,我分离出我的数字数据,并首先使用相关矩阵对其进行检查。代码和输出如下:
numeric_df = X_y_df.loc[:,["Box Ofice", 'Production Budget', 'Theaters', 'Avg. Run', 'Metascore', 'Runtime_x', "month", 'year', 'Title Length', '# of Languages', 'GDP_level-current','GDP_level-chained', 'GDP_change-current', 'GDP_change-chained', "sequel_num"]]# correlation matrix heatmap
plt.figure(figsize = (8,7))
sns.heatmap(numeric_df.corr(), cmap="RdYlBu", annot=True, vmin=-1, vmax=1);
plt.savefig("heatmap_blue_or.png", bbox_inches='tight')
从热图中,我可以收集到与票房表现高度相关并且会严重影响我的模型的主要特征是:
- 平均运行周数
- 剧院数量
- 生产预算
- 续集/翻拍
- 元得分
- 标题长度(标题中的字母数)
- 运行时间
- 国内生产总值水平环比
有意思的是,随着年限的增长,收益反而下降。这也可能与不得不削减数据集以包含准确的元得分有关。为了探索这些特征和票房表现之间的数学关系,我进一步观察了一个配对图。代码和结果如下:
sns_plot = sns.pairplot(numeric_df, height=4, aspect=1);
sns_plot.savefig(“pairplot.pdf”)
从配对图中(在 pdf 上放大很多倍后),我可以进一步理解这些关系,并看到一些更有影响力的特征:
- 平均运行周数
这个特征与票房有直接关系,斜率很小,截距大于零。
2.剧院数量
这一特征在达到最大值时似乎趋于平稳,表明与票房表现的关系更加复杂。
3.生产预算:
这个功能与票房有最直接的关系,截距为零。随着制作预算的增长,票房业绩成比例地增长。
4.续集/重拍
这一特征在异常值中是一致的,这些异常值是表现最好的电影。
5.元得分
这一特征确实与票房表现有直接关系,但许多元得分较高的电影在票房上表现不佳。
6.标题长度(标题中的字母数)
这条曲线与票房表现成反比。高回报的电影总是有较短的片名。
7.运行时间
该数据主要聚集在 90 分钟的直线周围,高回报电影更接近该长度。我觉得这个特点不太显著。
8.国内生产总值水平环比
这个特点也不是很显著。
9.月
这一特性非常重要,从图表中我们可以看出,初夏和年末的发布日期更为成功。但是,季节并不遵循线性关系,因此它可能无法在线性回归模型中很好地建模。
在这个 EDA 之后,我可以建立一个模型,测试我的功能之间的关系,以及目标变量,国内票房表现。
线性回归
我使用 SKlearn python 包来设置我的简单训练测试分割,并在变量的几次迭代中获得我的 R 平方、平均绝对误差和均方根误差,包括一些虚拟变量和超参数。我做了一个循环来测试下面的组合、代码和结果,我的第一次迭代只使用了开箱即用的数字数据,如下所示:
from sklearn.model_selection import train_test_split
from sklearn import metricsdef split_and_validate(X, y):
‘’’
For a set of features and target X, y, perform a 80/20 train/val split,
fit and validate a linear regression model, and report results
‘’’
# perform train/val split
X_train, X_val, y_train, y_val = \
train_test_split(X, y, test_size=0.2, random_state=42)
# fit linear regression to training data
lr_model = LinearRegression()
lr_model.fit(X_train, y_train)
# score fit model on validation data
val_score = lr_model.score(X_val, y_val)
lr_preds = lr_model.predict(X_val)
rmse = np.sqrt(metrics.mean_squared_error(y_val,lr_preds))
mae = metrics.mean_absolute_error(y_val,lr_preds)
# report results
print(‘\nValidation R² score was:’, val_score)
print(‘Feature coefficient results: \n’)
for feature, coef in zip(X.columns, lr_model.coef_):
print(feature, ‘:’, f’{coef:.2f}’)
print (“RMSE score was:”, rmse)
print (“MAE score was:”, mae)#vanilla training
split_and_validate(X, y)
我打印了每次迭代的系数和分数。我从大约 0.64 R 平方开始,这并不可怕。我进行了几次迭代,得出了下面的模型。
这些分数是我在我的数据集上能得到的最好的分数,R 平方达到 0.815,平均绝对误差达到 48,934,141 美元。如果时间允许的话,我会添加更多关于演员和导演的历史表现的数据,更多关于工作室的信息,以及公众对电影中启动力量的兴趣。
我还测试了 Ridge 和 Lasso,看看它们是否会产生更好的结果,但它们没有,因为过度拟合不是这个特定模型的问题。代码和输出如下:
#Standard Scaler for Lasso and Ridge
std = StandardScaler()
std.fit_transform(X_tr.values)
X_tr_std = std.transform(X_tr.values)
X_val_std = std.transform(X_va.values)#Ridge Linear Regression (code clip)
lr_model_ridge = Ridge(alpha = 100)
lr_model_ridge.fit(X_tr_std, y_tr)
#Lasso Linear Regression (code clip)
lr_model_lasso = Lasso(alpha = .01)
lr_model_lasso.fit(X_tr_std, y_tr)
为了评估我的模型,我绘制了残差图,发现它们是随机分布的。
residual = (y_test - lr_preds)
我还绘制了预期与预测的票房表现,如下所示。
plt.figure(figsize=(7,7))
plt.scatter(lr_preds, y_test, c = "k")
#plt.xlabel('Predicted Domestic Total Gross ', labelpad=15, color = "k")
#plt.ylabel("Actual Domestic Total Gross (in 100 millions)", labelpad=15)
#plt.title("Predicted Domestic Total Gross vs Actual", fontsize = 22, weight = 'bold', pad=40)
plt.savefig("Predicted vs Actual.svg", bbox_inches='tight')
总的来说,端到端地运行这个过程非常令人满意。令人惊讶的是看到了过程中涉及的 EDA 和迭代的数量,但也令人欣慰的是知道人类对模型的输入和模型本身一样重要。我期待将线性回归应用于无数的问题。
预测动画电影的表现
这是 METIS 正在进行的五个数据科学项目中的第二个,旨在使用线性回归来预测动画电影的票房表现。
从 Shutterstock 获得授权的吉卜力动画工作室角色
动机
我喜欢动画电影——大多是吉卜力工作室的,但有时,迪士尼/皮克斯制作的东西我不介意看无数遍。我希望看到更多伟大的作品,但我知道动画电影的制作成本近年来大幅增加。我想帮助制片人和电影制作人更早地了解投资回报:
- 动画电影制片人想知道投资哪部动画电影能获得最高回报。
- 动画电影制作人想知道电影中的简单变化是否能提高电影的回报。
目标
- 了解哪些因素会产生最高的国内票房回报
- 在电影上映前预测国内票房收入
数据
- 分销战略、资金、绩效—“the-numbers . com”
有史以来排名前 423 位的动画电影及其主要特点都是从这个“the-numbers.com”中刮出来的。
2.关键接收—“IMDB . com”
IMDB 元评分是一个数字,它总结了电影公开发行前专业电影评论家的评论,并从现有的公共数据集中提取。
3.经济数据—“bea . gov”
一系列 GDP 指标从最初来自 https://www.bea.gov/data/gdp/gross-domestic-product#gd的公共数据集中下载。
Anupama Garla 的数据集组件
方法
型号:
线性回归,拉索和山脊正则化测试(未使用)
指标:
判断我的模型是否成功的标准是平均绝对误差,它告诉我们预测的性能与实际性能平均相差多远。还参考了预测与预期票房表现值的图表。
在模型设计期间参考了 R 平方误差和均方根误差,并确定其用处不大。
结果
平均误差:48,934,141 美元| RMSE: 65,240,627 | R : 0.815
虽然 R 值很高,表明模型很好地描述了数据内的方差,但均方根误差和平均绝对误差高于预期。
平均绝对误差衡量预测的平均误差。我对这个模型的平均绝对误差是 48,934,141 美元,是国内总平均误差 162,500,951 美元的 30%。这表明我的模型在预测票房表现方面还可以,但还有待改进。
Anupama Garla 的预测与实际
该图显示,预测的国内票房表现与实际的国内票房表现处于相似的轨迹上。计算平均误差时模型表现不佳的一些原因是:
- 数据集内的异常值未被排除
- 有限的数据集 (432 个顶级动画电影数据集在与元评分数据集合并后减少到 166 个)
- 有限的功能(额外的功能,如导演的明星效应、表演声音和音乐人可能非常有预见性)
- 国内票房收入的右尾分布可以转换为正态分布,以便更好地与线性回归模型保持一致
洞察力
虽然该模型可以预测国内票房收入,但探索性数据分析结合预测模型得出了一些关于影响收入的数字特征的重要见解。
Anupama Garla 的特征选择
影响国内票房表现的前 5 名预发行
- 生产预算:美元美元
2.**分布:**影院数量,周数
3.**关键审查:**预发布关键接收+
4.**上映日期:**夏季/12 月
5.标题长度名称:越短越好
6.续集:表现最好的电影是续集
- 有趣的是,流派、语言数量和制作国家对票房表现没有显著影响。
我深入研究了下面的具体数字、分布和临界值:
Anupama Garla 绘制的配对图
#1 预测因素:生产预算
投入电影的钱越多,电影产生的钱就越多。这可能部分是因为如今制作如此精美的动画所需的计算和人力。
Anupama Garla 的配对图
#2 预测因素:分销战略和广度
这些对票房收入有重大影响。接触到广泛的观众,并在关键的剧院首演中击败竞争对手是非常值得努力的。
Anupama Garla 绘制的配对图
第三大预测因素:Metascore
批评性评论可以从无用的东西中发现宝石,然而,它本身并不是票房收入的良好指标。
Anupama Garla 绘制的配对图
#4 最大的预测因素:发布月份
人们倾向于在假期和家人一起看更多的电影。高性能电影往往在五月、六月、七月、十一月和十二月上映。
Anupama Garla 绘制的配对图
第五大预测因素:电影名称中的字母数
虽然片名长度本身并不是一个预测因素,但大多数票房超过 4 亿美元的高性能电影都有 15 个字母以下的片名。
结论
线性回归模型能够充分预测票房表现。然而,该模型将受益于更多捕捉方差的特征——也许是量化明星效应或情节特征的特征。
虽然投入的资金直接反映了电影的表现,但发行和评论紧随其后。较短的标题更好,也许是因为它们更吸引人,续集往往会大获全胜!
预测德国的公寓租金价格
使用随机森林预测租赁价格
在 Unsplash 上由 Wiktor Karkocha 拍摄的照片
T 通过这篇文章,我试图使用包含德国租金价格的公寓租金数据集来预测租金价格。该数据集由从德国最大的房地产平台之一收集的数据组成。这里的主要目的是研究和理解数据,并利用这些知识构建一个基本预测模型来预测基础租赁价格(在德国通常称为“Kaltmiete”)。
原始数据集由 268850 个公寓(行)* 49 个要素(列)组成,但是缺失值和不平衡值的组合意味着在当前上下文中只有 14 个要素对我有用。这些列包含以下信息:
- 公寓所在的联邦州。
- *供暖类型:*公寓使用的供暖系统类型。
- *阳台:*列表示公寓是否有阳台。
- 建造年份: 公寓建造的年份。
- hasKitchen: 列表示公寓是否有厨房。
- *地窖:*表示公寓是否有地窖的栏。
- 基本租金:不包括电费和取暖费的租金。
- *居住空间:*以平方米为单位的居住空间。
- *状况:*持平的状况。
- 电梯:表示公寓是否有电梯的栏目。
- typeOfFlat: 户型。
- noRooms: 公寓房间总数。
- *花园:*一栏表示公寓是否有花园。
- regio2: 公寓所在城市。
数据框架一览(1/2)
数据框架一览(2/2)
探索性数据分析:
由于该数据集是通过网络抓取创建的,因此它远非干净。因此,挑战之一是摆脱极端和空值。例如,有几排居住空间超过 60 平方米。在€10-€30 的范围内,这是明显的异常值。还有几个房间总数超过 100 间的公寓。清理后研究得出以下结论:
1.德国平均房租最高的城市是慕尼黑,这并不奇怪,因为这座城市以生活成本高而闻名。慕尼黑市内及周边地区(用 München_Kreis 表示)也位列前十。有趣的事实是,紧随法兰克福排名第三的施塔恩堡是德国最富有的城镇。我很惊讶没有在名单上找到杜塞尔多夫和波恩。
各城市的平均租金
2.)汉堡是平均租金最高的联邦州,其次是柏林和拜仁(巴伐利亚)。东北部的萨克森-安哈尔特州和图林根州的价格最低。
各州平均租金
3.)应该是,居住空间的大小和基础租金价格似乎或多或少是正相关的。看起来像离群值的价格高的小(尺寸)公寓是位于市中心(柏林市中心,法兰克福)的公寓,这解释了成本。
总租金与居住空间
4.)德国最常见的基本租金价格在€300-€400 之间。
德国的租金分配
5.中央供暖系统似乎是德国家庭中最常见的供暖系统,远远超过其他任何一种。
6.)大多数出售的公寓都有 3 个房间,属于“公寓”类型。
每套公寓的房间数
租赁类型
模型开发:
在创建原型模型之前,转换数据集是很重要的。在将数据集输入模型之前,对数据集执行了以下预处理步骤。
- 在*‘条件’*栏中的七个独特值(‘保持良好’,‘翻新’,‘第一次使用’,‘完全翻新’,‘全新状态’,
,‘第一次使用’,‘翻新后’,‘现代化’,‘可协商’,【T5’,‘需要翻新’,‘适合拆除’),被分成三个等级‘新’,‘旧’和‘中’公寓。这样做是为了获得更清晰的界限。 - 根据列值是真还是假,列【T6’‘阳台’,‘厨房’,‘地窖’,‘电梯’和【T8’‘花园’中的数据被编码为 1 或 0。
- 使用 sklearn 的 MinMaxScaler()对连续值变量 ‘baseRent ‘,’ livingSpace’ 和’ noRooms '进行标准化。虽然在处理基于树的算法时,这不是一个必要的步骤,但是它简化了可解释性,并且使得与其他模型的性能比较更加容易。
- 分类变量使用一个热编码进行编码,通过熊猫的 get_dummies 变得容易。
- 列*‘base rent’*被选为目标变量,其余为预测变量。
- 在应用上述步骤后,使用 sklearn 的 train_test_split 将数据集分成训练集(70%的数据)和测试集(30%的数据)。
我选择随机森林来开发原型,因为它是一个强大的模型,可以很好地处理连续变量和分类变量。
使用 RandomForestRegressor()对训练集拟合模型。使用测试集来检查模型的性能,获得了以下结果。
模型结果
该模型约占模型中数据的 83.4%,或者说该模型的预测能力为 0.83(最好为 1.0),考虑到该模型是使用默认参数运行的且未进行调整,这已经相当不错了。MSE 和 MAE 也较低。
结论:
这种模式还能改进吗?是的,当然!。这个模型远远不是最好的模型。我的第一种方法是使用网格搜索技术进行超参数调整和交叉验证,以找到理想的参数。第二,原始数据集包含许多缺少数据的列,我选择从模型中排除这些数据,这意味着丢失了相当多的信息。使用领域知识的智能插补技术可以帮助解决这个问题。原始数据集还包含描述公寓设施和描述的列。通过使用 NLP 技术,可以从这些列中获得更多的信息。较重的特征工程也会有所帮助。不用说,我将使用这些步骤作为线索来提高模型的性能。
我很想听到你对此的反馈。如果您有任何问题或建议,可以联系 me 。感谢您的阅读。
用脸书的预言家预测苹果公司的股价
时间序列预测的最新方法
亚历克斯·哈尼在 Unsplash 上的照片
时间序列预测是用于根据以前观察到的值预测未来值的模型。时间序列数据是在离散的时间尺度上记录的。
时间序列预测广泛应用于非平稳数据。统计属性(如均值和方差)不随时间变化的数据是非平稳数据。非平稳数据的最好例子是股票价格。
时间序列预测广泛用于预测销售和股票价格。已经有人尝试使用时间序列分析算法来预测股票价格,尽管它们仍然不能用于在真实市场中下注。
为了开发一种可以捕捉时间序列数据中季节性的模型,脸书开发了 Prophet,这是脸书数据科学团队发布的开源软件。
Prophet 试图捕捉每日、每周和每年的季节性以及假日效应,实现加法回归模型。
先知方程式
正如我前面引用的,Prophet 是一个加法回归模型。下面的等式代表了 Prophet 背后的数学。
y(t) = g(t) + s(t) + h(t) + e(t)
g(t)代表趋势。Prophet 使用分段线性模型进行趋势预测。
s(t)代表周期性变化(每周、每月、每年)。
h(t)表示持续时间超过一天的假期的影响。假期影响商业。
e(t)涵盖了模型未涵盖的变更或错误。
Prophet 是一个易于使用的模型。它速度很快,不需要数据预处理。它处理带有几个异常值的缺失数据。
我们将尝试使用脸书的先知来预测苹果公司的股票价格。苹果公司的每日股票价格可以从雅虎财经网站下载。雅虎财经是股市数据的主要来源之一。我们将获得苹果公司自 2015 年以来的股价数据。
接下来,我们需要下载先知包。
conda install gccconda install -c conda-forge fbprophetconda install pystan #prophet dependency
现在,我们可以从模型的 Python 实现开始。
我们将从导入库和数据集开始。
#importing the libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as pltdata = pd.read_csv("F:\\AAPL.csv")
data.head()
苹果股票价格数据集
我们需要数据集中的日期和收盘价,然后我们将把列“日期”和“收盘”分别重命名为“ds”和“y ”,因为这是 Prophet 的标准输入方式。这是 Prophet 要求的唯一预处理步骤。
data = data[['Date','Close']] #selecting the important features
data = data.rename(columns = {'Date':'ds','Close':'y'}) #renaming the columns of the dataset
接下来,我们将把数据分为训练和测试,因为我们不想在测试集上训练数据。如果我们隐藏测试数据,那么模型将会预测看不见的数据的值。我们希望机器只从以前的数据中学习,而不知道测试数据的趋势。
train = data.iloc[:1000,0:2] #training set(this will be the data to train the model)
test = data.iloc[1000:0:2] #we can use this data to compare the results of the predictions made by the model
接下来,我们将从 fbprophet 模块导入 prophet 类,然后创建 Prophet 类的一个对象。我们将把训练数据输入到模型中。
from fbprophet import Prophet
m = Prophet(daily_seasonality = True) #creating an object of the Prophet class
m.fit(train) #fitting the training data to the model
现在,对于最后一步,我们将要求模型预测未来值,然后尝试将预测可视化。
future = m.make_future_dataframe(periods=341) #we need to specify the number of days in future, for which we want to predict the prices
prediction = m.predict(future)
m.plot(prediction)
苹果股票价格
如果您想要查看预测组件、周组件、季组件、年组件和假日组件,那么您可以使用以下命令。
m.plot_components(prediction)
Prophet 还提供了一个交互式的预测图。这显示了过去一周、一个月、六个月和一年内的预测。为此,我们需要安装 Plotly,它不会随 fbprophet 一起安装,只需在命令提示符下键入’pip install Plotly【T1]'即可。
from fbprophet.plot import plot_plotly
import plotly.offline as py
py.init_notebook_mode()
fig = plot_plotly(m, prediction)
py.iplot(fig)
股票价格的交互式图表
尝试为不同的数据集实现该模型,看看它是否对您有益。
来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语 。
预测新冠肺炎时代的苹果股票
简单是关键。
介绍
2 月 13 日,我发表了一篇关于“使用连续 ML 预测苹果股票的杰出成果”的文章。
有人建议在“不受欢迎”的场景中尝试一下,所以我重新运行了一个改进的练习**,包括最后几周**,看看它在这些艰难时期的表现。
我们要做什么
- 步骤 1:定义并理解 ML 的目标
- 步骤 2:设置技术先决条件
- 第三步:获取数据
- 步骤 4: 准备我们的数据和应用 ML 运行模拟
- 步骤 5:测量和分析结果
第一步。定义和理解目标
*免责声明: 本次演习中有交易、做空佣金等费用未考虑在内。 作者不分担使用本文所带来的风险或利益 。
苹果价格一直在上涨,但也在下跌,比如最近几周。
截图取自 Investing.com
我们想要的是检测第二天的价格是否会上涨或下跌,这样我们就可以在前一天买入或做空。
我们还希望变化率高于 0.5% ,这样交易就值得了。
随着时间而改变
上面是随着时间的变化,绿点是价格上涨超过 0.5%的天数,红点是相反的。
让我们定义我们的目标变量:
阳性 POC: “变化”增加超过 0.5%
阴性 POC: “变化”下降超过 0.5%
在最后一篇文章中,我们创建了一个 ML 模型,使用新闻来预测第二天的起义以及随后的表现:
这意味着,从所有的观察来看,这个模型预测第二天价格将上涨 0.5% 或更多(82 倍),这是正确 72% 倍 (62 倍)。
这个比率(也就是精度: TP / TP & FP)是一个重要的指标,因为对于这个实验,每次预测为“将上升”(或者预测为下降时为“短”】时,我们都会“投资”,所以我们通常会优先考虑正确与否,即使我们会失去一些机会。
现在让我们现在制作一个模型来预测上涨和下跌在“牛市”和“熊市”的时候。
苹果价格过去几个月受到石油和新冠肺炎的影响
第二步。先决条件
- 安装 Python 2.6+或 3.1+版本
- 安装熊猫、sklearn 和 openblender(带 pip)
$ pip install pandas OpenBlender scikit-learn
第二步。获取数据
注意:这一步重复了第一篇文章中所做的,所以如果你已经做了,你可以跳过它。
让我们从每日苹果股票数据集中提取
它在那一天有百分之的变化。
所以让我们通过 OpenBlender API 拉数据。
在 Python 上运行以下代码:
# Import the librariesfrom sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import accuracy_score
from sklearn.metrics import roc_auc_score
from sklearn import metrics
import pandas as pd
import OpenBlender
import json
%matplotlib inline*# Specify the action* action = 'API_getObservationsFromDataset'*# Specify your Token
token =* '**YOUR_TOKEN_HERE**' *# Specify the 'Apple Inc. Price' id_dataset*parameters = {
'token' : token,
'id_dataset':'**5d4c39d09516290b01c8307b**',
'consumption_confirmation' : 'on',
'date_filter':{"start_date":"2017-01-01T06:00:00.000Z",
"end_date":"2020-03-29T06:00:00.000Z"}
}*# Pull the data into a Pandas Dataframe* df = pd.read_json(json.dumps(OpenBlender.call(action, parameters)['sample']), convert_dates=False, convert_axes=False).sort_values('timestamp', ascending=False)
df.reset_index(drop=True, inplace=True)
**注意:**要获得令牌,你需要在 openblender.io (免费)上创建一个帐户,你可以在你个人资料图标的“帐户”标签中找到它。
#Let's take a look
df.head()
为了融合商业新闻,我们需要:
- 与我们的目标相关的有用的新闻数据
- 将它融合到我们的数据中,使消息与第二天的价格“变化”(这样模型就可以学习预测第二天的价格)
- 将它转换成数字特征,这样它就可以遍历一个 ML 模型。
让我们来看看这个华尔街日报新闻数据集:
以及今日美国推特新闻。
- 注意:我选择这些是因为它们有意义,但你可以搜索数百个其他的。
现在,让我们创建一个文本矢量器,这是 OpenBlender 上的一个模型,它能够将令牌(矢量化文本)作为特征,就像它是另一个数据集一样:
action = 'API_createTextVectorizerPlus'parameters = {
'token' : token,
'name' : 'Wall Street and USA Today Vectorizer',
'sources':[
{'id_dataset':"5e2ef74e9516294390e810a9",
'features' : ["text"]},
{'id_dataset' : "5e32fd289516291e346c1726",
'features' : ["text"]}
],
'ngram_range' : {'min' : 1, 'max' : 2},
'language' : 'en',
'remove_stop_words' : 'on',
'min_count_limit' : 2
}response = OpenBlender.call(action, parameters)
response
根据上述内容,我们指定了以下内容:
- **名称:**我们将其命名为“华尔街和今日美国矢量器”
- sources :作为源包含的数据集的 id 和源列(在这种情况下,两者都只有一个名为“text”)
- ngram_range :将被分词的单词集的最小和最大长度
- 语言:英语
- remove_stop_words :这样就从源头上消除了停用词
- min_count_limit :被认为是令牌的最小重复次数(出现一次很少有帮助)
现在,如果我们转到 OpenBlender 的仪表板,我们可以看到矢量器:
它生成了 4999 个 n-gram,这些 n-gram 是最多 2 个单词的令牌的二进制特征,如果提到了 **n-gram 则为“1”**否则为“0”。
第三步。准备数据
现在我们希望矢量化数据在 24 小时时滞内压缩,并与第二天的苹果股票价格一致。
你需要添加你的矢量器的 id (它是由 API 返回的,或者你可以在 OpenBlender 中得到它。
*注:要下载 所有的矢量化数据 你需要支付大约 6 美元升级到 OpenBlender 的“现收现付”。您仍然可以继续处理一小部分数据,从而缩短日期间隔。
action = 'API_getObservationsFromDataset'interval = 60 * 60 * 24 # One dayparameters = {
'token' : token,
'id_dataset':'5d4c39d09516290b01c8307b',
'date_filter':{"start_date":"2017-01-01T06:00:00.000Z",
"end_date":"2020-03-29T06:00:00.000Z"},
'aggregate_in_time_interval' : {
'time_interval_size' : interval,
'output' : 'avg',
'empty_intervals' : 'impute'
},
'blends' :
[{"id_blend" : "**5e46c8cf9516297ce1ada712**",
"blend_class" : "closest_observation",
"restriction":"None",
"blend_type":"text_ts",
"specifications":{"time_interval_size" : interval}
}],
'lag_feature' : {'feature' : 'change', 'periods' : [-1]}
}df = pd.read_json(json.dumps(OpenBlender.call(action, parameters)['sample']), convert_dates=False, convert_axes=False).sort_values('timestamp', ascending=False)
df.reset_index(drop=True, inplace=True)
这是与之前相同的服务调用,但是有一些新的参数:
- aggregate _ in _ time _ interval:以 24 小时为间隔平均汇总数据,如果有间隔没有观测值,则进行估算
- 混合:按时间加入聚合的新闻 24 小时数据
- lag_feature :我们希望“变化”功能与过去 24 小时内发生的新闻保持一致
让我们来看看最上面的数据:
print(df.shape)
df.head()
我们有 1122 观察和 4908 特征。其中大部分是来自矢量器的 n-grams ,我们也有我们原始的苹果股票数据集。
“ lag-1_change ”简单地说就是将“change”值与“前一天的数据对齐,这正是我们所需要的。最后一个观察是 NaN,因为那是“明天”将要发生的事情。
现在让按照之前的定义创建我们的目标特征:
# Where ‘change’ **decreased** more than 0.5%
df['negative_poc'] = [1 if val < 0.5 else 0 for val in df['lag-1_change']]# Where ‘change’ **increased** more than 0.5%
df['positive_poc'] = [1 if val > 0.5 else 0 for val in df['lag-1_change']]df[['lag-1_change', 'positive_poc', 'negative_poc']].head()
步骤 3.5 应用 ML 并运行模拟
我们想要 2 个模型,一个将预测价格是否会上涨(高于 0.5%),一个将预测等量的下跌,然后将两者结合到交易策略。
此外,我们希望通过时间来训练和测试,以便模型学习相关信息。
最后,我们希望模拟,如果我们以**1000 美元开始,**我们会以结束。
# First we create separeate dataframes for positive and negativedf_positive = df.select_dtypes(['number']).iloc[::-1]
for rem in ['negative_poc']:
df_positive = df_positive.loc[:, df_positive.columns != rem]df_negative = df.select_dtypes(['number']).iloc[::-1]
for rem in ['positive_poc']:
df_negative = df_negative.loc[:, df_negative.columns != rem]
给定一个数据帧和一个目标,下一个函数将返回应用 ML 的结果和一个带有预测与结果的数据帧。
def getMetricsFromModel(target, df):
# Create train/test sets
X = df.loc[:, df.columns != target]
X = X.loc[:, X.columns != 'lag-1_change'].values
y = df.loc[:,[target]].values
# Create X and y.
div = int(round(len(X) * 0.89))
real_values = df[div:].loc[:,['lag-1_change']].values
X_train = X[:div]
y_train = y[:div] X_test = X[div:]
y_test = y[div:]
# Perform ML
rf = RandomForestRegressor(n_estimators = 1000, random_state = 1)
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)
# Get Metrics
print("AUC score:")
auc = roc_auc_score(y_test, y_pred)
print(auc)
print('---') preds = [1 if val > 0.6 else 0 for val in y_pred]
print('Confusion Matrix:')
conf_matrix = metrics.confusion_matrix(y_test, preds)
print(metrics.confusion_matrix(y_test, preds))
print('---')
print('Acurracy:')
acc = accuracy_score(y_test, preds)
print(acc)
print('---')
df_compare = pd.DataFrame({'real_values' : real_values.ravel(), 'y_test' : y_test.ravel(), 'preds' : y_pred})
return auc, conf_matrix, acc, df_compare
我们希望通过 300 次观察和预测在接下来的 50 个跳跃日进行时间迭代学习,因此我们在每次跳跃时进行再训练。
当我们这样做时,我们希望从我们的两个模型中收集建议(负面/正面)。
df_compare_acc = None
for i in range(0, df_positive.shape[0] - 450, 50):
print(i)
print(i + 450)
print('-')
auc, conf_matrix, acc, df_compare_p = getMetricsFromModel('positive_poc', df_positive[i : i + 450])
auc, conf_matrix, acc, df_compare_n = getMetricsFromModel('negative_poc', df_negative[i : i + 450])
df_compare = df_compare_p[['y_test', 'real_values']]
df_compare.rename(columns={'y_test':'price_rised_5'}, inplace=True)
df_compare['F_p'] = df_compare_p['preds']
df_compare['price_dropped_5'] = df_compare_n['y_test']
df_compare['F_n'] = df_compare_n['preds']
df_compare
if df_compare_acc is None:
df_compare_acc = df_compare
else:
df_compare_acc = pd.concat([df_compare_acc, df_compare], ignore_index=True)
让我们来看看结果。
df_compare_acc
实际值 =价格的实际百分比变化
price_rised_5 =如果变化> 0.5
F_p =上升区间(0,1)内的预测
价格 _ 下降 _5 =如果变化> -0.5
F_n =下降范围(0,1)内的预测
我们的组合模型很简单,如果一个模型推荐,另一个不反对,我们买入/做空:
# This function will run a simulation on all the tested data
# given an invested 'starting_sum' and will return its
# trayectory.def runSimulation(include_pos, includle_neg, starting_sum):
sum_lst = []
actual_sum = starting_sum
for index, row in df_compare_acc.iterrows(): if row['F_p'] > 0.5 and row['F_n'] < 0.5 and include_pos:
actual_sum = actual_sum + (actual_sum * (row['real_values'] / 100)) if row['F_n'] > 0.5 and row['F_p'] < 0.5 and includle_neg:
actual_sum = actual_sum - (actual_sum * (row['real_values'] / 100)) sum_lst.append(actual_sum)
return sum_lst
让我们首先运行模型**,只有“积极的”预测**。
sum_lst = runSimulation(**True**, **False**, 1000)
df_compare_acc['actual_sum'] = sum_lst
print(sum_lst[len(sum_lst)-1])
df_compare_acc.plot(y = ['actual_sum'])
在当前的 COVID/oil/recession 形势下,它绝对暴跌,失去了近一半的收益。
现在让我们只使用负面预测来尝试一下。
sum_lst = runSimulation(**False**, **True**, 1000)
df_compare_acc['actual_sum'] = sum_lst
print(sum_lst[len(sum_lst)-1])
df_compare_acc.plot(y = ['actual_sum'])
因此,它的整体表现不如正面,但它现在真的表现很好在 covid 时间。
现在,让我们一起运行。
sum_lst = runSimulation(**True**, **True**, 1000)
df_compare_acc['actual_sum'] = sum_lst
print(sum_lst[len(sum_lst)-1])
df_compare_acc.plot(y = ['actual_sum'])
这是迄今为止表现最好的模型,以 574.4%的回报率结束了 3 年期,但这些天仍然非常不稳定。
至此,自 1 月 20 日结束以来,其损失了近 25% ,而苹果价格仅暴跌 20% 。
需要做的是根据情况优先考虑正面或负面建议**。**
几天后,我将发表一篇后续文章,介绍一个模型的结果,该模型的根据增加或减少多长时间来最大化回报,在正/负建议之间切换。
用神经网络预测苹果股票价格
如何使用递归神经网络预测股票价格?
克里斯·利维拉尼在 Unsplash 上的照片
股票价格预测肯定不是一件容易的事情,因为有许多因素需要考虑。整体市场状况、竞争对手的表现、新产品发布、全球关系的缓和都是有可能提高或降低股价的一些关键因素。除此之外,还可能发生意想不到的事件,例如我们目前遇到的冠状病毒情况。
我们到目前为止列出的因素很难预测。因此,在这篇文章中,我们将把它们放在一边。可以用来预测股票价格的一个关键因素是历史价格。例如,如果一只股票已经稳定上涨了两年,我们可能会认为它还会继续上涨一个月。然而,股票通常不会遵循简单的连续上升或下降趋势。因此,我们需要更复杂的工具来进行难以捕捉的观察。
LSTM(长短期记忆),这是一种 RNN(递归神经网络),可用于预测股票价格使用历史数据。LSTM 适合对序列数据建模,因为它维护一个内部状态来跟踪它已经看到的数据。LSTMs 的常见应用包括时间序列分析和自然语言处理。
让我们首先使用 pandas datareader 模块获取数据。它使得用几行代码获取股票价格数据变得非常简单。
import numpy as np
import pandas as pd
from pandas_datareader import dataaapl = data.DataReader("AAPL",
start='2015-1-1',
end='2019-12-31',
data_source='yahoo')
仅此而已!我们现在已经将 2015 年至 2020 年的苹果股价数据保存在熊猫数据框架中。
我们将使用调整后的收盘价格。我们来看看 2015 年到 2020 年的大趋势。
#import dataviz libraries
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style='darkgrid')
%matplotlib inline#Plot "Adj Close"
plt.figure(figsize=(12,8))
plt.title("APPLE Stock Prices", fontsize=15)
sns.lineplot(x=aapl.index, y='Adj Close', data=aapl)
2015 年似乎不是一个盈利的一年,随后是近 3 年的稳定上升趋势。我们观察到 2019 年底的急剧下降,随后是大约一年的稳定增长。
我们将尝试对 LSTM 层使用过去 90 天(即从 t-90 到 t-1)的历史价格来预测时间 t 的价格。请记住,我们将努力捕捉趋势,而不是确切的价格。
LSTM 要求输入是具有形状(batch_size,timesteps,input_dim)的 3D 张量。
由于我们使用 90 天(t-90 到 t-1)的历史数据在时间 t 进行预测,因此时间步长的数量为 90。我们仅使用“Adj Close”价格进行预测,因此 input_dim 为 1。Input_dim 可以通过添加附加功能来增加。例如,竞争对手股票价格的价值可能会影响苹果公司的股票价格。如果我们还使用第二个变量来进行预测,那么 input_dim 将是 2。 batch_size 是在更新权重之前馈入 LSTM 层的观测值的数量。
数据预处理
我们需要格式化数据,使每个输入包含 90 天期间(t-90 到 t-1)的股票价格,目标是时间 t 的价格。我们可以使用基本的 for 循环,如下所示:
hist = []
target = []
length = 90adj_close = aapl['Adj Close']for i in range(len(adj_close) - length):
x = adj_close[i:i+length]
y = adj_close[i+length]
hist.append(x)
target.append(y)
“hist”的每个元素是 90 个项目的列表。既然我们加 1,那么“hist”的第二个元素的最后一项一定等于“target”的第一个元素。我们来确认一下:
hist[1][89] == target[0]
True
“历史”和“目标”是列表。我们需要将它们转换成 numpy 数组,并将目标变量整形为二维数组。
hist = np.array(hist)
target = np.array(target)
target = target.reshape(-1,1)print(hist.shape)
print(target.shape)(1168, 90)
(1168, 1)
由于在神经网络中进行了过多的计算,因此最好将这些值标准化。标准化可以通过一些简单的数学运算来完成,或者可以使用库的预定义函数。我会用 scikit-learn 的 MinMaxScaler 。默认情况下,它将值规范化为范围[0,1]。
我们正在进行一项监督学习任务。我们将使用一些数据来训练该模型,并使用以前未见过的数据来测试其性能。因此,我们需要将数据分成训练集和测试集。为了获得准确的性能结果,模型不应该有任何关于测试集中数据的线索。在标准化数据时,我们也应该记住这一点。我们首先需要拆分数据。然后分别应用归一化。
#train/test splitX_train = hist[:1138]
X_test = hist[1138:]y_train = target[:1138]
y_test = target[1138:]
我们以这样一种方式分割数据,即用 1138 天的数据训练模型,并用随后 30 天的数据进行测试。
我们现在可以进行标准化了。我们将首先创建一个 MinMaxScaler 对象,并对训练集应用 fit_transform 方法。然后,我们将仅对测试集应用转换方法。进行这种分离是非常重要的。否则,我们将会从测试集中向模型泄露信息。
from sklearn.preprocessing import MinMaxScaler
sc = MinMaxScaler()#train set, fit_transform
X_train_scaled = sc.fit_transform(X_train)
y_train_scaled = sc.fit_transform(y_train)#test set, only transform
X_test_scaled = sc.transform(X_test)
y_test_scaled = sc.transform(y_test)
数据预处理的最后一步是将输入转换为三维数组,因为 LSTM 接受三维数组作为输入。
X_train_scaled = X_train_scaled.reshape((len(X_train_scaled), length, 1))X_test_scaled = X_test_scaled.reshape((len(X_test_scaled), length, 1))
型号
我们将使用 Keras 的 LSTM 层实现神经网络,Keras 是 TensorFlow 的高级 API。
import tensorflow as tf
from tensorflow.keras import layers
我们将创建一个有 4 个 LSTM 层和一个密集层的序列模型。
model = tf.keras.Sequential()model.add(layers.LSTM(units=64, return_sequences=True, input_shape=(90,1), dropout=0.2))model.add(layers.LSTM(units=32, return_sequences=True, dropout=0.2))model.add(layers.LSTM(units=32, return_sequences=True, dropout=0.2))model.add(layers.LSTM(units=16, dropout=0.2))model.add(layers.Dense(units=1))model.summary()
有一些要点需要记住:
- 如果一个 LSTM 层后面是另一个 LSTM 层, return_sequences 参数必须设为真。
- 输入 _ 形状参数只需要为第一个 LSTM 层指定。对于其他层,模型根据前一层的输出计算出输入。
- Input_shape 参数是一个包含时间步长和 input_dim 的元组。Batch_size 是在训练期间指定的。
- 单位参数是一层中使用的节点数。没有严格的规则来定义最佳节点数。
- 剔除用于防止模型过拟合。
- 密集图层的单位应为 1,因为它被用作输出图层。
我们现在可以通过指定优化器和损失函数来编译模型。
model.compile(optimizer='adam', loss='mean_squared_error')
然后,我们训练模型。
history = model.fit(X_train_scaled, y_train_scaled,
epochs=30, batch_size=16)
我们已经讨论了 batch_size。Epochs 表示整个数据集输入神经网络的次数。
你在每个时期都会看到数字 72。它来自训练点数除以批量大小。X_train_scaled 有 1138 个数据点。批量大小为 16。1138/15=71.125,所以它在 72 个周期内完成。
该模型实现了 0.0017 的 MSE。让我们看看它是如何通过 30 个时代发生变化的。
loss = history.history['loss']
epoch_count = range(1, len(loss) + 1)plt.figure(figsize=(12,8))
plt.plot(epoch_count, loss, 'r--')
plt.legend(['Training Loss'])
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.show();
该损失呈下降趋势,在第 25 个纪元后低于 0.002。然而,该模型尚未收敛。如果我们做更多的纪元,损失似乎会继续减少。让我们试试 50 个纪元。
现在亏损在 0.001 以下。请注意,不断减少损失并不总是最佳做法。过了一段时间后,我们可能会有一个过度拟合的模型,它过于关注训练集,而不是很好地推广。
是时候做预测了。我们将尝试预测未来 30 天的股票价格趋势。请记住,我们的目标是预测趋势,而不是实际价格。
pred = model.predict(X_test_scaled)
pred_transformed = sc.inverse_transform(pred)y_test_transformed = sc.inverse_transform(y_test_scaled)plt.figure(figsize=(12,8))
plt.plot(y_test_transformed, color='blue', label='Real')
plt.plot(pred_transformed, color='red', label='Prediction')
plt.title('Apple Stock Price Prediction')
plt.legend()
plt.show()
尽管这些值不完全匹配,但我们能够预测 30 天内的总体趋势。该模型在几天后的第 7 天到第 10 天之间对下降做出反应。然后它赶上了上升趋势。
有许多方法可以尝试改进该模型的性能。您可以通过调整获得更好的结果:
- 层数
- 一层中的节点数
- 时间步数
- 辍学率
- 时代数
- 批量
感谢您的阅读。如果您有任何反馈,请告诉我。
使用公共房地美数据预测不良住房贷款——使用不平衡数据的教程
机器学习能阻止下一次次贷危机吗?
房地美(Freddie Mac)是一家美国政府支持的企业,购买单户住房贷款,并将其打包作为抵押贷款支持证券出售。二级抵押贷款市场增加了新住房贷款的资金供应。然而,如果大量贷款违约,这将对经济产生连锁反应,就像我们在 2008 年金融危机中看到的那样。因此,迫切需要开发一种机器学习管道来预测贷款发放时贷款是否会违约。
在这个分析中,我使用了来自房地美单户贷款级别数据集的数据。数据集由两部分组成:(1)贷款发放数据,包含贷款开始时的所有信息;以及(2)贷款偿还数据,记录贷款的每次支付以及任何不利事件,如延迟支付甚至抛售。我主要使用还款数据来跟踪贷款的最终结果,使用原始数据来预测结果。原始数据包含以下几类字段:
- 唯一标识符:贷款 _ 序列号
- **借款人财务信息:**信用评分、首次购房者标志、原始债务收入比(DTI)、借款人数、居住状况(主要住所、投资或第二套住房)
- 贷款信息: First_Payment (date),Maturity_Date,MI_pert (%抵押担保),原始 LTV(贷款与价值)比率,原始组合 LTV 比率,原始利率,原始未付余额,PPM(提前还款罚金抵押)标志,贷款目的(购买与再贷款),原始贷款期限,超符合标志
- **房产信息:**单元数量,房产类型(公寓,独栋住宅等。)
- 位置: MSA_Code(大都市统计区),属性 _ 州,邮政编码
- **卖家/服务商信息:**渠道(零售、经纪等。)、卖家名称、服务商名称
传统上,次级贷款被定义为信用分数为 600 或 650 的任意分界点。但这种方法是有问题的,即 600 的临界值仅占不良贷款的约 10 %, 650 仅占不良贷款的约 40%。我的希望是,原始数据的附加特征会比信用评分的硬性限制表现得更好。
按好贷款与坏贷款分组的信用评分累积直方图
因此,该模型的目标是根据贷款发放数据预测贷款是否为坏账。 *在这里,我定义“好”贷款是指已经全部还清的贷款,“坏”贷款是指因任何其他原因而终止的贷款。*为简单起见,我只检查 1999 年至 2003 年间产生的贷款,这些贷款已经终止,因此我们不必处理中间状态的持续贷款。其中,我将使用 1999-2002 年的贷款作为训练集和验证集;以 2003 年的数据作为测试集。
这个数据集的最大挑战是结果有多不平衡,因为不良贷款仅占所有终止贷款的大约 2%。在这里,我将展示解决这个问题的四种方法:
- 欠采样
- 过采样
- 把它变成一个异常检测问题
- 使用不平衡集成分类器
让我们开始吧:
过度/欠采样前后的不良贷款计数
1。 欠采样
此处的方法是对多数类进行子采样,使其数量大致与少数类相匹配,从而使新数据集达到平衡。在测试的分类器(*)列表下,这种方法似乎在 70–75%的 F1 分数下工作正常。欠采样的优势在于,您现在处理的数据集更小,这使得训练速度更快。另一方面,由于我们只是从良好贷款中抽取了一部分数据,我们可能会遗漏一些可以定义良好贷款的特征。
(*)使用的分类器:SGD、随机森林、AdaBoost、梯度增强、来自上述所有分类器的硬投票分类器以及 LightGBM
2。过采样
与欠采样类似,过采样意味着对少数群体(在我们的例子中是不良贷款)进行重采样,以匹配多数群体的数量。这样做的好处是,您可以生成更多的数据,因此您可以训练模型,使其比原始数据集更适合。然而,缺点是由于较大的数据集而降低了训练速度,以及由于更同质的不良贷款类别的过度表现而导致的过度拟合。对于房地美数据集,许多分类器在训练集上显示出 85-99%的高 F1 分数,但在测试集上测试时崩溃到 70%以下。唯一的例外是 LightGBM ,其在所有训练、验证和测试集上的 F1 分数都超过了 98%。
欠采样/过采样后分类器的性能
欠采样/过采样的问题在于,对于现实应用来说,这不是一个现实的策略。不可能在贷款开始时预测贷款是否是不良贷款。因此,我们不能使用上述两种方法。作为旁注,当用于评估不平衡数据时,准确性或 F1 分数会偏向多数类。因此,我们将不得不使用一种叫做平衡准确度得分的新指标来代替。虽然我们知道准确度分数是(TP+TN)/(TP+FP+TN+FN),但是平衡的准确度分数对于类的真实身份是平衡的,使得(TP/(TP+FN)+TN/(TN+FP))/2。
3。将其转化为异常检测问题
在很多时候,不平衡数据集的分类实际上与异常检测问题没有什么不同。“阳性”案例非常罕见,因此在训练数据中没有得到很好的代表。如果我们可以使用无监督学习技术将它们作为离群值来捕捉,这可能会提供一种潜在的解决方法。对于房地美的数据集,我使用隔离森林来检测异常值,并查看它们与不良贷款的匹配程度。不幸的是,平衡准确度分数仅略高于 50%。也许这并不奇怪,因为数据集中的所有贷款都是批准的贷款。机器故障、停电或欺诈性信用卡交易等情况可能更适合这种方法。
4。使用不平衡集成分类器
所以这是银弹。因为我们无论如何都在使用集成分类器,所以我们实际上可以使用那些被设计来处理不平衡数据的分类器的版本。对于房地美的数据,我使用了平衡的 bagging 分类器、平衡的随机森林分类器和来自包不平衡学习的简单集成分类器;以及参数为 is_unbalanced = True 的 LightGBM 分类器。在大约 70%的平衡准确度分数下,性能有所下降。有了 LightGBM 的最佳模型,我可以标记 75%的不良贷款,代价是将 25%的良好贷款标记为误报。如果我严格根据信用评分截止值标记不良贷款,为了实现 75%的召回率,我将截止值设置为 720,我们将有 47%的误报率。**因此,与严格的截止方法相比,我将假阳性率降低了将近一半。**尽管当前的假阳性率仍有改进的空间,测试数据集中有 130 万笔贷款(相当于一年的贷款),贷款规模中值为 152,000 美元,但潜在的好处可能是巨大的,值得为此带来的不便。被标记为有希望的借款人将在金融知识和预算方面获得额外的支持,以改善他们的贷款结果。
无过采样/欠采样的不平衡分类器的性能
轻 GBM 对所有原始数据的混淆矩阵
包含所有要素的原始数据集上的轻型 GBM 模型的要素重要性表
我在开头问的另一个问题是,除了信用评分之外的特征对我们的模型有多大贡献?让我们关注用所有原始数据训练的不平衡光 GBM 模型的特征重要性。虽然信用评分仍然是最重要的特征之一,但它的相对重要性并不是压倒性的。当它从模型中删除时,它对模型的影响是最小的,性能下降 1-2 个百分点。地理信息是另一个最重要的特性。但考虑到我国中产阶级化的历史,我测试了如果我删除房产的地理空间信息,模型的性能是否会下降。我在这一点上相当激进,我不仅去掉了显而易见的内容,如邮政编码和财产状态;还包括与位置信息稍微相关的特征,例如服务者姓名。这导致了大约 3%点相当显著的性能下降。由于房地美本身并不决定贷款审批,我认为最好保留模型中的所有功能。
总之,我演示了四种不同的方法来处理不平衡的数据集。未来的几个方向包括优化一些分类器以提高性能,建立一个管道来训练和测试每年贷款数据的连续流,以及尝试不良贷款的不同定义,如超过 3 个月的逾期付款。如果你对这个作品的细节和我在媒体、上的其他作品感兴趣,请在、和 Github 、、上找到我的笔记本。也可以在LinkedIn上联系我。
预测华盛顿特区的自行车共享需求(下)
马库斯·温克勒在 Unsplash 上的照片
2017 年,我写了这篇帖子,在那里我用 Prophet 预测了华盛顿特区的自行车共享需求。当时,Prophet 只有几个月大,它只能将时间序列分解为趋势、季节性和假日部分。从那以后,Prophet 得到了很大的改进,并继续成为时间序列预测的默认技术之一。
Prophet 是一个用 R 和 Python 实现的预测程序。它速度很快,并提供完全自动化的预测…
facebook.github.io](https://facebook.github.io/prophet/)
在这篇文章中,我将继续我以前的工作,并在模型中加入一些天气和环境变量。这应该提供额外的信息,可以用来改善我们原来的预测。数据集将与第一部分相同,取自华盛顿特区一个与预测自行车共享需求相关的 Kaggle 竞赛。
在整篇文章中,我将扼要重述第 1 部分的内容,以便读者更容易理解。这个项目的所有代码都可以在这个 repo 中获得。
数据
数据集包含几个特征,包括:
- 日期时间(YYYY-MM-DD HH:MM:SS)
- 假日(作为一个二元变量,表示该日是否被视为假日)
- 天气状况(一个有 4 类的分类变量)
- 温度/表观温度(摄氏度)
- 相对湿度
- 风速
- 自行车租赁总数
该数据集提供了跨越两年(2011 年和 2012 年)的每小时租金数据。训练集由每个月的前 19 天组成,而测试集是从每月的第 20 天到月末。目标是预测测试集覆盖的每个小时内租赁的自行车总数,只使用租赁期之前可用的信息。
因为数据来自一场比赛,测试集不包含租赁自行车的总数,所以对于这个实验,它不能用于评估模型的性能。此外,Prophet 最适合处理每日周期数据,因此我必须将数据从每小时转换为每天。
在第 1 部分中,我考虑的特征是日期时间、假期和自行车租赁总数。这次我还将包括天气、表观温度、相对湿度和风速。选择是主观的,因为我认为这些是人们选择骑自行车出行的主要驱动因素。
设置
首先,我决定将竞赛网站提供的训练集分成三部分:2011 年全年用于模型拟合,2012 年上半年作为参数调优的验证集,2012 年下半年作为检验所选模型性能的测试集。虽然我们没有整个月的数据,但这似乎不是 Prophet 软件包的问题,因为它对丢失的数据很健壮。
对于数据操作,我广泛使用了 tidyverse 工具,自上一篇文章以来,这些工具也有了很大的改进。假设我们将每小时的数据汇总为每天的数据,我将所有外部特性的平均值作为每天的数据。
假日特性是一个二元变量,它只告诉我们日期是否是假日,但不提供它所指的是哪个假日的信息。对于第 1 部分,我必须做一些研究来确定这些日期,因为 Prophet 使用这些信息来正确地确定特定节日的贡献(这非常有用)。我用来获取这些信息的网站已经不存在了,但是我几年前写的代码仍然适用于 2011 年和 2012 年的美国联邦假日。
最后,需要一些调整的参数与我们希望给予模型的灵活性有关,以适应变点、季节性、节假日和外部特征。进行非详尽的网格搜索只是为了对参数的最佳值有一个模糊的概念。我不得不限制可能的值,因为旧代码在网格搜索过程中遇到了问题。此外,这次我将回归变量 _ 先验 _ 尺度作为一个超参数。如果用户对手头的任务有一些专业知识,可以跳过这整个步骤。
模型
使用平均绝对误差(MAE)作为性能度量来执行网格搜索,以识别最佳参数。考虑到我们包括外部信息,模型设置略有不同。首先,需要初始化 Prophet 模型,然后在拟合模型之前,需要手动添加每个外生特征。更多详情,请查看文档。
找到的最佳参数是:
- 运载能力:8000 人
- 变点先验标度:0.5
- 季节性先验标度:10
- 假日优先比例:1
- 回归变量先验标度:10
然后使用这些参数用训练集和验证集重新训练该模型。完成后,Prophet 提供了一个功能,可以绘制出时间序列中的不同部分。这些显示如下,可以观察到一些有趣的事情。首先,似乎有些节日会增加租赁数量(如独立日——7 月 4 日),而其他节日则会减少(如元旦)。第二,一旦我们纳入外生信息,租金记录较少的一天是星期一。此外,随着周末的临近,租金往往会上涨,周六达到最高。最后,在一年中,4 月至 6 月的租赁数量往往较高,冬季月份会有所减少。剧情也包括了外生特征的综合贡献,但是这个更难解读。
使用 Prophet 软件包识别的时间序列组件。
最后,我们可以在测试集上评估模型的性能,并将其与第 1 部分中训练的不考虑外部信息的模型进行比较。下表显示了结果,表明引入外源信息确实减少了【RMSE】(减少了 16%)【MAE】(减少了 23%),以及【MAPE】(减少了 19%)。
下面是两个比较两个模型的图。在这里,从视觉上更容易看出,引入外源信息确实提高了模型性能。
使用 Prophet 软件包对自行车共享需求时间序列进行建模和预测。黑点对应于训练集,绿色点对应于验证集,红色点对应于测试集。蓝线及其周围的阴影对应于置信区间为 80%的预测。包含外部信息可以提高模型性能。
评论
这只是原始帖子的扩展,仍然有几件事情可以考虑(可能是第 3 部分):
- 使用原始的每小时数据集,而不是每天数据集。我尝试这样做,但注意到 Prophet 预测负值,即使我在逻辑模型中指定了零值下限。我想知道为什么会这样…
- 将其他外生特征合并到模型中。此处介绍的功能选择是主观的,绝不应被视为唯一的选择。一些功能工程可以帮助获得更好的性能。
- 为超参数调整执行贝叶斯优化。这里提出的网格搜索只是获得一些(初始)好的超参数的一种快速方法。
- 为正确的模型选择执行模拟历史预测。Prophet 提供了一个有趣的诊断工具,可以用来更深入地研究模型性能。
- 获取参数系数。Prophet 是一个很棒且简单易用的工具,但由于其简单性,用户很难获得参数系数。当一个模型被拟合时,Prophet 返回一个包含大量元素的列表,其中一个是另一个名为 params 的列表,它包含模型中的参数值。除非深入探究,否则很难猜测哪个参数对应哪个特性。如果你富有冒险精神,你会发现 Prophet 在 Stan 中构建了模型,这是一种用 C++编写的用于统计推断的概率编程语言。如果你继续下去,你最终会发现有另一个 R 包叫做 rstan ,一旦你决定从后验分布中采样(而不是优化)来释放概率编程的全部力量,它将允许你使用一堆不同的函数来评估模型和参数的训练。
- 使用 dyplot.prophet 探索预测。Prophet 还提供了一个不错的功能,允许您与您的预测进行交互。它使用了 dygraphs ,结果相当有用。
使用 Prophet 软件包对自行车共享需求时间序列进行建模和预测。一旦选择了超参数,黑点对应于训练集。蓝线及其周围的阴影对应于置信区间为 80%的预测。
这就是我第二部分的内容。尽管如此,仍有许多东西可以考虑,新的工具可以使用,但这将是另一个时间。
用线性回归预测波士顿房价
线性、多元回归和正则化(LASSO、岭回归)
线性回归:理论与应用
来源: Pixabay 经【pexels.com】T2
介绍
什么是线性回归?它是一种预测性建模技术,可以发现自变量和因变量(连续变量)之间的关系。自变量(iv)s 可以是分类的(如美国,英国,0/1)或连续的 (1729,3.141 等),而因变量(dv) s 是连续的。底层函数映射 iv 和 dv 可以是线性、二次、多项式或其他非线性函数(如逻辑回归中的 sigmoid 函数),但本文讨论的是线性技术。
回归技术在房地产价格预测、金融预测、交通到达时间(ETA)预测中被大量使用。
来源:阿尤什·潘特经TowardsDataScience.com
变量的类型
分类:取不同的值:垃圾邮件/非垃圾邮件、糖尿病+ve/-ve
连续:可以取无限个值,如金钱、时间、重量。
依赖:实验结果,本博客房屋价值
独立变量:与研究者的行为无关的变量。面积、位置、卧室数量等。
如需更多参考,请查看: statistichowto 。
线性回归技术
1.普通最小二乘法(OLS)
在 OLS 中,目标是通过数据点找到最佳拟合线。最佳拟合线通过最小化距离预测线的数据平方距离的总和获得。这是一个无偏估计(尽管方差没有最小化),因为它最小化了该观察空间中数据集的偏差。
最小二乘法的目标
关键假设:
(一)OLS 假设 dv 和 iv 成线性关系。
(ii)假设同质性。因此,它患上了**。简而言之,就是随着 iv 的值的增加,因变量相对于自变量的可变性。数据散点图中的圆锥形表示异方差*。*
异方差,来源: statsmakemecry
例如,仅通过查看房屋面积(1 个变量)、房屋面积和位置(2 个预测变量)来预测房价。
2.多元案例
在多变量 OLS 中,目标函数与单变量 OLS 相似。
多元最小二乘法的目标
多元 OLS 的关键问题是 多重共线性 。这是两个或更多预测因子彼此高度相关的情况(1 表示 100%相关,0 表示不相关)。
在具有多重共线性的数据中,OLS* 不会产生一个好的估计值,因为方差项的误差很大,而 OLS 只会最小化偏差误差而不是方差导致的*误差。因此,我们采用正则化技术来最小化由于方差引起的误差,并改进我们的模型。**
3.里脊回归
如上所述,当数据遭受多重共线性时,像 OLS 这样的无偏估计量由于方差项而具有较高的误差。岭回归通过引入具有 L2 正则化项的参数α来解决这个问题,从而除了最小平方损失之外还缩小了权重 W 。
岭回归的目标
除了同方差之外,它与 OLS 有相似的假设。岭回归缩小了不高度相关的系数的值**(不完全为零)**。
4.套索回归
类似于岭回归,它通过正则化来解决多重共线性问题。将具有 L1 范数的收缩参数引入权重 W 有助于减少 LASSO 回归中的方差误差。
套索回归的目标
拉索做了与 OLS 相似的假设,除了的同质性。* LASSO 将非高度相关的系数值缩小到零。*
预测波士顿房价
让我们开始编写线性回归模型的代码。在本帖中,我们将使用波士顿房价数据集。它由 506 个样本组成,有 13 个特征,价格从 5.0 到 50.0 不等
使用最小二乘法的单变量模型
具有一个特征(13 个特征中的第 5 个)的线性回归,MSE 为 54.926
让我们画出最佳拟合线
最小二乘法最佳拟合直线
你可以清楚地看到,我们有一个使用 sklearn 和几行代码的预测模型。对于一个特性来说还不错。不过,我们可以显著提高 54.926 的均方误差(MSE)。
多元最小二乘法
类似于单变量方法,除了我们在 X 的所有特征上训练,而不是一个特征。所以只需复制前面的代码片段和注释行 3。我们需要检查 MSE 和回归系数来确定最佳拟合线,因为绘制 13 维变量还不是主流:/
显然,我们的模型将 MSE 指标从 54.926 提高到 37.894。由于有 13 个特征,很有可能出现多重共线性*。为了验证这一点,我们将看到一个新的统计数据,叫做方差膨胀因子(VIF) 。*
VIF 什么 via GIPHY
VIF 估计由于多重共线性引起的回归系数的膨胀。Vif 的计算方法是采用一个预测值,并将其与模型中的所有其他预测值进行回归。VIF 的数值给出了每个系数的方差膨胀的百分比。根据经验,VIF 大于 5.0 表明变量高度相关。因此,对于一个好的预测模型,必须去除那些高度相关的变量。
计算 VIF 以检查多重共线性
除了 3 个特征外,所有特征的 VIF 都非常高(VIF 超过 5.0 被视为高)。因此,我们使用岭和套索回归的正则化模型应该比普通的最小二乘法更好地处理这些数据。
里脊回归
两个要点 : MSE 减小,岭回归将 X 的系数挤压到接近零。
套索回归
MSE 从普通最小二乘法中的 38.894 进一步提高到 21.669。那是相当大的胜利。很明显,LASSO 将几个特征的系数推到了零。
结论
总而言之,我们看到了如何使用 sklearn 库在几行代码中实现线性回归。
- 获得最佳拟合线的普通最小二乘法在许多情况下效果很好,而且非常直观。
- 然而,当数据遭受多重共线性或异方差时,我们需要使用正则化技术来执行回归。
- VIF 是一种可用于检测预测变量中多重共线性的度量。
- 山脊线和套索线在执行回归建模方面做得很好。
快乐学习:)
附加源
用神经网络预测加州野火的规模(上)
从问题到解决方案构建机器学习项目
“你可以环游世界,但没有什么比得上黄金海岸.”—凯蒂·佩里
加利福尼亚是个美丽的地方。
湾区起伏的群山(来源:me)
鉴于其干燥、阳光充足的地中海气候,它允许一些最好的户外活动。
但是,由于这些自然因素和随之而来的人类活动的存在,该州也有超过 200 万个家庭处于高度或极端的野火损害风险中。仅在 2018 年,加利福尼亚州就有超过【2018 万英亩被野火烧毁。
当大火以这种规模燃烧时,它不仅会对着火地点的人构成直接威胁,还会对几英里外的人造成广泛的影响,就像我亲身经历的 2018 年营地大火一样:加州最致命,最具破坏力的野火。
浓烟从该州东北部吹向海湾地区,关闭了学校,造成当地缺乏阻挡污染物的 N95 口罩。对于那些受影响的人来说,最好的情况是与户外隔离两周,就像我一样,但在最坏的情况下,这意味着悲惨的死亡,被迫无家可归,以及对不幸者来说整个社区的破坏。
旧金山市中心,尽管大火在东北方向约 200 英里处(来源:me)
呀!当时圣何塞的真实照片(来源:我)
获得可以提供早期风险指示的工具非常重要,因为它们可以让官员做出更加知情和主动的决定,帮助社区为这些潜在的灾难性事件做好准备。
因此,我想看看我们是否可以使用历史野火数据、统计数据和现代机器学习技术来构建一个模型,该模型可以预测野火事件中被烧毁的土地的大致面积,并希望生产这样一个系统来实时帮助官员。
在我继续之前,我想提一下,这个项目目前是我以前与我的前研究伙伴 Michael L .一起进行的本科生研究的唯一延续,Michael l .在我们构建基于决策树的风险分类模型和深度回归模型(就像本系列中将要探讨的那些模型)时,帮助我们制定问题、设计数据模式并指导模型分析。
数据源
仅使用与每个事件相关的时间和空间的气象(气候)数据是模型输入的合理起点,因为温度、风速和湿度等因素已通过火灾指数在事件预测中使用多年。拥有一个基于这些输入的工具可以让消防专家感觉到一个新的火灾事件会有多深远后点火。我们将讨论模型开发中可能考虑的其他潜在有用的因素,并在稍后迭代不同的模型架构时尝试将它们纳入进来。
为了得到对训练有用的初步数据集,我们必须结合两种不同的数据源:野火数据和气候数据。
Wildfire 数据源
通过一些搜索,我发现了一个由美国地质调查局(USGS)运行的 REST API,这是一个致力于研究美国自然灾害的组织。该 API 为用于追踪实时野火事件的 ArcGIS 地图系统提供支持,并显示关于这些事件的有用信息,包括每个火源的发现日期、纬度、经度和燃烧区域。该 API 在公开,涵盖了从 2002 年开始的事件,并在 2019 年积极更新。
气候数据源
假设 USGS API 获得的每个野火事件都包含一个相应的时空(时间和空间)坐标,我们应该能够通过一些气象服务将每个坐标映射到追溯检查与每个事件对应的点火现场的场景。
在搜索和使用不同访问限制的不同气候数据源后,我偶然发现了黑暗天空的时间机器 API 。虽然不是完全自由的( 也不是永恒的 😢),这个 REST API 允许用户查询每个小时观察到的天气情况,包括由纬度、经度和历史日期描述的给定时空坐标的温度、风速和湿度。因此,我们可以通过查询 USGS API 来获得火灾事件的发现日期、纬度和经度,提出一个时间范围来表示火灾事件的上下文和持续时间,然后将该信息作为输入提供给向 Dark Sky API 发出的请求。
太好了!现在我们已经有了数据源,并且知道我们想要用它们完成什么,让我们看看我们需要什么工具来获得实际的数据。
数据技术栈
决定,决定。
网络自动化
由于我们需要发出的 API 请求的数量,并且考虑到每一个“黑暗天空”请求都会导致超出特定请求数量的实际金额,我决定使用我为 web 自动化选择的武器:Node.js。虽然像 Python 这样的语言也可以很好地工作,但是创建像 web 请求这样的异步任务链最好在节点环境中完成,我们将在稍后创建数据转换管道时看到这一点。
太好了,我们已经建立了获取所需数据的工具,但是我们将在哪里存储这些 API 请求的结果呢?我们需要一个数据库!
数据库ˌ资料库
由于每个 API 请求可能会生成一个 JSON 响应对象,该对象因字段名称而异,即具有不同的模式,自然选择是使用基于文档的 NoSQL 解决方案。此外,由于在发出请求之前,我们无法完全了解这些响应对象的结构,因此我们应该使用无模式的解决方案,这样我们就可以转储所有的响应对象,然后分析并清除任何意外的属性排列或退化的响应。(注意:这是一个方便的选择,先验地找到所有理论上的属性变化是非常耗时的,并且没有很大的回报,因为不使用某些数据的成本是最小的)由于其易用性、大量的社区支持以及与 Node 的强大集成,MongoDB 似乎是正确的选择。
数据来源✔Automation 工具✔数据库✔
让我们设置使用这些工具的环境。
环境
在进行这个项目时,我碰巧在桌面环境中使用了MongoDB Community Server 4.0、 Node.js v8.11.3 和 Windows 10,所以你应该可以顺利地完成安装。一旦你安装了这些,我们将直接从命令行工作,并遵循自述文件。
首先,我们确保启动 MongoDB 服务器(这将占用一个终端窗口)。
> mongo
克隆项目后,在 scripts 文件夹内的新终端中,我们将使用 npm 安装项目依赖项。这可能需要一些时间。
> npm install
现在我们将设置一个环境文件,这样我们就可以从剩余的代码中抽象出一些常用的变量,这些变量将根据部署模式而变化。确保用本地服务器实例的 URL 替换您的 _MONGODB_URL,很可能是“mongodb://localhost:27017”。如果您选择部署到远程 MongoDB 服务器,请确保相应地更改这个 URL。另外,一定要用注册访问 Dark Sky API 后获得的 API 密钥替换 YOUR_DARKSKY_API_KEY。
> touch .env
> echo export PRIMARY_MONGODB_URL=YOUR_MONGODB_URL >> .env
> echo export DARKSKY_API_KEY=YOUR_DARKSKY_API_KEY >> .env
> source .env
数据来源✔Automation 工具✔数据库✔环境✔
好吧,让我们看看代码。
数据收集代码
我们将从 USGS REST API 收集历史野火事件开始。
野火数据
下面是我们将要查询的基本 URL:
API 通过一个整数 id 来区分每年的历史 wildfire 事件数据集,该整数 id 标识保存该数据的 ArcGIS 图层,从 10 开始表示最近的一年,一直增加到最早的 2002 年。例如,在撰写本文时,id=10 的层保存 2019 年的火灾数据,id=11 的层保存 2018 年的火灾数据,…,id=27 的层保存 2002 年的火灾数据。我们可以将这些 Id 硬编码到一个数组中,遍历每个条目,用该 id 替换查询 URL 的${ year id }参数,然后对新的查询 URL 执行 API 请求,从而将每个 id 映射到一个响应对象,并获得每年的 fire 数据。
我们现在可以使用结果数组来填充我们的数据库。首先,我们使用之前设置的 PRIMARY_MONGODB_URL 字段连接到数据库,然后在成功连接后执行上面的代码。一旦 API 请求完成,响应对象的结果数组将在数组 mapRes 中。我们可以使用名为 saveToDBBuffer 的函数将该数组作为集合“原始”存储在数据库“arcgis”中。整个过程被包装在一个 Promise 对象中,并由 downloadRaw 函数返回。
使用 Promises,我们可以将异步操作(如处理网络请求)封装到直观的同步代码块中,然后我们可以对这些代码块进行排序,以构建可以有效记录和测试的数据转换管道。在成功处理时,我们解决承诺,在不成功处理时,我们拒绝承诺,传递失败的流水线步骤的错误状态。当向数据处理流水线添加额外的阶段时,建立这样的结构的价值将会显现。
我们在这里所做的是模块化的管道异步部分(例如,构造和导出 wildfireStages Promise ),允许任何阶段从另一个脚本导入到 pipeline.js 中的执行序列(导出数组)中。
代表我们管道的承诺数组可以通过 require()导入。/pipeline)并由我们的主脚本执行…
…现在,每当我们想要重现流水线时,例如当我们需要更多数据时,就可以自动运行。
太棒了。
正如你在 pipeline.js 中看到的,我们还有另外两个承诺:climateStages 和 combineStages。这些阶段将在处理 wildfireStages Promise 后利用我们的数据库的更新状态,因此在导出的数组中排序。它们分别下载每个事件的气候数据,并将生成的数据集加入到单个训练集中。
执行 wildfireStages 序列的结果是 arcgis 数据库中的一些新集合,这些集合包含在我们将原始数据集转换为更有用的工作集时有用的快照。最终的集合是“训练”集合。现在让我们来看看气候数据。
气候数据
与我们使用 USGS API 将年份映射到火灾事件响应对象类似,我们将使用 Dark Sky API 将 arcgis training 集合中的火灾事件对象的属性映射到气候数据响应对象,只是现在将结果响应对象直接流式传输到数据库,而不是下载到内存中的缓冲区。这样做是为了防止数据丢失,以防我们从 API 获得大量数据,而无法将它们全部存储在内存中。
通过为来自训练集合的火灾事件创建一个读取流,我们启动了流式传输过程,将每个火灾事件通过管道传输到一个转换流,该转换流为该事件执行一个黑暗天空 API 请求,然后将结果响应对象通过管道传输到一个转换流,该转换流将文档上传到气候数据库。getClimateDataEach 函数通过生成一个由 CLIMATE_CONFIG 对象定制的转换流对象来开始这个过程。在这个转换流对象中,我们执行 getHistoricalClimateDataEach 函数,生成结果气候响应对象“res”,然后将它推送到管道中的下一个转换流对象。下一个转换流对象由数据库配置对象定制,并且是 saveToDBEach 的结果。在返回的流对象中有执行数据库上传的代码。
在 getHistoricalClimateDataEach 函数中,使用 CLIMATE_CONFIG 对象中指定的每小时或每天的时间间隔,围绕 wildfire 事件的点火时间构建一个时间窗口。得到的开始和结束日期然后被传递给下载函数,该函数从开始时间开始为每个时间单位执行 API 请求,并向结束时间递归(基本情况),将结果聚集到结果对象中。
酷!现在,我们有了来自 arcgis training 集合的每个火灾事件的气候数据,这些数据保存在气候数据库的“training”集合中。我们只需要将我们创建的两个数据库中的两个训练数据集合并成一个主数据集,用于模型开发。
培训用数据
我们可以从 arcgis training 集合中加载每个火灾事件,加载由“事件”属性链接的每个相应的气候响应对象,然后连接所需的属性并格式化列以适应典型的关系模式。我们很快就会看到,拥有一个关系模式将使数据集易于解释并方便地导出到 Python 中。
主数据集的子集
对于每个火灾事件,列名标有气候属性和表示相对于该火灾事件点火时间的小时的索引字符串,例如,温度 _336、温度 0 和温度 336 分别表示火灾点火时间之前 336 小时、准确时间和之后 336 小时的点火地点的温度。点火时间前后 14 天的每小时测量给出了每个气候特性点火前后的 336 个数据点,以及代表点火时间的每个气候特性的附加数据点。
好了,我们拿到数据了。现在,在本系列的第 2 部分中,让我们看看如何使用这个数据集来构建一些回归模型。(即将推出!)
利用 K 近邻算法预测心血管疾病
用机器学习的力量预测和预防疾病
图片来源:https://unsplash.com/photos/4R6pg0Iq5IU
根据维基百科,心血管疾病是全球死亡的首要原因[1]。它是不同心脏和血管的组合,如心脏病、心脏病发作、中风、心力衰竭、心律失常、心脏瓣膜问题等。高血压、高胆固醇、糖尿病、缺乏运动是增加患这种疾病风险的一些主要原因。通过最大限度地减少行为风险因素,如吸烟、不健康饮食、饮酒和缺乏锻炼,这种疾病是可以预防的。
如果人们能够在这种疾病转变为更高风险水平之前提前意识到这种疾病,我们就可以在相当大的程度上最小化死亡和高风险水平患者的数量。借助机器学习和高计算能力的发展,推动了医学领域人工智能的指数级发展,人们可以使用这些技术,提出一个模型,进行预测,以确定人们在最早阶段患这种疾病的可能性。
在这篇文章中,提出并实现了一个机器学习模型,通过关注从在线数据集收集的事实信息、医疗检查结果和患者信息等因素来确定一个人是否患有这种疾病的可能性[2]。k 近邻算法是一种众所周知的和性能良好的分类算法,被用来实现这个模型。
算法选择
k 最近邻是一个简单的算法,但在实践中非常有效,它存储所有可用的案例,并基于相似性度量对新数据或案例进行分类。这表明,如果添加到样本中的新点与相邻点相似,则该点将属于相邻点的特定类别。一般来说,KNN 算法用于人们寻找相似物品的搜索应用。KNN 算法中的 k 表示需要预测的新点的最近邻居的数量。
KNN 算法也被称为懒惰学习器,因为它的学习能力非常快,所以模型的学习阶段较少。相反,它会记住训练数据集,所有工作都发生在请求预测的时候。
算法是如何工作的?
图 1:KNN 算法的简单解释。图片作者:Tharuka Sewwandi
当我们使用 KNN 算法向数据集添加新点时,我们可以预测该新点属于哪个类。为了开始预测,我们需要做的第一件事是选择 K 的值。根据图 1,绿色的点属于 X 类,蓝色的点属于 Y 类,黄色的点属于 z 类。当 K=8 时,我们需要选择 8 个相邻点,它们与三角形表示的新点的距离最小。如图 1 所示,当 K=8 时,新点接近一个黄色点、三个绿色点和四个蓝色点。因为我们有大多数蓝点,在这种情况下,我们可以说对于 K=8,新点属于 y 类。
继续向前,如果 K=16,我们必须寻找最接近新点的 16 个不同的点。在计算距离之后,发现当 K=16 时,新点更接近三个黄色点、五个蓝色点和八个绿色点。因此,我们可以说,当 K=16 时,新点属于 x 类。
为了找到最佳 K 值,我们可以使用交叉验证技术来测试 K 的几个值。我将在本文中向您展示如何使用交叉验证技术来找到最佳 K 值。为了找到相邻点之间的最小距离,我们可以使用欧几里德距离或曼哈顿距离。在欧几里得距离中,它将采用欧几里得空间中两点之间的直线距离,而曼哈顿距离将使用它们的绝对差之和来计算实向量之间的距离。
数据收集
为了预测一个人是否患有心血管疾病,数据集选自 Kaggale.com[2]。该数据集包括三种类型的数据,分别是事实信息、医学检查结果(检查特征)和患者给出的信息(主观特征)。此外,数据集中的数据可以分为分类数据和数值数据。原始数据集由 70000 个数据实例和 14 个特征组成,如表 1 所示。
表 1:数据集描述
模型实现
导入库
作为第一步,高性能计算、数据可视化、数据模型分析所需的所有库都导入如下。
导入数据集
心血管疾病的在线数据集[2]作为 CSV 文件导入,以便进行如下分析。由于“id”特性的低重要性,它被从数据集中删除并导入剩余的数据集。
数据可视化
已经进行了图形表示来比较年龄范围和心血管疾病之间的关系。
这段代码将生成一个条形图,x 轴代表年龄,y 轴代表人数。如图 2 所示,红色代表患有心血管疾病的人,而绿色代表未患该疾病的人。
图 2:年龄范围和心血管疾病的比较。图片作者:Tharuka Sewwandi
根据图表可以清楚地看出,年龄在 56 岁到 60 岁之间的人更容易患这种疾病。
此外,从下面的代码片段中进行了分类数据分布的可视化分析。
图 3:分类数据分布的可视化表示。图片作者:Tharuka Sewwandi
如图 3 所示,第一个柱状图代表患有心血管疾病的人群中的分类数据分布,而第二个柱状图代表未患有该疾病的人群中的分类数据分布。上述双变量分析表明,患有心血管疾病的人比其他人具有更高的胆固醇水平和葡萄糖水平。
数据预处理
功能选择
如前所述,由于“id”特征的重要性较低,因此将其从数据集中删除。然而,由于身体质量指数值对心血管疾病有相当大的影响,因此增加了一个称为“bmi”的新特征,作为两个现有特征“身高和“体重”的衍生特征。
在特征选择之后,最终确定的特征集如下图 4 所示。
图 4:最终数据集的统计描述。图片作者:Tharuka Sewwandi
检查空值
使用 pandas 提供的 isnull()函数,可以检查整个数据帧以识别缺失值或 NAN 值。如图 5 所示,通过确认数据集中没有丢失的值,它给出了 false。
图 5:使用 isnull()函数查找空值
数据清理
为了得到准确的数据集,通过数据清理来检测损坏或不需要的记录并删除它们。如图 4 所示,最大身高为 250 厘米,最大体重为 200 公斤,从身高和体重得出的最大身体质量指数值为 298,这两个值在相互考虑和比较时是不相关的。因此,不相关的数据被删除,并通过删除异常值来概括数据集,如下所示。
此外,舒张压(ap_lo)不能超过收缩压(ap_hi ),因为收缩压是心脏跳动时施加的最大压力,而舒张压是动脉在两次跳动之间的压力量。此外,收缩压和舒张压之间的数字差异称为血压,它不能是负值。通过考虑这些事实,来自 ap_hi 和 ap_lo 的异常值已经被去除以消除不准确的血压数据。
在数据清理过程之后,我们可以看到一个更新的数据集,新的计数减少了,相当于 63866 个数据集,身高、体重、ap_hi 和 ap_lo 的最小值和最大值都发生了变化,如图 6 所示。
图 6:清理数据集的统计描述。图片作者:Tharuka Sewwandi
数据标准化
为了确保数据在内部保持一致,以便于相互比较,对数据集中的数字数据进行了数据标准化。
分割数据集
数据分割在两种主要方法下进行,
- 将数据集分割为要素和标注
- 标签——最终选择或需要预测的结果
- 要素-用于预测标注的属性
2.将数据集分为训练数据集和测试数据集
- 训练数据集-用于拟合模型的数据样本
- 测试数据集—用于对最终模型进行评估的样本数据集
构建 K 近邻分类器
开始时,由于我们不知道模型的最佳 K 值,我们可以将“n_neighbors”的值设为 1。然后模型将由训练数据来拟合。
那么我们可以做如下预测。
为了更好地理解分类模型的性能,使用了混淆矩阵,如图 7 所示。
图 7:K = 1 时的混淆矩阵。图片作者:Tharuka Sewwandi
根据混淆矩阵,它将给出如图 8 所示的分类报告,准确度为 60.54。但是这个预测是对 K=1 做的。因此,我们需要选择最佳的 K 值。
图 8:K = 1 的分类报告。图片作者:Tharuka Sewwandi
选择最佳 K 值
肘方法已被用于通过关注准确性和错误率来挑选好的 K 值。
- 根据准确率选择 K 值
这里已经创建了一个存储准确率值的列表,为了考虑 K 值,将从 1 到 40 运行一个循环。在循环内部,它将计算从 1 到 40 的相关 K 的精度值,并将其存储在列表中。从生成的列表中,已经绘制了一个图表来识别最佳 K 值,这将使精度更加稳定。
图 9:准确率与 K 值的关系。图片作者:Tharuka Sewwandi
2。基于误差率选择 K 值
与准确率相同,差错率也计算如下。
图 10:误码率与 K 值的关系。图片作者:Tharuka Sewwandi
根据图 9,可以清楚地看到,在 K>5 之后,准确率将增加,并且不会低于 K>5 的点。类似地,在 K>5 之后,图 10 中的错误率下降,并且从未超过 K>5 的特定点。
因此,在 K 值选择过程之后,我们可以假设 K=5 是一个非常好的值。在选择了最佳 K 值之后,我们可以用等于 5 的新 K 值再次运行该算法。
K=5 的分类报告如下图 11 所示,根据图 11,我们可以看到精度和召回值比 K=1 时有所增加,并且精度值也有所增加。
图 11:K = 5 的分类报告。图片作者:Tharuka Sewwandi
结论
一旦模型的实现完成,我所揭示的是在通过移除异常值来清理不相关的数据之前,模型的准确性是 55%。在清理了体重、身高、ap_hi 和 ap_lo 的数据之后,模型的准确性变成了 60%。但这是针对 K=1 的。在给出模型的最佳 K 值 K=5 后,精确度提高到 63%。这背后的主要思想是该模型为不同的 K 值给出不同的精度水平,并且可以使用模型的分析误差率或精度率来识别最佳 K 值。然而,数据集的大小和特征对模型产生很大的影响,以获得良好的准确率。
然而,KNN 算法不能很好地处理大型数据集,也不能很好地处理高维数据,因为很难计算每个数据点之间的距离,这是该算法的一个缺点。所以,未来我希望将同样的数据集应用到其他分类算法中,找到最合适的算法来提高模型的性能,并在我以后的文章中与大家分享。
最新代码可在 https://github.com/tharuka-amaraweera/Cardiovascular获得
参考
[1] " 心血管疾病",世界卫生组织(世卫组织),2017 年 5 月 17 日,[在线]:https://www . who . int/news-room/fact-sheets/detail/cardio vascular-Diseases-(cvds),[访问日期:2020 年 4 月 26 日]
[2] Onel Harrison,“使用 K-Nearest Neighbors 算法的机器学习基础知识”,2018 年 9 月 11 日,[在线]:[https://towardsdatascience . com/Machine-Learning-Basics-with-the-K-Neighbors-Algorithm-6a 6 e 71d 01761, 访问日期:2020 年 4 月 23 日
预测 Sparkify(一种数字音乐服务)的用户流失
用 PySpark 构建客户流失预测模型。
Sparkify 是由 Udacity 创建的虚拟音乐流媒体服务
Sparkify 是一种虚构的数字音乐服务,由 Udacity 创建,旨在模拟 Spotify 或 Pandora 等现实世界的公司。在 Sparkify 上,用户可以播放免费计划或高级订阅计划的歌曲,这些计划提供了高级功能,并且没有广告。用户可以随时升级、降级或取消他们的服务。每当用户与服务交互时都会生成数据,包括播放歌曲、将歌曲添加到播放列表、用拇指向上或向下对歌曲进行评级、添加朋友、登录或注销、升级或降级等。根据经验,获得一个新客户比保留一个现有客户的成本更高,保持客户满意并识别那些有取消服务风险的用户是服务公司的高优先级任务。
因此,这个项目的目的是分析用户活动日志,并建立一个分类器来识别有可能流失的用户——取消了 Sparkify 音乐流媒体服务。此外,考虑到现实压倒性的流数据,我只使用完整 Sparkify 数据(12GB)的一小部分数据(98MB)进行数据探索和模型开发。最终的模型是使用 Spark 构建的,因此它可以扩展到在分布式集群环境中运行。
用户为什么会流失?
在假设中,用户有更多的互动与更少的摩擦应该是满意和积极的。因此,我们首先要考虑的是数据,churns 用户的行为是否与现有用户不同?
在开始回答业务问题之前,让我们探索一下日志中有哪些内容。
原始数据样本
在这里,我描述了我将用于切片和切块的主要功能:
- userId :用户标识符
- sessionId :日志所属的会话
- 歌曲 :每个用户播放的歌曲
- 注册 :用户注册时间戳
- ts :给定事件的时间戳
- 页面 :用户访问过的页面。
- 等级 :免费或付费
页面字段显示用户可以在 Sparkify 上进行的活动
最后,我们需要定义流失并相应地标记流失用户。流失定义为点击了**cancellation confirmation**
页面的用户。
现在,我们将分而治之,看看搅动者用户的参与度是否低于现有用户。
下面我们深入探讨某些维度,看看流失群体和其他用户之间是否存在差异。
从上面的图表中,我们可以总结出:
- 流失用户在 Sparkify 上的参与度较低。
- 付费用户流失更多。这可能是因为付费服务不够好,或者高级功能让用户感到沮丧。
- 流失用户的社交联系(朋友)较少,降低了他们对平台的忠诚度。
建立机器学习模型来检测客户流失
特征工程
我们根据洞察力准备特征。关于工程过程的细节,请查看我的 Github 笔记本。
创建新功能
- 收听的歌曲总数
- 竖起大拇指的次数
- 竖起大拇指的次数
- 自注册以来的总时间(总寿命)
- 每次会话播放的平均歌曲数
- 添加到播放列表的歌曲数量
- 朋友总数
- 降级(分类变量)
设置目标变量
- 搅拌
建模和评估
最后,我们将所有特征矢量化为一个向量,最重要的是,然后进行标准化,以避免一个较大规模的特征主导整个模型。
数据集分为 60%用于训练,40%用于测试。每个模型都将获得测试集的准确性和 F1 分数。然而,由于被搅动的用户是一个相当小的子集,我将只使用 F1 分数作为优化模型的指标。
在这里,我用下面的超参数调整信息来探索三个模型:
- 随机森林:numTrees[10,20],maxDepth[10,20]
- 渐变增强树:maxIter[10,20],maxDepth[10,20]
- 支持向量机:maxIter[10,20]
绩效结果排名:
1.随机森林:F1 分 0.746,准确率 0.781
2。梯度提升树:F1 得分 0.731,准确率 0.734
3。支持向量机:F-1 得分 0.685,准确率 0.781
我们基于 F1 进行优化,随机森林是最好的模型。
最佳模型的特征重要性
从图表中,我们可以看到总寿命实际上对检测搅动起着非常重要的作用。但这可能会引发一场争论,即自然搅拌的人使用服务的时间更短。然而,也可以解释为,只要用户在平台上保持活跃的时间较长,他们就不容易流失,因为他们已经习惯了流媒体服务。此外,朋友总数很重要,因为我们假设平台上社交联系越多的用户忠诚度越高。每次收听的总歌曲数和平均播放的歌曲数衡量了用户的参与度和活跃程度,也有助于表明用户是否会流失。降级并不能有效预测用户流失,这可能是因为用户仍然留在他们的免费帐户中,尽管他们对付费计划并不满意。
结论和今后的改进
在这个项目中,我实现了一个模型来预测 Sparkify 音乐流媒体服务的客户流失。我研究了数据集,以了解哪些特征可能有用,并为建模过程创建特征。在这里,我评估了 3 个模型:随机森林(RF),梯度推进树(GBT),和支持向量机(SVM)。调整后的 RF 模型能够实现大约 0.746 的 F1 得分,这仍然优于基线模型——预测每个人都不会流失,F1 得分为 0.685,尽管其性能实际上由于数据集的不平衡而被夸大了。根据 F1 得分,最终模型比基准模型提高了 9%。
由于在小数据集中只有 175 个唯一用户,因此数据量越大,模型性能越好,越可靠。因此,下一步将是在云上移动选定的模型,并建立 Spark 集群,如亚马逊 EMR 或 IBM Watson Studio ,以利用分布式计算资源处理真实的完整数据集。
如果考虑更多的因素或添加更多的领域知识,这些特性还可以得到改进。它随着公司用户群的增长和从数据中挖掘更多洞察力而发展。
关于这个项目的更多细节,请查看我的 Github 可用这里。
用 PySpark ML 预测客户流失
使用 Sparkify 订阅数据解决分类问题
留住客户对繁荣的企业至关重要。当我们正在享受一键订阅的数字服务时,一些公司正在拔头发,因为有人只是点击一下就退出了。如果我们能够确定哪些用户面临流失风险,那么企业就可以采取行动,并有可能留住他们。
为了实现这一点,我们需要不仅准确,而且足够强大的机器学习解决方案来快速处理大量数据。 Apache Spark 是一个适合这种需求的大数据平台。部署在 Spark 上的数据科学管道可以利用像 HDFS 这样的分布式系统来增加模型的可扩展性。 Spark ML 支持逻辑回归、随机森林和其他线性扩展模型等算法。
激发客户流失预测
资料来源:Udacity
Sparkify 是 Udacity 宇宙中的一项音乐流媒体服务。就像 Spotify 一样,用户可以选择带广告的免费订阅层或不带广告的付费订阅层。
在这个项目中,我们将根据 Sparkify 用户数据预测有流失风险的用户。我们将首先分析较小子集(128MB)上的数据,然后将管道部署到 AWS EMR 等云服务,以使用完整数据集(12GB)调优选定的模型。
探索性数据分析
这个小数据集包含 286500 条记录和 18 个字段:
df.printSchema()
df 模式
由于我们只对现有的 Sparkify 用户感兴趣,我们将排除与用户 Id 无关的访客流量或活动,这样我们就有了 225 个不同的用户。
流失定义
在这项研究中,我们将用户流失定义为用户取消订阅并离开 Sparkify。当用户提交取消时,记录将有auth == 'Cancelled'
和page == 'Cancellation Confirmation'
。取消立即生效。
在这个小数据集中,有 52 个用户产生了争议。流失概率 23.11% 。
用户活动
用户 _ 活动
除了播放歌曲,用户还可以对歌曲进行评级,更改设置和添加朋友。Sparkify 上互动越多的用户对平台的粘性越大吗?用户会因为订阅了太多他们不喜欢的歌曲而离开吗?
为了回答这些问题,我们在特性中添加了interactions, thumbs_down
。
活动日期
数据集中的日期范围是从2018-09-30
到2018-12-02
。我们可以看到,付费层和免费层在开始时具有相似的用户会话数量和不同的用户,然后随着时间的推移,付费层的两个指标都增加了,而免费用户的指标则减少了。
一段时间内的用户活动
用户年龄(自注册后)
用户在 Sparkify 上停留多长时间后就会流失?从用户流失时的年龄直方图中,我们可以看到大多数流失发生在注册后的 100 天内。
流失时的用户年龄
特征选择
探索数据集后,选择了 11 个要素进行进一步分析:
**用户信息:**性别,用户 _ 年龄,付费 _ 用户,降级
**活动测量:**艺术家、歌曲、长度、互动、拇指向下、总时段、时段间隙
壮举直方图
相关性矩阵
- 除了
user_age
之外cancelled
没有明显的强预测因子 songs, interactions, thumbs_down, length, artists
根据直方图非常相似。尽管它们都显示出彼此之间的高度相关性,但这可能是由小数据集(225 个用户)造成的。如果我们有更多的数据,我们可能会看到更多的用户行为差异。因此,我们将只排除songs
和artists
,因为它们总是与length
相似。
特征相关性(皮尔逊)
造型
要使用 PySpark 中的功能,需要将这些功能组合成矢量,然后使用 StandardScaler 进行归一化:
assembler = VectorAssembler(inputCols=['female','user_age','paid_user',\
'downgraded','total_session','interactions',\
'thumbs_down','length','session_gap'],\
outputCol='NumFeatures',handleInvalid = 'skip')standardscaler = StandardScaler(inputCol="NumFeatures", outputCol="features", withMean=True, withStd=True)
然后,数据被分成测试集和验证集:
test, validation = data.randomSplit([0.8, 0.2], seed=42)
型号选择
因为我们预测用户是否有流失的风险(1/0),所以预测是一个分类问题。4 种分类算法用于初始训练:
- 逻辑回归
- 随机森林
- 线性支持向量分类器
- 梯度增强树分类器
模型拟合
def fit_model(model, paramGrid = None):
# Model fitting with selected model and paramgric(optional)
# Input: model, paramgrid
# Output: fitted model, prediction on validation set
pipeline = Pipeline(stages=[standardscaler, model])
if paramGrid != None:
crossval = CrossValidator(estimator=pipeline,
estimatorParamMaps=paramGrid,
evaluator=MulticlassClassificationEvaluator(),
numFolds=3)
fitmodel = crossval.fit(test)
else:
fitmodel = pipeline.fit(test)
results = fitmodel.transform(validation)
return fitmodel, results
为了找到最佳的模型和参数,我们使用 CrossValidator 来评估模型性能并验证模型的健壮性。使用numFolds = 3
,CrossValidator 生成 3 组训练/测试对,每组使用 2/3 的数据进行训练,1/3 的数据进行测试。为了评估特定的模型/参数选择,CrossValidator 计算适合 3 个训练/测试对的 3 个模型的平均评估指标。
模型评估
为了对模型进行评估,我们通过验证数据上的模型预测的 **f1_score、**准确度、精确度和召回率对算法进行了比较。
验证数据的模型性能
f1-score: 精度和召回率的调和平均值。
准确度:(真阳性+真阴性)/所有预测
精度:真阳性/(真阳性+假阳性)
**回忆:**真阳性/(真阳性+假阴性)
因为我们在一个小的数据集上工作,所以我们需要一个具有精确度和召回率的平衡模型。我们将使用 f1 分数来选择最佳型号。
逻辑回归表现最好,F 值= 0.83 。它预测验证集中的 44% 的流失和 100% 的流失预测是正确的。根据系数,对客户流失影响最大的前 5 个特征是:
- 会话间隔、总会话、拇指向下、用户年龄、长度
逻辑回归系数
随机森林也表现不错 F 值= 0.73 。由于 RF 在大型数据集中具有更强的预测能力,因此也值得用完整数据调整随机森林模型。根据随机森林功能的重要性,前 5 位功能是:
- 用户年龄、会话间隔、总会话、拇指向下、交互
随机森林要素重要性
LSVC 在这个数据集上表现不佳。召回 为 0 ,这意味着它无法识别任何流失。
梯度提升树的 F 值略高于 LSVC,但也存在召回率低的问题。
通过处理不平衡数据改进模型
在我们的数据集中,客户流失的结果是不平衡的(23%),这损害了模型的实际预测能力(参见 LSVC,盲目地将一切赋值为 0 仍将得到 0.6 的 f1 分)。
对于逻辑回归,有多种方法来处理不平衡数据。在这项研究中,我们将尝试两种解决方案:
- 设置类别权重
- 设置不同的阈值
py spark 中的类权重
我们想给正面的东西分配更高的权重(cancelled == 1
)。生成类权重:
balancingRatio = data.filter(col(‘label’) == 1).count() / data.count()calculateWeights = udf(lambda x: 1 * balancingRatio if x == 0 else (1 * (1.0 — balancingRatio)), DoubleType())weightedDataset = data.withColumn(“classWeightCol”, calculateWeights(‘label’))
用 classWeightCol 重新拟合逻辑回归模型:
lrweightedmodel, lrweightedresults = fit_model(lr.setWeightCol(‘classWeightCol’))print(“LogisticRegression with weight: f1 score,accuracy,precision,recall”, val_evaluation(lrweightedresults))
具有类别权重结果的逻辑回归
哇!使用类权重重新平衡数据集在小数据集中非常有效,这将 f1 分数增加到 0.85 ,召回到 0.67 。
最佳阈值
另一种平衡数据的方法是设置不同的阈值来进行正面预测。
在当前逻辑回归模型中通过 f-score 找到最佳阈值:
fMeasure = trainingSummary.fMeasureByThreshold
maxFMeasure = fMeasure.groupBy().max('F-Measure').select('max(F-Measure)').head()
bestThreshold = fMeasure.where(fMeasure['F-Measure'] == maxFMeasure['max(F-Measure)']) \
.select('threshold').head()['threshold']
当前模型的最佳阈值为 0.27 。这似乎有点过于严格,可能会导致大型数据集中的低精度。为了测试不同阈值的有效性,我们可以使用 paramGrid 来拟合阈值在[0.3,0.4,0.5]的模型。
结论
- 对于 Sparkify 订阅,样本数据集中的整体流失率为 23% 。大多数搅动发生在注册后的 100 天内。
- 除了用户年龄,他们使用 Sparkify 服务
(session_gap, total_session
的频率,以及他们在使用平台thumbs_down, interactions
时的活跃程度也对他们是否会流失有很大影响。 - 带类别权重的 Logistic 回归模型对 f1-score = 0.85 的小数据集的预测能力最强。它能够以 75%的精度预测验证集中的 67%的搅动(75%的预测用户实际搅动)。
我们学到了什么
- 正确地清理和处理数据不仅可以提高模型性能,还可以提高管道的操作效率和可伸缩性。对于 Sparkify mini 数据,我们将 268k 个事件级记录聚合为 225 个用户级记录,其大小是原始数据的 0.1%。
- 理解您的数据是数据科学项目成功的关键。从 18 个原始字段中,我们只选择了与用户行为相关的指标,并创建了 11 个特性。然后,我们进一步根据相关性将数据精简为 9 个具有独特特征的特征,以训练模型。
挑战
- 季节性:我们使用的数据只包含两个月的数据,这意味着分析可能会因季节性而有偏差。
- 小数据集:在没有进行所有探索性分析的情况下,管道在我的本地机器上运行需要 2 个多小时。如果我们在两个月内收集了 12 GB 的用户数据,这意味着我们只在 0.6 天的数据量上训练我们的模型。假设业务随着时间的推移而增长,在本地运行管道是不可伸缩的。
下一步是什么?
超参数调谐
- 从这个小数据集,我们知道逻辑回归和随机森林模型对于预测我们数据的变动是很好的。我们可以通过使用网格搜索调整超参数来进一步改进模型。
- 目前的模型提供了良好的 f1 分数和准确性,但相对而言召回率较低,这意味着我们没有捕捉到所有有风险的用户。
- 我们想要如何评估模型取决于我们想要回答什么样的业务问题:例如,如果我们想要研究什么类型的用户更有可能流失,那么我们将需要好的 f1-score 。如果我们想找到所有有风险的用户并试图让他们留下来,那么召回率就变得更加重要。
使用完整数据集将管道部署到 AWS EMR
AWS EMR(Elastic MapReduce)为 Spark 提供了一个高性能环境。下一步,我们将部署我们的管道 AWS EMR。然后,我们将能够使用完整的数据训练模型,并使用超参数调整来改进模型。
你最喜欢的客户流失预测解决方案是什么?你有什么建议可以让这个项目做得更好?请在下面留下你的想法吧!
所有脚本和结果都包含在 项目 git repo 中。
参考
使用来自数字音乐流媒体应用的用户日志数据预测流失
当你不知道如何开始时,你应该考虑什么
照片由 @mantashesthaven 在 Unsplash 上拍摄
预测客户流失是公司为了更好地了解客户和预测收入变化所能做的最有趣的事情之一。在这篇文章中,我将使用一个名为 Sparkfy 的数字音乐流媒体平台的数据来解释如何创建一个预测用户流失的机器学习模型。
在这篇文章中,我们将讨论这个数据集是如何组织的,以及我们可以做些什么来定义这个问题的流失。在对业务有所了解之后,我将通过各种方式来寻找能够帮助我们更好地识别不满意的用户的特性。此外,我将使用这些特性来构建一些基本模型,这些模型应该可以预测用户是否会流失。最后,我将使用一些评估指标来帮助我选择用于预测的最佳模型和参数。
在这些步骤的最后,我们将有一个机器学习模型,它接收关于用户活动的信息,并说谁更有可能离开平台。
首先,解释一下这家公司是如何运作的很重要。Sparkify 基本上类似于 Spotify,它有免费和付费账户。免费账户时不时会显示广告,而保费账户则不会。这里的主要目标是预测哪些用户将停止使用 Sparkfy 流媒体服务,而不考虑其帐户类型。
以下数据库是由 Udacity 为数据科学家提供的纳米级数据库,代表了用户在平台内的每次交互的日志。完整的数据集有 12GB 大小,这就是为什么这篇文章的代码是用 pyspark 编写的。这样,我可以用较小的数据子集(124MB)编写一个基本代码,然后扩展到一个集群。在这篇文章中,我将使用子集作为每个步骤的例子。
1.数据理解和清理
获取数据集的第一行为我们提供了在日志的每个字段中会发生什么的预览。像艺人、名字、性别这样的栏目很容易理解。它还有一些标识字段,如 itemSession 、sessionId 和 userId,我们在操作一些聚合函数时应该记住这些字段。对于这个 id,很重要的一点是,每个用户都有自己的 Id,每次登录时,用户都会启动一个会话,每次交互都是该会话中的一个项目,直到他注销。
其他重要的列是 ts ,它代表日志的时间戳,注册,它代表用户注册其帐户的时间戳,以及页面,它基本上是交互的内容。下面是平台中一些可能的页面。
理解了数据库中每个元素的含义后,现在可以开始查找一些错误或不需要的寄存器了。我开始检查没有 Id 的行,最终发现有一些来自 guests 用户的注册,这在 auth 列中有描述。这不符合我们的利益,因为我们无法预测非客户的流失。
user_log = user_log.filter(~user_log.auth.isin([‘Guest’,’Logged Out’]))
对未来的分析很有帮助的第二步是将 ts 和 registration 列转换成日期-时间格式,这样我们就可以读取日期和时间信息并执行一些日期操作。
get_date = udf(lambda x: dt.fromtimestamp(x / 1000.0).strftime(“%d/%m/%Y”) )user_log = user_log.withColumn(“date”, to_date(get_date(user_log.ts),’dd/mm/yyyy’))user_log = user_log.withColumn("RegistrationDate", to_date(get_date(user_log.registration),'dd/mm/yyyy'))
原木底座看起来并不太乱,不需要太多的清洁,因此,这两个步骤可能就足够了。通常,许多清洁步骤是在我们为下一步付出一些努力后出现的。
2.定义流失
定义什么是实验的流失是至关重要的。在本例中,客户流失将被定义为访问了页面*取消确认的用户。*当用户点击此取消选项并确认完成操作时,出现此页面。付费和免费账户都可以访问这个页面。
客户流失的定义可能符合你的预测目标。例如,您可能对保持付费帐户中的用户感兴趣,为此,您的流失定义可能是有权访问提交降级页面的用户。这个定义应该遵循一个明确的行为变化,你可以衡量,并希望避免。
3.探索性数据分析
在定义了客户流失之后,是时候对事件进行初步假设了。探索数据让您有机会发现和测试一些模式,以及发现一些新的未清理的数据部分。一个好的开始是显示关于基地的一些基本统计数据。
这个小的子集有 225 个唯一的用户 Id,其中 52 个是被取消的。就这些基本的统计数据,我们可以看到我们的数据是不平衡的,也就是说,它有相当多的一种类型的标签。在这种情况下,所有用户的 23%有搅动用户,77%没有。这种数据在建立模型时带来了一些问题,我们将进一步讨论这些问题。
稍微思考了一下这个问题,我提出了一些可能影响用户流失的假设:
- 被搅动的用户在会话中有较少的项目
- 被搅动的用户的歌曲种类较少
- 喝醉的用户听的歌更少了
- 喝醉的用户与朋友的互动更少
- 在使用的最后一个月中,被搅动的用户的会话更少
为了看看这是不是一个好的假设,我开始在每个标签周围做一些简单的聚合。
按已取消用户和活动用户进行聚合。取消= 1 表示搅动,0 表示活动
上表显示了每个时段的项目、听的不同歌曲和播放的歌曲总数的微小差异。这给出了关于前三个假设的方向,但是可以说活跃用户在平台上有更多的时间,因此有更多的时间来增加这些统计数据的所有数字。
探索用户互动,我们可以看到,被激怒的用户添加的好友更少,在他们的歌曲中竖起大拇指的也少得多。尽管否定没有显示出太多的差异,平均来说,用户的互动次数似乎在用户选择流失方面有很大的差异。
取消= 1 表示搅动,0 表示活动
最后,如前所述,人们可能会质疑用户在平台中停留的时间。因此,下表考虑了最近 30 天的会话数。很明显,和以前没有太大区别。
过去 30 天内的会话。取消= 1 表示搅动,0 表示活动
4.特征工程
在考虑了一些想法之后,你应该根据 EDA 选择你最有希望的想法。经过一番考虑,我总结出以下特点:
- AvgSongsPlayes :每个用户平均播放的歌曲。预计注销帐户的用户在平台上的参与度较低,因此播放的歌曲较少
- LikedSongsProportion :每个用户 id 不喜欢的歌曲占喜欢的歌曲的比例。如果用户不喜欢该平台的歌曲,预计他会离开
- FriendsAdded :用户按下添加好友按钮的次数。与他人互动越多的用户在平台上停留的时间越长
- DaysInPremium :用户使用 Premium 账户的天数。创建该功能是为了控制用户账户生活中的里程碑。可能用户根据他们在 premium 帐户中的时间长短表现出不同的方式。
- SessionsLast30days :用户在过去 30 天内有多少个会话。预计用户在取消之前会减少会话的数量。
- 性别:用户的性别。
- **Sparkfy 中的天数:**用户保留其帐户的天数。
对于某些特性来说,标准化这些值是很重要的。在这种情况下,我只将性别分类数据转换为二进制数值数据,以便可以在模型中使用。
5.分割培训/测试并定义评估指标
您理解了数据集,做出了一些假设,测试了假设,现在是时候将所有这些放入机器学习模型中了!在测试某些模型之前,让我们将数据集分成随机样本,其中 80%用于训练,20%用于测试模型。
features = [ "Avg_Songs_Played_Session",
"genderIndexed",
"ThumbsProportion",
"Friends_Added",
"Days_In_Premium",
"SessionsLast30days",
"DaysInSparkfy"]assembler = VectorAssembler(inputCols=features,outputCol="features")ModelData = assembler.transform(ModelData)train, test = ModelData.randomSplit([0.8, 0.2], seed=42)
在拟合任何模型之前,我们应该定义如何比较它们。出于这个原因,准确性总是一个很好的起点,毕竟,我们希望模型预测尽可能多的正确标签。然而,通常,我们更重视分类模型中的错误类型,因此,我们将考虑其他评估指标,如召回率和精确度。如果你想更好地理解每个指标是什么,我推荐下面的帖子。
在这个具体的问题中,找到可能的用户的全部目的是与他们互动,以避免他们的帐户被取消。也许给他们折扣或提供新的特别设计的播放列表,让他们在平台上保持活跃。因此,最糟糕的情况是,如果我们预测用户会取消其账户,而他不会,Sparkfy 会让已经活跃的用户更多地参与到平台中。
然而,当模型预测用户不太可能流失,而实际上他是,这个分类错误正在花费 Sparkfy 客户端的成本,这意味着我们正在陷入分类问题的主要目标。因此,在我们的评估中,我们应该优先考虑回忆而不是精确。
6.构建模型
在这种二元分类的情况下,我们可以应用许多可能的模型。我将尝试 3 种不同的模型,它们是解决这类问题的主流模型,并比较它们的结果。最好的表演之一就是我们要调音的那场。第一次试验选择的模型是逻辑回归、梯度推进决策树和支持向量机分类器。
逻辑回归分类器是最简单的,因此将成为我们比较其余模型的基线。我创建了一个基本函数,它从我们的分类器中获取结果数据帧,并显示我们将要比较的指标。
逻辑回归 1
尽管精确度很高,但这个模型的精确度和召回率是可以接受的。如前所述,这是由于数据不平衡造成的。由于活跃用户比不活跃用户更占优势,该模型将大多数用户分类为活跃用户,并仍然获得良好的准确性,这是该模型试图改善的唯一指标。
出于这个原因,我将考虑对这个模型进行权重修正,以使它对类别的不平衡具有鲁棒性。这种技术更重视看起来不太明显的标签。我使用了下面来自 Dan Vatterott 的帖子中的代码,在我的数据框中创建了一个创建理想平衡的列。
创建权重后,我们应该在拆分前将其放在一个列上:
通过类平衡,该模型极大地提高了它的精确度和召回率,同时在精确度上有一点损失。
逻辑回归 2 —权重的使用
对于梯度提升树分类器,我们不需要使用类权重。增强分类器通过许多交互作用来惩罚错误的预测。这使得它们成为应用于不平衡数据的良好统计模型,因为它们自然地对那些在上次交互中被错误分类的情况给予更多的权重。在这篇文章中,你可以更深入地探究这个主题。
gbt = GBTClassifier(labelCol=”Cancelled”, featuresCol=”features”)
gbtModel = gbt.fit(train)
results = gbtModel.transform(test)
ShowMetrics(results)
梯度增强决策树分类器
三个分类器中最好的基础模型是逻辑回归。它预测更多具有良好召回值的校正标签。此外,我们不需要为了获得好的召回率而放弃这个分类器的精度。下一步将是超调模型。
为了调整模型,您应该直观地了解每个可用参数对分类器的影响。对于逻辑回归,我选择了两个我认为可以改进模型的参数。第一个是 regParam ,它表示模型的正则化或模型的修改,帮助它更好地推广到看不见的数据。第二个是迭代次数。默认值是 100,但我尝试了 150 和 50,这样我们可以检查分类器是否可以在更多的迭代中做得更好,或者它是否会因为太多的迭代而失去性能。
交叉验证的结果与默认的线性回归模型相同。但是,最佳模型的参数与默认模型的参数不同。迭代次数设置为 50,正则化率设置为 0.1。由于训练数据集只包含 191 个观察值,超调不会在结果中产生太大的差异。
在这篇文章中,我介绍了创建预测客户流失的机器学习模型的基本步骤:
- 问题动机
- 问题的定义和解决策略
- 基本数据清理
- 探索性数据分析
- 特征的创建
- 定义用于比较模型的指标
- 处理阶级不平衡
- 测试和选择模型
- 调整最终模型
因此,我们有一个分类模型,可以定期预测哪些注册用户更有可能取消他们的帐户,准确率为 79%。通过这种方式,Sparkify 可以在失去客户之前采取行动。
到目前为止,这是一个很好的结果,但是要改进这个模型还有很多工作要做。例如,我们可以在更大的数据集上训练分类器。如前所述,这些结果仅考虑全部数据的一小部分,随着新寄存器的加入,结果可能会发生巨大变化。
另一个改进是不仅预测注销账户的用户的流失,还预测从付费账户降级到免费账户的用户的流失。通过这种方式,Sparkfy 可以对其最重要的用户进行操作,这些用户是保持现金收入的用户。
这篇文章的详细代码可以在这个 git 仓库中找到。希望你喜欢它!