TowardsDataScience-博客中文翻译-2020-九十三-

TowardsDataScience 博客中文翻译 2020(九十三)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

Spark 3 中的谓词与投影下推

原文:https://towardsdatascience.com/predicate-vs-projection-pushdown-in-spark-3-ac24c4d11855?source=collection_archive---------7-----------------------

谓词和投影下推及其在 PySpark 3 中实现的比较

(来源)

处理大数据伴随着大量处理成本和花费大量时间扩展这些成本的挑战。It 需要了解适当的大数据过滤技术,以便从中受益。对于希望在过滤子领域(尤其是在嵌套结构化数据上)使用 Apache Spark 的最新增强功能的数据科学家和数据工程师来说,这篇文章是必不可少的。

Spark 2.x 和 Spark 3.0 在嵌套过滤方面的差异

Spark 2.x ,用最大 2 级嵌套结构的文件。json。拼花地板扩展可以被读取。

示例:

过滤器(col(' library.books ')。isNotNull())

使用 Spark 3 ,现在可以同时使用读取文件。2+级嵌套结构中的 snappy parquet 扩展,无需任何模式展平操作。

例如:

过滤器(col('library . books . title')。isNotNull())

用于下推过滤的火花会话配置

创建 spark 会话时,应启用以下配置,以使用 Spark 3 的下推功能。默认情况下,链接到下推过滤活动的设置值被激活。

*"spark.sql.parquet.filterPushdown", "true"
"spark.hadoop.parquet.filter.stats.enabled", "true"
"spark.sql.optimizer.nestedSchemaPruning.enabled","true"
"spark.sql.optimizer.dynamicPartitionPruning.enabled", "true"*

Spark 中有两种下推过滤技术,分别是谓词下推投影下推,它们具有以下不同的特性,如本文以下部分所述。

1.谓词下推

谓词下推指向影响返回行数的 where过滤器子句。基本上关系到哪些行* 会被过滤,而不是哪些列。由于这个原因,在嵌套列上应用过滤器作为【library . books】仅仅返回值不为空的记录时,谓词下推函数将使 parquet 读取指定列中不包含空值的块。*

1.1.带有分区修剪的谓词下推

分区消除技术允许在从相应的文件系统读取文件夹时优化性能,以便可以读取指定分区中的所需文件。它将致力于将数据过滤转移到尽可能靠近源的位置,以防止将不必要的数据保存在内存中,从而减少磁盘 I/O。

下面,可以观察到 filter of partition 的下推动作,也就是' library . books . title ' = ' HOST 'filter 被下推进入 parquet 文件扫描。该操作能够最小化文件和扫描数据。

*data.filter(col('library.books.title') == 'THE HOST').explain()*

对于更详细的输出,包括解析的逻辑计划、分析的逻辑计划、优化的逻辑计划、物理计划、*‘扩展’参数可以添加到 explain()函数中,如下所示。*****

*****data.filter(col('library.books.title') == 'THE HOST').explain(**'extended'**)*****

它还可以减少传递回 Spark 引擎的数据量,以便在' price' 列的聚合函数中进行平均运算。

*****data.filter(col('library.books.title') == 'THE HOST').groupBy('publisher').agg(avg('price')).explain()*****

Parquet 格式的文件为每一列保留了一些不同的统计指标,包括它们的最小值和最大值。谓词下推有助于跳过不相关的数据,处理所需的数据。

2.投影下推

Projection Pushdown 代表带有 select 子句的选定列,该子句影响返回的列数。它将数据存储在中,因此当您的投影将查询限制到指定的列时,将会返回这些列。

*****data.select('library.books.title','library.books.author').explain()*****

这意味着对‘library . books . title’,‘library . books . author’
列的扫描意味着在将数据发送回 Spark 引擎之前,将在文件系统/数据库中进行扫描。

结论

对于投影谓词下推,有一些关键点需要强调。下推过滤作用于分区的列,这些列是根据拼花格式文件的性质计算的。为了能够从中获得最大的好处,分区列应该携带具有足够匹配数据的较小值,以便将正确的文件分散到目录中。****

防止过多的小文件会导致扫描效率因过度并行而降低。此外,阻止接受太少的大文件可能会损害并行性。

****投影下推功能通过消除表格扫描过程中不必要的字段,使文件系统/数据库和 Spark 引擎之间的数据传输最小化。它主要在数据集包含太多列时有用。

另一方面,谓词下推通过在过滤数据时减少文件系统/数据库和 Spark 引擎之间传递的数据量来提高性能。****

****投影下推通过基于列的谓词下推通过基于行的过滤来区分。

非常感谢您的提问和评论!

参考文献

  1. 火花释放 3.0.0
  2. 下推析取谓词
  3. 一般化嵌套列修剪
  4. 嵌套字段的 Parquet 谓词下推

使用全球新闻预测任何应用 NLP 的加密货币

原文:https://towardsdatascience.com/predict-any-cryptocurrency-applying-nlp-with-global-news-e938af6f7922?source=collection_archive---------6-----------------------

使用 Python 的分步教程。

图片来自shutterstuck.com

来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

在当今严峻的全球经济条件下,传统的指标和技术可能表现不佳(至少可以这么说)。

在本教程中,我们将搜索关于新闻的有用信息,并使用 NLP 将其转换为数字格式,以训练一个机器学习模型,该模型将预测任何给定加密货币的上涨下跌(使用 Python)。

先决条件

  • 安装 Python 3.1 以上版本
  • 安装熊猫、sklearn 和 openblender(带 pip)
$ pip install pandas OpenBlender scikit-learn

第一步。获取数据

我们可以使用任何加密货币。对于这个例子,让我们使用这个比特币数据集

我们来拉一下 2020 年初的日价蜡烛

import pandas as pd
import numpy as np
import OpenBlender
import jsontoken = '**YOUR_TOKEN_HERE**'action = 'API_getObservationsFromDataset'# ANCHOR: 'Bitcoin vs USD'

parameters = { 
    'token' : token,
    'id_dataset' : '5d4c3af79516290b01c83f51',
    'date_filter':{"start_date" : "2020-01-01",
                   "end_date" : "2020-08-29"} 
}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)
df['date'] = [OpenBlender.unixToDate(ts, timezone = 'GMT') for ts in df.timestamp]
df = df.drop('timestamp', axis = 1)

注意:需要openblender.io (免费)上创建一个帐户,然后添加你的令牌(你会在“帐户”部分找到它)。

让我们来看看。

print(df.shape)
df.head()

自年初以来,我们每天有 254 次对比特币价格的观察。

*注意:将应用于这些 24 小时蜡烛的同一管道可以应用于任何大小的蜡烛(甚至每秒)。

第二步。定义并理解我们的目标

在我们的比特币数据中,我们有一列“价格和当天的收盘价,以及“开盘”和当天的开盘价。

我们希望得到收盘价相对于开盘价的百分比差,这样我们就有了当天表现的变量。

为了得到这个变量,我们将计算收盘价和开盘价之间的对数差。

****df['log_diff'] = np.log(df['price']) - np.log(df['open'])
df****

' log_diff '可以被认为是近似的百分比变化,对于本教程来说,它们实际上是等价的。****

(我们可以看到与'变化'的相关性非常高)**

让我们来看看。

我们可以看到全年的看跌行为和-0.1 到 0.1 之间的稳定变化(注意剧烈的异常值)。

现在,让我们通过设置“1”来生成我们的 目标变量,如果性能为正(log_diff > 0),否则设置“ 0 ”。

df['target'] = [1 if log_diff > 0 else 0 for log_diff in df['log_diff']]df

简单地说,我们的目标是预测第二天的表现是** 正还是(这样我们就可以做出潜在的交易决定)。**

第三步。用我们自己的数据获取新闻

现在,我们想将外部数据与我们的比特币数据进行时间混合。简单地说,这意味着使用时间戳作为键来外连接另一个数据集。

我们可以用 OpenBlender API 很容易地做到这一点,但是首先我们需要创建一个 Unix 时间戳变量。

Unix 时间戳是 UTC 上自 1970 年以来的秒数,这是一种非常方便的格式,因为它在世界上的每个时区都与相同!

format = '%d-%m-%Y %H:%M:%S'
timezone = 'GMT'df['u_timestamp'] = OpenBlender.dateToUnix(df['date'], 
                                           date_format = format, 
                                           timezone = timezone)df = df[['date', 'timestamp', 'price', 'target']]
df.head()

现在,让我们搜索与我们的时间交叉的有用数据集。

search_keyword = 'bitcoin'df = df.sort_values('timestamp').reset_index(drop = True)print('From : ' + OpenBlender.unixToDate(min(df.timestamp)))
print('Until: ' + OpenBlender.unixToDate(max(df.timestamp)))OpenBlender.searchTimeBlends(token,
                             df.timestamp,
                             search_keyword)

我们在一个列表中检索了几个数据集,包括它们的名称、描述、界面的 url 甚至是特征,但更重要的是,与我们的数据集重叠(相交)的时间百分比。****

浏览了一些后,这一篇关于比特币的新闻和最新的线程看起来很有趣。

****

比特币新闻数据集截图

现在,从上面的数据集中,我们只对包含新闻的“文本”特征感兴趣。所以让我们混合过去 24 小时的新闻

# We need to add the '**id_dataset**' and the '**feature**' name we want.blend_source = {
                'id_dataset':'**5ea2039095162936337156c9**',
                'feature' : '**text**'
            } # Now, let's 'timeBlend' it to our datasetdf_blend = OpenBlender.timeBlend( token = token,
                                  anchor_ts = **df.timestamp**,
                                  blend_source = **blend_source**,
                                  blend_type = 'agg_in_intervals',
                                  interval_size = 60 * 60 * 24,
                                  direction = 'time_prior',
                                  interval_output = 'list',
                                  missing_values = 'raw')df = pd.concat([df, df_blend.loc[:, df_blend.columns != 'timestamp']], axis = 1)df.head()

时间混合的参数:

  • anchor_ts :我们只需要发送我们的时间戳列,这样它就可以作为一个锚来混合外部数据。
  • blend_source :关于我们想要的特性的信息。
  • ****blend _ type:‘agg _ in _ intervals’因为我们想要对我们的每个观察值进行 24 小时间隔聚合。
  • inverval_size :间隔的大小,以秒为单位(本例中为 24 小时)。
  • ****方向:‘time _ prior’因为我们希望时间间隔收集之前 24 小时的观察结果,而不是向前。

现在我们有了相同的数据集,但是增加了 2 列。一个包含 24 小时间隔(“过去 1 天”)内收集的文本列表,另一个包含计数。

现在让我们更具体一点,让我们试着用一个添加了一些 ngrams 的过滤器来收集‘正面’和‘负面’消息(我马上想到的)。

# We add the ngrams to match on a 'positive' feature.
**positive_filter** = {'name' : '**positive**', 
                   'match_ngrams': [**'positive', 'buy', 
                                    'bull', 'boost'**]}blend_source = {
                'id_dataset':'5ea2039095162936337156c9',
                'feature' : 'text',
                'filter_text' : **positive_filter**
            }df_blend = OpenBlender.timeBlend( token = token,
                                  anchor_ts = df.timestamp,
                                  blend_source = blend_source,
                                  blend_type = 'agg_in_intervals',
                                  interval_size = 60 * 60 * 24,
                                  direction = 'time_prior',
                                  interval_output = 'list',
                                  missing_values = 'raw')df = pd.concat([df, df_blend.loc[:, df_blend.columns != 'timestamp']], axis = 1) # And now the negatives
**negative_filter** = {'name' : '**negative**', 
                   'match_ngrams': [**'negative', 'loss', 'drop', 'plummet', 'sell', 'fundraising'**]}blend_source = {
                'id_dataset':'5ea2039095162936337156c9',
                'feature' : 'text',
                'filter_text' : **negative_filter**
            }df_blend = OpenBlender.timeBlend( token = token,
                                  anchor_ts = df.timestamp,
                                  blend_source = blend_source,
                                  blend_type = 'agg_in_intervals', #closest_observation
                                  interval_size = 60 * 60 * 24,
                                  direction = 'time_prior',
                                  interval_output = 'list',
                                  missing_values = 'raw')df = pd.concat([df, df_blend.loc[:, df_blend.columns != 'timestamp']], axis = 1)

现在我们有了 4 个新栏目,即“正面”和“负面”新闻的数量和列表。

让我们看看目标和其他数字特征之间的相关性。

features = ['target', 'BITCOIN_NE.text_COUNT_last1days:positive', 'BITCOIN_NE.text_COUNT_last1days:negative']df_anchor[features].corr()['target']

我们可以注意到与新生成的特征分别存在轻微的负相关和正相关。

现在,让我们使用 TextVectorizer 来获得大量自动生成的令牌特征。

我在 OpenBlender 上创建了这个 TextVectorizer,用于 BTC 新闻数据集的“文本”功能,该数据集有超过 1200 个 ngrams。

让我们把这些特点与我们的结合起来。我们可以使用完全相同的代码,我们只需要在 blend_source 上传递“id_textVectorizer”。

# BTC Text Vectorizer
blend_source = { 
                '**id_textVectorizer**':'**5f739fe7951629649472e167**'
               }df_blend = OpenBlender.timeBlend( token = token,
                                  anchor_ts = df_anchor.timestamp,
                                  blend_source = blend_source,
                                  blend_type = 'agg_in_intervals',
                                  interval_size = 60 * 60 * 24,
                                  direction = 'time_prior',
                                  interval_output = 'list',
                                  missing_values = 'raw') .add_prefix('VEC.')df_anchor = pd.concat([df_anchor, df_blend.loc[:, df_blend.columns != 'timestamp']], axis = 1)
df_anchor.head()

现在我们有了一个 1229 列的数据集,在每个时间间隔的聚合新闻上有 ngram 出现的二进制特征,与我们的目标一致。

第四步。应用 ML 并查看结果

现在,让我们应用一些简单的 ML 来查看一些结果。

from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_score# We drop correlated features because with so many binary 
# ngram variables there's a lot of noisecorr_matrix = df_anchor.corr().abs()
upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(np.bool))
df_anchor.drop([column for column in upper.columns if any(upper[column] > 0.5)], axis=1, inplace=True) # Now we separate in train/test setsX = df_.loc[:, df_.columns != 'target'].select_dtypes(include=[np.number]).drop(drop_cols, axis = 1).values
y = df_.loc[:,['target']].values
div = int(round(len(X) * 0.2))
X_train = X[:div]
y_train = y[:div]
X_test = X[div:]
y_test = y[div:]# Finally, we perform ML and see resultsrf = RandomForestRegressor(n_estimators = 1000, random_state=0)
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)
df_res = pd.DataFrame({'y_test':y_test[:, 0], 'y_pred':y_pred})threshold = 0.5
preds = [1 if val > threshold else 0 for val in df_res['y_pred']]
print(metrics.confusion_matrix(preds, df_res['y_test']))
print('Accuracy Score:')
print(accuracy_score(preds, df_res['y_test']))
print('Precision Score:')
print(precision_score(preds, df_res['y_test']))

虽然整体准确性并不令人印象深刻,但我们对“精确得分”特别感兴趣,因为我们的目标是检测未来几天最有可能上涨(并避免下跌)。

我们如何解读上述混淆矩阵:

  • 我们的模型预测“起义”102 次,其中 84 次是实际的起义,17 次不是(0.83 精度分数)。
  • 总共有 157 次起义。我们的模型检测到了其中的 84 个,漏掉了 73 个。
  • 总共有 32 个“垮台”(或者仅仅不是“起义”)案例,我们的模型检测到了其中的 15 个,漏掉了 17 个。

换句话说,如果当务之急是避免垮台——即使这意味着牺牲大量‘起义’案例——这种模式在这段时间内运行良好。

我们也可以说,如果优先考虑的是避免错过起义(即使有一些落马渗透),这个有这个阈值的模型根本不是一个好的选择。

用 Python 预测客户流失

原文:https://towardsdatascience.com/predict-customer-churn-in-python-e8cd6d3aaa7?source=collection_archive---------0-----------------------

使用 Python 中的监督机器学习算法预测客户流失的逐步方法

Emile Perron 在 Unsplash 上的照片

客户流失(又名客户流失)是任何组织最大的支出之一。如果我们能够合理准确地找出客户离开的原因和时间,这将极大地帮助组织制定多方面的保留计划。让我们利用来自 Kaggle 的客户交易数据集来理解在 Python 中预测客户流失所涉及的关键步骤。

有监督的机器学习只不过是学习一个基于示例输入-输出对将输入映射到输出的函数。监督机器学习算法分析训练数据并产生推断的函数,该函数可用于映射新的示例。假设我们在电信数据集中有当前和以前客户交易的数据,这是一个标准化的监督分类问题,试图预测二元结果(Y/N)。

在本文结束时,让我们尝试解决一些与客户流失相关的关键业务挑战,比如说,(1)活跃客户离开组织的可能性有多大?(2)客户流失的关键指标是什么?(3)根据调查结果,可以实施哪些保留策略来减少潜在客户流失?

在现实世界中,我们需要经历七个主要阶段来成功预测客户流失:

A 部分:数据预处理

B 部分:数据评估

C 部分:型号选择

D 部分:模型评估

E 部分:模型改进

F 部分:未来预测

G 部分:模型部署

为了了解业务挑战和建议的解决方案,我建议您下载数据集,并与我一起编写代码。如果你在工作中有任何问题,请随时问我。让我们在下面详细研究一下上述每一个步骤

A 部分:数据预处理

如果你问 20 岁的我,我会直接跳到模型选择,作为机器学习中最酷的事情。但是就像在生活中一样,智慧是在较晚的阶段发挥作用的!在目睹了真实世界的机器学习业务挑战之后,我不能强调数据预处理和数据评估的重要性。

永远记住预测分析中的以下黄金法则:

“你的模型和你的数据一样好”

理解数据集的端到端结构并重塑变量是定性预测建模计划的起点。

步骤 0:重启会话:在我们开始编码之前,重启会话并从交互式开发环境中移除所有临时变量是一个好的做法。因此,让我们重新启动会话,清除缓存并重新开始!

try:
    from IPython import get_ipython
    get_ipython().magic('clear')
    get_ipython().magic('reset -f')
except:
    pass

第一步:导入相关库:导入所有相关的 python 库,用于构建有监督的机器学习算法。

#Standard libraries for data analysis:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy.stats import norm, skew
from scipy import stats
import statsmodels.api as sm# sklearn modules for data preprocessing:from sklearn.impute import SimpleImputer
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler#sklearn modules for Model Selection:from sklearn import svm, tree, linear_model, neighbors
from sklearn import naive_bayes, ensemble, discriminant_analysis, gaussian_process
from sklearn.neighbors import KNeighborsClassifier
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from xgboost import XGBClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier#sklearn modules for Model Evaluation & Improvement:

from sklearn.metrics import confusion_matrix, accuracy_score 
from sklearn.metrics import f1_score, precision_score, recall_score, fbeta_score
from statsmodels.stats.outliers_influence import variance_inflation_factor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import ShuffleSplit
from sklearn.model_selection import KFold
from sklearn import feature_selection
from sklearn import model_selection
from sklearn import metrics
from sklearn.metrics import classification_report, precision_recall_curve
from sklearn.metrics import auc, roc_auc_score, roc_curve
from sklearn.metrics import make_scorer, recall_score, log_loss
from sklearn.metrics import average_precision_score#Standard libraries for data visualization:import seaborn as sn
from matplotlib import pyplot
import matplotlib.pyplot as plt
import matplotlib.pylab as pylab
import matplotlib 
%matplotlib inline
color = sn.color_palette()
import matplotlib.ticker as mtick
from IPython.display import display
pd.options.display.max_columns = None
from pandas.plotting import scatter_matrix
from sklearn.metrics import roc_curve#Miscellaneous Utilitiy Libraries:

import random
import os
import re
import sys
import timeit
import string
import time
from datetime import datetime
from time import time
from dateutil.parser import parse
import joblib

第二步:设置当前工作目录:

os.chdir(r”C:/Users/srees/Propensity Scoring Models/Predict Customer Churn/”)

第三步:导入数据集:让我们将输入数据集加载到当前工作目录下的 python 笔记本中。

dataset = pd.read_csv('1.Input/customer_churn_data.csv')

第 4 步:评估数据结构:在这一部分,我们需要大致了解数据集以及每一列的细节,以便更好地理解输入数据,从而在需要时聚合字段。

从 head & column 方法中,我们了解到这是一个电信客户流失数据集,其中每个记录都包含订阅、任期、付款频率和流失的性质(表示他们的当前状态)。

dataset.head()

输入数据集的快照(图片由作者提供)

dataset.columns

列名列表(作者图片)

快速描述法显示,电信客户平均停留 32 个月,每月支付 64 美元。但是,这可能是因为不同的客户有不同的合同。

dataset.describe()

描述方法(图片由作者提供)

从表面上看,我们可以假设数据集包含几个数字和分类列,提供关于客户交易的各种信息。

dataset.dtypes

列数据类型(作者图片)

重新验证列数据类型和缺失值:始终关注数据集中缺失的值。缺少的值可能会扰乱模型的构建和准确性。因此,在比较和选择模型之前,我们需要考虑缺失值(如果有的话)。

dataset.columns.to_series().groupby(dataset.dtypes).groups

聚合列数据类型(按作者分类的图片)

数据集包含 7043 行和 21 列,数据集中似乎没有缺失值。

dataset.info()

数据结构(图片由作者提供)

dataset.isna().any()

检查 NA(图片由作者提供)

识别唯一值:“付款方式”和“合同”是数据集中的两个分类变量。当我们查看每个分类变量中的唯一值时,我们会发现客户要么是按月滚动合同,要么是一年/两年的固定合同。此外,他们通过信用卡、银行转账或电子支票支付账单。

#Unique values in each categorical variable:dataset["PaymentMethod"].nunique()dataset["PaymentMethod"].unique()dataset["Contract"].nunique()dataset["Contract"].unique()

第五步:检查目标变量分布:我们来看看流失值的分布。这是检验数据集是否支持任何类别不平衡问题的一个非常简单而关键的步骤。正如您在下面看到的,数据集是不平衡的,活跃客户的比例比他们的对手高。

dataset["Churn"].value_counts()

流失值的分布(按作者分类的图片)

第六步:清理数据集:

dataset['TotalCharges'] = pd.to_numeric(dataset['TotalCharges'],errors='coerce')dataset['TotalCharges'] = dataset['TotalCharges'].astype("float")

第 7 步:处理缺失数据:正如我们前面看到的,所提供的数据没有缺失值,因此这一步对于所选的数据集是不需要的。我想在这里展示这些步骤,以供将来参考。

dataset.info()

数据结构(图片由作者提供)

dataset.isna().any()

检查 NA(图片由作者提供)

以编程方式查找平均值并填充缺失值:如果我们在数据集的数字列中有任何缺失值,那么我们应该查找每一列的平均值并填充它们缺失的值。下面是以编程方式执行相同步骤的一段代码。

na_cols = dataset.isna().any()na_cols = na_cols[na_cols == True].reset_index()na_cols = na_cols["index"].tolist()for col in dataset.columns[1:]:
     if col in na_cols:
        if dataset[col].dtype != 'object':
             dataset[col] =  dataset[col].fillna(dataset[col].mean()).round(0)

重新验证 NA:重新验证并确保数据集中不再有空值总是一个好的做法。

dataset.isna().any()

重新验证 NA(图片由作者提供)

步骤 8:标签编码二进制数据:机器学习算法通常只能将数值作为它们的独立变量。因此,标签编码非常关键,因为它们用适当的数值对分类标签进行编码。这里我们对所有只有两个唯一值的分类变量进行标签编码。任何具有两个以上唯一值的分类变量都将在后面的部分中用标签编码和一键编码来处理。

#Create a label encoder objectle = LabelEncoder()# Label Encoding will be used for columns with 2 or less unique values
le_count = 0
for col in dataset.columns[1:]:
    if dataset[col].dtype == 'object':
        if len(list(dataset[col].unique())) <= 2:
            le.fit(dataset[col])
            dataset[col] = le.transform(dataset[col])
            le_count += 1
print('{} columns were label encoded.'.format(le_count))

B 部分:数据评估

第 9 步:探索性数据分析:让我们尝试通过独立变量的分布来探索和可视化我们的数据集,以更好地理解数据中的模式,并潜在地形成一些假设。

步骤 9.1。绘制数值列的直方图:

dataset2 = dataset[['gender', 
'SeniorCitizen', 'Partner','Dependents',
'tenure', 'PhoneService', 'PaperlessBilling',
'MonthlyCharges', 'TotalCharges']]#Histogram:

fig = plt.figure(figsize=(15, 12))
plt.suptitle('Histograms of Numerical Columns\n',horizontalalignment="center",fontstyle = "normal", fontsize = 24, fontfamily = "sans-serif")
for i in range(dataset2.shape[1]):
    plt.subplot(6, 3, i + 1)
    f = plt.gca()
    f.set_title(dataset2.columns.values[i])vals = np.size(dataset2.iloc[:, i].unique())
    if vals >= 100:
        vals = 100

plt.hist(dataset2.iloc[:, i], bins=vals, color = '#ec838a')
plt.tight_layout(rect=[0, 0.03, 1, 0.95])

数字柱直方图(图片由作者提供)

可以根据数值变量的直方图进行一些观察:

  • 性别分布显示,该数据集的特点是男性和女性客户的比例相对相等。在我们的数据集中,几乎一半的顾客是女性,而另一半是男性。
  • 数据集中的大多数客户都是年轻人。
  • 似乎没有多少顾客有家属,而几乎一半的顾客有伴侣。
  • 组织中有许多新客户(不到 10 个月),然后是平均停留超过 70 个月的忠诚客户群。
  • 大多数客户似乎有电话服务,3/4 的客户选择了无纸化计费
  • 每个客户的月费在 18 美元到 118 美元之间,其中 20 美元的客户占很大比例。

第 9.2 步。分析分类变量的分布:

9.2.1。合同类型分布:大多数客户似乎都与电信公司建立了预付费连接。另一方面,1 年期和 2 年期合同的客户比例大致相同。

contract_split = dataset[[ "customerID", "Contract"]]
sectors = contract_split .groupby ("Contract")
contract_split = pd.DataFrame(sectors["customerID"].count())
contract_split.rename(columns={'customerID':'No. of customers'}, inplace=True)ax =  contract_split[["No. of customers"]].plot.bar(title = 'Customers by Contract Type',legend =True, table = False, 
grid = False,  subplots = False,figsize =(12, 7), color ='#ec838a', 
fontsize = 15, stacked=False)plt.ylabel('No. of Customers\n',
horizontalalignment="center",fontstyle = "normal", 
fontsize = "large", fontfamily = "sans-serif")plt.xlabel('\n Contract Type',
horizontalalignment="center",fontstyle = "normal", 
fontsize = "large", fontfamily = "sans-serif")plt.title('Customers by Contract Type \n',
horizontalalignment="center",fontstyle = "normal", 
fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='top right', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")x_labels = np.array(contract_split[["No. of customers"]])def add_value_labels(ax, spacing=5):   
    for rect in ax.patches:      
        y_value = rect.get_height()
        x_value = rect.get_x() + rect.get_width() / 2       
        space = spacing        
        va = 'bottom'      
        if y_value < 0:           
            space *= -1            
            va = 'top'       
        label = "{:.0f}".format(y_value)      

            ax.annotate(
            label,                      
            (x_value, y_value),         
            xytext=(0, space),          
            textcoords="offset points", 
            ha='center',                
            va=va)  

add_value_labels(ax)

按合同类型划分的客户分布(按作者划分的图片)

9.2.2 支付方式类型分布:数据集表明,客户最喜欢以电子方式支付账单,其次是银行转账、信用卡和邮寄支票。

payment_method_split = dataset[[ "customerID", "PaymentMethod"]]
sectors = payment_method_split  .groupby ("PaymentMethod")
payment_method_split  = pd.DataFrame(sectors["customerID"].count())
payment_method_split.rename(columns={'customerID':'No. of customers'}, inplace=True)ax =  payment_method_split [["No. of customers"]].plot.bar(title = 'Customers by Payment Method', legend =True, table = False, grid = False, subplots = False,  figsize =(15, 10),color ='#ec838a', fontsize = 15, stacked=False)plt.ylabel('No. of Customers\n',
horizontalalignment="center",fontstyle = "normal", 
fontsize = "large", fontfamily = "sans-serif")plt.xlabel('\n Contract Type',
horizontalalignment="center",fontstyle = "normal", 
fontsize = "large", fontfamily = "sans-serif")plt.title('Customers by Payment Method \n',
horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='top right', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")x_labels = np.array(payment_method_split [["No. of customers"]])def add_value_labels(ax, spacing=5):   
    for rect in ax.patches:      
        y_value = rect.get_height()
        x_value = rect.get_x() + rect.get_width() / 2       
        space = spacing        
        va = 'bottom'      
        if y_value < 0:           
            space *= -1            
            va = 'top'       
        label = "{:.0f}".format(y_value)

           ax.annotate(label,
           (x_value, y_value),         
            xytext=(0, space),textcoords="offset points", 
            ha='center',va=va)add_value_labels(ax)

按支付方式划分的客户分布(按作者划分的图片)

9.2.3。标签编码分类变量的分布:

services= ['PhoneService','MultipleLines',
'InternetService','OnlineSecurity',  'OnlineBackup','DeviceProtection',
'TechSupport','StreamingTV','StreamingMovies']fig, axes = plt.subplots(nrows = 3,ncols = 3,
figsize = (15,12))
for i, item in enumerate(services): if i < 3:
    ax = dataset[item].value_counts().plot(
    kind = 'bar',ax=axes[i,0],
    rot = 0, color ='#f3babc' )

    elif i >=3 and i < 6:
    ax = dataset[item].value_counts().plot(
    kind = 'bar',ax=axes[i-3,1],
    rot = 0,color ='#9b9c9a')

    elif i < 9:
    ax = dataset[item].value_counts().plot(
    kind = 'bar',ax=axes[i-6,2],rot = 0,
    color = '#ec838a')ax.set_title(item)

标签编码分类变量的分布(图片由作者提供)

  • 大多数客户拥有电话服务,其中几乎一半的客户拥有多条线路。
  • 四分之三的客户选择了通过光纤和 DSL 连接的互联网服务,近一半的互联网用户订阅了流媒体电视和电影。
  • 利用在线备份、设备保护、技术支持和在线安全功能的客户是少数。

第 9.3 步:通过分类变量分析流失率:

9.3.1。整体流失率:对整体流失率的初步观察显示,约 74%的客户是活跃的。如下图所示,这是一个不平衡的分类问题。当每个类的实例数量大致相等时,机器学习算法工作得很好。由于数据集是倾斜的,我们在选择模型选择的指标时需要记住这一点。

import matplotlib.ticker as mtick
churn_rate = dataset[["Churn", "customerID"]]
churn_rate ["churn_label"] = pd.Series(
np.where((churn_rate["Churn"] == 0), "No", "Yes"))sectors = churn_rate .groupby ("churn_label")
churn_rate = pd.DataFrame(sectors["customerID"].count())churn_rate ["Churn Rate"] = (
churn_rate ["customerID"]/ sum(churn_rate ["customerID"]) )*100ax =  churn_rate[["Churn Rate"]].plot.bar(title = 'Overall Churn Rate',legend =True, table = False,grid = False,  subplots = False, 
figsize =(12, 7), color = '#ec838a', fontsize = 15, stacked=False, 
ylim =(0,100))plt.ylabel('Proportion of Customers',horizontalalignment="center",
fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('Churn',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.title('Overall Churn Rate \n',horizontalalignment="center", 
fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='top right', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")
ax.yaxis.set_major_formatter(mtick.PercentFormatter())x_labels = np.array(churn_rate[["customerID"]])def add_value_labels(ax, spacing=5):   
    for rect in ax.patches:     
        y_value = rect.get_height()
        x_value = rect.get_x() + rect.get_width() / 2       
        space = spacing
        va = 'bottom'        
        if y_value < 0:           
            space *= -1          
            va = 'top'
        label = "{:.1f}%".format(y_value)    

     ax.annotate(label,
                (x_value, y_value),         
                 xytext=(0, space),
                 textcoords="offset points", 
                 ha='center',va=va)add_value_labels(ax)
ax.autoscale(enable=False, axis='both', tight=False)

总体流失率(图片由作者提供)

9.3.2。按合同类型划分的客户流失率:与 1 年或 2 年合同的同行相比,预付费或按月连接的客户流失率非常高。

import matplotlib.ticker as mtick
contract_churn =
dataset.groupby(
['Contract','Churn']).size().unstack()contract_churn.rename(
columns={0:'No', 1:'Yes'}, inplace=True)colors  = ['#ec838a','#9b9c9a']ax = (contract_churn.T*100.0 / contract_churn.T.sum()).T.plot(kind='bar',width = 0.3,stacked = True,rot = 0,figsize = (12,7),color = colors)plt.ylabel('Proportion of Customers\n',
horizontalalignment="center",fontstyle = "normal", 
fontsize = "large", fontfamily = "sans-serif")plt.xlabel('Contract Type\n',horizontalalignment="center",
fontstyle = "normal", fontsize = "large", 
fontfamily = "sans-serif")plt.title('Churn Rate by Contract type \n',
horizontalalignment="center", fontstyle = "normal", 
fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='top right', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")
ax.yaxis.set_major_formatter(mtick.PercentFormatter())for p in ax.patches:
    width, height = p.get_width(), p.get_height()
    x, y = p.get_xy() 
    ax.text(x+width/2, 
            y+height/2, 
            '{:.1f}%'.format(height), 
            horizontalalignment='center', 
            verticalalignment='center')ax.autoscale(enable=False, axis='both', tight=False)

按合同类型分类的流失率(按作者分类的图片)

9.3.3。按付款方式分类的流失率:通过银行转账付款的客户似乎在所有付款方式类别中流失率最低。

import matplotlib.ticker as mtick
contract_churn = dataset.groupby(['Contract',
'PaymentMethod']).size().unstack()contract_churn.rename(columns=
{0:'No', 1:'Yes'}, inplace=True)colors  = ['#ec838a','#9b9c9a', '#f3babc' , '#4d4f4c']ax = (contract_churn.T*100.0 / contract_churn.T.sum()).T.plot(
kind='bar',width = 0.3,stacked = True,rot = 0,figsize = (12,7),
color = colors)plt.ylabel('Proportion of Customers\n',
horizontalalignment="center",fontstyle = "normal", 
fontsize = "large", fontfamily = "sans-serif")plt.xlabel('Contract Type\n',horizontalalignment="center",
fontstyle = "normal", fontsize = "large", 
fontfamily = "sans-serif")plt.title('Churn Rate by Payment Method \n',
horizontalalignment="center", fontstyle = "normal", 
fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='top right', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")
ax.yaxis.set_major_formatter(mtick.PercentFormatter())for p in ax.patches:
    width, height = p.get_width(), p.get_height()
    x, y = p.get_xy() 
    ax.text(x+width/2, 
            y+height/2, 
            '{:.1f}%'.format(height), 
            horizontalalignment='center', 
            verticalalignment='center')ax.autoscale(enable=False, axis='both', tight=False

按合同类型分类的流失率(按作者分类的图片)

步骤 9.4。找到正相关和负相关:有趣的是,流失率随着月费和年龄的增长而增加。相反,伴侣、受抚养人和任期似乎与流失负相关。让我们在下一步中用图表来看看正相关和负相关。

dataset2 = dataset[['SeniorCitizen', 'Partner', 'Dependents',
       'tenure', 'PhoneService', 'PaperlessBilling',
        'MonthlyCharges', 'TotalCharges']]correlations = dataset2.corrwith(dataset.Churn)
correlations = correlations[correlations!=1]
positive_correlations = correlations[
correlations >0].sort_values(ascending = False)
negative_correlations =correlations[
correlations<0].sort_values(ascending = False)print('Most Positive Correlations: \n', positive_correlations)
print('\nMost Negative Correlations: \n', negative_correlations)

第 9.5 步。图正&负相关:

correlations = dataset2.corrwith(dataset.Churn)
correlations = correlations[correlations!=1]correlations.plot.bar(
        figsize = (18, 10), 
        fontsize = 15, 
        color = '#ec838a',
        rot = 45, grid = True)plt.title('Correlation with Churn Rate \n',
horizontalalignment="center", fontstyle = "normal", 
fontsize = "22", fontfamily = "sans-serif")

与流失率的相关性(图片由作者提供)

第 9.6 步。绘制所有自变量的相关矩阵:相关矩阵有助于我们发现数据集中自变量之间的二元关系。

#Set and compute the Correlation Matrix:sn.set(style="white")
corr = dataset2.corr()#Generate a mask for the upper triangle:mask = np.zeros_like(corr, dtype=np.bool)
mask[np.triu_indices_from(mask)] = True#Set up the matplotlib figure and a diverging colormap:f, ax = plt.subplots(figsize=(18, 15))
cmap = sn.diverging_palette(220, 10, as_cmap=True)#Draw the heatmap with the mask and correct aspect ratio:sn.heatmap(corr, mask=mask, cmap=cmap, vmax=.3, center=0,
square=True, linewidths=.5, cbar_kws={"shrink": .5})

自变量的相关矩阵(图片由作者提供)

步骤 9.7:使用 VIF 检查多重共线性:让我们尝试使用可变通货膨胀系数(VIF)来研究多重共线性。与相关矩阵不同,VIF 确定一个变量与数据集中一组其他独立变量的相关性强度。VIF 通常从 1 开始,任何超过 10 的地方都表明自变量之间的高度多重共线性。

def calc_vif(X):# Calculating VIF
    vif = pd.DataFrame()
    vif["variables"] = X.columns
    vif["VIF"] = [variance_inflation_factor(X.values, i) 
    for i in range(X.shape[1])]return(vif)dataset2 = dataset[['gender', 
'SeniorCitizen', 'Partner', 'Dependents',
'tenure', 'PhoneService',
'PaperlessBilling','MonthlyCharges',
'TotalCharges']]calc_vif(dataset2)

计算 VIF(图片作者)

我们可以看到“每月费用”和“总费用”具有很高的 VIF 值。

'Total Charges' seem to be collinear with 'Monthly Charges'.#Check colinearity:

dataset2[['MonthlyCharges', 'TotalCharges']].
plot.scatter(
figsize = (15, 10), 
x ='MonthlyCharges',
y='TotalCharges', 
color =  '#ec838a')plt.title('Collinearity of Monthly Charges and Total Charges \n',
horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")

每月费用和总费用的共线性(图片由作者提供)

让我们尝试删除其中一个相关要素,看看它是否有助于降低相关要素之间的多重共线性:

#Dropping 'TotalCharges':

dataset2 = dataset2.drop(columns = "TotalCharges")#Revalidate Colinearity:dataset2 = dataset[['gender', 
'SeniorCitizen', 'Partner', 'Dependents',
'tenure', 'PhoneService', 'PaperlessBilling',
'MonthlyCharges']]calc_vif(dataset2)#Applying changes in the main dataset:

dataset = dataset.drop(columns = "TotalCharges")

计算 VIF(图片作者)

在我们的例子中,在去掉“总费用”变量后,所有独立变量的 VIF 值都大大降低了。

探索性数据分析结束语:

让我们试着总结一下这次 EDA 的一些关键发现:

  • 数据集没有任何缺失或错误的数据值。
  • 与目标特征最强正相关的是月费和年龄,而与伴侣、家属和任期负相关。
  • 数据集不平衡,大多数客户都很活跃。
  • 每月费用和总费用之间存在多重共线性。总费用的下降大大降低了 VIF 值。
  • 数据集中的大多数客户都是年轻人。
  • 组织中有许多新客户(不到 10 个月),随后是 70 个月以上的忠实客户群。
  • 大多数客户似乎都有电话服务,每个客户的月费在 18 美元到 118 美元之间。
  • 如果订阅了通过电子支票支付的服务,月结用户也很有可能流失。

步骤 10:对分类数据进行编码:任何具有两个以上唯一值的分类变量都已经在 pandas 中使用 get_dummies 方法进行了标签编码和一键编码。

#Incase if user_id is an object:

identity = dataset["customerID"]dataset = dataset.drop(columns="customerID")#Convert rest of categorical variable into dummy:dataset= pd.get_dummies(dataset)#Rejoin userid to dataset:dataset = pd.concat([dataset, identity], axis = 1)

第 11 步:将数据集分成因变量和自变量:现在我们需要将数据集分成 X 和 y 值。y 将是“变动”列,而 X 将是数据集中独立变量的剩余列表。

#Identify response variable:

response = dataset["Churn"]dataset = dataset.drop(columns="Churn")

第十二步:生成训练和测试数据集:让我们将主数据集解耦为 80%-20%比例的训练和测试集。

X_train, X_test, y_train, y_test = train_test_split(dataset, response,stratify=response, test_size = 0.2, #use 0.9 if data is huge.random_state = 0)#to resolve any class imbalance - use stratify parameter.print("Number transactions X_train dataset: ", X_train.shape)
print("Number transactions y_train dataset: ", y_train.shape)
print("Number transactions X_test dataset: ", X_test.shape)
print("Number transactions y_test dataset: ", y_test.shape)

训练和测试数据集(图片由作者提供)

步骤 13:移除标识符:将“customerID”从训练和测试数据帧中分离出来。

train_identity = X_train['customerID']
X_train = X_train.drop(columns = ['customerID'])test_identity = X_test['customerID']
X_test = X_test.drop(columns = ['customerID'])

步骤 14:进行特征缩放:在进行任何机器学习(分类)算法之前,标准化变量是非常重要的,以便所有的训练和测试变量都在 0 到 1 的范围内缩放。

sc_X = StandardScaler()
X_train2 = pd.DataFrame(sc_X.fit_transform(X_train))
X_train2.columns = X_train.columns.values
X_train2.index = X_train.index.values
X_train = X_train2X_test2 = pd.DataFrame(sc_X.transform(X_test))
X_test2.columns = X_test.columns.values
X_test2.index = X_test.index.values
X_test = X_test2

C 部分:型号选择

步骤 15.1:比较基线分类算法(第一次迭代):让我们在训练数据集上对每个分类算法进行建模,并评估它们的准确性和标准偏差分数。

分类准确性是比较基准算法的最常见的分类评估指标之一,因为它是正确预测的数量与总预测的比率。然而,当我们有阶级不平衡的问题时,这不是理想的衡量标准。因此,让我们根据“平均 AUC”值对结果进行排序,该值只不过是模型区分阳性和阴性类别的能力。

models = []models.append(('Logistic Regression', LogisticRegression(solver='liblinear', random_state = 0,
                                                         class_weight='balanced')))models.append(('SVC', SVC(kernel = 'linear', random_state = 0)))models.append(('Kernel SVM', SVC(kernel = 'rbf', random_state = 0)))models.append(('KNN', KNeighborsClassifier(n_neighbors = 5, metric = 'minkowski', p = 2)))models.append(('Gaussian NB', GaussianNB()))models.append(('Decision Tree Classifier',
               DecisionTreeClassifier(criterion = 'entropy', random_state = 0)))models.append(('Random Forest', RandomForestClassifier(
    n_estimators=100, criterion = 'entropy', random_state = 0)))#Evaluating Model Results:acc_results = []
auc_results = []
names = []# set table to table to populate with performance results
col = ['Algorithm', 'ROC AUC Mean', 'ROC AUC STD', 
       'Accuracy Mean', 'Accuracy STD']model_results = pd.DataFrame(columns=col)
i = 0# Evaluate each model using k-fold cross-validation:for name, model in models:
    kfold = model_selection.KFold(
        n_splits=10, random_state=0)# accuracy scoring:
cv_acc_results = model_selection.cross_val_score(  
model, X_train, y_train, cv=kfold, scoring='accuracy')# roc_auc scoring:
cv_auc_results = model_selection.cross_val_score(  
model, X_train, y_train, cv=kfold, scoring='roc_auc')acc_results.append(cv_acc_results)
    auc_results.append(cv_auc_results)
    names.append(name)
    model_results.loc[i] = [name,
                         round(cv_auc_results.mean()*100, 2),
                         round(cv_auc_results.std()*100, 2),
                         round(cv_acc_results.mean()*100, 2),
                         round(cv_acc_results.std()*100, 2)
                         ]
    i += 1

model_results.sort_values(by=['ROC AUC Mean'], ascending=False)

比较基线分类算法第一次迭代(图片由作者提供)

第 15.2 步。可视化分类算法精度对比:

使用精度均值:

fig = plt.figure(figsize=(15, 7))
ax = fig.add_subplot(111)
plt.boxplot(acc_results)
ax.set_xticklabels(names)#plt.ylabel('ROC AUC Score\n',
horizontalalignment="center",fontstyle = "normal", 
fontsize = "large", fontfamily = "sans-serif")#plt.xlabel('\n Baseline Classification Algorithms\n',
horizontalalignment="center",fontstyle = "normal", 
fontsize = "large", fontfamily = "sans-serif")plt.title('Accuracy Score Comparison \n',
horizontalalignment="center", fontstyle = "normal", 
fontsize = "22", fontfamily = "sans-serif")#plt.legend(loc='top right', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.show()

准确度分数比较(图片由作者提供)

使用 ROC 曲线下面积:从基线分类算法的第一次迭代中,我们可以看到,对于具有最高平均 AUC 分数的所选数据集,逻辑回归和 SVC 已经优于其他五个模型。让我们在第二次迭代中再次确认我们的结果,如下面的步骤所示。

fig = plt.figure(figsize=(15, 7))
ax = fig.add_subplot(111)
plt.boxplot(auc_results)
ax.set_xticklabels(names)#plt.ylabel('ROC AUC Score\n',
horizontalalignment="center",fontstyle = "normal",
fontsize = "large", fontfamily = "sans-serif")#plt.xlabel('\n Baseline Classification Algorithms\n',
horizontalalignment="center",fontstyle = "normal", 
fontsize = "large", fontfamily = "sans-serif")plt.title('ROC AUC Comparison \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", 
fontfamily = "sans-serif")#plt.legend(loc='top right', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.show()

ROC AUC 比较(图片由作者提供)

步骤 15.3。为基线模型获取正确的参数:在进行第二次迭代之前,让我们优化参数并最终确定模型选择的评估指标。

为 KNN 模型确定 K 个邻居的最佳数量:在第一次迭代中,我们假设 K = 3,但实际上,我们不知道为所选训练数据集提供最大准确度的最佳 K 值是什么。因此,让我们编写一个迭代 20 到 30 次的 for 循环,并给出每次迭代的精度,以便计算出 KNN 模型的 K 个邻居的最佳数量。

score_array = []
for each in range(1,25):
    knn_loop = KNeighborsClassifier(n_neighbors = each) #set K neighbor as 3
    knn_loop.fit(X_train,y_train)
    score_array.append(knn_loop.score(X_test,y_test))fig = plt.figure(figsize=(15, 7))
plt.plot(range(1,25),score_array, color = '#ec838a')plt.ylabel('Range\n',horizontalalignment="center",
fontstyle = "normal", fontsize = "large", 
fontfamily = "sans-serif")plt.xlabel('Score\n',horizontalalignment="center",
fontstyle = "normal", fontsize = "large", 
fontfamily = "sans-serif")plt.title('Optimal Number of K Neighbors \n',
horizontalalignment="center", fontstyle = "normal",
 fontsize = "22", fontfamily = "sans-serif")#plt.legend(loc='top right', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.show()

K 近邻的最佳数量(图片由作者提供)

从上面的迭代可以看出,如果我们使用 K = 22,那么我们将得到 78%的最高分。

确定随机森林模型的最佳树木数量:与 KNN 模型中的迭代非常相似,这里我们试图找到最佳决策树数量,以组成最佳随机森林。

score_array = []
for each in range(1,100):
    rf_loop = RandomForestClassifier(
n_estimators = each, random_state = 1)     rf_loop.fit(X_train,y_train) score_array.append(rf_loop.score(X_test,y_test))

fig = plt.figure(figsize=(15, 7))
plt.plot(range(1,100),score_array, color = '#ec838a')plt.ylabel('Range\n',horizontalalignment="center",
fontstyle = "normal", fontsize = "large", 
fontfamily = "sans-serif")plt.xlabel('Score\n',horizontalalignment="center",
fontstyle = "normal", fontsize = "large", 
fontfamily = "sans-serif")plt.title('Optimal Number of Trees for Random Forest Model \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")#plt.legend(loc='top right', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.show()

随机森林模型的最佳树数(图片由作者提供)

从上面的迭代中我们可以看出,当 n_estimators = 72 时,随机森林模型将获得最高的精度分数。

第 15.4 步。比较基线分类算法(第二次迭代):

在比较基线分类算法的第二次迭代中,我们将使用 KNN 和随机森林模型的优化参数。此外,我们知道,在流失中,假阴性比假阳性的成本更高,因此让我们使用精确度、召回率和 F2 分数作为模型选择的理想指标。

步骤 15.4.1。逻辑回归:

# Fitting Logistic Regression to the Training set
classifier = LogisticRegression(random_state = 0)
classifier.fit(X_train, y_train)# Predicting the Test set results
y_pred = classifier.predict(X_test)#Evaluate results
acc = accuracy_score(y_test, y_pred )
prec = precision_score(y_test, y_pred )
rec = recall_score(y_test, y_pred )
f1 = f1_score(y_test, y_pred )
f2 = fbeta_score(y_test, y_pred, beta=2.0)results = pd.DataFrame([['Logistic Regression', 
acc, prec, rec, f1, f2]], columns = ['Model', 
'Accuracy', 'Precision', 'Recall', 'F1 Score', 
'F2 Score'])results = results.sort_values(["Precision", 
"Recall", "F2 Score"], ascending = False)print (results)

逻辑回归结果(图片由作者提供)

步骤 15.4.2。支持向量机(线性分类器):

# Fitting SVM (SVC class) to the Training set
classifier = SVC(kernel = 'linear', random_state = 0)
classifier.fit(X_train, y_train)# Predicting the Test set results y_pred = classifier.predict(X_test)#Evaluate results
acc = accuracy_score(y_test, y_pred )
prec = precision_score(y_test, y_pred )
rec = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred )
f2 = fbeta_score(y_test, y_pred, beta=2.0)model_results = pd.DataFrame(
[['SVM (Linear)', acc, prec, rec, f1, f2]],
columns = ['Model', 'Accuracy', 'Precision', 
'Recall', 'F1 Score', 'F2 Score'])results = results.append(model_results, ignore_index = True)results = results.sort_values(["Precision", 
"Recall", "F2 Score"], ascending = False)print (results)

SVM 线性结果(图片由作者提供)

步骤 15.4.3。k-最近邻:

# Fitting KNN to the Training set:
classifier = KNeighborsClassifier(
n_neighbors = 22, 
metric = 'minkowski', p = 2)
classifier.fit(X_train, y_train)# Predicting the Test set results 
y_pred  = classifier.predict(X_test)#Evaluate results
acc = accuracy_score(y_test, y_pred )
prec = precision_score(y_test, y_pred )
rec = recall_score(y_test, y_pred )
f1 = f1_score(y_test, y_pred )
f2 = fbeta_score(y_test, y_pred, beta=2.0)model_results = pd.DataFrame([['K-Nearest Neighbours', 
acc, prec, rec, f1, f2]], columns = ['Model',
 'Accuracy', 'Precision', 'Recall',
 'F1 Score', 'F2 Score'])results = results.append(model_results, ignore_index = True)results = results.sort_values(["Precision", 
"Recall", "F2 Score"], ascending = False)print (results)

k-最近邻(图片由作者提供)

步骤 15.4.4。内核 SVM:

# Fitting Kernel SVM to the Training set:
classifier = SVC(kernel = 'rbf', random_state = 0)
classifier.fit(X_train, y_train)# Predicting the Test set results 
y_pred = classifier.predict(X_test)#Evaluate results
acc = accuracy_score(y_test, y_pred )
prec = precision_score(y_test, y_pred )
rec = recall_score(y_test, y_pred )
f1 = f1_score(y_test, y_pred )
f2 = fbeta_score(y_test, y_pred, beta=2.0)model_results = pd.DataFrame([[
'Kernel SVM', acc, prec, rec, f1, f2]],
columns = ['Model', 'Accuracy', 'Precision', 
'Recall', 'F1 Score', 'F2 Score'])results = results.append(model_results, ignore_index = True)results = results.sort_values(["Precision", 
"Recall", "F2 Score"], ascending = False)print (results)

内核 SVM 结果(图片由作者提供)

步骤 15.4.5。天真的轮空:

# Fitting Naive Byes to the Training set:
classifier = GaussianNB()
classifier.fit(X_train, y_train)# Predicting the Test set results 
y_pred = classifier.predict(X_test)#Evaluate results
acc = accuracy_score(y_test, y_pred )
prec = precision_score(y_test, y_pred )
rec = recall_score(y_test, y_pred )
f1 = f1_score(y_test, y_pred )
f2 = fbeta_score(y_test, y_pred, beta=2.0)model_results = pd.DataFrame([[
'Naive Byes', acc, prec, rec, f1, f2]],
columns = ['Model', 'Accuracy', 'Precision',
'Recall', 'F1 Score', 'F2 Score'])results = results.append(model_results, ignore_index = True)results = results.sort_values(["Precision", 
"Recall", "F2 Score"], ascending = False)print (results)

天真的 Byes 结果(作者图片)

步骤 15.4.6。决策树:

# Fitting Decision Tree to the Training set:classifier = DecisionTreeClassifier(criterion = 'entropy', random_state = 0)
classifier.fit(X_train, y_train)# Predicting the Test set results 
y_pred = classifier.predict(X_test)#Evaluate results
acc = accuracy_score(y_test, y_pred )
prec = precision_score(y_test, y_pred )
rec = recall_score(y_test, y_pred )
f1 = f1_score(y_test, y_pred )
f2 = fbeta_score(y_test, y_pred, beta=2.0)model_results = pd.DataFrame([[
'Decision Tree', acc, prec, rec, f1, f2]],
 columns = ['Model', 'Accuracy', 'Precision', 
'Recall', 'F1 Score', 'F2 Score'])results = results.append(model_results, ignore_index = True)results = results.sort_values(["Precision", 
"Recall", "F2 Score"], ascending = False)print (results)

决策树结果(图片由作者提供)

步骤 15.4.7。随机森林:

# Fitting Random Forest to the Training set:

classifier = RandomForestClassifier(n_estimators = 72, 
criterion = 'entropy', random_state = 0)
classifier.fit(X_train, y_train)# Predicting the Test set results 
y_pred = classifier.predict(X_test)#Evaluate results
from sklearn.metrics import confusion_matrix, 
accuracy_score, f1_score, precision_score, recall_score
acc = accuracy_score(y_test, y_pred )
prec = precision_score(y_test, y_pred )
rec = recall_score(y_test, y_pred )
f1 = f1_score(y_test, y_pred )
f2 = fbeta_score(y_test, y_pred, beta=2.0)model_results = pd.DataFrame([['Random Forest', 
acc, prec, rec, f1, f2]],
columns = ['Model', 'Accuracy', 'Precision', 
'Recall', 'F1 Score', 'F2 Score'])results = results.append(model_results, ignore_index = True)results = results.sort_values(["Precision", 
"Recall", "F2 Score"], ascending = False)print (results)

比较基线分类算法第二次迭代(图片由作者提供)

从第二次迭代,我们可以明确地得出结论,逻辑回归是给定数据集的最佳选择模型,因为它具有相对最高的精确度、召回率和 F2 分数的组合;给出最大数量的正确肯定预测,同时最小化假否定。因此,让我们在接下来的章节中尝试使用逻辑回归并评估其性能。

D 部分:模型评估

步骤 16:训练&评估选择的模型:让我们将选择的模型(在这种情况下是逻辑回归)拟合到训练数据集上,并评估结果。

classifier = LogisticRegression(random_state = 0,
penalty = 'l2')
classifier.fit(X_train, y_train)# Predict the Test set results
y_pred = classifier.predict(X_test)#Evaluate Model Results on Test Set:
acc = accuracy_score(y_test, y_pred )
prec = precision_score(y_test, y_pred )
rec = recall_score(y_test, y_pred )
f1 = f1_score(y_test, y_pred )
f2 = fbeta_score(y_test, y_pred, beta=2.0)results = pd.DataFrame([['Logistic Regression',
acc, prec, rec, f1, f2]],columns = ['Model', 'Accuracy', 'Precision', 'Recall', 'F1 Score', 'F2 Score'])print (results)

k-Fold 交叉验证:模型评估通常通过“k-Fold 交叉验证”技术完成,该技术主要帮助我们修正方差。当我们在训练集和测试集上运行模型时获得了良好的准确性,但当模型在另一个测试集上运行时,准确性看起来有所不同,这时就会出现方差问题。

因此,为了解决方差问题,k 折叠交叉验证基本上将训练集分成 10 个折叠,并在测试折叠上测试之前,在 9 个折叠(训练数据集的 9 个子集)上训练模型。这给了我们在所有十种 9 折组合上训练模型的灵活性;为最终确定差异提供了充足的空间。

accuracies = cross_val_score(estimator = classifier,
 X = X_train, y = y_train, cv = 10)print("Logistic Regression Classifier Accuracy: 
%0.2f (+/- %0.2f)"  % (accuracies.mean(), 
accuracies.std() * 2))

k 倍交叉验证结果(图片由作者提供)

因此,我们的 k-fold 交叉验证结果表明,在任何测试集上运行该模型时,我们的准确率都在 76%到 84%之间。

在混淆矩阵上可视化结果:混淆矩阵表明我们有 208+924 个正确预测和 166+111 个错误预测。

准确率=正确预测数/总预测数* 100
错误率=错误预测数/总预测数* 100

我们有 80%的准确率;标志着一个相当好的模型的特征。

cm = confusion_matrix(y_test, y_pred) 
df_cm = pd.DataFrame(cm, index = (0, 1), columns = (0, 1))
plt.figure(figsize = (28,20))fig, ax = plt.subplots()
sn.set(font_scale=1.4)
sn.heatmap(df_cm, annot=True, fmt='g'#,cmap="YlGnBu" 
           )
class_names=[0,1]
tick_marks = np.arange(len(class_names))plt.tight_layout()
plt.title('Confusion matrix\n', y=1.1)
plt.xticks(tick_marks, class_names)
plt.yticks(tick_marks, class_names)
ax.xaxis.set_label_position("top")plt.ylabel('Actual label\n')
plt.xlabel('Predicted label\n')

困惑矩阵(图片由作者提供)

用 ROC 图评估模型:用 ROC 图重新评估模型很好。ROC 图向我们展示了一个模型基于 AUC 平均分数区分类别的能力。橙色线代表随机分类器的 ROC 曲线,而好的分类器试图尽可能远离该线。如下图所示,微调后的逻辑回归模型显示了更高的 AUC 得分。

classifier.fit(X_train, y_train) 
probs = classifier.predict_proba(X_test) 
probs = probs[:, 1] 
classifier_roc_auc = accuracy_score(y_test, y_pred )rf_fpr, rf_tpr, rf_thresholds = roc_curve(y_test, classifier.predict_proba(X_test)[:,1])
plt.figure(figsize=(14, 6))# Plot Logistic Regression ROCplt.plot(rf_fpr, rf_tpr, 
label='Logistic Regression (area = %0.2f)' % classifier_roc_auc)# Plot Base Rate ROC
plt.plot([0,1], [0,1],label='Base Rate' 'k--')plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])plt.ylabel('True Positive Rate \n',horizontalalignment="center",
fontstyle = "normal", fontsize = "medium", 
fontfamily = "sans-serif")plt.xlabel('\nFalse Positive Rate \n',horizontalalignment="center",
fontstyle = "normal", fontsize = "medium", 
fontfamily = "sans-serif")plt.title('ROC Graph \n',horizontalalignment="center", 
fontstyle = "normal", fontsize = "22", 
fontfamily = "sans-serif")plt.legend(loc="lower right", fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.show()

ROC 图(图片由作者提供)

步骤 17:预测特征重要性:逻辑回归允许我们确定对预测目标属性有意义的关键特征(在这个项目中为“流失”)。

逻辑回归模型预测,流失率将随着逐月合同、光纤互联网服务、电子支票、支付安全和技术支持的缺失而正增长。

另一方面,如果任何客户订阅了在线证券、一年期合同或选择邮寄支票作为支付媒介,该模型预测与客户流失呈负相关。

# Analyzing Coefficientsfeature_importances = pd.concat([
pd.DataFrame(dataset.drop(columns = 'customerID').
columns, columns = ["features"]),
pd.DataFrame(np.transpose(classifier.coef_), 
columns = ["coef"])],axis = 1)
feature_importances.sort_values("coef", ascending = False)

预测功能的重要性(图片由作者提供)

E 部分:模型改进

模型改进基本上包括为我们提出的机器学习模型选择最佳参数。任何机器学习模型中都有两种类型的参数——第一种类型是模型学习的参数类型;通过运行模型自动找到最佳值。第二类参数是用户在运行模型时可以选择的参数。这样的参数被称为超参数;模型外部的一组可配置值,这些值无法由数据确定,我们正试图通过随机搜索或网格搜索等参数调整技术来优化这些值。

超参数调整可能不会每次都改进模型。例如,当我们试图进一步调优模型时,我们最终得到的准确度分数低于默认分数。我只是在这里演示超参数调整的步骤,以供将来参考。

步骤 18:通过网格搜索进行超参数调谐:

# Round 1:

# Select Regularization Method   
import time
penalty = ['l1', 'l2']# Create regularization hyperparameter space
C = [0.001, 0.01, 0.1, 1, 10, 100, 1000]# Combine Parameters
parameters = dict(C=C, penalty=penalty)lr_classifier = GridSearchCV(estimator = classifier,
                           param_grid = parameters,
                           scoring = "balanced_accuracy",
                           cv = 10,
                           n_jobs = -1)
t0 = time.time()
lr_classifier  = lr_classifier .fit(X_train, y_train)
t1 = time.time()
print("Took %0.2f seconds" % (t1 - t0))lr_best_accuracy = lr_classifier.best_score_
lr_best_parameters = lr_classifier.best_params_
lr_best_accuracy, lr_best_parameters

超参数调整-第一轮(图片由作者提供)

# Round 2:# Select Regularization Method
import time
penalty = ['l2']# Create regularization hyperparameter space
C = [ 0.0001, 0.001, 0.01, 0.02, 0.05]# Combine Parameters
parameters = dict(C=C, penalty=penalty)lr_classifier = GridSearchCV(estimator = classifier,
                           param_grid = parameters,
                           scoring = "balanced_accuracy",
                           cv = 10,
                           n_jobs = -1)
t0 = time.time()
lr_classifier  = lr_classifier .fit(X_train, y_train)
t1 = time.time()
print("Took %0.2f seconds" % (t1 - t0))lr_best_accuracy = lr_classifier.best_score_
lr_best_parameters = lr_classifier.best_params_
lr_best_accuracy, lr_best_parameters

超参数调整-第二轮(图片由作者提供)

步骤 18.2:最终超参数调整和选择:

lr_classifier = LogisticRegression(random_state = 0, penalty = 'l2')
lr_classifier.fit(X_train, y_train)# Predict the Test set resultsy_pred = lr_classifier.predict(X_test)#probability score
y_pred_probs = lr_classifier.predict_proba(X_test)
y_pred_probs  = y_pred_probs [:, 1]

F 部分:未来预测

步骤 19:将预测与测试集进行比较:

#Revalidate final results with Confusion Matrix:cm = confusion_matrix(y_test, y_pred) 
print (cm)#Confusion Matrix as a quick Crosstab:

pd.crosstab(y_test,pd.Series(y_pred),
rownames=['ACTUAL'],colnames=['PRED'])#visualize Confusion Matrix:cm = confusion_matrix(y_test, y_pred) 
df_cm = pd.DataFrame(cm, index = (0, 1), columns = (0, 1))
plt.figure(figsize = (28,20))fig, ax = plt.subplots()
sn.set(font_scale=1.4)
sn.heatmap(df_cm, annot=True, fmt='g'#,cmap="YlGnBu" 
           )
class_names=[0,1]
tick_marks = np.arange(len(class_names))
plt.tight_layout()
plt.title('Confusion matrix\n', y=1.1)
plt.xticks(tick_marks, class_names)
plt.yticks(tick_marks, class_names)
ax.xaxis.set_label_position("top")
plt.ylabel('Actual label\n')
plt.xlabel('Predicted label\n')print("Test Data Accuracy: %0.4f" % accuracy_score(y_test, y_pred))

困惑矩阵(图片由作者提供)

步骤 20:格式化最终结果:不可预测性和风险是任何预测模型的亲密伴侣。因此,在现实世界中,除了绝对的预测结果之外,建立一个倾向评分总是一个好的做法。除了检索二进制估计目标结果(0 或 1),每个“客户 ID”都可以获得一个额外的倾向得分层,突出显示他们采取目标行动的概率百分比。

final_results = pd.concat([test_identity, y_test], axis = 1).dropna()final_results['predictions'] = y_predfinal_results["propensity_to_churn(%)"] = y_pred_probsfinal_results["propensity_to_churn(%)"] = final_results["propensity_to_churn(%)"]*100final_results["propensity_to_churn(%)"]=final_results["propensity_to_churn(%)"].round(2)final_results = final_results[['customerID', 'Churn', 'predictions', 'propensity_to_churn(%)']]final_results ['Ranking'] = pd.qcut(final_results['propensity_to_churn(%)'].rank(method = 'first'),10,labels=range(10,0,-1))print (final_results)

高风险类别(图片由作者提供)

低风险类别(图片由作者提供)

G 部分:模型部署

最后,使用“joblib”库将模型部署到服务器上,这样我们就可以生产端到端的机器学习框架。稍后,我们可以在任何新的数据集上运行该模型,以预测未来几个月内任何客户流失的概率。

第 21 步:保存模型:

filename = 'final_model.model'
i = [lr_classifier]
joblib.dump(i,filename)

结论

因此,简而言之,我们利用 Kaggle 的客户流失数据集来建立一个机器学习分类器,该分类器可以预测任何客户在未来几个月内的流失倾向,准确率达到 76%至 84%。

接下来是什么?

  • 与组织的销售和营销团队分享您从探索性数据分析部分获得的关于客户人口统计和流失率的关键见解。让销售团队了解与客户流失有积极和消极关系的特征,以便他们能够相应地制定保留计划。
  • 此外,根据倾向得分将即将到来的客户分为高风险(倾向得分> 80%的客户)、中风险(倾向得分在 60-80%之间的客户)和最后低风险类别(倾向得分< 60%的客户)。预先关注每个客户群,确保他们的需求得到充分满足。
  • 最后,通过计算当前财务季度的流失率来衡量这项任务的投资回报(ROI)。将季度结果与去年或前年的同一季度进行比较,并与贵组织的高级管理层分享结果。

GitHub 库

我已经从 Github 的许多人那里学到了(并且还在继续学到)。因此,在一个公共的 GitHub 库中分享我的整个 python 脚本和支持文件,以防它对任何在线搜索者有益。此外,如果您在理解 Python 中有监督的机器学习算法的基础方面需要任何帮助,请随时联系我。乐于分享我所知道的:)希望这有所帮助!

关于作者

[## Sreejith Sreedharan - Sree

数据爱好者。不多不少!你好!我是 Sreejith Sreedharan,又名 Sree 一个永远好奇的数据驱动的…

srees.org](https://srees.org/about)

利用 PySpark 和机器学习预测客户流失

原文:https://towardsdatascience.com/predict-customer-churn-with-pyspark-and-machine-learning-981d1eedb00b?source=collection_archive---------45-----------------------

客户流失是指客户终止与公司的关系。它对企业的健康和长期成功有相当大的影响,因为它可能会大大降低收入和利润。根据 Forrester research 的统计,获得新客户的成本是保持现有客户的 5 倍。因此,公司投入时间和资源来识别可能流失的特定客户,并在这些客户决定停止使用公司的服务之前解决他们的问题总是值得的。

在本文中,我们将探索一个名为 Sparkify 的虚构音乐流媒体服务的用户日志数据,并建立有监督的机器学习模型来预测客户是否有可能流失。

我们的数据集

这个项目有两个数据集:大小为 12GB 的完整数据集,以及大小为 128MB 的完整数据集的一个子集。我们将使用 128MB 版本的数据集,它足够小,可以放入本地机器的内存中,就像本文中的例子一样。在其他情况下,为了使用完整的数据集进行模型训练,我们可能需要在像 AWS 这样的云服务上部署一个集群。

让我们快速浏览一下数据集中的所有字段:

df.printSchema()root
 |-- artist: string (nullable = true)
 |-- auth: string (nullable = true)
 |-- firstName: string (nullable = true)
 |-- gender: string (nullable = true)
 |-- itemInSession: long (nullable = true)
 |-- lastName: string (nullable = true)
 |-- length: double (nullable = true)
 |-- level: string (nullable = true)
 |-- location: string (nullable = true)
 |-- method: string (nullable = true)
 |-- page: string (nullable = true)
 |-- registration: long (nullable = true)
 |-- sessionId: long (nullable = true)
 |-- song: string (nullable = true)
 |-- status: long (nullable = true)
 |-- ts: long (nullable = true)
 |-- userAgent: string (nullable = true)
 |-- userId: string (nullable = true)

页面字段为我们提供了更多关于用户行为的详细信息:

df.select('page').dropDuplicates().sort('page').show()+--------------------+
|                page|
+--------------------+
|               About|
|          Add Friend|
|     Add to Playlist|
|              Cancel|
|Cancellation Conf...|
|           Downgrade|
|               Error|
|                Help|
|                Home|
|              Logout|
|            NextSong|
|         Roll Advert|
|       Save Settings|
|            Settings|
|    Submit Downgrade|
|      Submit Upgrade|
|         Thumbs Down|
|           Thumbs Up|
|             Upgrade|
+--------------------+

因为 userId 是我们的目标变量,可以帮助我们唯一地识别用户,所以带有空 userId 的日志对于我们预测哪个客户会流失没有帮助。我们将从数据集中删除那些缺少 userId 的记录。

df = df.where(col('userId').isNotNull())
df.count()278154

探索性数据分析

在我们继续比较频繁用户和不频繁用户之前,我们首先需要考虑一下什么是频繁用户。一个狭义的定义可能只包括那些已经删除了他们的帐户的人,这在我们的数据中被捕获为页面特征取值为“取消确认”的情况。

我们将使用页面的取消确认事件来定义流失。我们将创建一个新的列“churned ”,为我们的模型标记 Churned 用户。

Number of users who have churned 52
Number of users who have not churned 173

我们可以看到,在这个数据集中,流失类和非流失类的数量不平衡。在这种情况下,我们稍后将使用 F1 分数来评估我们的模型,因为与准确度和精确度相比,它对类别不平衡不太敏感。

性别影响

there were 19 percent female users churned
there were 26 percent male users churned

影响等级(付费/免费)

there were 23 percent free users churned
there were 21 percent paid users churned

用户听歌时间的影响

播放歌曲数量的影响

登记后天数的影响

被浏览页面的影响

显示每个用户页面事件数量的数据透视表

特色工程

现在我们已经熟悉了数据,我们构建了我们认为有前途的功能,并结合页面事件来训练模型:

user_df.printSchema()root
 |-- userId: string (nullable = true)
 |-- churn: long (nullable = true)
 |-- n_act: long (nullable = false)
 |-- n_about: long (nullable = true)
 |-- n_addFriend: long (nullable = true)
 |-- n_addToPlaylist: long (nullable = true)
 |-- n_cancel: long (nullable = true)
 |-- n_downgrade: long (nullable = true)
 |-- n_error: long (nullable = true)
 |-- n_help: long (nullable = true)
 |-- n_home: long (nullable = true)
 |-- n_logout: long (nullable = true)
 |-- n_rollAdvert: long (nullable = true)
 |-- n_saveSettings: long (nullable = true)
 |-- n_settings: long (nullable = true)
 |-- n_submitDowngrade: long (nullable = true)
 |-- n_submitUpgrade: long (nullable = true)
 |-- n_thumbsDown: long (nullable = true)
 |-- n_thumbsUp: long (nullable = true)
 |-- n_upgrade: long (nullable = true)
 |-- playTime: double (nullable = true)
 |-- numSongs: long (nullable = false)
 |-- numArtist: long (nullable = false)
 |-- active_days: double (nullable = true)
 |-- numSession: long (nullable = false)
 |-- encoded_level: double (nullable = true)
 |-- encoded_gender: double (nullable = true)

多重共线性增加了系数的标准误差。增加的标准误差,反过来,意味着一些独立变量的系数可能会发现没有明显不同于 0。换句话说,通过过度夸大标准误差,多重共线性使得一些本应显著的变量在统计上变得不显著。如果没有多重共线性(因此标准误差较低),这些系数可能很重要。

我们可以看到,有一些变量对的相关系数超过 0.8,这意味着那些变量是高度相关的。为了处理多重共线性,我们将尝试两种方法:

  • 手动移除相关要素
  • 主成分分析

手动移除相关特征

我们手动删除上一个热图中相关系数高的变量,并保留其余特征:

 user_df_m.printSchema()root
 |-- userId: string (nullable = true)
 |-- churn: long (nullable = true)
 |-- n_about: long (nullable = true)
 |-- n_error: long (nullable = true)
 |-- n_rollAdvert: long (nullable = true)
 |-- n_saveSettings: long (nullable = true)
 |-- n_settings: long (nullable = true)
 |-- n_submitDowngrade: long (nullable = true)
 |-- n_submitUpgrade: long (nullable = true)
 |-- n_thumbsDown: long (nullable = true)
 |-- n_upgrade: long (nullable = true)
 |-- active_days: double (nullable = true)
 |-- numSession: long (nullable = false)
 |-- encoded_level: double (nullable = true)
 |-- encoded_gender: double (nullable = true)

用 PCA 变换特征

主成分分析(PCA)是一种统计分析技术,它将可能相关的变量转换为正交线性不相关的值。我们可以将它用于数据压缩等应用,以获得主导的物理过程,并获得机器学习的重要特征。在不丢失太多信息的情况下,它减少了原始数据中的要素数量。

应用 PCA 时,我们需要首先将特征组合成一个向量,并标准化我们的数据:

*# Vector Assembler*
user_df_pca = user_df
cols = user_df_pca.drop('userId','churn').columns
assembler = VectorAssembler(inputCols=cols, outputCol='Features')
user_df_pca = assembler.transform(user_df).select('userId', 'churn','Features')

*# Standard Scaler*
scaler= FT.StandardScaler(inputCol='Features', outputCol='scaled_features_1', withStd=**True**)
scalerModel = scaler.fit(user_df_pca)
user_df_pca = scalerModel.transform(user_df_pca)
user_df_pca.select(['userId','churn', 'scaled_features_1']).show(5, truncate = **False**)pca = PCA(k=10, inputCol = scaler.getOutputCol(), outputCol="pcaFeatures")
pca = pca.fit(user_df_pca)

pca_result = pca.transform(user_df_pca).select("userId","churn","pcaFeatures")

型号选择

为了选择一个好的模型进行最终调优,我们将在 Spark 的 ML 中比较三个不同的分类器模型:

  • 逻辑回归
  • 决策图表
  • 随机森林

将数据分为训练集和测试集

从上一节展示的流失分布中,我们知道这是一个不平衡的数据集,只有 1/4 的用户被标记为流失。为了避免随机分裂中的不平衡结果,我们首先使用标签抽样建立一个训练集,然后从整个数据集中减去它们得到测试集。

*# prepare training and test data, sample by label*ratio = 0.7train_m = m_features_df.sampleBy('churn', fractions={0:ratio, 1:ratio}, seed=123)
test_m = m_features_df.subtract(train_m)train_pca = pca_features_df.sampleBy('churn', fractions={0:ratio, 1:ratio}, seed=123)
test_pca = pca_features_df.subtract(train_pca)

逻辑回归

*# initialize classifier*
lr = LogisticRegression(maxIter=10)*# evaluator*
evaluator_1 = MulticlassClassificationEvaluator(metricName='f1')*# paramGrid*
paramGrid = ParamGridBuilder() \
    .build()crossval_lr = CrossValidator(estimator=lr,
                          evaluator=evaluator_1, 
                          estimatorParamMaps=paramGrid,
                          numFolds=3)

使用测试数据集评估:

决策树

*# initialize classifier*
dtc = DecisionTreeClassifier()*# evaluator*
evaluator_2 = MulticlassClassificationEvaluator(metricName='f1')*# paramGrid*
paramGrid = ParamGridBuilder() \
    .build()crossval_dtc = CrossValidator(estimator=dtc,
                          evaluator=evaluator_2, 
                          estimatorParamMaps=paramGrid,
                          numFolds=3)

使用测试数据集评估:

随机森林

*# initialize classifier*
rfc = RandomForestClassifier()*# evaluator*
evaluator_3 = MulticlassClassificationEvaluator(metricName='f1')*# paramGrid*
paramGrid = ParamGridBuilder() \
    .build()crossval_rfc = CrossValidator(estimator=rfc,
                          evaluator=evaluator_3, 
                          estimatorParamMaps=paramGrid,
                          numFolds=3)

使用测试数据集评估:

结论

在所有三个模型中,主成分分析的结果优于手动降维后的特征。虽然逻辑回归模型为测试数据集提供了完美的 F1 分数和准确性,但它对训练数据集的表现远不如人意。由于逻辑回归模型在完整数据集上的表现也不尽如人意,这一完美的 F1 分数可能是由于模型的偶然性或简单性。因此,我将选择随机森林分类器用于未来的实现,其测试和训练 F1 分数都在 97%左右。

尽管将来我们可以尝试许多其他模型,如朴素贝叶斯和线性 SVM,但随机森林模型在这种情况下表现得相当好(小数据集的 F1 值为 97%,完整数据集的 F1 值为 99.992%)。

还有一些其他的改进,我们可以在未来继续努力:

  • 训练和评估模型的更加自动化和健壮的方法
  • 考虑那些降低服务等级的用户
  • 更注重用户行为特征

感谢阅读!

用神经网络预测日用电量。

原文:https://towardsdatascience.com/predict-daily-electric-consumption-with-neural-networks-8ba59471c1d?source=collection_archive---------19-----------------------

一个简单的三维结构如何减少错误,战胜更复杂的模型,并加倍节省。

2019 年初,我们建立了一个深度学习模型,以每小时为基础预测电力消耗。因为最小的误差都会让电力公司损失数万美元,所以我们研究了许多更复杂的预测工具。最后,我们发现一个简单的全天方法是最有效的,通常可以将错误减半。

该结构

在我们之前的模型中,我们输入了所有我们认为与给定小时负载相关的特性:日期、天气数据等。然后,神经网络输出单小时负荷预测。这个过程重复了 72 次,给出了一个 3 天的预报。想要更深入的解释,可以考虑阅读原文博文

新的结构有效地结合了 24 小时模型。但是,我们没有计算一个小时,而是将所有重量合并到一个平坦的、完全连接的密集层中(我们决定大约。900 个节点)。该层然后完全连接到一个 24 小时向量。然后,我们在 3 天内重复这一过程,给出 72 小时的预测。

为什么这应该有效?

主要的要点应该是不同的时间互相“通知”。在我们的旧模型中,我们有一个非常直接的方法:给定所有这些因素,这一小时的预测是什么?但是在我们的新模型中,我们可以让所有对 4pm 的负载预测有贡献的因素影响 5pm 的负载预测。如果早上 6 点的温度是 30 华氏度,这难道不会影响到 9 点时加热器是否还在工作吗?神经网络可以识别这些复杂的相关性,并提供更明智的预测。

这是怎么建的?

正确准备三维训练数据可能很棘手。下面是一个不太完美的函数,它将数据适当地分组到所需的维度。

然后,它被送入以下网络:

为什么不是 RNN?

一个递归神经网络,或 RNN,将类似于上面概述的网络运行。但是我们对 LSTMs 和 GRUs(两个流行的 RNN 模型)的测试并不成功。我们无法制造出超越我们最简单的逐时结构的模型。简而言之,传统的 RNN 结构似乎让事情变得更糟。

为什么一天 24 小时?

在我们的短期预测分析中,我们通常关心三天增量的负载(更远的预测很快变得无用)。那么为什么不在 72 小时的向量上训练呢?我们在技术上可以,但成本不会超过收益。在我们的 24 小时预测中,日模型的运行速度比小时模型慢三倍,但是回报(我们将在下面看到)非常高。但是,当我们增加到 48 或 72 小时的预测时,模型会严重变慢,但几乎没有改善。至少就我们的目的而言,分开训练三个 24 小时模型更好。

结果呢

我们在德克萨斯州的“中北部”地区测试了新模型。数据可以在这里找到。虽然实际上模型会每天训练,但在这次测试中,我们严格训练了前 16 年的数据(2002 年至 2017 年),并在最后一年(2018 年)进行了测试。为了模拟天气预报的不确定性,我们向历史天气数据中添加了噪声,即 24、48 和 72 小时分组的标准偏差分别为 2.5、4 和 6 度的正态分布。

准确(性)

新模型的平均绝对百分比误差(MAPE)为 3,而旧模型的前 24 小时 MAPE 为 4。但是每小时的结果更令人信服。

最重要的问题不仅是 MAPE,而且是误差的传播(下面表示为四分位距,或 IQR)。在开发我们的第一个模型时,我们发现当我们的模型是错误的时候,它通常是非常错误的。新模型中减少的方差可以帮助我们更有信心地向公用事业公司传达我们的不确定性。

这些模型假设用户将在晚上 11 点预测第二天的电力消耗。因此,下图中的“提前 0 小时”意味着“凌晨 12 点”,“提前 30 小时”类似于“两天后的凌晨 5 点”,等等。

节省的资金

而且最重要的是,省下来的钱!误差减少 1 个百分点可能看起来微不足道,但在 2018 年,这将使德克萨斯州的调峰储蓄增加一倍。(如果你对调峰不熟悉,可以考虑看看这位讲解者)。

假设电池的充电功率为 700 千瓦,额定功率为 500 千瓦,我们可以通过完美的预测计算出可能出现的调峰量。使用我们的每小时神经网络模型,您可以捕获 36%的最佳值。通过替换新模型(不确定性分析下没有任何花哨的优化),我们能够捕获 64%的成本,几乎使我们的节约翻倍!

欢迎建议

我们无法开发出比我们的模型更好的 RNN,但这并不意味着它不存在。精度的微小提高可以极大地帮助电力公司,所以如果你认为有我们没有考虑到的结构,请随时联系我们!

疑问?更正?数据科学笑话?联系我或者在 我的网站 上看更多项目。

合作研究开放式建模框架

这是关于神经网络调峰的三部分系列的更新。考虑在这里阅读更多:

[## 基于神经网络的⚡️负荷预测和调峰

预测技术给了公用事业单位一个机会来拉平他们的负荷曲线,提出了一个全新的家庭…

www.kmcelwee.com](https://www.kmcelwee.com/load-forecasting/)

用 R 预测世界大赛的本垒打

原文:https://towardsdatascience.com/predict-home-runs-in-the-world-series-with-r-d8c0bb2e6f02?source=collection_archive---------38-----------------------

使用历史棒球数据和带 R 的逻辑回归来预测世界职业棒球大赛的得分。

蒂姆·高在 Unsplash 上拍摄的照片

介绍

你有没有想过美国棒球、机器学习、统计学有什么共同点?嗯,你今天很幸运!

在这个项目中,我们将使用一些免费的历史棒球数据和 R 中的 glm() 函数,来看看哪些变量在预测世界职业棒球大赛中有多少本垒打发生时起作用。

这个项目有几个假设。首先,您有一个 R 环境设置。对于这个项目,我将在 Mac 上的 RStudio 中使用 R Markdown (RMD)文件,但代码在其他操作系统和环境下也能正常工作。第二,你至少对棒球有一个基本的了解。我绝不是棒球专家,但也不需要什么重要的知识。只要你知道什么是本垒打,我们就没事了!

为了您的方便,RMD 的文件可以在我的 GitHub 这里获得

现在,让我们进入目标,开始编写代码吧!

目标

  1. 了解如何在不使用本地文件或手动将数据加载到环境中的情况下导入数据
  2. 将数据分成训练集和测试集,用于机器学习
  3. 使用非正态数据分布进行机器学习
  4. 使用逐步回归方法创建逻辑回归模型
  5. 使用模型进行预测,并检查我们的模型的准确性

数据

在我们进入代码之前,我们需要谈谈肖恩·拉赫曼的惊人工作。他和他的团队已经创建并免费提供了数量惊人的棒球历史数据。他们还做了大量的工作,用其他几种编程语言制作了一个 R 包和易于使用的实现。我会经常引用他们的话,把数据归功于他们。他们的整个项目只靠他们网站上描述的捐赠来运作。如果你真的想帮助他们,体育分析领域的许多人会用这个数据集来以一种有趣的方式学习机器学习。

这是肖恩的网站:http://www.seanlahman.com/baseball-archive/statistics/

现在该编码了!

代码

加载库

我们将在整个项目中使用 tidyverseLahman 包。

代码如下:

# Uncomment the commands below if you have not installed either the tidyverse or Lahman packages
# install.packages("tidyverse")
# install.packages("Lahman")# Load Libraries
require(tidyverse)
require(Lahman)

如果您以前使用过 R,请特别注意它明显缺少导入本地数据和命名对象的功能。我们只需要使用 data() 函数从拉赫曼的数据集中拉出我们想要的表。默认情况下,对象将以数据框的形式出现,并被称为表的名称,对于我们的目的来说就是 BattingPost。

代码如下:

# Imports the BattingPost data set from the Lahman database. Notice how there is not a file to read in. The data is part of the package!
data(BattingPost)# Check the data import
# Notice again that we did not have create and object and assign it data like we normally do with R. It just knows to create a data frame called "BattingPost"
head(BattingPost)

以下是输出结果:

从拉赫曼的数据库[1]导入 BattingPost 表

过滤数据

我们现在已经把数据输入 R 了。我们需要稍微清理一下。首先,由于这是一个关于世界职业棒球大赛的项目,我们需要确保我们的 round 列中只有“WS”值。其次,我们需要确保 yearID 列大于或等于 1920。我不是棒球历史学家,但那是现代“实况球时代”开始的时候[2]。如果你对那种历史感兴趣,可以看看 Bradford Doolittle 关于 ESPN 的文章。

代码如下:

# Filter down the data a bit. We went the year to be 1920 and later because that's when the "Live Ball Era" starts. We also want only WS in the round column because that's for the World Series.SlimBattingPost <- BattingPost %>%
  filter(yearID >= 1920) %>%
  filter(round == "WS")# Check the data
head(SlimBattingPost)

以下是输出结果:

从拉赫曼的数据[1]中筛选出大于或等于 1920 年的数据和仅等于世界系列的舍入数据

让我们为跟随的人澄清一下。你经常看到的“%>%”就是所谓的“管道”字符[3]。当使用 tidyverse 时,特别是其中的 dplyr 部分,处理数据时,我喜欢把它理解为管道字符后面的每个函数或条件都会使假设的数据漏斗变小一点。

我们很少需要一个数据集中的所有数据,因此通过一个周长越来越小的“漏斗”来“倾倒”它是一种可视化这里正在发生什么的好方法。仅仅通过应用这两个过滤器,我们就从原始数据中的 14,750 行增加到了新数据中的 4,280 行。您可以通过查看 RStudio 中的对象或者使用 nrow() 函数来获得这些数字。

代码如下:

# Print number of rows in each data set
nrow(BattingPost)
nrow(SlimBattingPost)

机器学习简介

让我们用我们的例子用简单的英语来解释机器学习的含义。我们将要做的事情被称为“监督机器学习”,因为我们作为人类正在“监督”什么数据被输入到机器中[3]。

当像这样使用真实数据时,我们想要做的是将整个数据集的一部分分割成“训练”数据,而将其余部分分割成“测试”数据[3]。这是出于一个非常合理的原因。如果你想让一台机器能够做出预测,你需要对照现实对它进行测试,以确保它实际上工作正常。

传统上,我可以补充一个很好的理由,即 80%的训练数据和 20%的测试数据分开。我见过各种其他组合,如 70/30 和 75/25,但我喜欢 80/20 的分割,因为我通常会得到最好的结果,听起来与帕累托原则相同[4]。拜托,我控制不了自己。我的学士学位是经济学。

因此,在接下来的几段代码中,我们将把数据分成训练集和测试集,使用 glm() 函数创建一个广义线性模型,然后随着时间的推移对其进行改进,以获得更好的结果。你会看到,我们可以让机器“学习”什么变量重要,什么不重要,以便随着时间的推移做出越来越好的预测。

播种

在我们分割数据之前,我们真的应该设定一个种子[3]。我们将使用随机(嗯,伪随机,如果你想精确)分裂。这意味着代码每次都会将数据分成不同的集合,除非我们使用带有数字的 set.seed() 函数,这样我们就能确保可再现性[3]。对于那些跟随的人来说,这意味着只要我们使用相同的数字,你的代码将与我的代码一致。

代码如下:

# Set Seed
set.seed(1337)

设置种子没有任何输出。它只是确保幕后参数设置正确的东西[3]。

培训和测试数据

有很多方法可以做到这一点,但这是我在实践中发现或看到的最简单的方法。这是秘密。我们将创建一个任意 ID 号的列,并将其添加到现有的数据中。这让我们可以轻松地使用 R 中最隐蔽的函数之一 tidyverse 中 dplyr 包中的 anti_join() 函数。这样做的目的是从一个表中获取在另一个表中没有匹配项的所有行。太偷偷摸摸了。我喜欢它,你可以在这里的文档中阅读所有关于它的内容

代码如下:

# Creates an ID column so we can more easily sort train from test
SlimBattingPost$id <- 1:nrow(SlimBattingPost)# Creates set of data randomly sampling 80% of total data
train <- SlimBattingPost %>% dplyr::sample_frac(.80)# Creates set of data with other 20%
test <- dplyr::anti_join(SlimBattingPost, train, by = 'id')# Check the data
head(test)
paste("The test data has this many rows:", nrow(test))
head(train)
paste("The train data has this many rows:",nrow(train))

以下是输出结果:

来自拉赫曼数据集[1]的过滤数据的前六行测试数据

我们从拉赫曼数据集[1]中筛选出的前六行训练数据

过滤后的拉赫曼数据[1]中每个测试和训练数据集中的行数

确定分布

大多数时候,机器学习处理的是正态分布的数据[3]。当你想到一个我们都见过很多次的正态钟形曲线时,它被称为“高斯”分布,因为数学家这么说[3]。看起来是这样的:

泰勒·哈里斯绘制的正态钟形曲线

在正态分布中,有一个平均值(μ,蓝线)和该平均值的标准偏差(σ,绿线)。进入细节并不是非常重要,但这意味着 95%的数据都在平均值的 2 个标准差(2 sigma)以内[3]。机器学习想要正常数据的原因有很多,但有时我们会得到不正常的数据。

另一种分布被称为“泊松”分布[3]。当然,它是以另一位数学家的名字命名的,但关键是,它是一种标准的分布类型,其中大多数数据都严重倾斜[3]。大多数时候,它看起来像这样:

泰勒·哈里斯绘制的基本泊松分布

对于机器学习,我们真正关心的是我们试图预测的变量的分布[3]。在我们的例子中,游程(R)将是因变量。让我们制作一个超级快速的直方图来检查我们是否有正态或泊松分布。

代码如下:

# Visually determine type of distribution of Runs (R) in dataset
hist(SlimBattingPost$R)# Classic Poisson distribution. Almost all data is 0 or 1, heavily skewed

以下是输出结果:

过滤后的拉赫曼数据的基本运行直方图[1]

对我来说,游程(R)变量看起来像一个非常经典的泊松分布!

建立模型

有趣的部分来了!我们现在开始建立逻辑回归模型!让我们先看看代码,然后再讨论它。

代码如下:

# Start with everything else as independent variables with runs (R) as the dependent variable
# For a data dictionary about what each abbreviation means, go to: [http://www.seanlahman.com/files/database/readme2017.txt](http://www.seanlahman.com/files/database/readme2017.txt)
# Search for "BattingPost" in that document and the third match should be the table where the abbreviations are defined. G = Games, AB = At Bats, etc.# Create the logistic regression with everything in it, make sure to include the Poisson distribution as the family. If we had normal data, we would use Gaussian in its place.fitAll <- glm(R ~ G + AB + H + X2B + X3B + HR + RBI + SB + CS + BB + SO + IBB + HBP + SH + SF + GIDP , data = train, family = "poisson")summary(fitAll)

以下是输出结果:

包含所有独立变量的第一个 glm()模型的输出

这里有很多东西需要打开。

首先,我们创建了一个名为“fitAll”的模型对象,该对象使用了 glm() 函数,其中 R 作为因变量,用~字符与所有用 a +分隔的自变量分隔开,同时还使用了我们的训练数据(还记得前面的 80%吗?)并使用泊松分布来获得更精确的结果[3]。

一旦我们创建了模型, summary() 函数将以简单的形式给出上面的输出。

摘要的第一部分是“Call:”它只是说实际使用了什么模型。这里没什么可说的。

“偏差残差:”试图告诉我们在处理错误时现实和期望之间的差异[3]。实际上,在这一点上,这与学习逻辑回归并不完全相关,所以我们将继续前进。

“系数:”部分是我们需要关注的地方。第一列是所有变量加上截距。还记得代数一课的公式“ y = mx + b ”吗?这是截距[3]的 b 值的极端版本。

“估计”栏告诉我们每个值对运行次数的影响是积极的还是消极的,以及它的系数有多大[3]。这类似于一堆不同的 m 值,其中 x 值是实际数据集中的数字。一个等式可能是这样的y = mx+mx+m₃x… + b 具有所有不同的系数和值【3】。

“性病。“错误”栏是我们错误程度的统计指标[3]。z 值在统计学中用于给出分布曲线上的 z 值[3]。现在对我们来说没那么重要。

与我们最相关的是优雅地标记为“Pr(>|z|)”的列,这是 p 值的一种非常复杂的表达方式[3]。对于 p 值,我们关心的是我们所说的是有意义的一定程度的信心[3]。此外,p 值的范围在 0 和 1 之间,所以如果有负数或大于 1 的数字,数学在某个地方是错误的[3]。

例如,如果我们要至少 95%确定一个自变量是因变量的一个统计上显著的预测因子,p 值将小于 0.05[3]。如果我们希望 90%确定变量是显著的,那么我们需要看到一个小于 0 . 10 的 p 值[3]。要 99%确定,我们需要看到小于. 01 的 p 值[3]。明白我的意思了吗?

r 为我们提供了一个方便的小功能,它标记了每个变量的显著性水平。放一个单曲“.”像 SBSF 这样的变量意味着我们有 90%到 95%的把握这些变量在统计上是显著的[3]。变量旁边的“*”表示我们有 95%到 99%的把握该变量具有统计显著性,p 值越小,其余变量的预测能力越强[3]。

目标是最终得到一个只有统计上显著的独立变量的模型。那么我们该怎么做呢?我们使用一种叫做“逐步回归”的方法[3]。

逐步回归

这是一个听起来很有趣的术语,简单地说就是我们取出一个最不重要的变量,然后重新运行我们的模型,重复这个过程,直到我们只剩下具有统计意义的独立变量[3]。我们来做一个例子。在继续之前,找到具有最大 p 值的变量。

代码如下:

# Start step-wise regression.
# Looks like G is the least significant
# Make sure to create a new object name so we do not overwrite our models as we go along!fit1 <- glm(R ~ AB + H + X2B + X3B + HR + RBI + SB + CS + BB + SO + IBB + HBP + SH + SF + GIDP , data = train, family = "poisson")summary(fit1)

以下是输出结果:

删除最不重要变量后逻辑回归的新结果表

那么,你注意到了什么?在我们去掉了最不重要的变量 G 之后,很多 p 值都变了!这很正常。当所有的数字都被处理后,那些被认为是统计上显著变化的变量就被拿走了[3]。这也有道理。当你想到这一点时,不管是第一场还是第三场还是第六场比赛都会影响得分,这是没有意义的。

注意:当你删除一个变量时,确保也从公式的自变量侧删除“+”so,以避免不必要的错误!此外,请务必将您的模型重命名为不同的对象名称,以避免在学习时覆盖过去的工作!

然而,看起来我们仍然有不具有统计显著性的独立变量。看起来是下一个要去的变量。

代码如下:

# Looks like SO is the least significant
# Make sure to create a new object name so we do not overwrite our models as we go along!fit2 <- glm(R ~ AB + H + X2B + X3B + HR + RBI + SB + CS + BB + IBB + HBP + SH + SF + GIDP , data = train, family = "poisson")summary(fit2)

以下是输出结果:

移除 SO 后的第二个逐步回归摘要

希望在这一点上,你得到了模式。直到模型只剩下统计上显著的变量达到 95%的置信阈值(p 值< 0.05), we will look this process.

Rather than take up a ton of space, I am going to skip ahead to the final model after going through the process of removing non-significant independent variables. On your end, do it until you match up with my answer for learning purposes.

Here’s the code:

# Final Fit
fitFinal <- glm(R ~ AB + H + X2B + X3B + HR + CS + BB + IBB + HBP + GIDP , data = train, family = "poisson")summary(fitFinal)

Here’s the output:

Final logistic regression model after completing the step-wise regression process

Make Predictions

Now is the time where we see how well we did with our model. Fortunately for us, R has an easy-to-use tool for this — the 预测()函数。我们现在将使用我们的最终逻辑回归模型,对照我们的测试数据(我们之前保留的 20%)进行测试,然后看看我们有多准确!

代码如下:

# Create predictions
predictions <- predict(fitFinal, test, type = 'response')# Check the output
head(predictions)

以下是输出结果:

逻辑回归的前 6 个预测

现在,我知道我将要向你们展示的过程并不是做到这一点的捷径。然而,我发现这是最容易一步一步形象化的,这更好地支持了我们学习技术的目标。

我们现在要做的是将我们刚刚做出的预测添加到我们的测试数据中,选择我们实际上想要生成较小数据集的列,在新列中对预测进行舍入,并创建一列真布尔值和假布尔值,以便您可以轻松地看到幕后。

代码如下:

# Add predictions to test data and create new data frame
predictDF <- data.frame(test, predictions)# Create new data frame with less columns
SlimPredictDF <- select(predictDF, "yearID", "round", "playerID", "teamID", "R", "predictions")# Add rounded predictions as a column
SlimPredictDF$roundedPredictions <- round(SlimPredictDF$predictions, 0)# Create Boolean Column to see if real and predictions match
SlimPredictDF$TFmatch <- SlimPredictDF$R == SlimPredictDF$roundedPredictions# Check data structure 
head(SlimPredictDF)

以下是输出结果:

拉赫曼数据测试部分的四舍五入预测表[1]

结果

我们可以使用 tidyverse 中的几个函数创建一个简单的表来计算匹配和未匹配的次数。

代码如下:

# Get the results!
results_table <- SlimPredictDF %>%
  group_by(TFmatch) %>%
  summarise(count = n())
results_table

以下是输出结果:

逻辑回归模型预测值的结果表

嗯,66%还不算太糟,对吧?只要将 564 除以 856 就可以得到结果。

结果—奖励积分

我们可以检查结果的另一种方法是使用 lm() 函数制作一个快速线性模型,并查看我们的 R 平方值。我们会得到 R 平方的两个变量,但它们会很接近。这将告诉我们自变量(roundedPredictions)解释了因变量(R,runs)的多少。

代码如下:

# Simple linear model to get p-vale for whether real Runs (R) are significantly prediction by predictionsfitLM <- lm(R ~ roundedPredictions, data = SlimPredictDF)
summary(fitLM)

以下是输出结果:

使用线性模型的结果版本

当以这种方式检查时,我们得到了大约 63%正确的类似答案。

结论

这个项目旨在教育,有趣,真实。我们可以做很多实验,比如使用不同的分布,包括不仅仅是世界职业棒球大赛的季后赛,改变数据开始的年份等等。

在一天结束的时候,我们使用真实的数据进行真实的预测,并获得了大约 2/3 的正确率。我们还逐步回归,并在此过程中学习了一些非标准的 R 技巧。

如果您有任何问题、意见或对未来探索的想法,请告诉我。享受使用你新发现的逻辑回归技巧来预测其他数据吧!

参考

[1] S .拉赫曼,下载拉赫曼的棒球数据库 (2020),http://www.seanlahman.com/baseball-archive/statistics/

直播球时代已经过去了一百年,棒球是一项更好的运动吗? (2019),https://www . ESPN . com/MLB/story/_/id/27546614/100 年-直播球时代-棒球-更好-游戏

[3] R. Kabacoff, R 在行动(第二版。) (2015),纽约州谢尔特岛:曼宁出版公司

[4].K. Kruse,80/20 法则及其如何改变你的生活 (2016),https://www . Forbes . com/sites/kevinkruse/2016/03/07/80-20-Rule/# 230185973814

用机器学习预测房价

原文:https://towardsdatascience.com/predict-house-prices-with-machine-learning-5b475db4e1e?source=collection_archive---------4-----------------------

对 1,883 个家庭进行回归模型训练

图片来源:格雷戈·卡特大律师&事务律师。

财产估价是一门不精确的科学。个人评估师和估价师把他们自己的经验、标准和技能带到工作中。一致性是很难的,英国和澳大利亚的研究表明,两个专业人士的估值 相差高达 40% 。哎呀!

也许一台训练有素的机器可以代替人类来完成这项任务,而且一致性和准确性更高。

让我们将这一想法原型化,并使用关于房屋的 特征成本邻居简介 的数据来训练一些 ML 模型,以预测其价值。我们的目标变量房地产价格是数字,因此 ML 任务是回归。(对于分类目标,任务变为分类。)

我们将使用来自 elitedatascience.com 的数据集来模拟属于房地产投资信托基金的 1883 处房产的投资组合。有 26 列。这里有一小段:

原始数据集的快照。

这些步骤是:

  1. EDA &数据处理:探索、可视化和清理数据。
  2. 特性工程:利用领域专长,创造新特性。
  3. 模型训练:我们将训练和调优一些屡试不爽的分类算法,比如岭和套索回归。
  4. 性能评估:我们将看看常见的回归任务指标,如 R 分数和均方平均值。
  5. 部署:批量运行还是弄几个数据工程师/ ML 工程师来建一个自动化流水线?

加入 Medium 这里并获得无限制访问互联网上最好的数据科学文章。

1.数据探索和处理

探索性数据分析(EDA) 帮助我们理解数据,为数据清洗特征工程提供思路和见解。数据清理为我们的算法准备数据,而特征工程是真正帮助我们的算法从数据集中提取潜在模式的神奇调味汁。请记住:

更好的数据总是胜过更好的算法!

我们首先将一些标准数据科学 Python 包加载到 JupyterLab 中。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sbfrom sklearn.linear_model import LinearRegression
from sklearn.linear_model import Lasso, Ridge, ElasticNet
from sklearn.ensemble import RandomForestRegressor,
                             GradientBoostingRegressorfrom sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import GridSearchCVfrom sklearn.metrics import r2_score,
                            mean_absolute_error import pickle

导入数据集:

df = pd.read_csv('real_estate_data.csv')

这是我们数据帧的快照。形状是(1,883,26)。

原始数据集的快照。单击以展开。

目标变量是 tx_price ,它表示房产最后出售的价格。

共有 25 个栏/特征。

  • 房产特征: tx_year —最后出售的年份, property_type (独栋与公寓/公寓/联排别墅)。
  • 物业费:每月财产税保险
  • 物业特点:床、浴池sqrt (建筑面积)、 lot_size (含套外面积)、year _ build&地下室(是/否)。
  • 邻里生活方式:数量餐厅杂货夜生活咖啡馆购物艺术 _ 娱乐美容 spa、&、活跃 _ 生活(健身房、瑜伽馆等。)半径 1 英里以内。
  • 邻里人口统计:中位年龄已婚 (%)、大学毕业生 (%)。
  • 邻里学校:数量 _ 学校(区内)& 中位数 _ 学校(区内公立学校 10 分中的中位数)。

1.1 数字特征

我们的数字特征列表可以通过代码获得:

df.dtypes[df.dtypes!=’object’]

我们将在这里跳过它。相反,让我们直奔所有数字特征的直方图:

df.hist(figsize=(20,20), xrot=-45)

这看起来基本没问题。我用红色留下了一些评论。

目标变量(tx_price)的分布:

我们有一个右尾分布,也可以通过看一个小提琴图来看。

sns.violinplot(data=df, x=’tx_price’)

df.tx_price.median()**Output: 392000**

2020 年 10 月,美国房价中值为 325,000 美元,因此平均而言,房地产投资信托组合中的房屋似乎更靠近住宅区。

缺失值:

df.select_dtypes(exclude=[‘object’]).isnull().sum()**Output:
tx_price              0
beds                  0
baths                 0
sqft                  0
year_built            0
lot_size              0
basement              223
restaurants           0
groceries             0
nightlife             0
cafes                 0
shopping              0
arts_entertainment    0
beauty_spas           0
active_life           0
median_age            0
married               0
college_grad          0
property_tax          0
insurance             0
median_school         0
num_schools           0
tx_year               0**

基底特性的进一步研究表明基底=0 的行是用 NaN 编码的。因此,这实际上是一个标签不正确的问题。我们需要把 NaN 转换成 0 来进行运算。

df.basement.fillna(0, inplace=True)

注意:如果这些 NaN 是真正缺失的值,我们应该在将 基底 中的 NaN 转换为 0 之前,创建一个指示变量 基底 _ 缺失 (当基底=NaN 时值为 1)。

异常值:lot _ sizelot _ size的直方图表明我们有一些相当大的豪宅!

df.lot_size.sort_values(ascending=False)**Output:
102     1220551
1111     436471
1876     436035
1832     436035
1115     435600
Name: lot_size, dtype: int64**

实际上,只有一处房产比其他的大很多。让我们把它看作一个离群值,并为我们的建模过滤掉它。

df = df[df.lot_size < 500000]

这里有一张关联热图来展示我们的数字特征。

# mask out upper triangle
mask = np.zeros_like(df.corr(), dtype=np.bool)
mask[np.triu_indices_from(mask)] = True# heatmap
sb.heatmap(df.corr()*100, 
           cmap='RdBu_r', 
           annot = True, 
           mask = mask)

红色的三角形块表明邻近地区的生活方式特征往往相互关联得很好。例如,活跃生活、美容水疗、咖啡馆、夜生活餐馆都高度相关。这种多重共线性可能会影响模型性能,因为回归要素应该独立于

1.2 分类特征

我们的分类变量可以用代码列出:

df.dtypes[df.dtypes==’object’]

这些是:物业 _ 类型外墙屋顶。

这些分类特征中的每一个的类都可以用下列方式列出:

df.property_type.value_counts()**Output:
Single-Family                    1080
Apartment / Condo / Townhouse     802
Name: property_type, dtype: int64**df.exterior_walls.value_counts()**Output:
Brick                  686
Siding (Alum/Vinyl)    503
Metal                  120
Combination            107
Wood                    72
Wood Siding             49
Brick veneer            48
Stucco                  26
Other                   10
Concrete                 8
Concrete Block           7
Block                    7
Asbestos shingle         6
Rock, Stone              5
Masonry                  3
Wood Shingle             2
Name: exterior_walls, dtype: int64**df.roof.value_counts()**Output:
Composition Shingle      1179
Asphalt                   132
Shake Shingle              55
Other                      49
Wood Shake/ Shingles       30
Gravel/Rock                30
Roll Composition           12
Asbestos                    9
Slate                       9
Composition                 5
asphalt                     5
Metal                       4
composition                 4
shake-shingle               3
Built-up                    2
asphalt,shake-shingle       1
Name: roof, dtype: int64**

由此,我们可以稍微清理一下类。我们将

  • 将稀疏类合并在一起(那些观察值太少的类)
  • 合并具有相似含义的类(例如将混凝土砌块归入更一般的混凝土砌块类。
  • 修正标签错误(例如混凝土应为混凝土)。
df.exterior_walls.replace(['Wood Siding', 'Wood Shingle', 'Wood'],
                           'Wood', inplace=True)df.exterior_walls.replace(‘Rock, Stone’, ’Masonry’, inplace=True)df.exterior_walls.replace([‘Concrete’,’Block’], ’Concrete Block’,
                            inplace=True)df.exterior_walls.replace(['Concrete Block', 'Stucco', 'Concrete',
                           'Block', 'Masonry', 'Other', 
                           'Asbestos shingle', 'Rock, Stone'],
                           'Other', inplace=True)df.roof.replace(['Composition', 'Wood Shake/ Shingles', 
                 'Composition Shingle'], 'Composition Shingle',
                  inplace=True)df.roof.replace(['Other', 'Gravel/Rock', 'Roll Composition',
                 'Slate', 'Built-up', 'Asbestos', 'Metal'], 'Other',
                  inplace=True)df.roof.replace(['asphalt','asphalt,shake-shingle',
                 'shake-shingle'], 'Shake Shingle', inplace=True)df.roof.replace('composition', 'Composition',inplace=True)

缺失值:

df.select_dtypes(include=[‘object’]).isnull().sum()**Output:
property_type       0
exterior_walls    223
roof              353
dtype: int64**

我们想告诉我们的算法,这些值是缺少。这比简单地删除行更有指导意义。

for feat in df.select_dtypes(include=[‘object’]):
    df[feat] = df[feat].fillna(“Missing”)

让我们画出三个分类特征的柱状图。

for feat in df.dtypes[df.dtypes==’object’].index:
   sb.countplot(y=feat, data=df)

最后,对于我们的算法,分类特征必须是一次性编码的。我们现在就去做。

df = pd.get_dummies(df, columns = [‘exterior_walls’, 
                                   ‘roof’, 
                                   ‘property_type’])

1.3 细分

分割结合了数字和分类特征。

让我们根据我们的目标 tx_price 来分割我们所有的分类变量( property_type外墙屋顶)。这将提供一个可能驱动财产价值的细节。

for feat in df.dtypes[df.dtypes==’object’].index:
   sb.boxplot(data=df, x = ‘tx_price’, y = ‘{}’.format(feat))

让我们通过使用 groupby 来看看单户住宅和公寓/共管公寓/联排别墅之间的房产和街区特征有何不同。

df.groupby('property_type').agg(['mean','median'])

总的来说,独栋房子更贵,面积更大,而公寓/公寓/联排别墅更靠近娱乐场所/商店,吸引更年轻的居民。这并不奇怪。家庭住宅往往位于郊区,而公寓和更高密度的居住往往更靠近市中心。

2.特征工程

许多特征工程依赖于领域专业知识。如果你有一个房地产方面的主题专家(SME)来提供指导,你将有更好的机会设计一些令人敬畏的功能,这些功能将真正使你的建模发光。

在这里,我们将设计四个新功能:

  • 两房两卫:两房两卫房产。为什么?通过领域专业知识,你可能知道这些财产受投资者欢迎。这是一个指示变量。
  • 衰退期间:美国房地产市场在 2010 年至 2013 年间陷入衰退。因此,处于这一时期可能会在很大程度上影响定价。
  • property_age :这是一种常识。较新的物业应该吸引较高的价格,对不对?(回答:会但不一定。)
  • school_score :我们将这个交互特征定义为 num_schoolmedian_school 的乘积,它给出了代表该地区学校教育质量的单一分数。

以下代码创建了这些新功能。

df[‘two_and_two’] = ((df.beds == 2) & (df.baths == 2)).astype(int)df['during_recession'] = ((df.tx_year >= 2010) & 
                          (df.tx_year <= 2013))
                          .astype(int)df['property_age'] = df.tx_year - df.year_built
df.drop(['tx_year', 'year_built'], axis=1, inplace=True)df['school_score'] = df.num_schools * df.median_school

新的 property_age 功能可以说取代了原来的 tx_yearyear _ build,因此我们将删除它们。

此外,出于兴趣,我们可以看到大约 9%的房产有两张床/两个浴室,26%是在 2010 年至 2013 年的房地产衰退期间出售的:

df.two_and_two.mean()
df.during_recession.mean()**Outputs:
0.09458023379383634
0.2635494155154091**

分析基表:应用所有这些数据清洗步骤和特征工程后的数据集就是我们的分析基表。这是我们训练模型的数据。

我们的 ABT 有 1863 个属性和 40 列。回想一下,我们的原始数据集只有 26 列!通常,abt 比原始数据集有更多的列,因为:

  • one-hot 编码,其中为每个分类特征中的每个类创建一个新列;和
  • 特征工程。

与此相关,ML 中的一个问题是维数灾难,其中你的 ABT 有太多的列/特征。这是深度学习中的一个主要问题,在深度学习中,数据处理可能会产生具有数千个或更多特征的 abt。主成分分析(PCA) 是一种降维技术,将高维相关数据转化为一组低维的不相关成分,称为主成分 (PC)。好消息是,低维的 PCs 捕获了高维数据集中的大部分信息。

我计划写一篇关于无监督学习技术的文章,包括 PCA。睁大你的眼睛!

3.系统模型化

我们将训练四个屡试不爽的回归模型:

  • 正则化线性回归(山脊套索&弹性网)
  • 随机森林
  • 梯度增强树

首先,让我们拆分我们的分析基表。

y = df.status
X = df.drop('tx_price', axis=1)

然后我们将分成训练集和测试集。

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1234)

我们将设置一个管道对象来训练。这将简化我们的模型训练过程。

pipelines = {
    'lasso' : make_pipeline(StandardScaler(),
              Lasso(random_state=123)),
    'ridge' : make_pipeline(StandardScaler(),
              Ridge(random_state=123)),
    'enet' :  make_pipeline(StandardScaler(),
              ElasticNet(random_state=123)),
    'rf' :    make_pipeline(
              RandomForestRegressor(random_state=123)),
    'gb' :    make_pipeline(
              GradientBoostingRegressor(random_state=123))
}

我们还想调整每个算法的超参数

对于所有三个正则化回归,我们将调整 alpha (L1 & L2 惩罚强度),以及弹性网的 l1_ratio (即 L1 & L2 惩罚之间的权重)。

lasso_hyperparameters = {
    ‘lasso__alpha’ : [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, 10]}ridge_hyperparameters = {
    ‘ridge__alpha’ : [0.001, 0.005, 0.01, 0.1, 0.5, 1, 5, 10]}enet_hyperparameters = { 
    ‘elasticnet__alpha’: [0.001, 0.005, 0.01, 0.05, 0.1, 1, 5, 10], 
    ‘elasticnet__l1_ratio’ : [0.1, 0.3, 0.5, 0.7, 0.9]}

对于我们的随机森林,我们将调整估计器的数量( n_estimators )和分割期间要考虑的最大特征数量( max_features ),以及作为一片叶子的最小样本数量( min_samples_leaf )。

rf_hyperparameters = {
     ‘randomforestregressor__n_estimators’ : [100, 200],
     ‘randomforestregressor__max_features’ : [‘auto’, ‘sqrt’, 0.33],
     'randomforestregressor__min_samples_leaf' : [1, 3, 5, 10]}

对于我们的梯度增强树,我们将调整估计器的数量( n_estimators )、学习速率,以及每棵树的最大深度( max_depth )。

gb_hyperparameters = {
      ‘gradientboostingregressor__n_estimators’ : [100, 200],
      ‘gradientboostingregressor__learning_rate’ : [0.05, 0.1, 0.2],
      ‘gradientboostingregressor__max_depth’ : [1, 3, 5]}

最后,我们将拟合和调整我们的模型。使用 GridSearchCV ,我们可以用几行代码在我们声明的所有超参数上对所有这些模型进行交叉验证训练!

fitted_models = {}
for name, pipeline in pipelines.items():
    model = GridSearchCV(pipeline, 
                         hyperparameters[name], 
                         cv=10, 
                         n_jobs=-1)
    model.fit(X_train, y_train)
    fitted_models[name] = model

4.估价

我写了一篇关于流行的机器学习指标的专门文章,包括下面使用的那些。

4.1 绩效得分

我们将从打印交叉验证分数开始。这是 10 个保留折叠的平均性能,是仅使用您的训练数据获得模型性能的可靠估计的一种方式。

for name, model in fitted_models.items():
    print( name, model.best_score_ )**Output:
lasso 0.3085486180300333
ridge 0.3165464682513239
enet 0.34280536738492506
rf 0.4944720180590308
gb 0.48797200970900745**

移动到测试数据,我们将输出平均绝对误差 (MAE)

R -score 代表模型解释的总方差的比例,范围从 0 到 100。如果 R -score = 100,则因变量( tx_price )与特征完全相关。

MAE 是预测值和实际值之间的平均误差。

for name, model in fitted_models.items():
   pred = model.predict(X_test)
   print(name)
   print(‘ — — — — ‘)
   print(‘R²:’, r2_score(y_test, pred))
   print(‘MAE:’, mean_absolute_error(y_test, pred))
   print()**Output:
lasso
--------
R^2: 0.4088031693011063
MAE: 85041.97658598644

ridge
--------
R^2: 0.4092637562314514
MAE: 84982.89969349177

enet
--------
R^2: 0.40522476546064634
MAE: 86297.65161608408

rf
--------
R^2: 0.5685576834419455
MAE: 68825.53227240045

gb
--------
R^2: 0.5410951822821564
MAE: 70601.60664940192**

胜出的算法是随机森林,R 分最高 0.57,MAE 最低。我们实际上可以做得更好。

还记得之前我们移除了 tx_yearyear _ build特性后的工程 property_age 吗?事实证明这是个错误的选择。如果将它们包括在内,模型的性能将大幅提升,达到 R = 0.81。此外,省略一些高度相关的邻居简档特征(即活跃 _ 生活、美容 _ 水疗、咖啡馆、夜生活餐馆)会进一步提高性能。这突出了特征工程特征选择的重要性。****

仅供参考,这里是获胜随机森林的超参数,使用 GridSearchCV 进行了调整。

RandomForestRegressor(bootstrap=True, 
                      criterion='mse',
                      max_depth=None,
                      max_features='auto',
                      max_leaf_nodes=None,
                      min_impurity_decrease=0.0,
                      min_impurity_split=None,
                      min_samples_leaf=10, 
                      min_samples_split=2,
                      min_weight_fraction_leaf=0.0,
                      n_estimators=200, 
                      n_jobs=None,
                      oob_score=False, 
                      random_state=123,
                      verbose=0, 
                      warm_start=False))],

4.2 特性重要性

考虑下面的代码。

coef = winning_model.feature_importances_
ind = np.argsort(-coef)for i in range(X_train.shape[1]):
    print("%d. %s (%f)" % (i + 1, X.columns[ind[i]], coef[ind[i]]))x = range(X_train.shape[1])
y = coef[ind][:X_train.shape[1]]plt.title("Feature importances")
ax = plt.subplot()
plt.barh(x, y, color='red')
ax.set_yticks(x)
ax.set_yticklabels(X.columns[ind])
plt.gca().invert_yaxis(

这将打印按重要性排序的特性列表和相应的条形图。

**1\. insurance (0.580027)
2\. property_tax (0.148774)
3\. sqft (0.033958)
4\. property_age (0.031218)
5\. during_recession (0.027909)
6\. college_grad (0.022310)
7\. lot_size (0.020546)
8\. median_age (0.016930)
9\. married (0.015506)
10\. beauty_spas (0.013840)
11\. active_life (0.011257)
12\. shopping (0.010523)
13\. school_score (0.010032)
14\. restaurants (0.009975)
15\. median_school (0.007809)
16\. baths (0.007009)
17\. cafes (0.005914)
18\. groceries (0.005578)
19\. nightlife (0.004049)
20\. arts_entertainment (0.003944)
21\. beds (0.003364)
22\. exterior_walls_Siding (Alum/Vinyl) (0.001808)
23\. exterior_walls_Brick (0.001348)
24\. roof_Composition Shingle (0.001239)
25\. roof_Missing (0.000778)
26\. roof_Shake Shingle (0.000750)
27\. exterior_walls_Missing (0.000632)
28\. num_schools (0.000616)
29\. exterior_walls_Metal (0.000578)
30\. basement (0.000348)**

到目前为止,前两个预测值是

  • 每月房主保险的费用
  • 每月财产税

这并不完全令人惊讶,因为保险费通常是由保险公司根据重置建筑物的成本来计算的。这需要——令人惊讶的是——对建筑物的价值进行良好的估价。同样,财产税的金额通常与房产价值挂钩。

接下来的两个最强的预测器是资产的大小( sqft )和它有多老( property_age )。较大和较新的房产往往在市场上卖得更多,因此这些结果也符合预期。

5.部署

图片由 ThisisEngineering RAEng 提供。

此模型的可执行版本(。pkl)可以从 Jupyter 笔记本中保存:

with open('final_model.pkl', 'wb') as f:
    pickle.dump(fitted_models['rf'].best_estimator_, f)

房地产投资信托基金可以在将新的住房数据输入训练模型之前对其进行预处理。这称为批量运行。

在一个大型组织中,REIT 可能希望通过与数据工程师机器学习工程师合作,将模型部署到生产环境中。这些专家将围绕我们的模型建立一个自动化的管道,确保新的属性数据可以通过我们的清洗和功能工程逻辑进行预处理,并自动和定期地将预测推送到下游决策者。

最终意见

我们从一个业务问题开始:一家从事购买、持有和出售大型投资物业组合业务的公司希望为其物业估值带来一致性和更高的表现。

我们在包含 1800 多项过去房地产交易的历史数据负载上训练了一个获胜的随机森林模型。

人力资源部可以在我们训练有素的员工身上运行新数据。pkl 文件,或者可以由他们的工程部门构建自动管道。

我们的模型是一个回归模型,其中目标变量是数字。

监督学习硬币的另一面是分类模型,其目标变量是分类的。在这里,我训练了一个二元分类模型,预测员工是否有离开公司的风险。

最后,我在这里写了一篇关于机器学习在数学建模领域的位置的文章。

在 YouTube 和 Twitter 上关注我。

无限制媒体访问

提升你的知识和技能到一个新的水平。

加入 Medium 享受无限制访问互联网上的最佳分析&数据科学文章。你可以在这里加入来支持我和其他顶级作家。

我的数据科学文章

  • 微分方程与机器学习——此处
  • 新冠肺炎的数学建模与机器学习— 此处
  • 回归预测房价— 此处
  • 分类预测员工流失— 此处
  • 流行的机器学习性能指标— 此处
  • Jupyter 笔记本与 Dataiku DSS — 此处
  • Power BI —从数据建模到令人惊叹的报告— 此处

使用机器学习和 NLP 预测 IT 支持票

原文:https://towardsdatascience.com/predict-it-support-tickets-with-machine-learning-and-nlp-a87ee1cb66fc?source=collection_archive---------4-----------------------

通过 Python 中的监督分类技术。

来源:alenesetril通过 unsplash (CC0)

处理大量 IT 服务请求?对降低运营成本感兴趣?希望提升用户体验?别再看了。

本文可作为数据科学爱好者在 IT 服务管理(ITSM)环境中部署生产级机器学习解决方案的指南。规定的 ML 解决方案将帮助我们深入了解 IT 服务请求的黑匣子,并跨业务管理孤岛整合 ITSM 战略。

我们将使用受监督的分类算法,根据输入文本对新票据进行分类。我采用了 PythonRESTful API 框架、 Scikit-LearnSpaCy 来完成这个任务;但是,有许多解决方案更适合您的组织。我将尽最大努力解决分歧的机会,并为我为什么选择特定的方法提供专门的理由。

Susan Li 提供了关于使用 SpaCy 进行文本分类的机器学习的出色概述。我的过程、代码和演示(如本文所述)都受到了她的影响。如果你觉得我的任何内容有帮助/有趣,我强烈推荐订阅她的频道。

最终模型对流入生产环境的所有票据的预测准确率超过 85%。SLA 响应时间缩短了一半,每年节约成本近 60 万美元。

背景

IT 服务管理(ITSM)是一项重要的企业职能,负责利用创新来增加价值,最大限度地提高用户生产力,提供端到端的技术服务,等等。尽管企业责任如此重大,但前端 IT 交互通常是通过与支持专家进行长时间艰苦的对话(通过网络或电话)来定义的。无论您是在申请新密码、提交应用程序的配置更改,还是只是寻求帮助,您都将经历一段令人沮丧的前路。这种耻辱依然存在,因为 IT 领导很难为服务于整个企业的全面帮助台管理解决方案配备人员和提供支持。

尽管有良好的意图,支持组织经常错过高效 ITSM 的标志。在为我最近的一个全球医疗设备客户做项目时,我的任务是纠正企业事故单分类带来的令人沮丧的结果。领导层决定使用 ServiceNow(一个受欢迎的 ITSM 工作流平台)和外部供应商将资源投入到高成本的传统解决方案中,以缩短传入票证的响应时间,但收效甚微。普遍的使用和严格的 SLA 限制导致了全面的不准确性,其中业务组用落在他们队列中的票据玩跳房子游戏。用户被激怒了,支持专业人员冷酷无情,领导层被难住了。是时候换个新的视角了!

在 2019 年,超过 60,000 张票被提交 到我客户的 ServiceNow 平台,意图到达近 15 个商业团体。每张票花费 IT 组织 13 美元,尽管平均准确率(达到预期目标的机会)只有 40%。在到达正确的地方之前,错误分配的票据在业务组之间平均反复 21 天。C ost延迟 准确性受到巨大关注,并导致用户体验不佳。

当用户提交支持票时,它通过电子邮件、电话或嵌入式门户流入平台。每张票据都包含一些关于问题或请求的文本,由支持专业人员快速审阅并发送出去。一旦正确的分配组拿起工作单,一些工作就完成了,事故状态恢复为已关闭。

通过 监督机器学习 进行多项分类,根据固定数量的业务组对支持票进行分类的时机似乎已经成熟。我们可以轻松地从每张票上抓取文本和类别,并训练一个模型将特定的单词和短语与特定的类别关联起来。我的假设很简单:机器学习可以提供即时的成本节约,更好的 SLA 结果,以及比人类更准确的预测。我们开始吧!

数据收集和探索

在选择和训练机器学习模型之前,我们需要查看数据,以更好地了解事件票证中的趋势。ServiceNow 提供了一个健壮的 Table API 框架让我们直接从平台抓取数据。

**# Import Statements* **import** requests
**import** json
**import** pandas **as** pd
 *# Initialize url* **url** = "https://{instance.service-now.com}/api/now/table/incident"*# Set simple authorization* **user** = "{username}"
**pwd** = "{password}"*# Set proper headers* **headers** = {"Content-Type" : "application/json", 
"Accept" : "application/json",
"accept-encoding" : "gzip, deflate, br"}# Initialize GET response
**response** = requests.get(url, auth=(user, pwd), headers=headers)
**data** = json.loads(response.text)**dataframe** = pd.DataFrame(data['result'])*

ServiceNow 为您提供了一个绝佳的机会,让您通过其嵌入式 API Explorer 探索 RESTful API 调优的细微差别。这个工具帮助用户从头开始构建定制的 API 请求,减少查询参数、字段等。变成容易理解的增量。此外,您可以点击流行的表(事件、任务等。)或创建复杂的查询。对于任何数据专业人员来说,这都是一个非常棒的工具!

让我们看看我们的数据框架:

由于我们感兴趣的是将文本与相关的分类器关联起来,我们可以使用一个分类变量,比如“u_portfolio ”,来标记数据帧中的每一行。尽管存在非常严重的类别不平衡(“全球支持服务”,几乎占所有记录的 65%)和超过 2,000 个缺失值,我们希望消除那些少于 100 个票证的特定类别,以减少噪音并确保我们只使用相关类别。让我们通过连接“short_description”和“description”来创建一个名为“text”的纯文本列。我们肯定希望可视化更新的数据帧!

***import** matplotlib.pyplot **as** plt
**import** seaborn **as** sns# Eliminate categories with fewer than 100 tickets
classifier = "u_portfolio"
ticket_threshold = 100**df_classifiers** = df[df.groupby(classifier[classifier].transform(len) > ticket_threshold]# Print number of relevant categories & shape
print(**"Categories: " + str(df_classifiers[classifier].nunique())**)# Plot the classifiers
fig = plt.figure(figsize=(10,6))
sns.barplot(df_classifiers[classifier].value_counts().index, df_classifiers[classifier].value_counts())
plt.xticks(rotation=20)
plt.show()*

在将阈值设置为 100 张票后,我们似乎删除了 5 个以上的类别,只返回那些具有相关商业价值的类别。在深入研究了数据并询问了一些人之后,我确认这些被删除的类别已经有一年多没有被使用了,可以轻松地被删除。

阶级失衡与企业咨询的精彩世界:

全球支持服务(GSS)占总支持票证的 60%以上。这意味着我们可以编写一个简单的程序来**将 GSS 分配给每一个传入的票证,这样我们就有一半的时间是正确的!

来源:戈登·拉姆齐经由cbs.com/corden

在没有做任何深入分析的情况下,我们发现了一个主要问题。第三方供应商对每张票的交互收费 13 美元,平均准确率为 40%,比我的客户不采取任何行动的情况还要糟糕……想象一下向首席信息官透露这个消息!**

剩余的类别将被用作标签* 来训练/测试模型。让我们将它们保存为一个列表:***

*****category_labels = list(df_classifiers[classifier].value_counts().index)*****

现在我们有了 category_labels ,我们需要更好地理解每种票据的文本模式。通过窥视 ServiceNow 平台,我可以很快按类别收集到几个主题: GSS 处理大量密码重置和硬件问题;商业智能涵盖报告功能和数据问题;客户处理 SalesForce 和其他客户应用; SAP S/4 Security 管理所有与 ERP 相关的访问/配置。如果你以前在这个公司工作过,这些主题听起来很熟悉。通过研究数据,人类很容易识别每个类别的几个关键词——让我们看看计算机是否也能做到这一点!**

一旦我们运行代码,我们可以检查输出:

不幸的是,这里没有太多,因为最常见的单词在类别上几乎没有区别。我调查发现,邮件占了 75%以上的门票提交量;所有内部员工的签名下面都有某种版本的保密通知,这扭曲了类别之间的重大差异。我们可以尝试更改 N,看看是否会出现其他模式,或者将电子邮件签名硬编码到非索引字表变量中,以防止它出现,但这不会修复根本原因。而不是,我们想要找到与我们类别列表中的每个标签相关联的单词/短语。这被称为术语选择,可以帮助我们通过标签为数据集识别最相关的术语。**

让我们探索一些测量和评估相关性的 ML 解决方案!

构建模型

自然语言处理(NLP)位于计算机科学和语言学的结合点,定义了机器和人类语言如何相互交互的解决方案。在功能上,NLP 通过分析和操纵数据(通常以文本形式)来获取意义,从而消耗人类语言。为此,我们需要将人与人之间传递的数据转换成机器可读的数字格式。这种编码文本的过程被称为矢量化,并催化计算过程,如应用数学规则和执行矩阵运算,从而产生有价值的见解。**

尽管有一些超级酷的新兴方法可以为 NLP 矢量化文本数据,如迁移学习和高级神经网络,但我们将使用一种更简单的技术,称为词频——逆文档频率。Tf-idf 值与单词/短语(n-gram)在文档中出现的次数成比例增加,偏移量为文档总数。虽然听起来很复杂,但它基本上反映了 n-gram 对文档的重要性,而不偏向出现频率更高的单词。这对于处理像我们这样存在类不平衡的文本文档来说尤其强大!如果你的文本平衡良好,你可以使用计数矢量器**

既然我们已经了解了计算机是如何消耗文本数据的,我们可以使用不同的模型进行实验!下面是一些测试几个选项的起始代码:

让我们使用逻辑回归作为我们的最佳拟合模型。作为一名数据科学家,您应该能够将多种技术应用于一个项目,并从中选择一种最适合的技术。根据我的经验,人类心理学在用例的成功中起着重要的作用;指导企业接受新兴的、颠覆性的技术需要时间和精力!推广、品牌化和销售您的解决方案与构建优雅的算法一样重要。让我们建立我们的模型吧!****

在这个项目中,我有足够的机会系统地将概念社会化,以实时解决问题。对于这个用例,我的成功标准的一个主要部分是领导层理解并在上下文中传播这些数据科学概念。因为有许多其他算法/模型可以基于数据优化模型性能,所以我鼓励您进行试验。**

生产部署

当用户提交一张票时,很容易获取文本并通过模型进行处理。这样做,我们可以确定…

a)如果模型发现文本相关

b)哪个类别最适合该文本

***# Save the model to variable 'model'
model = pipe.fit(X_train, y_train)# Save array of predictions for given TEXT
predict_category = model.predict(TEXT) # Save array of prediction probabilities for given TEXT   
predict_probability = model.predict_proba(TEXT)***

我们的两个变量预测将返回一个与类别列表长度成比例的数字数组。如果我们打印 predict_category,我们期望一个 8 个数字的数组,对应于我们的 8 个类别,用 0 或 1 来表示相关性。如果文本字符串是“我需要一台新的公司笔记本电脑”,那么除了对应于“全球支持服务”的第 n 个位置的 1 之外,我们应该期待一个 0 的数组。我们可以使用“predict_probability”来查看在上下文中对 GSS 的预测结果有多强;对于这个特定的文本字符串,98%的概率是可信的,可以说我们信任这个模型😃。**

我们可以使用我们用来抓取数据的同一个表 API,用 PUT 请求替换 GET 响应,来更新 ServiceNow 中的票据。实时地,用户提交一张票,模型在不到一分钟的时间内用预测的类别更新 ServiceNow。让我们为实现了一个有效的机器学习解决方案而沾沾自喜吧!

在生产环境中部署模型取决于您的特定企业所订阅的技术堆栈。我的客户是一家 AWS 商店,通过访问全套 AWS 工具管理着良好的关系。

我使用了 LambdaSageMaker 在一个无服务器的 AWS 环境中自动分配支持票。然而,创建一个 EC2 实例来托管模型并与 ServiceNow 直接交互要容易得多。ServiceNow 具有内置的“业务规则”,可以对其进行配置以触发模型上的 API 调用并执行更新。最终的部署稍微便宜一些,而且在 EC2 服务器上更容易更新,并且依赖于 AWS 和 ServiceNow 的有效通信。AWS 文档以其深度和广度而闻名;我强烈建议在投入之前咨询适当的资源。

如果这些术语对你毫无意义,不要烦恼!基本上,机器学习管道需要被托管在与所涉及的人员和技术无关的环境中。如果新的开发人员加入进来,票证数量一夜之间增加了两倍,或者领导层选择使用 R 中的 KNN 而不是 Python 中的 LogReg,环境需要适应可变的规模。整个管道是在我的本地机器上开发的,但是从长远来看,生产部署不能依赖于我的计算资源和/或可用性。将它保存在服务器上(托管在云中)可以确保可持续性和有效性。这是构建阶段和实际部署之间的关键转变。

评估模型

在所有这些工作之后,我们完成了什么?首先,我们有一个很棒的 ML 解决方案,它使用自然语言处理对一家全球公司的所有事故单进行分类。通过自动化票证分配和规避第三方供应商,我们每年为企业节省近 60 万美元。我们将平均准确率从 40%提高到 85%,并将 SLA 响应时间缩短了一半!有趣的是,用户体验明显更加积极,对 ITSM 环境的信任度也直线上升。**

出乎意料的是,我对 ServiceNow 中数据和流程改进的高度关注有助于整合部门战略并提供更好的决策。由副总裁、董事和高级经理组成的 IT 领导层对节省资金、缩短响应时间和提升用户体验非常兴奋。尽管最初对支持新技术、在生产中操作模型、向供应商重构平台工作流等感到不安。领导层最终接受了改变。部署提供了民主化决策和传播复杂数据主题的机会。我相信,领导层能够更好地制定未来数据科学项目的战略并为其配备人员,将此使用案例展示为传达预测分析和数据科学成功的跳板。**

如果你对文章中概述的方法有任何问题或意见,请在下面留言或直接给我发消息!我很乐意收到你的来信😄。

学习 PyTorch 的同时预测英雄联盟比赛(第二部分)

原文:https://towardsdatascience.com/predict-league-of-legends-matches-while-learning-pytorch-part-2-38b8e982c7ea?source=collection_archive---------40-----------------------

学习在 PyTorch 中实现一个简单的前馈网络,并使用 GPU 为一个合适的用例场景进行训练,同时学习一些理论

这个小系列的第二部分,手绘版!

读者朋友,你好!如果你还没有读过这个由 2 部分组成的“系列”的第一部分,我强烈推荐你在阅读之前阅读它。您可以在此处或下方进行操作👇

[## 在学习 PyTorch 基础知识的同时预测英雄联盟中的比赛

请跟我来,我将使用 PyTorch 实现一个逻辑回归模型来预测英雄联盟中的比赛

towardsdatascience.com](/predict-matches-in-league-of-legends-while-learning-pytorch-basics-3dd43cf8d16f)

上一次,我们停止了用 PyTorch 做一个逻辑回归器来达到同样的目的。这一次,我们将事情推进了一步:创建一个前馈神经网络(只有完全连接的层)。如果你想知道更多关于这样做的意图,这个迷你项目将使用的数据集,和/或数据集的数据准备过程,那么你应该看看我的第一篇文章这里或以上。

《英雄联盟》是我一直以来最喜欢的游戏之一,尽管我真的很不擅长。LOL 是一个极具竞争力的 MOBA,两个由 5 人组成的队伍(蓝队和红队)相互对抗,以摧毁对方的基地(nexus)。获胜通常需要大量的团队合作、协调,或者对于一个倾斜的玩家来说,“运气”。不管怎样,对于一个联盟玩家(即使他们是相当新的)来说,根据游戏记录的死亡人数和许多其他数据来判断哪个队可能会赢并不太难。神经网络可以预测的东西……

等等,什么是神经网络?

嘶!如果你不想学习一些理论,可以跳过这一部分。你会错过一些我自己的画:(

上次我们已经看到了逻辑回归模型如何在预测方面做得相当好(它在测试数据集上实现了高达 74%的准确性)。事实上,逻辑回归变量几乎完全是一个线性回归变量,它本身就是一个 T2,一个一批输入之间的矩阵点积,一个权重矩阵,外加一个偏差向量。 可变的权重和偏差使模型能够训练并更好地做它正在做的事情。线性回归和逻辑回归之间的唯一区别是,对于涉及简单的是或否问题(就像比赛中的一支球队赢得了比赛)或分类问题的预测,存在一个将输出“挤压”成一系列值(通常从 0 到 1)的函数。逻辑回归变量就是使用这种“挤压”函数的变量,它通常以 sigmoidsoftmax 函数的形式出现。

线性回归的基本数学,其中线性回归的矩阵运算用 sigmoid 函数包装。我画的😬 🔥

那么,神经网络如何设置自己以获得进一步的成功呢?简单地说,一个普通的神经网络是多个线性回归器堆叠在一起。 理论上,这应该允许神经网络拾取数据之间的更多关系/趋势,以帮助预测。但不可能这么简单!不做任何额外的事情,链接矩阵乘法和加法只会让我们一无所获。看一看:

这就是当你试图直接链接线性回归操作时会发生的情况。

您可以看到,将两个线性回归链接起来与仅一个线性回归同义,只是权重和偏差不同。那么,我们如何解决这个问题呢?我们引入一个非线性激活函数,它将环绕线性回归操作的每个实例。它不仅解决了上面普遍存在的问题,而且还模仿了(在某种意义上)生物神经元的工作方式。例如,神经元确定信号是否超过设定的阈值,以将信号向前传递到下一个神经元。类似地,激活函数将决定并调整神经网络层的最终输出。我可以详细说明激活功能,但我们会潜水太深!

顺便说一下,为了使我们对词汇的用法更趋向于约定俗成,从现在开始让我们把输入和输出之间的线性回归的每一个实例都称为一个 神经网络的隐藏层 ,而每一个个体的权重和偏差都称为一个 节点 考虑到这一点,这就是神经网络的“样子”:

或者,你可以谷歌搜索“神经网络”,你会看到更好的图像!

好了,现在让我们回到编码上来!如果你想要一个更直观的方法来研究神经网络&更多,看看 3blue1brown 关于深度神经网络的视频系列

制作前馈神经网络

TL;对于我们刚才所说的博士:一个神经网络基本上是多个线性回归操作(隐藏层)链接在一起,在每一层之后有一个 激活函数 下面是定义模型时的样子:

每个特性的输入大小将是 29(参见第一篇文章),输出大小将是 2,每一个都是对团队输赢的预测。

当我们初始化模型时,我们现在有多个“nn.Linear”实例,我们将通过每一层和“F.relu()”传递输入(稍后将详细介绍)。

酷,但是什么是 *F.relu()*?整流线性单元(ReLU)是深度学习中使用的许多激活函数之一,与其他替代方法(例如 Sigmoid)相比,它的性能非常好。如果你想知道更多关于 ReLU 和其他激活功能的信息,去看看这篇文章。PyTorch 在torch.nn.functional(通常作为F导入)中提供了过多的激活函数,所以一定要检查他们的文档,看看你有哪些选项可以自己使用。

我们将使用 SGD 优化器和交叉熵损失函数来训练模型。我们将训练循环定义如下:

我们在这里定义了很多函数来形成训练循环。这里提供了注释,向您展示大多数代码行的用途。

在 GPU 上训练

随着神经网络模型变得越来越复杂,训练这些模型的计算需求也急剧增加。图形处理单元,被称为 GPU 或显卡,是专门设计来进行大规模矩阵运算的。如果你还不知道,除非启用,PyTorch 总是使用你的 CPU 进行计算,这肯定不如 GPU 有效。这一次,我们将发现如何利用 GPU 来为我们的神经网络处理数据。

在我们开始之前,只支持 NVIDIA GPUs,对不起 AMD 粉丝😢。

PyTorch 提供了一个函数torch.cuda.is_available(),它输出一个布尔值,表明安装了 CUDA 的兼容(NVIDIA) GPU 的存在。如果你有一个受支持的 GPU,你可以完成设置过程,或者你可以创建一个 kagglegoogle colab 帐户,并访问免费的 GPU 以进行深度学习(当然有一些限制)。让我们使用is_available()函数来设置 GPU 的使用,但是如果没有 GPU,就退回到 CPU:

Torch.device(…)是指 PyTorch 中可用的硬件。

使用 PyTorch,您可以通过使用任何张量或模型的.to()方法将数据移入和移出 GPU 设备。因此,要开始使用 GPU,您首先必须将您的模型移动到 GPU 上:

我们初始化模型“LOLModelmk2()”,并通过使用方法“to(device)”将其移动到 GPU,其中 device =“torch . device(“cuda”)”

现在,我们开始训练:

在训练之前用测试数据测试模型。损耗徘徊在 16%左右,准确率 50%。

您可以看到验证损失急剧下降,准确性出现峰值。

这种趋势在很小的范围内继续

下面是一些漂亮的图表😁:

这里是我们从测试数据集得到的结果:

嗯嗯…

嗯… 与线性回归模型(74%)相比,我们的模型看起来表现完全相同。现在,我们对这个结果有一些可能性:

  1. 某段代码不正确
  2. 神经网络通常比逻辑回归模型差
  3. 神经网络过拟合
  4. 逻辑回归模型在其训练中是幸运的(这是可能的,因为数据集被随机分为回归器和神经网络的训练集、验证集和测试集)
  5. 在这种情况下使用神经网络可能没有优势,我们正在经历收益递减。

好吧,我们用排除法,好吗?

经过长时间的调试,我在代码中没有发现任何错误(如果你发现了什么,请告诉我!!!),所以#1 出局了。#2 可能不是这种情况:我们之前建立了神经网络如何基于线性回归模型,线性回归模型基本上是没有 sigmoid/softmax 函数的逻辑回归。他们应该能够从数据中得出更多的关系,这需要更好的准确性,而不是相反。

3 比其他两个更有可能,因为神经网络比逻辑回归更复杂,因此更容易接受这类问题。通常,过度拟合可以通过使用丢弃来解决,这仅仅意味着在训练时禁用随机选取的模型节点的一部分。对于 PyTorch 来说,这意味着在__init__()中初始化一个nn.Dropout()层,并用 ReLU 把它放在层之间。下面是实现过程:

我们只需初始化“nn.Dropout”的一个实例,因为它可以在模型类的 forward 函数中多次使用。

尽管如此,该模型在测试数据集上的准确率仍保持在 70%左右。

令人惊讶的是,即使这样也不起作用,这意味着模型没有过度拟合训练数据。最后,为了测试我们的假设#4,我在逻辑回归器上重新查看了我的旧笔记本,并用这个模型进行了几次试验。事实证明,逻辑回归器上次 74%的准确率是相当幸运的。事实上,让我们再来看看#个时期的精度图:

准确性在很大程度上是相当不稳定的,但总体来说,它徘徊在 70%左右,这更类似于我后来在逻辑回归和本文中的神经网络上运行的试验。

结论

通过这个例子,深度学习学科可以学到很多东西。主要是,深度学习不是巫毒魔法;它不能神奇地解决你给它的每一个分类问题。它不能预测每一场英雄联盟的比赛;在许多情况下,比赛的前 10 分钟不足以决定哪支球队会赢(我可以通过我的经验证明)。尽管如此,从这种经历中还是有很多收获的,比如学习神经网络的概念并在 PyTorch 中实现它,利用 GPU,以及在模型过拟合的情况下退出。在这一点上,我希望你喜欢和我一起为这个英雄联盟数据集构建 PyTorch 模型的旅程。编码快乐(还有继续打联赛)!

如果你想知道这个迷你项目使用的 jupyter 笔记本的来源,请看这里:https://jovian.ml/richardso21/lol-nn

预测勒布朗詹姆斯与 RNN 的比赛结果

原文:https://towardsdatascience.com/predict-lebron-jamess-game-results-with-rnn-1709f364d4d4?source=collection_archive---------43-----------------------

机器学习

众所周知,RNN 擅长分析序列数据。但是我们能应用它根据游戏历史预测游戏结果吗?

埃德加·恰帕罗在 Unsplash 上拍摄的照片

A 递归神经网络(RNN)是序列处理中最常用的深度学习算法之一。RNN 和前馈神经网络之间的区别在于,前者可以“记忆”序列中的时序信息,而后者可以一次性处理整个序列。

因此,当数据的时间顺序对问题很重要时,我们最好使用 RNN,例如时间序列数据分析或自然语言处理(NLP)。

然而,一个球员之前的比赛是否能够影响即将到来的比赛的结果仍在争论之中。所以,我想探究一下 RNN 是否适合篮球场上的比赛预测问题。

在这篇短文中,我试图使用一个深度学习模型,根据之前的比赛统计数据和结果来预测勒布朗·詹姆斯未来的比赛结果。

数据集

我用 Python 刮了勒布朗从 赛季 2003–04赛季 2019–20场 1258 场的比赛统计。对刮痧程序感兴趣的可以参考我之前的一篇帖子

这是数据的样子。

数据头

我的另一个帖子中,我已经说明了“GmSc”(玩家的游戏分数)、“+/-”(加减分)和“Minutes”(上场时间)是解释相应游戏结果的三个最重要的特征。因此,为了减少输入数据的维度,我只在我们的模型中保留这些游戏统计数据和游戏结果(“赢”)。对于每个数据点,我提取过去 10 场比赛的统计数据(t-9,t-8,…,t-1,t),目的是预测下一场比赛(t + 1)的比赛结果。

我用前 800 场作为我们的训练数据,后 300 场作为验证数据,后 158 场作为测试数据。

数据的整个预处理如下所示。

data_u = df[["GmSc","+/-","Minutes","Win"]].to_numpy()
mean = data_u[:800].mean(axis=0)
data_u -= mean
std = data_u[:800].std(axis=0)
data_u /= std

标准化参数(平均值和标准偏差)仅从训练数据(前 800 场比赛)中生成,然后将这些参数应用于整个数据集。

加载整个数据集非常消耗内存,有时甚至是不可能的。所以使用数据生成器(在 Keras 中实现)向模型提供数据是处理这个问题的一个好选择。即使这里我有一个非常小的(1,258 个数据点)数据集,我仍然希望在我的管道中使用一个数据生成器,这将有利于将来的扩展。

def generator(data, lookback, delay, start, end, batch_size = 64):
    if end is None:
        end = len(data) - delay - 1
    i = start + lookback
    while True:
        if i + batch_size >= end:
            i = start + lookback
        rows = np.arange(i, min(i + batch_size, end))
        i += len(rows)
        samples = np.zeros((len(rows),
                           lookback,
                           data.shape[-1]))
        res_s = np.zeros((len(rows),))

        for j, row in enumerate(rows):
            indices = range(rows[j] - lookback, rows[j])
            samples[j] = data[indices]
            tar_v = data[rows[j] + delay][3]
            if tar_v > 0:
                res_s[j] = 1
            else:
                res_s[j] = 0
        yield samples, res_s

我将回看设置为 10,这意味着使用之前的 10 场比赛作为输入。我把延迟设为 1,表示预测下一场比赛结果。

lookback = 10
delay = 1
batch_size = 128
steps_per_epc = int(800/batch_size)

为了定义训练、验证和测试数据生成器,我只需要将开始和结束值提供给生成器函数。

train_generator = generator(data_u,
                           lookback = lookback,
                           delay = delay,
                           start = 0,
                           end = 800,
                           batch_size = batch_size)val_generator = generator(data_u,
                           lookback = lookback,
                           delay = delay,
                           start = 801,
                           end = 1100,
                           batch_size = batch_size)test_generator = generator(data_u,
                           lookback = lookback,
                           delay = delay,
                           start = 1101,
                           end = None,
                           batch_size = batch_size)

相应地,我需要指定检查验证和测试数据集所需的步骤数量。

val_steps = (1100 - 801 - lookback)
test_steps = (len(data_u) - 1101 - lookback)

接下来,我将构建模型结构。

建模结果

首先,我构建了一个具有密集连接层的人工神经网络作为我的基线模型,以便与我的其他模型进行比较。

from keras.models import Sequential
from keras import layers
from keras.optimizers import RMSpropmodel_ann = Sequential()
model_ann.add(layers.Flatten(input_shape = (lookback, data_u.shape[-1])))
model_ann.add(layers.Dense(32,activation = 'relu'))
model_ann.add(layers.Dropout(0.3))
model_ann.add(layers.Dense(1,activation = 'sigmoid'))
model_ann.summary()

人工神经网络模型结构

然后,我编译模型,记录拟合过程。

model_ann.compile(optimizer = RMSprop(lr = 1e-2),
                 loss = 'binary_crossentropy',
                 metrics = ['acc'])
history = model_ann.fit_generator(train_generator,
                                  steps_per_epoch=steps_per_epc,
                              epochs = 20, 
                              validation_data = val_generator,
                              validation_steps = val_steps)

为了检查验证数据集的性能,我绘制了损失曲线。

acc_ = history_dic['loss']
val_acc_ = history_dic['val_loss']
epochs = range(1,21)
#plt.clf()
plt.plot(epochs,acc_, 'bo', label = "training loss")
plt.plot(epochs, val_acc_, 'r', label = "validation loss")
plt.xlabel('Epochs')
plt.ylabel('loss')
plt.legend()
plt.show()

训练和验证人工神经网络损失

正如所料,模型在几个时期后变得过度拟合。为了客观地评价该模型,我将其应用于测试集,得到的准确率为 60%。

scores = model_ann.evaluate_generator(test_generator,test_steps) 
print("Accuracy = ", scores[1]," Loss = ", scores[0])

人工神经网络测试集性能

接下来,我通过使用一个 LSTM 层后跟两个紧密连接的层来实现 RNN。

model_rnn = Sequential()
model_rnn.add(layers.LSTM(32,
                        dropout=0.2,
                        recurrent_dropout=0.2,
                        input_shape=(None,data_u.shape[-1])))model_rnn.add(layers.Dense(32,activation = 'relu'))
model_rnn.add(layers.Dropout(0.3))
model_rnn.add(layers.Dense(1,activation='sigmoid'))
model_rnn.summary()

一层 LSTM 结构

模型训练类似于上面的 ANN。

model_rnn.compile(optimizer = RMSprop(lr = 1e-2),
                 loss = 'binary_crossentropy',
                 metrics = ['acc'])
history = model_rnn.fit_generator(train_generator, 
                                  steps_per_epoch=steps_per_epc,
                              epochs = 20, 
                              validation_data = val_generator,
                              validation_steps = val_steps)

训练集和验证集的性能如下。

1 层 LSTM 损耗

过拟合不像人工神经网络那样严重。我还在测试数据上评估了该模型,其准确率为 62.5%。尽管在测试集上的性能优于具有密集连接层的人工神经网络,但是改进是微小的。

为了获得更好的性能,我试图通过增加一个递归层来增加模型的复杂性。然而,为了减少计算成本,我用门控递归单元(GRU)代替了 LSTM 层。模型如下所示。

model_rnn = Sequential()
model_rnn.add(layers.GRU(32,
                        dropout=0.2,
                        recurrent_dropout=0.2,
                         return_sequences = True,
                        input_shape=(None,data_u.shape[-1])))
model_rnn.add(layers.GRU(64, activation = 'relu',dropout=0.2,recurrent_dropout=0.2))
model_rnn.add(layers.Dense(32,activation = 'relu'))
model_rnn.add(layers.Dropout(0.3))model_rnn.add(layers.Dense(1,activation = 'sigmoid'))
model_rnn.summary()

2 层 GRU 结构

训练集和验证集的性能如下。

第二层 GRU 损失

在图上没有检测到严重的过度拟合。即使测试数据的准确性已经提高到 64%,改进仍然很小。我开始怀疑 RNN 能否胜任这项工作。

然而,我通过进一步增加模型的复杂性来做最后的尝试。具体来说,我使递归层成为双向的。

model_rnn = Sequential()
model_rnn.add(layers.Bidirectional(layers.GRU(32,
                        dropout=0.2,
                        recurrent_dropout=0.2,
                         return_sequences = True),
                        input_shape=(None,data_u.shape[-1])))
model_rnn.add(layers.Bidirectional(layers.GRU(64, activation = 'relu',dropout=0.2,recurrent_dropout=0.2)))model_rnn.add(layers.Dense(32,activation = 'relu'))
model_rnn.add(layers.Dropout(0.3))
model_rnn.add(layers.Dense(1,activation='sigmoid'))
model_rnn.summary()

双向 RNN 结构

这一次,训练集和验证集的性能如下。

双向损失

实际上,在模型开始过拟合之前,这个模型和上一个模型在验证损失上没有太大区别。测试集的准确率也达到了 64%。

通过探索上面的所有模型,我有点意识到 RNN 可能不太适合 NBA 比赛结果预测问题。确实有几十个超参数可以调整,但是人工神经网络和 RNN 之间的差异太小。

数据诊断

我不想被测试集准确性的值所迷惑,所以我进一步诊断数据集,以检查模型是否真的有效。

我在训练、验证和测试数据集中检查勒布朗的詹姆斯胜率。

胜率的数据诊断

哎呀!测试数据集中的胜率是 62.7%,这意味着如果我猜测勒布朗会赢得所有比赛,我仍然得到 62.7%的准确率。

这些结果表明,我的模型并不比随机猜测好多少。伤心…

可能是我没有全面探索超参数空间,也可能是勒布朗的比赛不可预测。但有一点是肯定的,大约 1000 个数据点远远不够。

讨论

在本文中,我展示了一个为游戏结果预测问题开发失败模型的例子。如果你认为你没有从中学到什么,我想强迫自己列出一些要点。至少你可能会在建模中遇到这些细节。

  1. 首先将模型推向过度拟合是很重要的,因为一个具有弱表示能力的模型永远不会解决问题。
  2. 如果你的模型在大量的时期后仍然不合适,比如说 40 个,你可能需要增加学习率。
  3. 如果你只接触到有限的数据,没有什么是新奇的。你的复杂模型可能比随机猜测更糟糕。

参考资料:

  1. 弗朗索瓦·乔莱。用 Python 进行深度学习。
  2. 篮球参考。

谢谢你的时间。如果你喜欢读这篇文章,请关注我的媒体。以下是我之前的一些文章。

[## 我以前从未注意到的过度拟合的一个潜在原因

当训练数据中的性能比测试数据中的性能好得多时,就会发生过度拟合。默认…

towardsdatascience.com](/one-potential-cause-of-overfitting-that-i-never-noticed-before-a57904c8c89d) [## 谁是本赛季 NBA 的最有价值球员?

一个案例研究,展示一个机器学习项目从开始到结束的样子。

towardsdatascience.com](/whos-the-mvp-of-nba-this-season-3e347c66a40a) [## 是否在我的模型中考虑多重共线性?

简要讨论是否有必要修复特征空间中的多重共线性。我希望它会…

towardsdatascience.com](/consider-multicollinearity-in-my-model-or-not-7aca16e74773)

皮特拉·施瓦兹勒在 Unsplash 上的照片

如何使用机器学习模型预测贷款资格

原文:https://towardsdatascience.com/predict-loan-eligibility-using-machine-learning-models-7a14ef904057?source=collection_archive---------0-----------------------

构建预测模型,以自动确定合适的申请人。

纽约公共图书馆拍摄于 Unsplash

介绍

贷款是银行的核心业务。主要利润直接来自贷款利息。贷款公司在经过严格的验证和确认后发放贷款。然而,他们仍然没有保证,如果申请人能够毫无困难地偿还贷款。

在本教程中,我们将建立一个预测模型来预测申请人是否有能力偿还贷款公司。我们将使用 Jupyter Notebook 准备数据,并使用各种模型来预测目标变量。

[## mridulrb/Predict-loan-eligibility-using-IBM-Watson-Studio

贷款是贷款公司的核心业务。主要利润直接来自贷款利息。贷款…

github.com](https://github.com/mridulrb/Predict-loan-eligibility-using-IBM-Watson-Studio)

注册一个 IBM Cloud 账号来试试这个教程——

[## IBM 云

使用 190 多种独特的服务立即开始建设。

ibm.biz](https://ibm.biz/BdqQBT)

目录

  1. 准备好系统并加载数据
  2. 理解数据
  3. 探索性数据分析(EDA)
    一、单变量分析
    二。双变量分析
  4. 缺失值和异常值处理
  5. 分类问题的评估标准
  6. 模型构建:第 1 部分
  7. 使用分层 k 倍交叉验证的逻辑回归
  8. 特征工程
  9. 建模:第二部分
    一、逻辑回归
    二。决策树
    三。随机森林
    四。XGBoost

准备好系统并加载数据

我们将在本课程中使用 Python 和下面列出的库。

规格

  • 计算机编程语言
  • 熊猫
  • 海生的
  • sklearn
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
import warnings
warnings.filterwarnings(“ignore”)

数据

对于这个问题,我们有三个 CSV 文件:训练、测试和样本提交。

  • 训练文件将用于训练模型,即我们的模型将从该文件中学习。它包含所有的自变量和目标变量。
  • 测试文件包含所有自变量,但不包含目标变量。我们将应用该模型来预测测试数据的目标变量。
  • 样本提交文件包含了我们提交预测的格式

读取数据

train = pd.read_csv(‘Dataset/train.csv’)
train.head()

test = pd.read_csv(‘Dataset/test.csv’)
test.head()

让我们制作一份训练和测试数据的副本,这样即使我们必须在这些数据集中进行任何更改,我们也不会丢失原始数据集。

train_original=train.copy()
test_original=test.copy()

理解数据

train.columnsIndex(['Loan_ID', 'Gender', 'Married', 'Dependents', 'Education',
       'Self_Employed', 'ApplicantIncome', 'CoapplicantIncome', 'LoanAmount',
       'Loan_Amount_Term', 'Credit_History', 'Property_Area', 'Loan_Status'],
      dtype='object')

我们有 12 个自变量和 1 个目标变量,即训练数据集中的 Loan_Status。

test.columnsIndex(['Loan_ID', 'Gender', 'Married', 'Dependents', 'Education',
       'Self_Employed', 'ApplicantIncome', 'CoapplicantIncome', 'LoanAmount',
       'Loan_Amount_Term', 'Credit_History', 'Property_Area'],
      dtype='object')

除了 Loan_Status 之外,测试数据集中的特性与训练数据集中的特性相似。我们将使用利用训练数据构建的模型来预测 Loan_Status。

train.dtypesLoan_ID               object
Gender                object
Married               object
Dependents            object
Education             object
Self_Employed         object
ApplicantIncome        int64
CoapplicantIncome    float64
LoanAmount           float64
Loan_Amount_Term     float64
Credit_History       float64
Property_Area         object
Loan_Status           object
dtype: object

我们可以看到有三种格式的数据类型:

  • 对象:对象格式意味着变量是分类的。我们数据集中的分类变量是 Loan_ID、性别、已婚、受抚养人、教育、自雇、财产面积、贷款状态。
  • int64:代表整数变量。ApplicantIncome 是这种格式。
  • float64:它表示包含一些小数值的变量。它们也是数字的
train.shape(614, 13)

我们在训练数据集中有 614 行和 13 列。

test.shape(367, 12)

我们在测试数据集中有 367 行和 12 列。

train[‘Loan_Status’].value_counts()Y    422
N    192
Name: Loan_Status, dtype: int64

Normalize 可以设置为 True 来打印比例而不是数字

train[‘Loan_Status’].value_counts(normalize=True) Y    0.687296
N    0.312704
Name: Loan_Status, dtype: float64train[‘Loan_Status’].value_counts().plot.bar()

614 人中有 422 人(约 69%)的贷款获得批准。

现在,让我们分别把每个变量形象化。不同类型的变量有分类变量、顺序变量和数值变量。

  • 分类特征:这些特征有类别(性别、已婚、自雇、信用记录、贷款状态)
  • 顺序特征:分类特征中的变量,具有某种相关的顺序(家属、教育、财产面积)
  • 数字特征:这些特征有数值(申请收入、共同申请收入、贷款金额、贷款金额期限)

独立变量(分类)

train[‘Gender’].value_counts(normalize=True).plot.bar(figsize=(20,10), title=’Gender’)
plt.show()
train[‘Married’].value_counts(normalize=True).plot.bar(title=’Married’)
plt.show()
train[‘Self_Employed’].value_counts(normalize=True).plot.bar(title=’Self_Employed’)
plt.show()
train[‘Credit_History’].value_counts(normalize=True).plot.bar(title=’Credit_History’)
plt.show()

从上面的柱状图可以推断出:

  • 数据集中 80%的申请者是男性。
  • 数据集中大约 65%的申请者已婚。
  • 数据集中大约 15%的申请者是个体经营者。
  • 大约 85%的申请者打消了他们的疑虑。

独立变量(序数)

train[‘Dependents’].value_counts(normalize=True).plot.bar(figsize=(24,6), title=’Dependents’)
plt.show()
train[‘Education’].value_counts(normalize=True).plot.bar(title=’Education’)
plt.show()
train[‘Property_Area’].value_counts(normalize=True).plot.bar(title=’Property_Area’)
plt.show()

从上面的柱状图可以得出以下推论:

  • 大多数申请人没有任何家属。
  • 大约 80%的申请者是毕业生。
  • 大多数申请者来自半城市地区。

独立变量(数字)

到目前为止,我们已经看到了分类变量和顺序变量,现在让我们来看看数字变量。我们先来看一下申请人收入的分布。

sns.distplot(train[‘ApplicantIncome’])
plt.show()
train[‘ApplicantIncome’].plot.box(figsize=(16,5))
plt.show()

可以推断,申请人收入分布中的大部分数据是向左的,这意味着它不是正态分布的。我们将在后面的章节中尝试使其正常化,因为如果数据呈正态分布,算法会工作得更好。

箱线图证实了大量异常值/极值的存在。这可以归因于社会的收入差距。部分原因可能是因为我们关注的是不同教育水平的人。让我们通过教育把他们分开。

train.boxplot(column=’ApplicantIncome’, by = ‘Education’) 
plt.suptitle(“”)

我们可以看到,有更多的高收入毕业生,他们似乎是局外人。

让我们看看共同申请人的收入分布。

sns.distplot(train[‘CoapplicantIncome’])
plt.show()
train[‘CoapplicantIncome’].plot.box(figsize=(16,5))
plt.show()

我们看到与申请人的收入分布相似的分布。大多数共同申请人的收入范围从 0 到 5000 英镑。我们也看到申请人的收入中有很多异常值,而且不是正态分布的。

train.notna()
sns.distplot(train[‘LoanAmount’])
plt.show()
train[‘LoanAmount’].plot.box(figsize=(16,5))
plt.show()

我们在这个变量中看到许多异常值,并且分布相当正常。我们将在后面的章节中处理异常值。

双变量分析

让我们回忆一下我们之前提出的一些假设:

  • 高收入的申请者应该有更多的贷款批准机会。
  • 偿还了以前债务的申请人应该有更高的贷款批准机会。
  • 贷款审批也应取决于贷款金额。贷款金额少的话,贷款获批的几率应该高。
  • 每月偿还贷款的金额越少,贷款获得批准的机会就越大。

让我们尝试使用双变量分析来检验上述假设。

在单变量分析中单独研究了每个变量后,我们现在将再次研究它们与目标变量的关系。

分类自变量与目标变量

首先,我们将找到目标变量和分类自变量之间的关系。现在让我们看看堆积条形图,它将给出已批准和未批准贷款的比例。

Gender=pd.crosstab(train[‘Gender’],train[‘Loan_Status’])
Gender.div(Gender.sum(1).astype(float), axis=0).plot(kind=”bar”,stacked=True,figsize=(4,4))
plt.show()

可以推断,无论是批准的贷款还是未批准的贷款,男女申请人的比例大致相同。

现在让我们把剩下的分类变量和目标变量形象化。

Married=pd.crosstab(train[‘Married’],train[‘Loan_Status’])
Dependents=pd.crosstab(train[‘Dependents’],train[‘Loan_Status’])
Education=pd.crosstab(train[‘Education’],train[‘Loan_Status’])
Self_Employed=pd.crosstab(train[‘Self_Employed’],train[‘Loan_Status’])
Married.div(Married.sum(1).astype(float), axis=0).plot(kind=”bar”,stacked=True,figsize=(4,4))
plt.show()
Dependents.div(Dependents.sum(1).astype(float), axis=0).plot(kind=”bar”,stacked=True,figsize=(4,4))
plt.show()
Education.div(Education.sum(1).astype(float), axis=0).plot(kind=”bar”,stacked=True,figsize=(4,4))
plt.show()
Self_Employed.div(Self_Employed.sum(1).astype(float), axis=0).plot(kind=”bar”,stacked=True,figsize=(4,4))
plt.show()

  • 对于已批准的贷款,已婚申请人的比例更高。
  • 有 1 个或 3 个以上受抚养人的申请人在两种贷款状态类别中的分布相似。
  • 从自营职业者与贷款者的对比图中,我们无法推断出任何有意义的东西。

现在我们来看看剩余的分类自变量和 Loan_Status 之间的关系。

Credit_History=pd.crosstab(train[‘Credit_History’],train[‘Loan_Status’])
Property_Area=pd.crosstab(train[‘Property_Area’],train[‘Loan_Status’])
Credit_History.div(Credit_History.sum(1).astype(float), axis=0).plot(kind=”bar”,stacked=True,figsize=(4,4))
plt.show()
Property_Area.div(Property_Area.sum(1).astype(float), axis=0).plot(kind=”bar”,stacked=True)
plt.show()

  • 看起来信用记录为 1 的人更有可能获得贷款批准。
  • 与农村或城市地区相比,半城市地区获得批准的贷款比例更高。

现在,让我们想象一下相对于目标变量的独立变量的数值。

数字自变量与目标变量

我们将尝试找出贷款已被批准的人的平均收入与贷款未被批准的人的平均收入。

train.groupby(‘Loan_Status’)[‘ApplicantIncome’].mean().plot.bar()

这里的 y 轴代表申请人的平均收入。我们看不到平均收入有任何变化。因此,让我们根据申请人收入变量中的值为其创建箱,并分析每个箱对应的贷款状态。

bins=[0,2500,4000,6000,81000]
group=[‘Low’,’Average’,’High’,’Very high’]
train[‘Income_bin’]=pd.cut(train[‘ApplicantIncome’],bins,labels=group)
Income_bin=pd.crosstab(train[‘Income_bin’],train[‘Loan_Status’])
Income_bin.div(Income_bin.sum(1).astype(float), axis=0).plot(kind=”bar”,stacked=True)
plt.xlabel(‘ApplicantIncome’)
P=plt.ylabel(‘Percentage’)

可以推断,申请人的收入不影响贷款批准的机会,这与我们的假设相矛盾,我们假设如果申请人的收入高,贷款批准的机会也高。

我们将以类似的方式分析共同申请人的收入和贷款额变量。

bins=[0,1000,3000,42000]
group=[‘Low’,’Average’,’High’]
train[‘Coapplicant_Income_bin’]=pd.cut(train[‘CoapplicantIncome’],bins,labels=group)
Coapplicant_Income_bin=pd.crosstab(train[‘Coapplicant_Income_bin’],train[‘Loan_Status’])
Coapplicant_Income_bin.div(Coapplicant_Income_bin.sum(1).astype(float), axis=0).plot(kind=”bar”,stacked=True)
plt.xlabel(‘CoapplicantIncome’)
P=plt.ylabel(‘Percentage’)

它表明,如果共同申请人的收入较低,贷款批准的机会很高。但这看起来不对。这背后可能的原因是,大多数申请人没有任何共同申请人,因此这些申请人的共同申请人收入为 0,因此贷款审批不依赖于此。因此,我们可以创建一个新的变量,将申请人和共同申请人的收入结合起来,以可视化收入对贷款审批的综合影响。

让我们结合申请人收入和共同申请人收入,看看总收入对贷款状态的综合影响。

train[‘Total_Income’]=train[‘ApplicantIncome’]+train[‘CoapplicantIncome’]
bins=[0,2500,4000,6000,81000]
group=[‘Low’,’Average’,’High’,’Very high’]
train[‘Total_Income_bin’]=pd.cut(train[‘Total_Income’],bins,labels=group)
Total_Income_bin=pd.crosstab(train[‘Total_Income_bin’],train[‘Loan_Status’])
Total_Income_bin.div(Total_Income_bin.sum(1).astype(float), axis=0).plot(kind=”bar”,stacked=True)
plt.xlabel(‘Total_Income’)
P=plt.ylabel(‘Percentage’)

我们可以看到,与平均收入、高收入和非常高收入的申请人相比,低总收入的申请人获得贷款批准的比例非常低。

让我们想象一下贷款金额变量。

bins=[0,100,200,700]
group=[‘Low’,’Average’,’High’]
train[‘LoanAmount_bin’]=pd.cut(train[‘LoanAmount’],bins,labels=group)
LoanAmount_bin=pd.crosstab(train[‘LoanAmount_bin’],train[‘Loan_Status’])
LoanAmount_bin.div(LoanAmount_bin.sum(1).astype(float), axis=0).plot(kind=”bar”,stacked=True)
plt.xlabel(‘LoanAmount’)
P=plt.ylabel(‘Percentage’)

可以看出,与高贷款额相比,低贷款额和平均贷款额的批准贷款比例更高,这支持了我们的假设,即我们认为当贷款额较低时,贷款批准的机会将会较高。

让我们删除为探索部分创建的垃圾箱。我们将把从属变量中的 3+改为 3,使它成为一个数字变量。我们还会将目标变量的类别转换为 0 和 1,以便我们可以找到它与数值变量的相关性。这样做的另一个原因是像逻辑回归这样的模型很少只接受数值作为输入。我们将用 0 代替 N,用 1 代替 Y。

train=train.drop([‘Income_bin’, ‘Coapplicant_Income_bin’, ‘LoanAmount_bin’, ‘Total_Income_bin’, ‘Total_Income’], axis=1)
train[‘Dependents’].replace(‘3+’, 3,inplace=True)
test[‘Dependents’].replace(‘3+’, 3,inplace=True)
train[‘Loan_Status’].replace(’N’, 0,inplace=True)
train[‘Loan_Status’].replace(‘Y’, 1,inplace=True)

现在让我们看看所有数值变量之间的相关性。我们将使用热图来可视化这种关联。热图通过不同的颜色将数据可视化。颜色越深的变量表示相关性越大。

matrix = train.corr()
f, ax = plt.subplots(figsize=(9,6))
sns.heatmap(matrix,vmax=.8,square=True,cmap=”BuPu”, annot = True)

我们看到最相关的变量是(申请收入—贷款金额)和(信用记录—贷款状态)。贷款金额也与共同申请人收入相关。

缺失值插补

让我们列出缺失值的特性计数。

train.isnull().sum()
Loan_ID               0
Gender               13
Married               3
Dependents           15
Education             0
Self_Employed        32
ApplicantIncome       0
CoapplicantIncome     0
LoanAmount           22
Loan_Amount_Term     14
Credit_History       50
Property_Area         0
Loan_Status           0
dtype: int64

性别、已婚、受抚养人、自营职业、贷款金额、贷款金额期限和信用历史记录要素中缺少值。

我们将逐一处理所有特性中缺失的值。

我们可以考虑用这些方法来填补缺失值:

  • 对于数值变量:使用平均数或中位数进行插补
  • 对于分类变量:使用模式插补

性别、已婚、受抚养人、信用记录和自营职业要素中很少有缺失值,因此我们可以使用要素的模式来填充它们。

train[‘Gender’].fillna(train[‘Gender’].mode()[0], inplace=True)
train[‘Married’].fillna(train[‘Married’].mode()[0], inplace=True)
train[‘Dependents’].fillna(train[‘Dependents’].mode()[0], inplace=True)
train[‘Self_Employed’].fillna(train[‘Self_Employed’].mode()[0], inplace=True)
train[‘Credit_History’].fillna(train[‘Credit_History’].mode()[0], inplace=True)

现在让我们尝试找到一种方法来填充 Loan_Amount_Term 中缺少的值。我们将查看贷款金额期限变量的值计数。

train[‘Loan_Amount_Term’].value_counts()
360.0    512
180.0     44
480.0     15
300.0     13
84.0       4
240.0      4
120.0      3
36.0       2
60.0       2
12.0       1
Name: Loan_Amount_Term, dtype: int64

可以看出,在贷款金额期限变量中,360 的值是重复最多的。所以我们会用这个变量的模式来替换这个变量中缺失的值。

train[‘Loan_Amount_Term’].fillna(train[‘Loan_Amount_Term’].mode()[0], inplace=True)

现在我们将看到 LoanAmount 变量。由于它是一个数值变量,我们可以使用均值或中值来估算缺失值。我们将使用中值来填充空值,因为之前我们看到贷款金额有异常值,所以平均值不是正确的方法,因为它受异常值的影响很大。

train[‘LoanAmount’].fillna(train[‘LoanAmount’].median(), inplace=True)

现在,让我们检查数据集中是否填充了所有缺失的值。

train.isnull().sum()
Loan_ID              0
Gender               0
Married              0
Dependents           0
Education            0
Self_Employed        0
ApplicantIncome      0
CoapplicantIncome    0
LoanAmount           0
Loan_Amount_Term     0
Credit_History       0
Property_Area        0
Loan_Status          0
dtype: int64

正如我们所看到的,所有缺失的值都已经被填充到测试数据集中。让我们用同样的方法填充测试数据集中所有缺失的值。

test[‘Gender’].fillna(train[‘Gender’].mode()[0], inplace=True)
test[‘Married’].fillna(train[‘Married’].mode()[0], inplace=True)
test[‘Dependents’].fillna(train[‘Dependents’].mode()[0], inplace=True)
test[‘Self_Employed’].fillna(train[‘Self_Employed’].mode()[0], inplace=True)
test[‘Credit_History’].fillna(train[‘Credit_History’].mode()[0], inplace=True)
test[‘Loan_Amount_Term’].fillna(train[‘Loan_Amount_Term’].mode()[0], inplace=True)
test[‘LoanAmount’].fillna(train[‘LoanAmount’].median(), inplace=True)

异常值处理

正如我们在前面的单变量分析中看到的,LoanAmount 包含异常值,因此我们必须将它们视为异常值的存在会影响数据的分布。让我们来看看有离群值的数据集会发生什么。对于样本数据集:
1,1,2,2,2,2,3,3,3,4,4
我们发现如下:均值、中值、众数和标准差
均值= 2.58
中值= 2.5
众数=2
标准差= 1.08
如果我们向数据集添加一个异常值:
1,1,2,2,2,2,2,2,3,3,4,4400
我们必须采取措施消除数据集中的异常值。
由于这些异常值,贷款金额中的大部分数据位于左侧,右尾较长。这叫做右偏度。消除偏斜的一种方法是进行对数变换。当我们进行对数变换时,它不会对较小的值产生太大的影响,但会减少较大的值。所以,我们得到一个类似于正态分布的分布。
我们来可视化一下 log 变换的效果。我们将同时对测试文件进行类似的修改。

train[‘LoanAmount_log’]=np.log(train[‘LoanAmount’])
train[‘LoanAmount_log’].hist(bins=20)
test[‘LoanAmount_log’]=np.log(test[‘LoanAmount’])

现在,分布看起来更接近正常,极端值的影响已经大大减弱。让我们建立一个逻辑回归模型,并对测试数据集进行预测。

模型构建:第一部分

让我们用第一个模型来预测目标变量。我们将从用于预测二元结果的逻辑回归开始。

  • 逻辑回归是一种分类算法。它用于预测给定一组独立变量的二元结果(1 / 0,是/否,真/假)。
  • 逻辑回归是对 Logit 函数的估计。logit 函数仅仅是对事件有利的概率的记录。
  • 该函数使用概率估计值创建一条 S 形曲线,这与所需的逐步函数非常相似

要进一步了解逻辑回归,请参考本文:https://www . analyticsvidhya . com/blog/2015/10/basics-logistic-regression/
让我们删除 Loan_ID 变量,因为它对贷款状态没有任何影响。我们将对测试数据集进行与训练数据集相同的更改。

train=train.drop(‘Loan_ID’,axis=1)
test=test.drop(‘Loan_ID’,axis=1)

我们将使用 scikit-learn (sklearn)来制作不同的模型,这是 Python 的一个开源库。它是最有效的工具之一,包含许多内置函数,可用于 Python 建模。

想进一步了解 sklearn,参考这里:http://scikit-learn.org/stable/tutorial/index.html

Sklearn 需要单独数据集中的目标变量。因此,我们将从训练数据集中删除目标变量,并将其保存在另一个数据集中。

X = train.drop(‘Loan_Status’,1)
y = train.Loan_Status

现在我们将为分类变量制造虚拟变量。虚拟变量将分类变量转化为一系列 0 和 1,使它们更容易量化和比较。让我们先了解一下假人的流程:

  • 考虑“性别”变量。它有两个阶层,男性和女性。
  • 由于逻辑回归只将数值作为输入,我们必须将男性和女性转换为数值。
  • 一旦我们对这个变量应用了虚拟变量,它就会将“性别”变量转换为两个变量(性别 _ 男性和性别 _ 女性),每个类一个,即男性和女性。
  • 如果性别为女性,则性别 _ 男性的值为 0,如果性别为男性,则值为 1。
X = pd.get_dummies(X)
train=pd.get_dummies(train)
test=pd.get_dummies(test)

现在,我们将在训练数据集上训练模型,并对测试数据集进行预测。但是我们能证实这些预测吗?一种方法是,我们可以将训练数据集分为两部分:训练和验证。我们可以在这个训练部分训练模型,并使用它对验证部分进行预测。这样,我们可以验证我们的预测,因为我们有验证部分的真实预测(我们没有测试数据集的真实预测)。

我们将使用 sklearn 的 train_test_split 函数来划分我们的训练数据集。所以,首先让我们导入 train_test_split。

from sklearn.model_selection import train_test_split
x_train, x_cv, y_train, y_cv = train_test_split(X,y, test_size=0.3)

数据集分为训练和验证两部分。让我们从 sklearn 导入 LogisticRegression 和 accuracy_score 并拟合逻辑回归模型。

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
model = LogisticRegression()
model.fit(x_train, y_train)LogisticRegression()

这里,C 参数表示正则化强度的倒数。正则化是应用惩罚来增加参数值的幅度,以便减少过度拟合。C 值越小,正则化越强。要了解其他参数,请参考这里:http://sci kit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html

让我们预测验证集的 Loan_Status 并计算其准确性。

pred_cv = model.predict(x_cv)
accuracy_score(y_cv,pred_cv)0.7891891891891892

因此,我们的预测几乎 80%准确,也就是说,我们已经正确识别了 80%的贷款状态。

让我们对测试数据集进行预测。

pred_test = model.predict(test)

让我们导入我们必须在解决方案检查器上提交的提交文件。

submission = pd.read_csv(‘Dataset/sample_submission.csv’)
submission.head()

我们只需要最终提交的 Loan_ID 和相应的 Loan_Status。我们将用测试数据集的 Loan_ID 和我们做出的预测(即 pred_test)分别填充这些列。

submission[‘Loan_Status’]=pred_test
submission[‘Loan_ID’]=test_original[‘Loan_ID’]

记住我们需要 Y 和 n 的预测,所以让我们把 1 和 0 转换成 Y 和 n。

submission[‘Loan_Status’].replace(0, ’N’, inplace=True)
submission[‘Loan_Status’].replace(1, ‘Y’, inplace=True)

最后,我们将把提交转换成。csv 格式。

pd.DataFrame(submission, columns=[‘Loan_ID’,’Loan_Status’]).to_csv(‘Output/logistic.csv’)

使用分层 k 倍交叉验证的逻辑回归

为了检查我们的模型对看不见的数据有多稳健,我们可以使用验证。这是一种涉及保留数据集的特定样本的技术,您不需要在该样本上训练模型。稍后,在最终确定之前,您将在这个样本上测试您的模型。下面列出了一些常用的验证方法:

  • 验证集方法
  • k 倍交叉验证
  • 遗漏一项交叉验证(LOOCV)
  • 分层 k 倍交叉验证

如果你希望了解更多的验证技术,那么请参考这篇文章:https://www . analyticsvidhya . com/blog/2018/05/improve-model-performance-cross-validation-in-python-r/

在本节中,我们将了解分层 k-fold 交叉验证。让我们了解它是如何工作的:

  • 分层是重新排列数据的过程,以确保每个折叠都是整体的良好代表。
  • 例如,在二进制分类问题中,每个类包含 50%的数据,最好安排数据,使得在每个文件夹中,每个类包含大约一半的实例。
  • 在处理偏差和方差时,这通常是一种更好的方法。
  • 随机选择的倍数可能不足以代表小类,特别是在存在巨大的类不平衡的情况下。

我们从 sklearn 导入 StratifiedKFold,拟合模型。

from sklearn.model_selection import StratifiedKFold

现在,让我们制作一个具有分层 5 层的交叉验证逻辑模型,并对测试数据集进行预测。

i=1
mean = 0
kf = StratifiedKFold(n_splits=5,random_state=1)
for train_index,test_index in kf.split(X,y):
 print (‘\n{} of kfold {} ‘.format(i,kf.n_splits))
 xtr,xvl = X.loc[train_index],X.loc[test_index]
 ytr,yvl = y[train_index],y[test_index]
 model = LogisticRegression(random_state=1)
 model.fit(xtr,ytr)
 pred_test=model.predict(xvl)
 score=accuracy_score(yvl,pred_test)
 mean += score
 print (‘accuracy_score’,score)
 i+=1
 pred_test = model.predict(test)
 pred = model.predict_proba(xvl)[:,1]
print (‘\n Mean Validation Accuracy’,mean/(i-1))1 of kfold 5 
accuracy_score 0.8048780487804879

2 of kfold 5 
accuracy_score 0.7642276422764228

3 of kfold 5 
accuracy_score 0.7804878048780488

4 of kfold 5 
accuracy_score 0.8455284552845529

5 of kfold 5 
accuracy_score 0.8032786885245902

Mean Validation Accuracy 0.7996801279488205

该模型的平均验证精度为 0.80。让我们想象一下 roc 曲线。

from sklearn import metrics
fpr, tpr, _ = metrics.roc_curve(yvl, pred)
auc = metrics.roc_auc_score(yvl, pred)
plt.figure(figsize=(12,8))
plt.plot(fpr, tpr, label=”validation, auc=”+str(auc))
plt.xlabel(‘False Positive Rate’)
plt.ylabel(‘True Positive Rate’)
plt.legend(loc=4)
plt.show()

我们得到的 auc 值为 0.70

submission[‘Loan_Status’]=pred_test
submission[‘Loan_ID’]=test_original[‘Loan_ID’]

记住我们需要 Y 和 n 的预测,所以让我们把 1 和 0 转换成 Y 和 n。

submission[‘Loan_Status’].replace(0, ’N’, inplace=True)
submission[‘Loan_Status’].replace(1, ‘Y’, inplace=True)pd.DataFrame(submission, columns=[‘Loan_ID’,’Loan_Status’]).to_csv(‘Output/Log1.csv’)

特征工程

基于领域知识,我们可以提出可能影响目标变量的新特性。我们将创建以下三个新功能:

  • 总收入 —正如在双变量分析中所讨论的,我们将合并申请人收入和共同申请人收入。如果总收入很高,贷款批准的机会也可能很高。
  • EMI — EMI 是申请人每月偿还贷款的金额。这个变量背后的想法是,高 EMI 的人可能会发现很难偿还贷款。我们可以通过贷款金额与贷款金额期限的比率来计算 EMI。
  • 余额收入 —这是支付 EMI 后剩下的收入。创建这个变量的想法是,如果这个值高,一个人偿还贷款的机会就高,因此增加了贷款批准的机会。
train[‘Total_Income’]=train[‘ApplicantIncome’]+train[‘CoapplicantIncome’]
test[‘Total_Income’]=test[‘ApplicantIncome’]+test[‘CoapplicantIncome’]

让我们检查总收入的分布。

sns.distplot(train[‘Total_Income’])

我们可以看到它向左移动,也就是说,分布是右偏的。所以,我们来取对数变换,使分布呈正态分布。

train[‘Total_Income_log’] = np.log(train[‘Total_Income’])
sns.distplot(train[‘Total_Income_log’])
test[‘Total_Income_log’] = np.log(test[‘Total_Income’])

现在,分布看起来更接近正常,极端值的影响已经大大减弱。现在让我们创建 EMI 特征。

train[‘EMI’]=train[‘LoanAmount’]/train[‘Loan_Amount_Term’]
test[‘EMI’]=test[‘LoanAmount’]/test[‘Loan_Amount_Term’]

让我们检查一下 EMI 变量的分布。

sns.distplot(train[‘EMI’])

train[‘Balance Income’] = train[‘Total_Income’]-(train[‘EMI’]*1000)
test[‘Balance Income’] = test[‘Total_Income’]-(test[‘EMI’]*1000)
sns.distplot(train[‘Balance Income’])

现在,让我们放弃用来创建这些新功能的变量。这样做的原因是,那些旧特征和这些新特征之间的相关性会非常高,而逻辑回归假设变量之间的相关性并不高。我们还希望从数据集中移除噪声,因此移除相关要素也有助于减少噪声。

train=train.drop([‘ApplicantIncome’, ‘CoapplicantIncome’, ‘LoanAmount’, ‘Loan_Amount_Term’], axis=1)
test=test.drop([‘ApplicantIncome’, ‘CoapplicantIncome’, ‘LoanAmount’, ‘Loan_Amount_Term’], axis=1)

模型构建:第二部分

创建新特征后,我们可以继续模型构建过程。因此,我们将从逻辑回归模型开始,然后转向更复杂的模型,如 RandomForest 和 XGBoost。在本节中,我们将构建以下模型。

  • 逻辑回归
  • 决策图表
  • 随机森林
  • XGBoost

让我们准备输入模型的数据。

X = train.drop(‘Loan_Status’,1)
y = train.Loan_Status

逻辑回归

i=1
mean = 0
kf = StratifiedKFold(n_splits=5,random_state=1,shuffle=True)
for train_index,test_index in kf.split(X,y):
 print (‘\n{} of kfold {} ‘.format(i,kf.n_splits))
 xtr,xvl = X.loc[train_index],X.loc[test_index]
 ytr,yvl = y[train_index],y[test_index]
 model = LogisticRegression(random_state=1)
 model.fit(xtr,ytr)
 pred_test=model.predict(xvl)
 score=accuracy_score(yvl,pred_test)
 mean += score
 print (‘accuracy_score’,score)
 i+=1
 pred_test = model.predict(test)
 pred = model.predict_proba(xvl)[:,1]
print (‘\n Mean Validation Accuracy’,mean/(i-1))1 of kfold 5 
accuracy_score 0.7967479674796748

2 of kfold 5 
accuracy_score 0.6910569105691057

3 of kfold 5 
accuracy_score 0.6666666666666666

4 of kfold 5 
accuracy_score 0.7804878048780488

5 of kfold 5 
accuracy_score 0.680327868852459

 Mean Validation Accuracy 0.7230574436891909submission['Loan_Status']=pred_test
submission['Loan_ID']=test_original['Loan_ID']submission['Loan_Status'].replace(0, 'N', inplace=True)
submission['Loan_Status'].replace(1, 'Y', inplace=True)pd.DataFrame(submission, columns=['Loan_ID','Loan_Status']).to_csv('Output/Log2.csv')

决策图表

决策树是一种监督学习算法(具有预定义的目标变量),主要用于分类问题。在这种技术中,我们根据输入变量中最重要的分割器/区分器将总体或样本分成两个或多个同类集合(或子总体)。

决策树使用多种算法来决定将一个节点拆分成两个或多个子节点。子节点的创建增加了结果子节点的同质性。换句话说,我们可以说节点的纯度随着目标变量的增加而增加。

详细解释请访问https://www . analyticsvidhya . com/blog/2016/04/complete-tutorial-tree-based-modeling-scratch-in-python/# six

让我们用 5 重交叉验证来拟合决策树模型。

from sklearn import tree
i=1
mean = 0
kf = StratifiedKFold(n_splits=5,random_state=1,shuffle=True)
for train_index,test_index in kf.split(X,y):
    print ('\n{} of kfold {} '.format(i,kf.n_splits))
    xtr,xvl = X.loc[train_index],X.loc[test_index]
    ytr,yvl = y[train_index],y[test_index]
    model = tree.DecisionTreeClassifier(random_state=1)
    model.fit(xtr,ytr)
    pred_test=model.predict(xvl)
    score=accuracy_score(yvl,pred_test)
    mean += score
    print ('accuracy_score',score)
    i+=1
    pred_test = model.predict(test)
    pred = model.predict_proba(xvl)[:,1]
print ('\n Mean Validation Accuracy',mean/(i-1))1 of kfold 5 
accuracy_score 0.7398373983739838

2 of kfold 5 
accuracy_score 0.6991869918699187

3 of kfold 5 
accuracy_score 0.7560975609756098

4 of kfold 5 
accuracy_score 0.7073170731707317

5 of kfold 5 
accuracy_score 0.6721311475409836

 Mean Validation Accuracy 0.7149140343862455submission['Loan_Status']=pred_test
submission['Loan_ID']=test_original['Loan_ID']submission['Loan_Status'].replace(0, 'N', inplace=True)
submission['Loan_Status'].replace(1, 'Y', inplace=True)pd.DataFrame(submission, columns=['Loan_ID','Loan_Status']).to_csv('Output/DecisionTree.csv')

随机森林

  • RandomForest 是一种基于树的自举算法,其中一定数量的弱学习器(决策树)被组合以形成强大的预测模型。
  • 对于每个单独的学习者,随机的行样本和一些随机选择的变量被用来建立决策树模型。
  • 最终预测可以是由单个学习者做出的所有预测的函数。
  • 在回归问题的情况下,最终预测可以是所有预测的平均值。

详细解释请访问本文https://www . analyticsvidhya . com/blog/2016/04/complete-tutorial-tree-based-modeling-scratch-in-python/

from sklearn.ensemble import RandomForestClassifier
i=1
mean = 0
kf = StratifiedKFold(n_splits=5,random_state=1,shuffle=True)
for train_index,test_index in kf.split(X,y):
 print (‘\n{} of kfold {} ‘.format(i,kf.n_splits))
 xtr,xvl = X.loc[train_index],X.loc[test_index]
 ytr,yvl = y[train_index],y[test_index]
 model = RandomForestClassifier(random_state=1, max_depth=10)
 model.fit(xtr,ytr)
 pred_test=model.predict(xvl)
 score=accuracy_score(yvl,pred_test)
 mean += score
 print (‘accuracy_score’,score)
 i+=1
 pred_test = model.predict(test)
 pred = model.predict_proba(xvl)[:,1]
print (‘\n Mean Validation Accuracy’,mean/(i-1))1 of kfold 5 
accuracy_score 0.8292682926829268

2 of kfold 5 
accuracy_score 0.8130081300813008

3 of kfold 5 
accuracy_score 0.7723577235772358

4 of kfold 5 
accuracy_score 0.8048780487804879

5 of kfold 5 
accuracy_score 0.7540983606557377

 Mean Validation Accuracy 0.7947221111555378

我们将通过调整该模型的超参数来提高精确度。我们将使用网格搜索来获得超参数的优化值。网格搜索是一种从一系列超参数中选择最佳参数的方法,这些参数由参数网格来确定。

我们将调整 max_depth 和 n _ estimators 参数。max_depth 决定树的最大深度,n_estimators 决定将在随机森林模型中使用的树的数量。

网格搜索

from sklearn.model_selection import GridSearchCV
paramgrid = {‘max_depth’: list(range(1,20,2)), ‘n_estimators’: list(range(1,200,20))}
grid_search=GridSearchCV(RandomForestClassifier(random_state=1),paramgrid)from sklearn.model_selection import train_test_split
x_train, x_cv, y_train, y_cv = train_test_split(X,y, test_size=0.3, random_state=1)
grid_search.fit(x_train,y_train)GridSearchCV(estimator=RandomForestClassifier(random_state=1),
             param_grid={'max_depth': [1, 3, 5, 7, 9, 11, 13, 15, 17, 19],
                         'n_estimators': [1, 21, 41, 61, 81, 101, 121, 141, 161,
                                          181]})grid_search.best_estimator_RandomForestClassifier(max_depth=5, n_estimators=41, random_state=1)i=1
mean = 0
kf = StratifiedKFold(n_splits=5,random_state=1,shuffle=True)
for train_index,test_index in kf.split(X,y):
    print ('\n{} of kfold {} '.format(i,kf.n_splits))
    xtr,xvl = X.loc[train_index],X.loc[test_index]
    ytr,yvl = y[train_index],y[test_index]
    model = RandomForestClassifier(random_state=1, max_depth=3, n_estimators=41)
    model.fit(xtr,ytr)
    pred_test = model.predict(xvl)
    score = accuracy_score(yvl,pred_test)
    mean += score
    print ('accuracy_score',score)
    i+=1
    pred_test = model.predict(test)
    pred = model.predict_proba(xvl)[:,1]
print ('\n Mean Validation Accuracy',mean/(i-1))1 of kfold 5 
accuracy_score 0.8130081300813008

2 of kfold 5 
accuracy_score 0.8455284552845529

3 of kfold 5 
accuracy_score 0.8048780487804879

4 of kfold 5 
accuracy_score 0.7967479674796748

5 of kfold 5 
accuracy_score 0.7786885245901639

 Mean Validation Accuracy 0.8077702252432362submission['Loan_Status']=pred_test
submission['Loan_ID']=test_original['Loan_ID']submission['Loan_Status'].replace(0, 'N', inplace=True)
submission['Loan_Status'].replace(1, 'Y', inplace=True)pd.DataFrame(submission, columns=['Loan_ID','Loan_Status']).to_csv('Output/RandomForest.csv')

现在让我们找出特征的重要性,即对于这个问题哪些特征是最重要的。我们将使用 sklearn 的 feature_importances_ attribute 来这样做。

importances=pd.Series(model.feature_importances_, index=X.columns)
importances.plot(kind=’barh’, figsize=(12,8))

我们可以看到,信用历史是最重要的特征,其次是余额收入、总收入、EMI。因此,特征工程帮助我们预测我们的目标变量。

XGBOOST

XGBoost 是一种快速高效的算法,已经被许多数据科学竞赛的获胜者使用。这是一个 boosting 算法,你可以参考下面的文章来了解更多关于 boosting 的信息:https://www . analyticsvidhya . com/blog/2015/11/quick-introduction-boosting-algorithms-machine-learning/

XGBoost 只适用于数字变量,我们已经用数字变量替换了分类变量。让我们看看我们将在模型中使用的参数。

  • n_estimator:这指定了模型的树的数量。
  • max_depth:我们可以使用这个参数指定一棵树的最大深度。

GBoostError:无法加载 XGBoost 库(libxgboost.dylib)。如果你在 macOS 中遇到这个错误,运行Terminal中的brew install libomp

from xgboost import XGBClassifier
i=1 
mean = 0
kf = StratifiedKFold(n_splits=5,random_state=1,shuffle=True) 
for train_index,test_index in kf.split(X,y): 
 print(‘\n{} of kfold {}’.format(i,kf.n_splits)) 
 xtr,xvl = X.loc[train_index],X.loc[test_index] 
 ytr,yvl = y[train_index],y[test_index] 
 model = XGBClassifier(n_estimators=50, max_depth=4) 
 model.fit(xtr, ytr) 
 pred_test = model.predict(xvl) 
 score = accuracy_score(yvl,pred_test) 
 mean += score
 print (‘accuracy_score’,score)
 i+=1
 pred_test = model.predict(test)
 pred = model.predict_proba(xvl)[:,1]
print (‘\n Mean Validation Accuracy’,mean/(i-1))1 of kfold 5
accuracy_score 0.7804878048780488

2 of kfold 5
accuracy_score 0.7886178861788617

3 of kfold 5
accuracy_score 0.7642276422764228

4 of kfold 5
accuracy_score 0.7804878048780488

5 of kfold 5
accuracy_score 0.7622950819672131

 Mean Validation Accuracy 0.7752232440357191submission['Loan_Status']=pred_test
submission['Loan_ID']=test_original['Loan_ID']submission['Loan_Status'].replace(0, 'N', inplace=True)
submission['Loan_Status'].replace(1, 'Y', inplace=True)pd.DataFrame(submission, columns=['Loan_ID','Loan_Status']).to_csv('Output/XGBoost.csv')

SPSS 建模器

要创建 SPSS Modeler 流程并使用它构建机器学习模型,请遵循以下说明:

[## 使用 IBM Watson Studio 预测贷款资格

本教程向您展示了如何创建一个完整的预测模型,从导入数据,准备数据,到…

developer.ibm.com](https://developer.ibm.com/tutorials/predict-loan-eligibility-using-jupyter-notebook-ibm-spss-modeler/)

注册一个 IBM Cloud 账户来试试这个教程

[## IBM 云

使用 190 多种独特的服务立即开始建设。

ibm.biz](https://ibm.biz/BdqQBT)

结论

在本教程中,我们学习了如何创建模型来预测目标变量,即申请人是否能够偿还贷款。

在学习 PyTorch 基础知识的同时预测英雄联盟中的比赛

原文:https://towardsdatascience.com/predict-matches-in-league-of-legends-while-learning-pytorch-basics-3dd43cf8d16f?source=collection_archive---------48-----------------------

在 PyTorch 中为一个很酷的独特用例场景构建一个简单的逻辑回归模型的演练

作者理查德·索

《英雄联盟》是我一直以来最喜欢的游戏之一,尽管我真的很不擅长。LOL 是一个极具竞争力的 MOBA,两个 5 人的队伍(蓝队和红队)相互对抗,以摧毁对方的基地(nexus)。获胜通常需要大量的团队合作、协调,或者对于一个倾斜的玩家来说需要“运气”。不管怎样,对于一个联盟玩家(即使他们是相当新的)来说,根据游戏记录的死亡人数和许多其他数据来判断哪个队可能会赢并不太难。机器学习模型可以预测的东西…… (这应该是这篇文章执行得不好的铺垫)

我也开始用 PyTorch 学一点机器/深度学习(通过这个py torch Zero to GANs课程)。其中一个课程作业是用 PyTorch 为一些用例场景建立一个回归模型,因此,我们现在就在这里!当然,我们可以使用 *scikit-learn* 并称之为完成,但是对我(和你)来说,重点是学习构建 PyTorch 模型的基本原理。 这将是我通过构建一个简单的英雄联盟比赛预测器来学习 PyTorch 的过程中的一次演练,该预测器将合理准确地确定任何一队获胜的机会。

xkcd

数据集

首先,我使用了大约 1 万场英雄联盟排名赛的 Kaggle 数据集。每场比赛的数据都是在开始的 10 分钟内收集的。所有的比赛都是由高钻石到低大师级别的玩家参加的。幸运的是,我没有需要填充的缺失值,也没有需要一次性编码的非数字数据。总而言之,不需要太多的数据操作。

首先,我们将导入所有必需的库:

我们会看到数据是什么样的:

df.read_csv('high_diamond_ranked_10min.csv')

这个数据集有 40 列,但其中一些实际上是多余的。例如,如果你知道蓝队(blueKills)的杀戮,这几乎直接转化为红队(redDeaths)的死亡。基于这个推论,我们只需要这两个中的一个。

df.drop(['gameId','redFirstBlood','blueTotalGold','redTotalGold','blueTotalExperience','redTotalExperience','redGoldDiff','redExperienceDiff','redKills','redDeaths'], axis=1, inplace=True)

这使得我们只剩下 30 列,包括标签列。这个数据集的标签(我们想要预测的)是列blueWins,0 或 1 表示蓝方是否在游戏的剩余时间内获胜。最后,我们将标签与功能分开…

targets = df[['blueWins']].values #only the `blueWins` column
features = df.drop('blueWins', axis=1).values #all the other columns

…拆分数据(80/10/10 拆分用于培训、验证和测试),并将它们转化为 PyTorch 张量…

test_size = int(.10 * 9879) *# 10% of the total size of the dataset*
val_size = test_size
train_size = 9879 - test_size*2
train_size , val_size, test_sizedataset = TensorDataset(torch.tensor(features).float(), torch.from_numpy(targets).float()) # turning arrays into tensorstrain_ds, val_ds, test_ds = random_split(dataset, [train_size, val_size, test_size]) # doing an 80/10/10 split on the data

…并用批处理大小128从它们中生成 DataLoader 对象。

batch_size = 128#making data loader objects out of the splits
train_loader = DataLoader(train_ds, batch_size, shuffle=True)
val_loader = DataLoader(val_ds, batch_size)
test_loader = DataLoader(test_ds, batch_size)

模型

好吧,这就是“有趣”的开始!是时候用 PyTorch 做 logistic 回归模型了。以下是我在构建这个过程中的思路:

  • 一个逻辑回归模型在我们的 PyTorch 模型中只需要一个nn.Linear层,接受 29 个输入,输出 1: nn.Linear(29, 1)
  • 因为我们预测的值是从 0 到 1,使用nn.Sigmoid()会将模型的输出缩小到这个范围。
  • 除了一个可能不可微的精度指标(这将意味着梯度无法确定,而这是模型在训练期间改进所必需的),我们将如何计算模型的“错误”程度?快速浏览一下 PyTorch 文档可以得到成本函数:binary_cross_entropy
  • 因为准确性度量不能用于模型训练,并不意味着它不应该被实现!在这种情况下,准确性将通过阈值来衡量,如果模型预测和实际标签之间的差异低于该阈值,则进行计数。
  • 我们希望跟踪每个历元后的验证损失/精度,每次这样做时,我们必须确保梯度没有被跟踪。
  • 我们希望打印出每隔几个时期的平均验证损失和精确度。

综上所述,实现如下:

定义一些变量供以后使用。

我们的模型“LOLModel”的 python 类。

精度函数。

然后,我们需要做一个训练循环,并决定使用哪个优化器。对于优化器,在首先尝试 SGD 之后,我选择了 Adam:

定义训练循环,由“fit()”函数定义。

我们定义了一个evaluate()fit()函数,后者是主训练循环,它:

  1. 将一批数据输入模型
  2. 以设定的学习率应用渐变
  3. 根据验证数据测试模型,得出验证损失/准确性
  4. 将数据追加到数组history中进行绘图

训练&最后的揭示

总之,对于超参数,我训练了750个时期,学习率为0.0001:

model = LOLModel() #initiate the model

让我们首先确保数据正确地通过模型。

最终验证损失和精度分别为0.54940.7209(该模型中精度从 0 到 1 测量)

在这里,我们可以看到模型在每个时期迭代时验证准确性的变化。大约在公元 150 年有一个急剧的增长,并且在.8 accuracy since.附近徘徊

现在,在过去的 10%分割中测试模型(请击鼓!):

忽略' val_loss '和' val_acc '!

使用evaluate(),我们发现该模型在预测 LOL 比赛结果时的准确率约为 74.5%,不算太差!

结论

总而言之,我认为这是我的一次成功。我学到了很多关于在 PyTorch 中制作模型的基础知识,即使模型很简单。更酷的是:我很开心地看到我做的一些事情最终得到了很好的解决!希望你能像我做模型一样喜欢阅读这个过程。无论如何,快乐编码(或继续玩联赛)!

如果你想知道这个迷你项目使用的 jupyter 笔记本的来源,请看这里:https://jovian.ml/richardso21/lol-logistic

预测数据集中缺失的值

原文:https://towardsdatascience.com/predict-missing-values-in-the-dataset-897912a54b7b?source=collection_archive---------10-----------------------

弗兰基·查马基在 Unsplash 上拍摄的照片

了解如何使用机器学习模型及其实现来预测数据集中的缺失值

真实世界的数据通常有很多缺失值。丢失值的原因可能是数据损坏或未能记录数据。在数据集的预处理过程中,缺失数据的处理非常重要,因为许多机器学习算法不支持缺失值。

有多种策略可以处理数据集中的缺失值,包括缺失值的预测。本文将介绍如何理解和实现通过使用机器学习算法预测缺失值来处理缺失值。

缺少值的列的类别:

  1. 分类(数字,对象)
  2. 连续变量(数值)

分类变量:

分类变量是一个变量,它可以取有限的、通常是固定的可能值。分类变量可以是字符串或数字类型。分类变量的一些可能的例子是:

  • 产品评级:1、2、3、4、5
  • 分类评级:差、满意、好、优秀
  • 性别:男,女

连续变量:

连续变量是可以取不可数的一组值的变量。例如,在实数的非空范围内的变量是连续的,如果它可以取该范围内的任何值。

为了预测分类变量,需要分类机器学习算法,如逻辑回归、SVM、朴素贝叶斯等。

要预测连续变量,需要回归机器学习算法,如线性回归、SVR 等。

[## 机器学习中处理缺失值的 7 种方法

处理数据集中缺失值的常用策略

towardsdatascience.com](/7-ways-to-handle-missing-values-in-machine-learning-1a6326adf79e)

准备数据集以预测缺失值:

使用的数据是来自 Kaggle泰坦尼克号数据集

若要预测数据集中缺失的值,请创建一个新的数据集,以便:

***new_data**: columns except the column with missing values
**target_class**: column with missing value*

(图片由作者提供),泰坦尼克号数据集样本

(图片由作者提供),泰坦尼克号数据集的信息

在上面的样本数据集图像中,列 Age,Cabin,Embarked 包含空值或缺失值。

如果我们首先要估算列 Age 的缺失值,用于训练模型以预测缺失值的新数据集将为:

***new_data**: columns except the column "Age"
**target_class**: column "Age"*

现在我们需要将数据分为训练数据和预测数据,在列年龄中没有缺失值的行将被声明为训练数据。从以上形成的数据集训练的模型可用于预测年龄列中的缺失值。

***training_data**: rows from new_data where column "Age" does not have missing values
**predict_data**: rows from new_data where column "Age" have missing values
**target_class_traing**: non-missing values in column "Age"*

栏目关联:

我们是否需要在具有所有剩余列的数据集上训练模型?有时,使用所有剩余列的训练模型比某些列更好地预测缺失值,但有时某些高度相关的列,由选择性高度相关列训练的模型往往会给出更好的结果。

如何找到列之间的关联?

Pandas 库有一个简单的单行实现来查找数据帧中所有列的相关性。

(图片由作者提供),Titanic 数据集中列之间的皮尔逊相关结果

*data.corr()*

上图显示了每列之间的皮尔逊相关系数值。PCC 测量两个变量 XY 之间的线性相关性。它的值介于+1 和-1 之间。值+1 表示完全正线性相关,0 表示没有线性相关,1 表示完全负线性相关。

计算列年龄和其他列之间的相关性,以找到与列年龄相关的列。从上表中可以看出,有 3 列与列年龄相关。

这些列是Pclass(PCC:-0.369226)SibSp(PCC:-0.308247)Parch(PCC:-0.189119)。

将数据集拆分成训练和预测数据:

选择与列年龄相似的 3 列,形成总共 891 行的数据集。

分隔具有空值或缺失值的行以进行预测。

**

通过对 X_train 数据集进行定型并预测 column Age 中缺少的值来准备机器学习模型。

实施:

(作者代码)

结论:

每个数据集都有需要智能处理的缺失值,以创建稳健的模型。在本文中,我讨论了预测缺失值的实现。没有以特定方式或使用特定模型来处理缺失值的经验法则,这种方法可以获得具有最佳性能的健壮模型。可以使用整个数据集来预测丢失的值或一些删除的列。了解数据集的领域知识非常重要,这有助于了解如何预处理数据和处理缺失值。

感谢您的阅读

预测 NBA 比赛,赚钱——机器学习项目

原文:https://towardsdatascience.com/predict-nba-games-make-money-machine-learning-project-b222b33f70a3?source=collection_archive---------22-----------------------

过去的表现并不能说明未来的表现…除非…我们能获得 136%的回报…?😉

mfw 我的深度学习模型编译//photomosh.com 制造

下注者和庄家没有太多的共同之处——人们可以把他们的关系描述为竞争。但在睡梦中,他们对同一个幻想垂涎三尺:一个历史表现如此完美的模型,它以精确的预测未来游戏的结果。有了深度学习,这可能成为可能——或者至少比以前的数据科学技术更容易。

我阅读了许多**好的和坏的期刊文章,看看这是否可能,下面是一些好的文章:
利用机器学习开发体育博彩市场
(2018)* 情绪偏差和资产价格:来自体育博彩市场的证据(2016) 美国国家篮球协会博彩中的情绪偏差***

潜在的假设是,NBA 市场是无效率的(价格或投注线并不反映游戏的所有可用信息)——并且可能比大多数市场更无效率,因为铁杆球迷的偏见只是押注于他们最喜欢的球队。如果你能赌赢市场的无效率,你就能赚钱。我们可以识别低效率的方法之一是分析硬数据。

尽管尝试这一挑战的许多模型都是精确的,但是大多数都离盈利还差得很远。原因很简单:博彩公司也非常准确。即使你匹配了庄家准确率,你也会因为 5%的投注费/房子边缘而输。

https://www . football-data . co . uk/blog/NBA _ pinnacle _ efficiency . PHP

左边的图表是 bet365 资金线与实际获胜百分比。一个成功的模型必须从完美回归中预测庄家的微小波动。

我的模型是用 Python 和 Tensorflow 构建的,分析了过去的 11 个 NBA 赛季,在许多方面,它与其他试图解决这个问题的深度学习模型相似,但有一个关键的不同——它使用一个定制的损失函数来与博彩公司去相关。我们正在挑选博彩公司虚报了实际百分比的游戏。

去相关损失公式——这非常重要!!!!!!!

Da 代码

模型架构

我使用 nba_api Python 库抓取了盒子得分历史。数据存储在 MongoDB 集合中。在过去的 11 个赛季中,每个球员的每场比赛总共有 42 个数据被存储,从罚球命中率到防守等级到抢断次数。投注数据是从的 betexplorer 上刮下来的。找到高质量的投注线比训练模型要难得多。向斯洛文尼亚卢布尔雅那大学的 trumbelj 教授寻求一些建议。

对于每场比赛,样本是用每个球员从赛季开始的最后 8 场比赛的平均值计算的。根据平均游戏时间选择前 8 名玩家。

型号:

该模型是 Conv2D 和密集层的组合,有很多漏失。该模型的独特之处在于去相关损失,我提到的第一篇论文对此进行了概述。尽管 Keras 本身不支持带有神经元值的损失函数,但是将函数包装在函数中是一种有用的解决方法。我在 GTX 1660Ti 上训练网络 20 个纪元,直到网络收敛。

结果:

使用 10%的余额模型置信度的非常原始的下注策略,并且仅在模型置信度> 0.6 的游戏上赌博,我们生成一个向上的余额趋势。有趣的是,该模型只对全部游戏的大约 10%下注。除了整个 2017-18 赛季的灾难性连败之外,我们的模型表现非常好,初始投资为 100 美元,最高为 292 美元。*

学习与未来:

这只是这种模式的开始。随着令人鼓舞的结果,我想制定一个更有活力的投注策略。如果你想嘲笑/怜悯我写的 Jupyter 笔记本的 1k 行,完整的未删节未编辑的笔记本可以在这里找到:https://github . com/calebcheng 00/NBA _ predictions/blob/master/NBA . ipynb
唯一有用的东西大概就是投注刮码和模型了。

使用 NoSQL 是一个错误,我应该坚持使用 SQLite,但学习一项新技术是很好的。编写自定义损失函数是一次非常有价值的经历,在未来的深度学习项目中会派上用场。

用蒙特卡罗模拟预测 NBA 球员阵容

原文:https://towardsdatascience.com/predict-nba-player-lines-with-monte-carlo-simulation-58a1c006a6e2?source=collection_archive---------24-----------------------

我们能利用数据科学在体育博彩市场中发现价值吗?

TJ·德拉戈塔在 Unsplash 上的照片

我绝不鼓励赌博。我不鼓励使用我的模型,事实上,我积极劝阻它。这是纯粹的教育用途,不应该使用或依赖任何真正的钱。说真的。

我以前作为职业体育赌客的经验非常依赖有效市场假说。这表明资产价格反映了所有可获得的信息。在体育博彩术语中,在自由市场(如 Betfair exchange 这样的交易所)中,任何事件的价格都准确地反映了该事件发生的几率。

这个理论起源于 20 世纪初(直到几十年后才流行起来),有一个故事很好地解释了这个理论。1906 年,伟大的统计学家弗朗西斯·高尔顿在一个乡村集市上观察了一场猜公牛体重的比赛。八百人参加了。高尔顿就是这样的人,他对这些数字进行了统计测试。虽然有些人的猜测过高,有些人的猜测过低,但他发现平均猜测值(1197 磅)与公牛的实际体重(1198 磅)非常接近。这个故事是詹姆斯·苏洛维耶茨基在他有趣的书《群体的智慧》中讲述的。我强烈推荐。

但是使用这些假设来发现价值和下注存在几个困难:

  • 这一假设只有在市场流动性充足的情况下才有效。许多市场都缺乏流动性。这意味着我们不能确信价格是正确的(我们只有很少的人群)。因此,像玩家线这样不太受欢迎的市场不能使用这种技术。即使是现在,当我写这篇文章时,一场德国德甲比赛有 150,000 场胜利/平局/客场比赛,只有 2500 场超过/低于 3.5 个进球。这一行缺乏流动性意味着我们不能假定它的价格是正确的。
  • 我以前使用的技术完全依赖于击败市场价格,这意味着人们不能在这些交易所交易。大多数庄家限制使用这种技术的人,因此为了持续的利润,必须开发不同的技术。除此之外,最有用的技术是可以在交易所获利的技术。
  • 有专业的体育博彩者和交易者,他们只通过交易所就能持续盈利。虽然他们可能是少数,但这意味着至少有可能比大众更明智。

这些限制促使我探索开发不依赖大众智慧的预测体育赛事结果的技术。

蒙特卡罗模拟是一种广泛的工具,它依靠重复采样来获得数值结果。当很难使用其他方法时,它们经常在物理或数学中使用。在预测随机性起重要作用的事件(如体育事件)时,它们尤其有用。

这是因为蒙特卡罗模拟不是像大多数典型的机器学习算法那样给出具有一定程度不确定性的确定性结果,而是反转这一点。它只使用一系列概率来解决确定性问题。它不是简单的给我们结果,而是会输出所有潜在结果的概率分布。这对体育博彩来说太棒了。如果我们设法精确地模拟一场游戏,就有可能创造一套赔率,或建立公平的线。然后可以将这个结果与市场和各种博彩公司进行比较,我们可以决定我们是否有价值。

体育包含了大量的随机性和变化,除此之外,可处理的数据量也是有限的。阵容经常变化,上赛季表现好的球队下赛季可能表现不佳。由于这个原因,历史数据在很大程度上是不相关的。

游戏中有如此多的随机性,以至于看一个游戏结果的预测并没有特别大的帮助。就像看轮盘赌的一次旋转没有太大帮助一样——赌场不关心一次旋转会发生什么。他们甚至不关心 100 次或 1000 次旋转后会发生什么。他们只关心理解他们的游戏如何在赌场一生中发生的数百万次旋转中产生优势。这限制了我们训练传统机器学习模型的能力。

赌场通过理解他们的优势是长期实现的来赚钱,所以敏锐的体育赌徒也应该这样做。然而,NBA 每个赛季每支球队只有 82 场比赛,由于冠状病毒,本赛季甚至更少,我们只有有限的数据来进行预测。因此,我们希望能够大量模拟游戏,即使不是数百万次,也是数千次,以建立一个准确的结果和概率范围。

当应用于体育时,我们基本上可以做的是从几个已知分布(以前的比赛结果)中取样,并产生一个新的未知分布(新的比赛结果和概率分布)。

我用的数据是从https://www.basketball-reference.com刮来的。它提供了 NBA 每名球员的每场比赛统计数据,我使用的是 2013 年以来的数据。

在探索数据的早期,我发现了一些见解,这些见解将影响我设计模型的方式。首先,不同位置的球员平均得分不同。其次,每个位置的得分都有主场优势。

图表显示每场比赛的平均分数,带有置信区间

这一点都不奇怪,因为这是一个即使是最基本的体育迷都会做出的假设。然而,在考虑如何构建游戏模拟时,检查它们是很重要的。假设存在主场优势,并且会出现位置差异,我们需要在任何模拟中包含这些信息。

我检查的另一个相对简单的假设是上场时间对得分的影响。这是有道理的,球员在场上的时间越长,他们得分的时间就越多。下面的回归图显示了这种关系的本质,因为很难看到分散点的密度。这种相关性延续到其他指标,这是有意义的——更多的时间,更多的助攻,抢断,盖帽,得分,等等。

PTS 对 MP 的回归图

球员表现指标和上场时间的相关性

所以总结一下:

  • 有主场优势
  • 得分与上场时间有关
  • 得分上存在着位置上的差异,这种差异通过主场优势得以延续。

这是我用来构建我将从中取样的分布的信息。我对这些指标做了一个很大的假设,那就是它们通常是正态分布的。

下面是尼克·杨的上场时间分布,虽然不完全是正态分布,但对我来说已经足够接近了。

得分当然更多的是一种延伸,这当然应该被认为是一种限制,以后再考虑调整。

尼克·杨主场上场时间直方图

在家得分的尼克·杨积分直方图

潜在的方法

我考虑了几种方法来构建可重复采样的发行版:

Bootstrapping :从这些已知分布中重复采样,进行替换。如果我们从上面的得分分布中反复取样,就不会有一个模拟显示尼克·杨得了 35 分。在过去,他得了大约 29 分和 38 分,所以这种情况显然是可能的,我们想反映这一点。

建立泊松分布:我考虑的另一个选择是建立泊松分布。它强制所有数字都是大于零的整数,这对我们的目的很有帮助。然而,在泊松分布中,均值和标准差是相同的数。然后我可以从这个人工构建的分布中取样

构建一个调整后的正态分布:我的选择是使用球员统计数据的均值和标准差生成一个正态分布,并从中重复采样。然后我强制数字为整数,负数为零。这有助于克服上述方法的局限性。

我用一个玩家的历史数据生成了他游戏结果的分布。这允许我建立一个数以千计的游戏的分布,而不仅仅是现有的有限的历史数据。

新的分布如下所示。虽然与原来的不同,但它有效地解决了上述问题,并且形状大致相似。

尼克·杨在家模拟得分直方图

模拟

现在终于到了有趣的部分。

我构建了几个函数来执行模拟。

第一个函数只是找到最近一个赛季的球队阵容(因为我们不关心不在球队中的球员),并返回一个字典,其中包含他们的位置,以便以后参考。

def get_player_position_dict(team):

    # This function collects all the players names of the team, and       inputs it into
    # A dictionary, along with each player prospective position.home_team_lineup = df.loc[(df['Tm'] == team) & (df['Date'] >= '2017-10-17 00:00:00')][['Player','Pos']]
    home_team_lineup = home_team_lineup.drop_duplicates().sort_values(by = 'Player')
    home_team_lineup_list = list(home_team_lineup['Player'])
    home_team_position_list = list(home_team_lineup['Pos'])
    team_player_position_dict = dict(zip(home_team_lineup_list, home_team_position_list ))

    return team_player_position_dict

下一个函数包含了很多代码,所以我会用文字解释,可以随意跳过。它也在我的 Github 上。

对于所要求的模拟次数,以及对于单个玩家,该函数从我为他们构建的分布中随机抽取样本。它需要一个他们玩了多长时间的样本,乘以一个他们每分钟得分多少的样本,再加上一个对方球队在那个位置上让出的分数的样本。这整个过程是一个游戏的模拟

这个数被 2 除,所以进攻和防守统计都考虑进去了,那个分数被输入一个列表。

def score_sim(mp_mean, scoring_rate_mean, mp_std, scoring_rate_std, away_PTS_conceded_mean, away_PTS_conceded_std, ns): 

    score_list = []

    for i in range(ns):
        # How long an individual home team player plays at home
        home_minutes_played = np.random.normal(mp_mean,
                                          mp_std)# How effective they are at scoring points at home
        home_player_scoring_effectiveness =  np.random.normal(scoring_rate_mean, scoring_rate_std)# How often does the team that is away concede when they are away, broken down by location
    # Note here location is also technically 'home' because we are looking at them as an Oppaway_positional_conceding = np.random.normal(away_PTS_conceded_mean, away_PTS_conceded_std)# Force negatives to be 0
        parameters = [home_minutes_played, home_player_scoring_effectiveness, away_positional_conceding]
        parameters = [0 if x<= 0 else x for x in parameters]# Convert to integer as we cannot score 0.5 points
        try:
            home_player_score = int((((parameters[0] * parameters[1]) + parameters[2])/2))
        except:
            home_player_score = 'NA'

        score_list.append(home_player_score)return score_list

在一个特定的球员(斯蒂芬·库里)对猛龙队的比赛中运行这个结果,给出了下面的结果(为了更容易查看,我已经将列表转换成了直方图。这显示了他在 10,000 场比赛中的预期分数分布。

斯蒂芬·库里对托尔

所以从本质上来说,我建立的是斯蒂芬·库里得分能力的新分布,但根据对方球队的防守能力进行了一些调整,即他们防守斯蒂芬·库里位置上球员的能力。

为简单起见,模型模拟的第一次迭代是为偶数钱寻找公平线。如果我们可以(准确地)找到公平线,那么我们可以搜索比我们预期的概率更好的价格,并思考它们是否提供价值。以下函数对模拟分数进行排序,并求出中值。

def convert_to_line(score):

    score.sort()
    freq = {x:score.count(x) for x in score}
    values_list = list()
    for val, count in freq.items():
        for count in range(count):
            values_list.append(val)median_computed = statistics.median(values_list)
    return median_computed

对于这组结果,它的输出是 17。这意味着,我们的模拟显示,在对阵猛龙的比赛中,斯蒂芬·库里一半时间得分在 17 分以上,另一半时间得分在 17 分以下。

对于体育博彩来说,这意味着如果我们能找到比这条线更好的地方(SC 得分超过或低于 17 分),纯粹基于这个模型,我们可能认为这是一个价值赌注。然而,警告一句——这是高度假设的。在投入任何资金之前,可能有更多的粒度来定义这个过程,这只是一个简单的宠物项目。我强烈建议你不要用这个来真钱下注,我也不鼓励任何形式的赌博。这只是开始构建您自己的模型的一个起点。

完整的模拟模型在我的 GitHub 上,所以请随意查看,但最终结果会为两队的每个球员生成球员线。然而,这是太多的代码张贴在媒体上,但这是金州勇士队对多伦多猛龙队的 10,000 次模拟(耗时不到 40 秒)的输出。

全点线仿真模型的输出

这个模型没有在之前的任何游戏上测试过,我目前正在寻找不同的方法来测试它的准确性。

一些未来的改进:

  • 对旧数据进行加权,使其在模型中变得不那么相关。2013 年发生的事情应该没有 2017 年发生的事情影响大
  • 包括关于每个玩家统计的更进一步的、更精细的统计。这个模型没有考虑到,例如,斯蒂芬·库里主要是三分球,也没有考虑到托尔斯对罚球的防守能力。
  • 因为游戏模拟仅限于得分,所以没有考虑盖帽、助攻、篮板及其对得分的贡献的输入。包括这一点将产生一个更加现实和适用的模型。
  • 它不考虑诸如受伤或比赛类型等信息。鉴于模拟比赛是一场 NBA 决赛,我们可能应该加入一些额外的假设,如与以前的比赛相比,与顶级球员比赛的时间更长,进攻和防守的强度更大。

如果任何人有任何意见,请联系,这是我的一个活跃的宠物项目,所以我将非常感谢听到来自更有经验的数据科学家或对篮球感兴趣的人的任何评论!

这篇文章写得很有启发性,我正在积极地考虑将类似的模型应用到封锁期间正在进行的其他运动中。我目前正在寻找所有运动的数据。我也在寻找立即开始的工作,所以如果你出于这样或那样的原因想要联系,请通过评论、我的 Linkedin 或我在 carterbouley@gmail.com 的电子邮件联系。

克里斯蒂安·门多萨在 Unsplash 上拍摄的照片

根据医学综述预测患者的医疗状况—第 1 部分

原文:https://towardsdatascience.com/predict-patients-medical-condition-based-on-medicine-review-part-1-c22ea39d9976?source=collection_archive---------26-----------------------

分析不同患者在不同药物评论网站上对特定药物所做的评论,以预测该药物的使用状况。

詹姆斯·亚雷马在 Unsplash 上的照片

互联网曾经是一个张贴漂亮网站以推广业务的地方,现在已经发展成为一个论坛,消费者可以根据印象和其他志同道合的消费者的反馈来评估不同的产品和服务。最近,在线评论在营销和交流中创造了一个新的领域,弥合了传统口碑和可以影响消费者意见的病毒式反馈之间的差距。然而,在医学领域,对特定药物的审查发挥着更重要的作用,因为它们可以帮助监测药物的不良反应,并确定使用者对药物的总体印象。

由于许多药物治疗多种疾病,当在大多数患者论坛上审查一种药物时,必须提供该药物用于的医学疾病。

医学状况是一个宽泛的术语,包括所有通常接受医学治疗的疾病、病变、失调或非病理状况,如怀孕或分娩。

在这一系列文章中,我们将分析不同患者在不同药物评论网站上对特定药物的评论,并预测医疗状况,药物正在用于治疗。

挑战

从评论中预测医疗状况是一项非常具有挑战性的任务。例如,考虑下面的评论:

这药对我有奇效。我肯定会推荐它

这种药物曾被用于治疗痤疮。但是,仅根据审查,很难确定患者是在谈论治疗痤疮,因为帖子中没有提及。由于大多数患者论坛要求在审查表中的单独字段中提供医疗条件的名称,因此患者通常不会在他们的审查中提到它。

方法

为了解决这个问题,在本部分中,我们将分析评论,并使用统计机器学习分类器进行预测。我们将使用来自 Kaggle 的 UCI ML 药物评论数据集。该数据集提供了患者对特定药物以及相关条件的评论,以及反映患者总体满意度的 10 星患者评级系统。这些数据是通过抓取在线药物评论网站获得的。该数据集由针对 700 多种不同医疗状况的 20 多万篇医学综述组成,数据分为训练(75%)和测试(25%)两部分。

分析数据集

首先,我们将首先导入分析和预测所需的所有模块。

然后,我们将下载数据,从中删除空值,然后查看训练和测试数据帧。我已经从前面提到的链接下载了数据集,并将其加载到 pandas dataframes 中。

我们看到数据集中有 7 列:

  1. uniqueID:每个帖子的标识符。
  2. drugName:被审评药品的名称。
  3. condition:使用该药物的医学病症的名称。
  4. review:患者对某一种药物的评价。
  5. rating:患者对每种药物的评分,10 分代表最大疗效。
  6. date:审核录入日期。
  7. usefulCount:认为评论有用的用户数量。

由于我们对预测医疗状况感兴趣,condition将是我们的目标变量。让我们首先分析condition变量的类分布。

我们将定义以下函数:

plot_bar_chart首先从condition列中提取每个类的评论数量,并使用**提供的函数绘制它们。* number_of_classes仅打印数据帧的condition 列中唯一类的数量。*

数据集中有 708 个类(见上面的快照),评论高度偏向于节育的类,这表明数据集高度不平衡。经过仔细观察,还发现有些类别(以红色突出显示)并不完全是医疗状况,而是在创建数据集期间添加的一些噪声。所有这些噪音都必须消除。

标签(类)预处理

标签的预处理包括三个步骤。我们将在训练数据帧上执行所有的预处理,然后在测试数据帧上应用它。

步骤 1:移除低频类别

我们已经观察到数据集是高度不平衡的。我们将开始预处理,首先删除样本少于 20 个的类,然后再次检查训练集中的类的数量。

我们观察到数量从 708 个显著减少到 214 个(上面的快照)。

步骤 2:对超过 200 个样本的类进行欠采样

为了解决类别不平衡问题,我们将对超过 200 个样本的类别进行欠采样。我们通过遍历每个类,从训练数据帧中提取所有样本,对其进行洗牌,然后将数组分割为 200 个元素来实现这一点。

步骤 3:从数据集中移除噪声类

正如我们在上一节中看到的,数据集由仅仅是噪声的类组成。这些类的典型格式是数字后跟一些文本,例如,数据集中的一个有噪声的类是“ 41 个用户找到了”。我们知道医疗条件不涉及数字,因此我们可以轻松地在数据集中查找字母数字类,并可以直接删除它们以消除噪声。

我们通过编写一个名为filter_labels的方法来实现这一点,该方法遍历所有标签,检查标签是否是字母数字的,并基于检查返回一个真值。然后,我们将它应用于训练数据帧,并检查类的数量。

我们现在在训练集中只剩下 210 个类(上面的快照),我们需要在这些类上训练我们的分类器。现在让我们来看看班级的分布情况:

分配看起来比以前好得多。仍然有很高的类别不平衡,但是超过这个范围的欠采样将导致信息的丢失。

对测试数据集标签应用预处理

正如我们所看到的,测试集中有 664 个类。测试数据集需要与训练数据中的类完全相同。由于我们的测试数据已经被标记,我们只保留那些出现在预处理过的训练集中的类,而丢弃其余的。

测试数据现在也包含 210 个类,与训练集完全相同。

预处理评论

到目前为止,我们只通过平衡数据集和移除低频类来处理标签。为了使评论准备好输入任何机器学习模型,我们必须对它们进行预处理,以便删除不必要的信息。我们将移除停用词,然后对语料库中的单词执行词干化

删除停用词和词干

我们定义了一个名为filter_data的函数,它接受小写评论,遍历句子中的每个单词,然后首先删除标点符号和停用词,然后对单词进行词干提取。

小写目标类

我们将目标类别标签小写,以便它们可以直接用于训练我们的机器学习分类器。

创建机器学习模型

为了获得最佳的机器学习模型,我们将对训练数据集执行 4 重交叉验证,然后使用最佳执行模型对测试数据集进行预测。我们将使用以下机器学习分类器,然后根据其性能选择最佳模型:

  1. 多项式朴素贝叶斯
  2. 随机梯度下降分类器
  3. 随机森林分类器
  4. k 近邻分类器

我们混洗训练数据集,并将数据集的相关列保存在变量 XY 中。

在将文本数据输入任何机器学习分类器之前,需要进行特殊的准备。必须对文本进行解析以删除单词,这称为标记化。然后,需要将单词编码为整数或浮点值,以用作机器学习算法的输入,称为特征提取(或矢量化)。

我们将使用 sklearn 的 CountVectorizer 包将我们的评论转换成向量。 CountVectorizer 提供了一种简单的方法,既可以标记一组文本文档,构建已知单词的词汇表,也可以使用该词汇表对新文档进行编码。

接下来,我们定义一个方法cross_val_multiple_classifiers,该方法接收数据和标签,对上述所有分类器执行 4 重交叉验证,并显示每个分类器所有重的精确度和标准偏差的平均值,并对矢量化的训练数据调用该方法。

我们看到随机森林分类器工作得最好,平均准确度分数大约为 54% 。让我们使用这个模型在完整的训练数据集上训练它,并在测试集上获得预测。

尽管该分类器的交叉验证分数仅为 54%,但该分类器在测试数据集上的总体准确度为 70%,F1 分数良好。这可能是因为测试集中的偏差。然而,由于交叉验证的准确度分数很低,我们仍然需要找到一个更好的策略来训练分类器,以提高整体性能。

结论

在系列的这一部分中,我们试图解决一个具有挑战性的问题,即使用消费者对药物的评论来预测医疗状况,这些评论使用统计机器学习分类器,并使用计数矢量器将文本转换为输入特征。尽管我们解决了数据集中的高级别不平衡,但结果仍然不够令人印象深刻,表现最好的分类器仅提供了 54% 交叉验证的准确度分数。

在下一部分中,我们将尝试通过采用不同的方法来解决问题,从而提高模型的性能。

笔记本的完整代码可以从这里获得——https://github . com/hamiz-Ahmed/Machine-Learning-Notebooks/blob/master/classified _ Medical _ Condition _ using _ Statistical _ Models _ Part _ 1 . ipynb

参考

UCI ML 评论数据集—https://www . ka ggle . com/Jessica Li 9530/kuc-hackathon-winter-2018

sci kit-learn—https://scikit-learn.org/stable/

如何用 scikit-learn 对机器学习的文本数据进行编码—https://machinelementmastery . com/prepare-Text-Data-Machine-Learning-scikit-learn/

用 Python 预测带时间戳的销售额

原文:https://towardsdatascience.com/predict-time-stamped-sales-in-python-1914292461ad?source=collection_archive---------26-----------------------

实践教程

马库斯·斯皮斯克Unsplash 上拍摄的照片

目标:使用 Python 中的自回归模型(ARIMA)预测即将到来的月销售额。

详情:各行各业的大多数业务部门都非常依赖时间序列数据来分析和预测,比如线索/销售/股票/网络流量/收入等。不时地产生一些战略性的商业影响。有趣的是,当我们有连续相关的数据点时,时间序列模型是洞察力的金矿。让我们来看看来自 Kaggle 的这样一个带时间戳的销售数据集,以理解在 Python 中使用自回归(ARIMA)模型进行时间序列预测所涉及的关键步骤。

在这里,我们将 ARIMA 模型应用于一个交易销售数据集,以预测一个具有入站和出站差异的组织的月销售额。在现实世界中,我们需要一个时间戳预测建模的五阶段计划,即数据预处理、数据评估、模型选择、模型评估,以及最后但并非最不重要的对未来的预测。让我们在下面详细了解这些步骤中的每一步:

第一阶段:数据预处理

第一步。导入库:导入时间序列预测的所有相关库:

#Data Preprocessing:import pandas as pd
import numpy as np
import os as os
import matplotlib.pyplot as plt
%matplotlib inline    
from matplotlib import dates
import warnings
warnings.simplefilter("ignore")
import easygui as es#Data Evaluation:from statsmodels.tsa.filters.hp_filter import hpfilter
from statsmodels.tsa.seasonal import seasonal_decompose
import statsmodels.api as sm
from statsmodels.tsa.stattools import acovf,acf,pacf,pacf_yw,pacf_ols
from pandas.plotting import lag_plot
from statsmodels.graphics.tsaplots import plot_acf,plot_pacf
from statsmodels.tsa.statespace.tools import diff
from statsmodels.tsa.stattools import ccovf,ccf,periodogram
from statsmodels.tsa.stattools import adfuller,kpss,coint,bds,q_stat,grangercausalitytests,levinson_durbin
from statsmodels.graphics.tsaplots import month_plot,quarter_plot
import matplotlib.ticker as ticker#Model Selection:

from statsmodels.tsa.holtwinters import SimpleExpSmoothing
from statsmodels.tsa.holtwinters import ExponentialSmoothing
from statsmodels.tsa.ar_model import AR,ARResults
from pmdarima import auto_arima
from statsmodels.tsa.stattools import arma_order_select_ic
from statsmodels.tsa.arima_model import ARMA,ARMAResults,ARIMA,ARIMAResults
from statsmodels.tsa.statespace.sarimax import SARIMAX
from statsmodels.tsa.api import VAR
from statsmodels.tsa.statespace.varmax import VARMAX, VARMAXResults#Model Evaluation & Forecasting:from statsmodels.tools.eval_measures import mse, rmse, meanabs
from sklearn.metrics import mean_squared_error

第二步。加载输入数据集:

这是相对较短的一步。因为我们在这里所做的只是使用 pandas 加载数据集。因为它是平面文件,所以我们使用 read_excel 方法加载数据集。

#Configure the current working directory:os.chdir(r"C:\Users\srees\Desktop\Blog Projects\1\. Timeseries Forecasting\2\. ARIMA\Input")input_dataframe = pd.read_excel("online_retail.xlsx",parse_dates = True)

第三步。检查输入数据集:

让我们使用 info、description 和 head 方法对数据集的结构进行一些初步评估。

input_dataframe.info()

数据集 1 的结构(图片由作者提供)

input_dataframe.describe()

数据集 2 的结构(图片由作者提供)

input_dataframe.head(10)

数据集的前 10 条记录(图片由作者提供)

步骤四。数据角力:

在 pandas 中使用 dropna()方法,确保数据集中没有任何带有空白或空值的记录中断。此外,将 date 对象(本例中的“月”字段)转换为 datetime。

#Converting date object to datetime :

input_dataframe["Month"]  =  pd.to_datetime(input_dataframe["Month"], format='%Y-%m-%d')#Dropping NA's:input_dataframe = input_dataframe.dropna()

将日期时间字段设置为索引字段:

input_dataframe = input_dataframe.set_index("Month")

第五步。重采样:

重采样基本上涉及修改时间序列数据点的频率。我们将根据数据集的性质对时间序列观测值进行上采样或下采样。我们不必对这个时间序列数据集进行重新采样,因为它已经汇总到月初。请查看 Pandas 以了解有关偏移别名和重采样的更多信息:https://Pandas . pydata . org/Pandas-docs/stable/user _ guide/time series . html # offset-aliases

#Set the datetime index frequency:

input_dataframe.index.freq = 'MS'

第六步。绘制源数据:

#Plot the Graph:ax =  input_dataframe['Sales'].plot.line(
title = 'Monthly Sales Timeseries Analysis'
, legend =True, table = False, grid = False
, subplots = False,  figsize =(15,8), colormap = 'Accent'
, fontsize = 15,linestyle='-', stacked=False)#Configure x and y labels:plt.ylabel('Volume of sales',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('Year & Quarter',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")#Set up title, legends and theme:plt.title('Monthly Sales Timeseries Analysis \n',horizontalalignment="center", 
fontstyle = "normal", fontsize = "22"
, fontfamily = "sans-serif")plt.legend(loc='upper left', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

月度销售时间序列分析(图片由作者提供)

第 7 步:滚动和扩展时间序列数据集:

滚动均线帮助我们识别支撑和阻力区域;数据集中历史时间序列观测值的“高于平均倾斜度”和“低于平均倾斜度”的区域。

计算移动平均线的主要优点是,它可以过滤掉随机销售活动中的噪音,消除波动,以查看一段时间内的平均趋势。

第 7.1 步。简单移动平均线趋势分析:

简单移动平均是对时间序列数据集进行趋势分析的最基本模型之一。滚动移动平均趋势分析背后的整个思想是将数据分成时间的“窗口”,然后为每个窗口计算一个聚合函数。

input_dataframe["3-Months-Moving-Avg"] = input_dataframe ["Sales"].rolling(window=3).mean()#Plot the Graph:ax =  input_dataframe[['Sales', '3-Months-Moving-Avg']].plot.line(
title = '3 Months Moving Average Trend Analysis'
, legend =True, table = False, grid = False,  
subplots = False,  figsize =(15,8), colormap = 'Accent', 
fontsize = 15,linestyle='-', stacked=False)#Configure x and y labels:plt.ylabel('Volume of sales',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('Year & Quarter',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")#Set up title, legends and theme:plt.title('Monthly Sales: 3 Months Moving Average Trend Analysis \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='upper left', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

从滚动的 3 个月移动平均趋势线中,我们可以清楚地看到,零售商店的销售额在每个季度的中期都呈上升趋势,而在同一季度的末期则出现了一系列阻力。因此,我们可以清楚地推断,零售商店的波段支持发生在日历年的每个季度的阻力波之前。

月销售额:3 个月移动平均趋势分析(图片由作者提供)

步骤 7.2。时间序列分析的标准差:

标准差图本质上帮助我们了解销售活动在一段时间内是增加还是减少;给出时间序列数据集中平稳性的早期指示。

input_dataframe ['3-Months-Moving-Avg'] = input_dataframe['Sales'].rolling(window=3).mean()
input_dataframe['3-Months-Standard-Deviation'] = input_dataframe['Sales'].rolling(window=3).std()#Plot the Graph:ax =  input_dataframe [['Sales', '3-Months-Moving-Avg', '3-Months-Standard-Deviation']].plot.line(title = 'Standard Deviation of Timeseries Datapoints', legend =True, table = False, grid = False,  subplots = False,  figsize =(15,8), colormap = 'Accent', fontsize = 15,linestyle='-', stacked=False)#Configure x and y labels:plt.ylabel('Volume of sales',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('Year & Quarter',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")#Set up title, legends and theme:plt.title('Monthly Sales: Standard Deviation of Timeseries Datapoints \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='upper left', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

所选时间序列数据集的标准偏差似乎随着时间的推移略有增加;暗示非平稳性。我们将在随后的步骤中达到平稳性。

月销售额:时间序列数据点的标准偏差(图片由作者提供)

步骤 7.3。扩展时间序列数据集:

时间序列分析中的扩展过程有助于我们识别销售活动的“稳定性”或“波动性”。因此,当我们在时间序列数据集上应用扩展技术时,我们将能够基本上看到数据集中每个历史时间序列观察值的累积平均值。

#Plot the Graph:ax =  input_dataframe['Sales'].expanding().mean().plot.line(
title = 'Expandind Timeseries Datapoints', legend =True, 
table = False, grid = False,  subplots = False,  figsize =(15,8), colormap = 'Accent', fontsize = 15,linestyle='-', stacked=False)#Configure x and y labels:plt.ylabel('Cumulative Volume of sales',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('Year & Quarter',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")#Set up title, legends and theme:plt.title('Monthly Sales: Expanded Timeseries Datapoints \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='upper left', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

知道历史时间戳上平均值的位置是非常好的;尤其是在时序建模的后续模型评估阶段。因为扩展技术最终有助于我们将均方根误差与销售额的累积平均值进行比较,以了解差异的大小。

月销售额:扩展的时间序列数据点(图片由作者提供)

第二阶段:数据评估

第八步。评估误差、趋势和季节性:

选择预测模型的一个有用的抽象是将时间序列分解成系统的和非系统的部分。系统的:时间序列的组成部分,具有一致性或重现性,可以描述和建模。非系统性:时间序列中无法直接建模的部分。

第 8.1 步。霍德里克-普雷斯科特滤波器:

Hodrick-Prescott 滤波器将时间序列数据集分解为趋势和周期分量。

#cyclicity:sales_cycle, sales_trend = hpfilter(
input_dataframe["Sales"], lamb = 1600)input_dataframe["cycle"] = sales_cycle#Plot the Graph:ax =  input_dataframe[["cycle", "Sales"]].plot.line(
title = 'Hodrick-Prescott Filter - Cyclicity'
, legend =True, table = False, grid = False
,  subplots = False,  figsize =(15,8), colormap = 'Accent'
, fontsize = 15,linestyle='-', stacked=False)#Configure x and y labels:plt.ylabel('Volume of sales',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('Year & Quarter',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")#Set up title, legends and theme:plt.title(' Monthly Sales: Hodrick-Prescott Filter - Cyclicity Analysis \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='upper left', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

当数据表现出非固定周期的上升和下降时,存在循环模式。此外,如果循环性值接近零,则表明数据是“随机的”。结果与零相差越多,就越有可能存在某种周期性。正如我们在这里看到的,在选择的数据集中存在循环性。

月销售额:Hodrick Prescott 过滤器——周期性分析(图片由作者提供)

#Trendlineinput_dataframe ["trend"] = sales_trend#Plot the Graph:ax =  input_dataframe[["trend", "Sales"]].plot.line(
title = 'Hodrick-Prescott Filter - Trendline', 
legend =True, table = False, grid = False,  subplots = False,  figsize =(15,8), colormap = 'Accent', fontsize = 15,
linestyle='-', stacked=False)#Configure x and y labels:plt.ylabel('Volume of sales',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('Year & Quarter',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")#Set up title, legends and theme:plt.title('Monthly Sales: Hodrick-Prescott Filter - Trendline Analysis \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='upper left', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

数据点的观察值的趋势线显示了在一段时间内以非线性速率的总体增长模式。

月销售额:霍德里克-普雷斯科特过滤器-趋势线分析(图片由作者提供)

第 8.2 步。误差、趋势和季节性(ETS)分解:

一个给定的时间序列由三个系统成分组成,包括水平、趋势、季节性和一个称为噪声/误差/残差的非系统成分。本节对时间序列的分解试图分离出时间序列中的这些单独的系统和非系统组成部分;抛出一个包含四个前述情节的图表。

乘法模型在这里更为合适,因为销售额似乎正以非线性的速度增长。另一方面,当季节性和趋势成分在一段时间内保持不变时,我们对时间序列应用“加法”模型。

result = seasonal_decompose(input_dataframe["Sales"]
, model = "multiplicative")fig, axes = plt.subplots(4, 1, sharex=True)result.observed.plot(ax=axes[0], legend=False, colormap = 'Accent')
axes[0].set_ylabel('Observed')result.trend.plot(ax=axes[1], legend=False, colormap = 'Accent')
axes[1].set_ylabel('Trend')result.seasonal.plot(ax=axes[2], legend=False, colormap = 'Accent')
axes[2].set_ylabel('Seasonal')result.resid.plot(ax=axes[3], legend=False, colormap = 'Accent')
axes[3].set_ylabel('Residual')plt.title(""" Monthly Sales: ETS Decomposition Plots \n""",horizontalalignment="center", fontstyle = "normal", fontsize = "15", fontfamily = "sans-serif")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

此处观察值的趋势线表明,随着时间的推移,总体增长模式呈非线性(类似于我们在 Hodrick-Prescott 过滤过程中注意到的情况)。此外,在固定的时间间隔内,数据集的时间戳似乎存在显著的季节性变化(范围远远超过零);暗示季节性。

月销售额:ETS 分解图(图片由作者提供)

步骤 8.3。用于季节性检查的自相关(ACF)图:

自相关是一种序列相关性,其中时间序列与其自身的滞后版本线性相关。滞后意味着“倒退”,就这么简单。因此,“自身的滞后版本”基本上意味着数据点被后移一定数量的周期/滞后。

因此,如果我们在时间序列数据集上运行自相关函数,我们基本上是在将其后移至一定数量的周期/滞后后绘制同一组数据点。

平均来说,在最初的几个(20-40)滞后期内绘制自相关的大小可以说明一个时间序列的很多情况。通过这样做,我们将能够很容易地发现和验证时间序列数据中的季节性成分。

fig = plt.figure(figsize=(15,8))
ax = fig.add_subplot(111)acf(input_dataframe["Sales"])
lags = 40plot_acf(input_dataframe["Sales"], 
lags = lags, color = 'g', ax = ax);
plt.figure(figsize=(15,8)) 
plt.title(' Monthly Sales: Autocorrelation Plots \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.ylabel('y(t+1)',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('y(t)',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

通过绘制滞后 ACF,我们首先可以确认季节性确实存在于这个时间序列数据集中。因为滞后 ACF 图展示了数据中可预测的季节性模式。我们能够清楚地看到,在第二大正峰值爆发之前,由固定数量的时间戳组成的季节性起伏模式。每个数据点似乎都与未来的另一个数据点密切相关;表明数据集中有很强的季节性。

月销售额:自相关图(图片由作者提供)

第九步。平稳性检查

如果时间序列数据不显示趋势或季节性,则称其为平稳的。也就是;它的均值、方差和协方差在序列的任何部分都保持不变,并且不是时间的函数。

显示季节性的时间序列肯定不是平稳的。因此,所选择的时间序列数据集是非平稳的。让我们使用自动迪基-富勒& KPSS 测试,并进一步通过绘制数据集的滞后自相关和偏相关函数,再次确认时间序列数据集的非平稳性,如下所示:

步骤 9.1。平稳性的增强 Dickey-Fuller 检验:

平稳性的增强 Dickey-Fuller 检验通常涉及单位根假设检验,其中零假设 H0 表明序列是非平稳的。替代假设 H1 支持具有小 p 值(p <0.05 ) indicating strong evidence against the null hypothesis.

print('Augmented Dickey-Fuller Test on Sales Data')input_dataframe_test = adfuller(input_dataframe["Sales"], autolag = 'AIC')input_dataframe_test

Augmented Dickey-Fuller Test for Stationarity 1 (Image by Author)

#For loop to assign dimensions to the metrices:

print('Augmented Dickey-Fuller Test on Sales Data')input_dataframe_out = pd.Series(input_dataframe_test[0:4], 
                                index = ['ADF test statistic', 'p-value', '#lags used', '#observations'])for key, val in input_dataframe_test[4].items():input_dataframe_out[f'critical value ({key})'] = val

print(input_dataframe_out)

Augmented Dickey-Fuller Test for Stationarity 2 (Image by Author)

Here we have a very high p-value at 0.99 ( p> 0.05)的平稳性,这提供了反对零假设的弱证据,因此我们无法拒绝零假设。因此,我们决定我们的数据集是非平稳的。

以下是使用 ADF 测试自动检查平稳性的自定义函数:

#Custom function to check stationarity using ADF test:

def adf_test(series,title=''):print(f'Augmented Dickey-Fuller Test: {title}')
    result = adfuller(series.dropna(),autolag='AIC') # .dropna() handles differenced data

    labels = ['ADF test statistic','p-value','# lags used','# observations'] out = pd.Series(result[0:4],index=labels)for key,val in result[4].items():
        out[f'critical value ({key})']=val
         print(out.to_string())          
    # .to_string() removes the line "dtype: float64"

    if result[1] <= 0.05:
        print("Strong evidence against the null hypothesis")
        print("Reject the null hypothesis")
        print("Data has no unit root and is stationary")
    else:
        print("Weak evidence against the null hypothesis")
        print("Fail to reject the null hypothesis")
        print("Data has a unit root and is non-stationary")

调用定制的增强 Dickey-Fuller 函数来检查平稳性:

adf_test(input_dataframe["Sales"], title = "Automated ADF Test for Stationarity")

平稳性 3 的增强 Dickey-Fuller 测试(图片由作者提供)

第 9.2 步。平稳性的 KPSS(科维亚特科夫斯基-菲利普斯-施密特-申)检验:

在解释零假设和交替假设时,KPSS(科维亚特科夫斯基-菲利普斯-施密特-申)检验结果与 ADF 检验结果正好相反。也就是;平稳性的 KPSS 检验通常涉及单位根假设检验,其中零假设 H0 表示序列是平稳的,具有较大的 p 值(p>0.05),而替代假设 H1 支持非平稳性,表明零假设的证据较弱。

def kpss_test(timeseries):

    print ('Results of KPSS Test:')
    kpsstest = kpss(timeseries, regression='c')
    kpss_output = pd.Series(kpsstest[0:3], index=
    ['Test Statistic','p-value','Lags Used']) for key,value in kpsstest[3].items():
        kpss_output['Critical Value (%s)'%key] = value
        print (kpss_output)

调用自定义 KPSS 函数来检查平稳性:

kpss_test(input_dataframe["Sales"])

这里我们有一个非常低的 p 值,为 0.01 ( p <0.05 ), which provides weak evidence against the null hypothesis, indicating that our time-series is non-stationary.

KPSS Test for Stationarity (Image by Author)

Step 9.3)。使用滞后&自相关图重新验证非平稳性:

步骤 9.3.1。滞后图:

当我们在非平稳数据集上绘制 y(t)对 y(t+1)时,我们将能够发现强自相关;也就是说,随着 y(t)值的增加,附近的滞后值也会增加。

fig = plt.figure(figsize=(15,8))
ax = fig.add_subplot(111)lag_plot(input_dataframe["Sales"], c= 'g', ax = ax);plt.title('Monthly Sales: Lag Plots \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

我们可以在这里的滞后图中找到 y(t)和 y(t+1)之间的强自相关,重申时间序列数据集的非平稳性。

月销售额:滞后图(作者图片)

步骤 9.3.2。自相关(ACF)图:

如前所述,我们可以清楚地看到一个没有明显截止或指数衰减迹象的季节性因素。

fig = plt.figure(figsize=(15,8))
ax = fig.add_subplot(111)acf(input_dataframe["Sales"])
lags = 40
plot_acf(input_dataframe["Sales"], lags = lags, c = 'g', ax = ax);plt.title('Monthly Sales: Autocorrelation Plots \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.ylabel('y(t+1)',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('y(t)',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

在第二大正峰值爆发之前,时间序列数据集显然具有由固定数量的时间戳组成的起伏的季节性模式。此外,ACF 图不会很快衰减,仍然远远超出显著性范围;证实时间序列数据集的非平稳性。

月销售额:自相关图(图片由作者提供)

步骤 9.3.3。部分自相关(PACF)图:

部分自相关(PACF)图只能在静态数据集上生成。由于所选的时间序列数据集显示非平稳性,我们在生成部分自相关(PACF)图之前应用了一阶差分。

input_dataframe["first_order_differentiation"] = diff(input_dataframe["Sales"], k_diff = 1)#Plot the Graph:ax =  input_dataframe["first_order_differentiation"].plot.line(title = 'Monthly Sales Timeseries Data : 1st order Differentiation'
, legend =True, table = False, grid = False , subplots = False,  figsize =(15,8), colormap = 'Accent', fontsize = 15,linestyle='-', stacked=False)#Configure x and y labels:plt.ylabel('Volume of sales',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('Year & Quarter',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")#Set up title, legends and theme:plt.title(' Monthly Sales: 1st order Differentiation Analysis \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='upper left', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

月销售额:一阶差异分析(图片由作者提供)

input_dataframe["first_order_differentiation"] = diff(input_dataframe["Sales"], k_diff = 1)fig = plt.figure(figsize=(15,8))
ax = fig.add_subplot(111)
lags = 40
plot_pacf(input_dataframe["first_order_differentiation"].dropna(), lags = np.arange(lags), c='g', ax = ax);plt.title('Monthly Sales: Partial Autocorrelation Plots \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.ylabel('y(t+1)',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('y(t)',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

具有一阶差分的数据点的 PACF 图显示了锐截止点或指数衰减,表明一阶积分的稳定性。此外,PACF 图衰减相当快,并基本保持在显著性范围内(蓝色阴影区域),加强了所选时间序列数据集默认为非平稳的假设。

月销售额:部分自相关图

第三阶段:型号选择

第十步。将数据集分为训练集和测试集

len(input_dataframe)training_dataframe = input_dataframe.iloc[:len(input_dataframe)-23, :1]testing_dataframe = input_dataframe.iloc[len(input_dataframe)-23:, :1]

步骤 11.1。确定 ARIMA 订单:

由于数据集是季节性的和不稳定的,我们需要拟合一个 SARIMA 模型。SARIMA 是首字母缩略词,代表季节性自回归综合移动平均线;一类统计模型,用于分析和预测具有季节性和非平稳性的时间序列数据。它只不过是对 ARIMA 的扩展,支持对该系列的季节性成分进行直接建模。

ARIMA 的标准符号是(p,d,q ),其中参数用整数值代替,以快速指示所使用的特定 ARIMA 模型。ARIMA 模型的参数是:

p:模型中包含的滞后观测值的数量,也称为滞后阶数。d:原始观测值的差异次数,也称为差异程度。
问:移动平均线窗口的大小,也叫移动平均线的顺序。

这些组件中的每一个都在模型中被明确指定为参数。在 SARIMA 中,它进一步添加了三个新的超参数,以指定序列的季节性成分的自回归(AR)、差分(I)和移动平均(MA),以及季节性周期的附加参数。

因此在这一节中,我们本质上是试图确定 P、D、Q 和 P、D、Q 和 m 的顺序(即;自动回归、积分和移动平均分量以及季节回归、差分和移动平均系数的顺序)应用于时间序列数据集以拟合 SARIMA 模型。

步骤 11.1.1。使用 pmdarima.auto_arima 的 ARIMA 订单:

auto_arima(input_dataframe["Sales"], seasonal = True, m=12, error_action = "ignore").summary()

auto_arima 建议我们应该拟合以下 SARIMA 模型(3,1,5)(2,1,1,12),以最佳预测所选时间序列数据集的未来值。让我们在下一步尝试通过逐步 AIC 准则法重新验证订单。

ARIMA 订单使用 pmdarima.auto_arima(图片由作者提供)

逐步 11.1.2。使用逐步 auto_arima 重新验证 ARIMA 订单:

stepwise_fit = auto_arima(input_dataframe["Sales"], start_p = 0
                          , start_q = 0,max_p =3, max_q = 5
                          , m=12, seasonal = True, d=None, 
                          trace = True, 
                          error_action ='ignore'
                          , suppress_warnings = True,
                          stepwise = True)

逐步 auto_arima 为我们提供了列表中所有可能的“Akaike 信息标准”或 AIC 分数的细分。逐步拟合得到了相同的结果;突出显示在所选时间序列数据集上拟合 SARIMA 模型时要使用的自回归、积分和移动平均系数的正确顺序。

使用逐步 auto_arima 重新验证 ARIMA 订单(图片由作者提供)

步骤 11.2。拟合萨里玛模型:

在训练数据集上拟合 SARIMA 模型,如下所示:

fitted_SARIMA_model = SARIMAX(training_dataframe["Sales"], order =(3,1,5), seasonal_order = (2,1,1,12))results = fitted_SARIMA_model.fit()results.summary()

拟合萨里玛模型(图片由作者提供)

第四阶段:模型评估

步骤 12.1。评估萨里玛模型:

start = len(training_dataframe)end = len(training_dataframe) + len(testing_dataframe) -1
test_SARIMA_predictions = results.predict(start = start, end = end).rename('SARIMA Predictions')#Root Mean Squared Errornp.sqrt(mean_squared_error(testing_dataframe, test_SARIMA_predictions))

步骤 12.2。构建差异—预测的入站和出站值:

test_SARIMA_predictions = pd.DataFrame(test_SARIMA_predictions)test_SARIMA_predictions["inbound_variance"] = (test_SARIMA_predictions["SARIMA Predictions"]-562.176565188264).round(decimals =0)test_SARIMA_predictions["outbound_variance"]= (test_SARIMA_predictions["SARIMA Predictions"]+562.176565188264).round(decimals = 0)test_SARIMA_predictions = test_SARIMA_predictions.join(testing_dataframe)test_SARIMA_predictions

步骤 12.3。将预测值与测试集的预期值进行比较:

test_SARIMA_predictions = test_SARIMA_predictions.reset_index()print(test_SARIMA_predictions.columns)type(test_SARIMA_predictions["index"])test_SARIMA_predictions["Month"] = test_SARIMA_predictions["index"].rename("Month")test_SARIMA_predictions["Month"] = test_SARIMA_predictions["Month"] .dt.strftime('%Y-%m-%d')test_SARIMA_predictions.set_index("Month", inplace=True)test_SARIMA_predictions[["Sales", "SARIMA-Predicted Sales",'Predicted Inbound Variance',
       'Predicted Outbound Variance']] = test_SARIMA_predictions[["Sales", "SARIMA-Predicted Sales",'Predicted Inbound Variance',
       'Predicted Outbound Variance']] .astype(int)#Plot the Graph:ax = test_SARIMA_predictions[["Sales", "SARIMA-Predicted Sales","Predicted Inbound Variance","Predicted Outbound Variance"]].plot.line(
                             title = 'Monthly Sales: Evaluating SARIMA Model', legend =True, table = False, grid = False
                            ,  subplots = False,  figsize =(15,8)
                            , colormap = 'Accent', fontsize = 15
                            ,linestyle='-', stacked=False)x=  pd.Series (range (0, len(test_SARIMA_predictions)  , 1))for i in x:
  ax.annotate(test_SARIMA_predictions["SARIMA-Predicted Sales"][i],
      xy=(i,test_SARIMA_predictions["SARIMA-Predicted Sales"][i]), 
      xycoords='data',
      xytext=(i,test_SARIMA_predictions["SARIMA-Predicted Sales"][i]+5 ), textcoords='data',arrowprops=dict(arrowstyle="->", connectionstyle="angle3",facecolor='black'),horizontalalignment='left',verticalalignment='top')#Configure x and y labels:plt.ylabel('Volume of sales',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('Year & Month',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")#Set up title, legends and theme:plt.title('Monthly Sales: Evaluating SARIMA Model \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='upper left', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

月销售额:评估 SARIMA 模型(图片由作者提供)

第五阶段:对未来的预测

步骤 13.1。在完整数据集上拟合所选预测模型:

final_model = SARIMAX(input_dataframe["Sales"], order = (3,1,5), seasonal_order = (2,1,1,12))SARIMAfit = final_model.fit()

步骤 13.2。获取整个数据集的预测值:

forecast_SARIMA_predictions = SARIMAfit.predict(start = len(input_dataframe), end = len(input_dataframe)+23, dynamic = False, typ = 'levels').rename ('Forecast')

第 13.3 步。构建差异:入站和出站差异:

forecast_SARIMA_predictions = pd.DataFrame(forecast_SARIMA_predictions)forecast_SARIMA_predictions = forecast_SARIMA_predictions.rename(columns = {'Forecast': "SARIMA Forecast"})forecast_SARIMA_predictions["minimum_sales"] = (forecast_SARIMA_predictions ["SARIMA Forecast"] -546.9704996461452).round(decimals = 0)forecast_SARIMA_predictions["maximum_sales"] = (forecast_SARIMA_predictions ["SARIMA Forecast"] +546.9704996461452).round(decimals = 0)forecast_SARIMA_predictions["SARIMA Forecast"] = forecast_SARIMA_predictions["SARIMA Forecast"].round(decimals = 0)forecast_SARIMA_predictions.to_csv('output.csv')forecast_SARIMA_predictions

预测的 SARIMA 数据集(图片由作者提供)

步骤 13.4。根据已知值绘制预测值:

forecast_SARIMA_predictions1 = forecast_SARIMA_predictionsforecast_SARIMA_predictions1 = forecast_SARIMA_predictions1.reset_index()print(forecast_SARIMA_predictions1.columns)type(forecast_SARIMA_predictions1["index"])forecast_SARIMA_predictions1["Month"] = forecast_SARIMA_predictions1["index"].rename("Month")forecast_SARIMA_predictions1["Month"] = forecast_SARIMA_predictions1["Month"] .dt.strftime('%Y-%m-%d')forecast_SARIMA_predictions1 = forecast_SARIMA_predictions1.drop(['index'], axis=1)forecast_SARIMA_predictions1.set_index("Month", inplace=True)forecast_SARIMA_predictions1[["SARIMA - Forecasted Sales"
,'Minimum Sales','Maximum Sales']] = forecast_SARIMA_predictions[["SARIMA - Forecasted Sales"
,'Minimum Sales','Maximum Sales']] .astype(int)#Plot the Graph:ax = forecast_SARIMA_predictions1[["SARIMA - Forecasted Sales",'Minimum Sales','Maximum Sales']].plot.line(
title = 'Predicting Monthly Sales: SARIMA Model', legend =True, table = False, grid = False,  subplots = False,  figsize =(15,8)
 , colormap = 'Accent', fontsize = 15,linestyle='-', stacked=False)x=  pd.Series (range (0, len(forecast_SARIMA_predictions1)  , 1))for i in x:
              ax.annotate(forecast_SARIMA_predictions1["SARIMA - Forecasted Sales"][i],xy=(i,forecast_SARIMA_predictions1["SARIMA - Forecasted Sales"][i]), xycoords='data',
xytext=(i,forecast_SARIMA_predictions1["SARIMA - Forecasted Sales"][i]+5 ), textcoords='data',#arrowprops=dict(arrowstyle="-",
#facecolor='black'),#horizontalalignment='left',
verticalalignment='top')#Configure x and y labels:plt.ylabel('Volume of sales',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('Year & Month',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")#Set up title, legends and theme:plt.title('Predicting Monthly Sales: SARIMA Model \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='upper left', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

预测月销售额:萨里玛模型

不可预测性和风险是任何预测模型的亲密伴侣。在现实世界中,我们可能无法始终将实际销售额精确到绝对预测值。

事实上,不仅仅是一个绝对值,根据预测的不可预测性程度来获得洞察力在业内被普遍认为是一种良好的做法。因此,让我们结合输入数据集中过去和现在的数据以及预测的入站/出站差异来预测未来几个月的销售情况。

input_dataframe["Sales"].plot.line(title = 'Monthly Sales: Evaluating SARIMA Model', legend =True, table = False, grid = False
,  subplots = False,  figsize =(15,8), colormap = 'Accent', fontsize = 15,linestyle='-', stacked=False)#forecast_SARIMA_predictions["SARIMA Forecast"].plot(legend = True, label = "SARIMA Forecast")forecast_SARIMA_predictions["Minimum Sales"].plot(legend = True, label = "Minimum Predicted Sales")forecast_SARIMA_predictions["Maximum Sales"].plot(legend = True, label = "Maximum Predicted Sales")#Configure x and y labels:plt.ylabel('Volume of sales',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")plt.xlabel('Year & Month',horizontalalignment="center",fontstyle = "normal", fontsize = "large", fontfamily = "sans-serif")#Set up title, legends and theme:plt.title('Monthly Sales: Evaluating SARIMA Model \n',horizontalalignment="center", fontstyle = "normal", fontsize = "22", fontfamily = "sans-serif")plt.legend(loc='upper left', fontsize = "medium")
plt.xticks(rotation=0, horizontalalignment="center")
plt.yticks(rotation=0, horizontalalignment="right")plt.style.use(['classic'])
ax.autoscale(enable=True, axis='x', tight=False)

月销售额:评估 SARIMA 模型(图片由作者提供)

结论

因此,简而言之,我们利用来自 Kaggle 的带时间戳的销售数据集,并使用 Python 中的 Statsmodels 库预测其未来数据点的实际进出差异。此外,在每一个接合点,我们使用 pandas.plot()和 Matplotlib 可视化输出,以获得洞察力。

接下来是什么?

预测未来的数据点只是故事的一半。在现实世界中,当洞察以可理解的方式与内部/外部的利益相关者共享时,项目就展开了,这样他们就能够不时地做出战略性的商业决策。

1)因此,让我们确保将最终输出数据集插入组织的 BI 平台(如 Tableau/ Power BI/ Qlik 等)。)并构建一个数据故事,突出项目的关键发现。在构建数据故事的同时,翻译调查结果的整个过程很大程度上取决于我们对行业和相关业务部门的了解。

2)与组织的内部/外部利益相关者以及仪表板分享见解,以便他们能够相应地制定营销/销售/财务计划。

3)在 python 中应用完全相同的 Statsmodels 库来预测带时间戳的未来线索/价格/网络流量/收入等。

GitHub 库

我已经从 Github 的许多人那里学到了(并且还在继续学到)。因此,在一个公共的 GitHub 库中分享我的整个 python 脚本和支持文件,以防它对任何在线搜索者有益。此外,如果您在理解使用 Python 中的 ARIMA 模型预测带时间戳的数据点的基础知识方面需要任何帮助,请随时联系我。乐于分享我所知道的:)希望这有所帮助!

关于作者

[## Sreejith Sreedharan - Sree

数据爱好者。不多不少!你好!我是 Sreejith Sreedharan,又名 Sree 一个永远好奇的数据驱动的…

srees.org](https://srees.org/about)

使用 R 中的分类方法进行预测

原文:https://towardsdatascience.com/predict-using-classification-methods-in-r-173477062576?source=collection_archive---------30-----------------------

使用乳腺癌威斯康星(诊断)数据集构建机器学习模型

图片由来自 PixabayJavier Rodriguez 拍摄

在这个分析中,我将建立一个模型,根据乳腺癌研究的数据预测肿瘤是恶性还是良性。建模过程中将使用分类算法。

数据集

这项分析的数据涉及一项乳腺癌研究中的 569 名患者。实际数据可以在 UCI(机器学习知识库)找到:https://archive . ics . UCI . edu/ml/datasets/Breast+Cancer+Wisconsin+(Diagnostic)。这些变量是从乳房肿块的数字化图像中计算出来的,并描述了图像中出现的细胞核的特征。具体而言,变量如下:

  1. 半径(中心到圆周上各点的平均距离)
  2. 纹理(灰度值的标准偏差)
  3. 周长
  4. 区域
  5. 平滑度(半径长度的局部变化)
  6. 密实度 (perimeter^ /面积— 1.0)
  7. 凹度(轮廓凹陷部分的严重程度)
  8. 凹点(轮廓的凹部数量)
  9. 对称性
  10. 分维(“海岸线近似”——1)
  11. (肿瘤可以是恶性-M-或良性-B-型)

探索性分析

对数据集有一个总体的了解是很重要的。下面是每个预测值对目标变量(肿瘤)的箱线图。使用预测值的对数值代替实际值,以便更好地查看图形。

作者图片

似乎对于大多数预测者来说,肿瘤类型的恶性水平比良性水平具有更高的值。

现在让我们看看预测因素是否相关。下面是所有预测值的散点图矩阵。

作者图片

我们可以看到,正如所料,有一些预测因子是密切相关的,如半径、周长和面积。

相关图将为我们提供更好的服务,并量化所有的相关性。

作者图片

我们可以发现一些不太重要的相关性,例如凹性&连接性&紧密性。也凹对半径,周长和面积。

使用分类方法进行预测

在该分析的第一部分中,目标是基于使用分类方法由数字化图像产生的变量来预测肿瘤是恶性还是良性。分类是根据包含已知类别成员的观察值(或实例)的训练数据集,识别新观察值属于哪一组类别(子群体)的问题。

因此,我们必须开发一个模型,将每个肿瘤(病例)分为恶性或良性。

用两种不同的方法进行分类,决策树

特征选择

在构建预测模型时,仅使用重要的预测值是很重要的。你不需要使用所有的特性来创建一个算法。你可以通过只输入那些真正重要的特征来帮助算法。以下是一些原因:

  • 它使机器学习算法能够更快地训练。
  • 它降低了模型的复杂性,使其更容易解释。
  • 如果选择了正确的子集,就可以提高模型的准确性。
  • 它减少了过度拟合。

特别是,我对数据使用了逐步(向前和向后)逻辑回归,因为数据集很小。这种方法的计算量非常大,因此不推荐用于非常大的数据集。

审查逐步选择后,决定将以下预测值用于所有模型构建:

  1. 半径(从中心到周边各点的平均距离)
  2. 纹理(灰度值的标准偏差)
  3. 区域
  4. 平滑度(半径长度的局部变化)
  5. 凹点(轮廓凹陷部分的数量)
  6. 对称

逻辑回归

逻辑回归是一种参数统计学习方法,用于分类,尤其是当结果为二进制时。逻辑回归模型的概率,一个新的观察属于一个特定的类别。为了拟合模型,使用了一种称为最大似然法的方法。下面是逻辑回归的一个实现。

作者图片

通过查看逻辑回归模型的汇总输出,我们可以看到几乎所有的系数都是正的,表明更高的测量值意味着恶性肿瘤的更高概率。

这里重要的一步是评估模型的预测能力。因为模型的预测是概率,我们必须决定分割两种可能结果的阈值。首先,我将尝试默认阈值 0.5。下面是使用此阈值的预测的混淆矩阵。

作者图片

模型的整体准确率为 96.47 % (3.53 %的错误率)。但是在这种特殊情况下,我们必须区分不同类型的错误。换句话说,有两种错误率,第一类和第二类错误。在我们的例子中,这些是相似的(第二类误差= 3.74% &第一类误差= 3.17%)。第一类错误是指良性肿瘤被预测为恶性;第二类错误是指恶性肿瘤被预测为良性。第二类误差更昂贵,我们必须找到消除它的方法(即使它增加了第一类误差)。

下面我把阈值提高到 0.8,改变了预测模型。

作者图片

虽然模型的总体精度保持不变,但现在第二类误差消除了,但第一类误差增加了。换句话说,我们现在有了一个模型,可以完美地预测恶性肿瘤,但也错误地将一些良性肿瘤预测为恶性(9.5%)。

决策树

决策树由一系列分割点组成,通常称为节点。为了使用决策树进行预测,我们从树的顶部的一个称为根节点的节点开始。根节点是一个决策点或分割点,因为它根据一个输入要素的值设置了一个条件,并且基于这个决策,我们知道是继续树的左侧部分还是树的右侧部分。我们在遇到的每个内部节点重复选择向左或向右的过程,直到到达一个叶节点。这些是树底部的节点,它们为我们提供了输出的特定值,用作我们的预测。

作者图片

当执行决策树时,从输出可以看出,整体预测率为 94.1% (5.9%的错误率),这对于特定领域来说是相对较低的。特别地,第二类误差为 5.61% &第一类误差= 6.35%。该模型的预测性能比前一个模型(逻辑回归)差。

现在让我们创建一个模型的分类树图。

作者图片

从上面的图中,我们可以假设凹面和纹理是肿瘤类型最重要的预测因子(分类树上的分裂)。

结果

最后,在使用不同的算法构建各种模型之后,基于其性能选择逻辑回归模型(详情见下表)。

作者图片

特别是,尤其是调整阈值后,消除了 II 型错误(将恶性肿瘤错误预测为良性)。这在这个具体问题上真的很重要。

正如预期的参数方法,如逻辑回归,在这种情况下表现更好,我们有一个小数据集(569 个观察值)。

虽然我们的分析是一个有趣的步骤,但它是基于有限的案例样本。更大样本的案例,可能会引导我们找到一个更好的分类模型。

完整代码点击这里

最初发表于T5【https://www.manosantoniou.com】

使用多任务深度学习框架预测 ICU 患者 30 天再入院风险

原文:https://towardsdatascience.com/predicting-30-readmission-risk-for-icu-patients-be3eec7e6681?source=collection_archive---------33-----------------------

图像来源

使用电子健康记录的用于多任务学习的患者亚群体的无监督聚类

问题

无论是有计划的还是无计划的再入院,美国医疗保健系统每年都要花费数十亿美元。这对于医疗保健系统非常重要,因为大约三分之一的再入院是可以预防的,这为医院系统提供了改善护理质量的巨大机会(1)。此外,作为奥巴马政府通过的 2012 年平价医疗法案(affordable care act)的一部分,医疗保险和医疗补助服务中心(CMS)还会对医院进行处罚,将再入院率降低高达 3%,这为使用数据构建算法创造了巨大的机会,该算法能够预测哪些患者可能会在提前出院的情况下再次入院。

近年来,许多使用电子健康记录(EHR)数据和机器学习技术的研究被执行,以帮助确定大数据是否可以检测到 30 天内再次入院的高风险患者。这些研究利用了大量的统计和机器学习技术,从基本的流行病学模型到深度学习 LSTM 和具有专业制作功能的 CNN 架构(3–12)。尽管取得了进展,但许多研究的一个缺点是用于预测患者再入院风险的通用一刀切方法主要针对特定的表型。随着我们朝着开发考虑到每个患者个体风险因素的个性化药物迈进,我们也应该应用同样的思维模式来创建针对复杂 EHR 数据中存在的大量亚人群的算法。因此,在这项研究中,我探索了使用无监督方法进行队列选择的可行性,以在预测每组在 30 天内再次入院的风险之前,首先识别数据集中的亚群。

拟议的研究

在这项研究中,我将使用单任务和多任务模型来预测使用 MIMIC III 数据集的 30 天再入院风险。这将通过首先使用数据驱动的无监督方法对患者进行聚类,以使用在患者住院的最后 48 小时内捕获的社会人口统计学、操作和临床因素对患者进行聚类来完成。这将用于使用多任务框架预测患者从 ICU 出院后 30 天内再次入院的风险。Suresh 等人(2018) (13)首先介绍了这种方法,用于预测 ICU 的住院死亡率。据我所知,这是第一个使用这种两步法来预测 ICU 异基因患者 30 天再入院风险的研究。此外,值得注意的是,这项研究的重点是实现和测试这种建模方法的可行性,如果成功的话,将在后续的文章中对这项研究进行跟进和改进。

数据源

该项目利用了 MIMIC III 电子健康记录(EHR)数据集,该数据集由 38,645 名成人和 7,875 名新生儿的 58,000 多个住院记录组成。该数据集是从 2001 年 6 月至 2012 年 10 月在贝斯以色列女执事医疗中心的去识别重症监护病房住院病人的集合。

数据预处理

社会人口统计学、手术和临床因素已被证明与再入院相关。为评估 30 天再入院风险而建立的绝大多数模型主要依赖于社会人口统计学、操作和专业制作的疾病特异性临床变量(共病)(14-16),一小部分包括时变测量,如实验室和生命体征,以全面捕捉患者住院期间的进展。因此,为了全面评估这种方法,除了管理和共病特征外,还使用了以下静态和时变变量。时变特征被窗口化以捕捉患者停留的最后 48 小时。为了解决数据缺失的问题,从最后一个测量数据点回填数据。

表 1。用于根据患者住院最后 48 小时内测量的生理和生命体征预测再入院风险的特征。

纳入标准:

  1. 18 岁以上的患者
  2. 患者首次入住 ICU 作为指标(对于多次住院的患者)

排除标准:

  1. 死在医院的病人
  2. 单位之间的转移

然后在以下步骤中使用上述纳入和排除标准创建队列:

步骤 1:计算年龄,删除 18 岁以下的患者并创建再入院标志

下面的 SQL 脚本从 ICU 中提取患者的首次出院日期,并使用该出院日期来估计首次出院日期和再次入住 ICU 之间的时间。每位患者的年龄计算为入住 ICU 的日期与出生年份之间的差值。当数据集中显示年龄为 300 时,请不要惊讶,这是由于在 MIMIC III 数据集中用 300 替换了所有大于 89 岁的年龄。

步骤 2:使用四种最常见的共病风险因素,从上述 SQL 视图中的每个患者中提取这些信息。

第三步:提取表 1 中列出的所有时变实验室和生命体征。对于群组中的每个患者

第 4 步:实验室和患者在同一时间测量的平均实验室数

方法

在预处理数据后,使用自动编码器首先创建特征的密集表示,给出它们的初始稀疏度。然后,自动编码器的输出用于拟合高斯混合模型(GMM ),这是一种概率模型,通过包括关于数据的协方差结构以及潜在高斯中心的信息,可以将其视为 k 均值的一般化版本。

图 1: 展示如何在学习之前发现群组聚类的建模方法(13)

全球模型架构:

为了帮助利用随时间变化的变量来预测 30 天的再入院风险,在每个架构中都使用了 LSTM。在全局模型中(图 2。),使用单个 LSTM 层对所有数据进行训练,创建一个全球基线,旨在展示“一刀切”模型的性能,而不是针对每个患者组使用单独的密集层。

图 2: 全局多任务模型配置,在最后一个输出层(13)具有每个群组的单独参数

多任务模型架构:

与全局方法类似,该模型使用单一 LSTM 层,但是最终的密集层是特定于每个群组的。与使用不考虑差异的共享密集层相比,这为模型提供了学习仅存在于特定患者队列中的显著模式的机会。这个模型的架构可以在下面的图 3 中看到:

图 3: 单独的密集层多任务模型配置,在最后输出层(13)具有用于每个群组的单独参数

结果

有多少个集群(组件)?

使用由自动编码器创建的嵌入,创建了赤池信息标准****【AIC】贝叶斯信息标准****【BIC】图,以确定最小化 AIC 和 BIC 的最佳分量(集群)数量。这些图的结果表明,5 个集群将是最好的。然而,集群规模越大,队列越小,我的实验使用 4 或 5 个具有高度不平衡数据集的集群,得到了只有阴性病例的同质集群。因此,为了建立一个具有一致流行率的有意义的队列,选择 3 个样本作为折衷。还需要注意的是,虽然 AIC 和 BIC 确实会产生负值,但决定所选模型是否最佳的不是 AIC 或 BIC 值的绝对大小,而是所考虑的一组模型的相对值(18)。​

图 4: AIC 和 BIC 绘制了所选组件数量对 GMM 密度估计器性能的影响

可视化无人监管的患者集群:

2D 聚类的 t 分布随机邻域嵌入表示

下图(图。5)是由 GMM 模型预测的输出聚类的 t-SNE 表示。在这里,你可以看到集群重叠安静一点,这使得它很难得到一个更好的二维集群图片。因此,在图 6 中创建了 3D t-SNE 表示。

图 5:GMM 创建的患者队列的 2D t-SNE 图

三维团簇的 t-SNE 表示

为了有助于改善所创建的 4 个聚类的可视化,创建了嵌入的 t-SNE 表示。下图显示了 GMM 模型生成的聚类的散点图和聚类图。这里我们可以看到,绝大多数患者属于第 1 组,即包含大多数再入院的组,其次是第 2 组。我们可以看到,集群 1 和集群 2 似乎比集群 0 更密集地分布,而集群 0 似乎更分散(交互图,点击右上角的集群编号查看各个集群)。

图 6: 使用 t-SNE 3D 表示的所有患者聚类的散点图。互动剧情

图 7: 患者群组聚类的 3D 表示

图 8: 每个患者群组的单个 3D 散点图,显示了每个组中患者的分布

按组群分列的再入院率

每个群组的患病率差异显著,从群组 0 的 5.6%、群组 1 的 13.04%到群组 2 的 10.27%不等。全局多任务模型在整个患者群组上进行训练,最终密集层共享每个患者群组的预测。

表 2: 过去 48 小时住院期间所有患者队列的患病率

按集群和再入院状态划分的患者特征

使用 GMM 模型生成的聚类,表 3 显示了每个患者队列分层的基线特征以及 33,972 例出院和 3602 例(10.6%)再入院的再入院状态。总体而言,30 天内再次入院的绝大多数患者属于第 1 组,59%的患者为男性,67.7%为白人,平均住院时间为 2.70 天,48.7%由医疗保险覆盖。由于年龄是离散的,所有组群中的大部分再入院发生在 51-70 岁年龄组,最初出院到专业护理机构(SNF)。患有充血性心力衰竭等疾病的患者也比数据集中的其他四种共病患者有更高的再入院率。

表 3: 按集群和 30 天再入院状态划分的患者队列的基线特征

无监督聚类的时变特征

重要器官

下面的热图显示了在患者住院的最后 48 小时内,实验室和生命体征特征的 z 分值的变化。生命体征的正值、负值或零值分别表示每种特征随时间的升高水平、降低水平或平均水平。在组 0 的情况下,其显示在过去 48 小时内血压和呼吸频率持续增加,而组 1 显示在出院前一天的早些时候 Glascow 昏迷评分增加。有趣的是,聚类 2 显示了相当多的缺失测量值,这是意料之中的,因为这些实验室中的许多在患者住院期间不会被捕获。

图 9: 出院前 48 小时的生命体征变化趋势

实验室

对于出院前 48 小时内的实验室测量;在大多数患者再次入院的第 1 组中,我们看到许多实验室在住院的最后 48 小时内仍大幅升高,除了白蛋白、血液 pH 和 pO2 仍相对低于平均水平。与实验室的生命体征热图一样,显示了在过去 48 小时内丢失实验室值的相同趋势,随着这些实验室的测量频率在入住 ICU 后降低,丢失的实验室值增加。

图 10: 出院前 48 小时的常规实验室变量趋势

模型结果

为了评估聚类是否在更好地预测患者风险方面发挥作用,向患者队列呈现了用于预测患者 30 天再入院风险的全局多任务模型和个体致密层多任务模型。结果如表 3 所示。虽然承诺要付出巨大的代价。虽然这些算法在预测负面案例方面表现出色,但在预测正面案例方面表现不佳。因此,下面的结果可能会产生误导,因为它们在很大程度上基于多数阶级。这可归因于几个因素。有了几个优化器、网络规模和学习率,而 PPV 没有改善,我认为这种情况的一个可能原因很可能是稀疏性和频率降低,其中许多常规生理数据是在接近出院时收集的,如图 9-10 所示。这导致了受缺失值严重影响的特性集的开发。然而,这种方法可以使用不同的特征工程方法。请注意,论文中提出的单一任务模式的表现也明显比作者在研究中经历的其他模式差,因此也没有包括在内。

表 4: 使用全局和多任务模型的 30 天再入院任务的无监督建模方法结果。

结论/局限性

这个项目展示了如何在现实世界中实现个性化的想法。然而,需要对该方法进行调整,以确保所选择的特征为预测即将到来的结果提供有意义的结果。如果要在其他研究项目中使用这种方法,在重新审视本文中介绍的工作时,应该注意的一些发现包括:

  1. 在将数据分成训练/测试/val 集之后执行 z 分数归一化,以避免信息从训练集泄漏到测试集中。
  2. 使用这些实验室的正常值填充缺失的数据集,并为算法提供一个掩膜来识别缺失与伪化要素并创建更大的稀疏要素集。

未来方向

该出版物朝着个性化医疗保健的正确方向迈出了一步,通过一些改变,这种建模方法可以为特定亚人群提供一些有趣的见解,这些亚人群在构建健康相关模型时经常被忽略,因为在应用纳入和排除标准后可用的队列规模有限。然而,虽然这仅仅是探索建模方法的初步研究。随着进一步的研究,通过精心制作的特性和可能使用的更健壮的特性工程策略,可以进一步推动和发展这种方法。如果我们:

  1. 试着进行平衡训练
  2. 使用住院第一天和最后 24 小时内的异常值精心制作实验室特征
  3. 用更简单的模型建立基线方法
  4. 然后,尝试使用 Harutyunyan 等人在 2017 年提出的通道式 LSTM 方法,通过明确显示哪些变量缺失,以及允许模型在与每个聚类中的其他变量混合之前学习和存储与该特定变量相关的相关信息,来更好地解决缺失问题。
  5. 尝试在提交给 LSTM 层之前嵌入患者数据,以帮助减少实验室的稀疏性。
  6. 添加从临床记录中提取的特征,以提取以前的药物使用情况,并添加高风险药物,如:类固醇、麻醉药、抗胆碱能药(7)

我的博客

代码可在 GitHub 上获得

致谢:

特别感谢 Eraldi Skendaj 的批判性阅读和提供反馈。

参考

  1. Bates,D. W .,Saria,s .,Ohno-Machado,l .,Shah,A. & Escobar,g,《医疗保健中的大数据:使用分析识别和管理高风险和高费用患者》。治愈。Aff。33, 1123–1131 (2014).
  2. https://www . CMS . gov/Medicare/Medicare-Fee-for-Service-Payment/acuteinpatientps/read emissions-Reduction-Program
  3. Y.P. Tabak、X. Sun、C. M .、V. Gupta 和 R. S. Johannes,“使用电子临床数据预测早期住院再入院:早期再入院风险评分”,医学关心,2017 年第 55 卷第 3 期。
  4. H.Wang,Z. Cui,Y. Chen,M. Avidan,A. B. Abdallah 和 A. Kronzer,“通过成本敏感的深度学习预测医院再入院”,载于 IEEE/ACM 计算生物学和生物信息学汇刊,第 15 卷,第 6 期,第 1968–1978 页,2018 年 11 月 1 日至 12 月,doi:10.1109/tcbb . 2018 . 2018 . 28282897
  5. 马克·d·银色啤酒杯乐队,秦焕英,s .奎·默瑟,方&齐亚德·海达尔(2008)年龄≥65 岁的患者 30 天再次住院的风险因素,贝勒大学医学中心论文集,21:4,363–372,DOI:10.1080/08999885896
  6. 韦利博尔·米希奇、埃隆·加贝尔、伊拉·霍费尔、库马尔·拉贾拉姆、阿曼·马哈詹;术后急诊医院再入院的机器学习预测。麻醉学2020;132(5):968–980.https://doi.org/10.1097/ALN.0000000000003140。
  7. 武尼基里、拉姆亚&格利克斯伯格、本杰明&约翰逊、基普&达德利、乔尔&苏布拉曼尼安、拉克什米纳拉亚南&卡德尔、沙梅尔。(2018).阿片类患者物质滥用易感性、死亡率和药物相互作用的预测模型。
  8. 麦金太尔路,阿巴比 S,罗宾逊 EF,迈尔 RV。普通外科出院 30 天后患者再次入院的危险因素分析。JAMA Surg. 2016151(9):855‐861.doi:10.1001/jamasurg.2016.1258
  9. 按 VG。是时候从确定 30 天慢性阻塞性肺疾病再住院的风险因素上继续前进了吗?呼唤风险预测工具。安胸足球。2018;15(7):801‐803.doi:10.1513/annalsats . 201804–246 ed
  10. M.J. Rothman 等人/生物医学信息学杂志 46(2013)837–848
  11. Ohnuma,d . Shinjo,a .Brookhart 等人与出院后 30 天内内科和外科重症监护病房幸存者非计划性再入院相关的预测因素。 j 重症监护 6、 14 (2018)。https://doi.org/10.1186/s40560-018-0284-x
  12. Hrayr Harutyunyan,Hrant Khachatrian,David C Kale 和 Aram Galstyan。2017.临床时间序列数据的多任务学习和基准测试。arXiv 预印本 arXiv:1703.07771 (2017)。
  13. Harini Suresh、Jen J Gong 和 John Guttag。多任务学习的学习任务:重症监护室中的异质性患者群体。arXiv 预印本 arXiv:1806.02878,2018
  14. Keenan PS,Normand SL,Lin Z,等:一种基于心力衰竭患者 30 天全因再入院率的适用于描述医院绩效的行政索赔指标。 Circ 心血管质量结果。2008;1:29–37
  15. Krumholz HM,Lin Z,Drye EE 等:一种基于急性心肌梗死患者 30 天全因再入院率的适用于描述医院绩效的行政索赔指标。 Circ 心血管质量结果。2011;4:243–252.
  16. Lindenauer PK,Normand SL,Drye EE,等。肺炎住院后 30 天再入院测量的发展、验证和结果。 J 医院医疗。2011;6:142–150.
  17. 托马斯·巴古利。行为科学高级统计指南。帕尔格雷夫·麦克米伦出版社,2012 年。(第 402 页)
  18. 模型选择和多模型推理:一种实用的信息论方法 (Burnham 和 Anderson,2004)

预测酒店预订需求

原文:https://towardsdatascience.com/predicting-a-hotel-booking-demand-7608a7dbf5a4?source=collection_archive---------20-----------------------

构建机器学习模型预测酒店预订需求。

在本文中,我想写的是如何使用 Python 和 Jupyter Notebook 构建预测模型。我在这个实验中使用的数据是来自 Kaggle 的酒店预订需求数据集。

在本文中,我将只向您展示建模阶段,只有逻辑回归模型,但是您可以在我的 Github 上访问完整的文档,包括数据清理、预处理和探索性数据分析。

事不宜迟,我们开始吧。

导入库

导入库

加载数据集

加载数据集

这是数据集的样子。

资料组

它有 32 栏,完整版是:

['hotel', 'is_canceled', 'lead_time', 'arrival_date_year',
       'arrival_date_month', 'arrival_date_week_number',
       'arrival_date_day_of_month', 'stays_in_weekend_nights',
       'stays_in_week_nights', 'adults', 'children', 'babies', 'meal',
       'country', 'market_segment', 'distribution_channel',
       'is_repeated_guest', 'previous_cancellations',
       'previous_bookings_not_canceled', 'reserved_room_type',
       'assigned_room_type', 'booking_changes', 'deposit_type', 'agent',
       'company', 'days_in_waiting_list', 'customer_type', 'adr',
       'required_car_parking_spaces', 'total_of_special_requests',
       'reservation_status', 'reservation_status_date']

根据我在笔记本上运行的信息,可以在三列中找到数据集中的 NaN 值,这三列是“国家”、“代理商”、“T11”和“公司”****

基于' lead_time' 列的' lead_time' 特性,我将' country 中的 NaN 值替换为 PRT(葡萄牙),其中 PRT 是最常见的国家,lead_time = 118。

我试图替换基于提前期到达日期月到达日期周数的“代理人”特性上的 NaN 值,但是他们中的大多数都将“240”作为最常见的代理人。在我阅读了可以在互联网上找到的数据集的描述和解释后,作者将' agent '特性描述为“进行预订的旅行社的 ID”所以,那些在数据集中有“代理人”的人是唯一通过旅行社制作图书的人,而那些没有“代理人”或值为 Nan 的人是那些没有通过旅行社制作图书的人。因此,基于此,我认为最好用 0 填充 NaN 值,而不是用代理填充它们,这会使数据集不同于原始数据集。

最后但同样重要的是,我选择放弃整个“公司”特性,因为该特性中的 NaN 约占数据的 96%。如果我决定修改数据,可能会对数据产生巨大的影响,并且可能会改变整个数据,尤其是在公司特性中。

分割数据集

分割数据集

设置 x 和 y(目标)

我试图根据与目标最相关的前 5 个( is_canceled )来拆分数据集,它们是required _ car _ parking _ spaces'、 lead_time '、 booking_changes '、 adr、is_canceled。

训练和测试各占 80%和 20%。

拟合模型

model_LogReg_Asli 是在使用超参数调优之前使用逻辑回归的原始模型,这里是模型预测。

车型性能

正如你在上面看到的,逻辑回归模型有大约 69.3%的准确率。

模型参数

带有随机搜索 CV 的逻辑回归

model_LR_RS 是使用带有超参数调整(随机化)的逻辑回归的模型。

如上图所示,带有随机搜索 CV 的逻辑回归模型与没有随机搜索 CV 的逻辑回归模型具有完全相同的结果,即 69.3%。

带网格搜索 CV 的逻辑回归

model_LR2_GS 是使用带有超参数调整(网格搜索)的逻辑回归的模型。

上图显示,具有网格搜索 CV 的逻辑回归模型具有完全相同的准确性,即 69.3%。

评估模型

混淆矩阵

TN 为真阴性,FN 为假阴性,FP 为假阳性,TP 为真阳性,而 0 不取消,1 取消。下面是该型号的分类报告。

分类报告

在本文中,我再次使用逻辑回归进行测试,但是您可以使用其他类型的模型,如随机森林、决策树等等。在我的 Github 上,我也尝试了随机森林分类器,但是结果非常相似。

这就是本文的全部内容。谢谢你,祝你愉快。

利用机器学习预测住院患者的急性肾损伤

原文:https://towardsdatascience.com/predicting-acute-kidney-injury-in-hospitalized-patients-53ca07525e67?source=collection_archive---------32-----------------------

通过使用机器学习算法预测肌酐值来预测住院患者的急性肾损伤。

来源:肾脏模型,横断面

K 肾脏是你体内过滤血液的重要器官。他们负责清除废物,维持和控制身体的体液平衡,保持电解质的正确水平等。

生病和住院的病人发生肾损伤的风险很高。

急性肾损伤(AKI):

“…是在几小时或几天内发生的肾衰竭或肾损害的突然发作。”

AKI 由 2012 年发布的 KDIGO 标准更精确地定义。

简而言之,当肾脏受损时,会出现以下问题:

  1. 身体的液体平衡和电解质逐渐变得紊乱,最终威胁生命。在严重的情况下,医生可能会对患者进行透析——这需要几个小时的准备,需要一个特殊的程序来建立血液与透析机的人工连接。更不用说,紧急透析是非常昂贵的,一次治疗通常要花费 10,000 美元左右。
  2. 大多数药物通过肾脏排出体外。受伤的肾脏无法迅速将药物清除出体外,体内的药物浓度会累积,导致用药过量。这通常是医生可能改变药物剂量或完全改变药物的原因。

血清肌酸酐通过血液测试来测量

医生测量肌酸酐,肌酸酐是肌肉产生的一种生物标志物,由肾脏从体内过滤到尿液中。它在你血液中的浓度可以作为肾脏健康/功能的代表。如果你的肾脏过滤血液的能力因为受伤而恶化,那么肌酐值就会上升。

然而,当肌酐上升时,对肾脏的损害已经发生了。理想的情况是能够在肾脏损伤发生之前预测到它的迫近。

模型假设

由于体内的器官系统是相互依赖的,我推断肌酐值(肾脏健康的代表)可能依赖于心脏和肝脏等其他器官的健康。这些其他器官的“健康状况”可以通过针对这些器官系统的不同实验室测试来测量。

我开发了一个预测性临床计算器,使用各种实验室测试和患者人口统计数据作为输入特征,以便预测第二天的肌酐值。肌酐预测值恶化表明 24 小时内即将发生急性肾损伤(AKI)。

示意图:输入输出,评估 AKI 风险

获取数据

为了制作这个计算器,我使用了一个名为 MIMIC-III 的可免费访问的去身份病人医疗数据库。关于访问数据库的信息可在生理网网站上找到。

MIMIC-III 数据库的概览页面

在获得对 MIMIC-III 数据库的访问权后,我按照 Physionet 的指令将数据传输到 PostgreSQL 的本地实例中。数据库中提供了 25 个表格,我针对我的具体项目查询了其中的[ADMISSIONS](https://mimic.physionet.org/mimictables/admissions/)[CHARTEVENTS](https://mimic.physionet.org/mimictables/chartevents/)[D_ITEMS](https://mimic.physionet.org/mimictables/d_items/)[D_LABITEMS](https://mimic.physionet.org/mimictables/d_labitems/)[INPUTEVENTS_MV](https://mimic.physionet.org/mimictables/inputevents_mv/)[LABEVENTS](https://mimic.physionet.org/mimictables/labevents/)[PATIENTS](https://mimic.physionet.org/mimictables/patients/)。我咨询了一位医生,以确定我应该在我的模型中包括哪些实验室测试——我最终得到了 78 个特征。

数据清理和处理

示意图:数据是如何获得、提取和清理的,以及一些数据混乱的例子

来自医院使用的真实电子健康记录的临床健康数据是混乱的。为了处理数据,我首先使用HADM_IDITEMIDSUBJECT_ID将必要的表(上面列出的表)连接起来。

  • HADM_ID:“代表单个患者入院”
  • SUBJECT_ID:“指定单个患者的唯一标识符”
  • ITEMID:“表示数据库中的测量值”

单个SUBJECT_ID下的患者可以在不同的时间点多次入院,每次新入院都列在HADM_ID下。出于这个项目的目的,我将每个HADM_ID视为一个独特的事件,并没有将它们归入SUBJECT_ID下(尽管如果我有时间,我会这样做以说明历史健康数据——这可能会改进我的模型)。

利用 PANDAS 数据框架,我将表格转换成一种格式,这样,实验室值就可以按照获得它们的日期和时间以YYYY-MM-DD HH:MM:SS格式进行索引。这样做的原因是,许多患者在一天内进行了多个实验室检查,但在一天中的许多不同时间点进行。这将被证明在我后面解释的数据处理管道中是有用的。

年龄等信息需要通过减去住院时间和出生日期来计算。然后我用整数编码分类变量,比如性别和种族。我还必须规范化实验室值及其对应的单元类型,因为它们在数据集中以混合类型存在。

健康数据很少,所以我在每个病人身上插入了任何缺失的实验室数据。

示意图:心形表示记录实验室数值的日期。x 表示没有实验室值。

每次住院的实验室可以在时间线上进行概念上的“绘制”。我将该时间线的每个 24 小时时间窗内的所有实验室作为输入特征,并将下一个 24 小时的肌酐作为输出“目标”,我将尝试对其进行预测。

示意图:抓取输入数据X和输出次日值Y的滑动窗口方法

结果是一个输入矩阵X,其中每行代表 1 天,每列是我用作特性的 78 个实验室之一。目标向量Y包含第二天的肌酸酐。缺失的特征被赋值为NaN

示意图:加工清洗后的数据表。X_matrix 包含输入特征,其中每个特征都是一种不同的实验室测试。Y 向量包括第二天的肌酸酐值。

型号选择和性能

我最初用线性回归做了一些探索性的数据分析。虽然线性回归似乎在预测第二天的值方面做得不错,但 AKI 中的肌酐趋势通常不是线性的。

我决定使用 XGBoost (极端梯度提升)来提高计算速度、准确性和可伸缩性。XGBoost 是陈天琦卡洛斯·盖斯特林对梯度增强树的应用——你可以在这里阅读更多关于它的详细信息。简而言之,它结合了梯度增强和决策树的概念,梯度增强迭代地建立在先前预测器的伪残差上。它的准确性来自于在它的log loss度量中使用二阶导数和内置的正则化参数。我发现这篇文章的答案有助于解释 XGBoost 的一些方面。

由于 XGBoost 无法处理缺失的数据,我用每个实验室测试的中值填充了所有的NaN,并咨询了医生,以验证这是模型开发的合理临床假设。

我以 80/10/10 的比例将数据集分为训练集、验证集和测试集。

每次分割的数据大小。超过 3400 万个数据点!

XGBoost 在获取高维实验室数据并从中推断关系方面被证明是不可思议的。下面是我的最终模型的性能和附带的超参数的可视化。

:通过绘制真实肌酐值与测试集中预测肌酐值的对比图,可视化模型性能。试验了超过 45 个超参数变量,这是表现最好的模型,r 值达到 0.9377。完美模型的 r 为 1.0,预测值将沿着斜率为 1 的直线排列。

:将训练和验证的回归误差设置为模型训练,并迭代添加估计量。RMSE 是均方根误差,MAE 是平均绝对误差,RMSLE 是均方根对数误差。模型训练了多达 1000 个估计量,此时误差值达到了稳定水平,表明额外的估计量对模型性能的改善很小。

总结思路

总之,我使用 XGBoost 建立了一个模型来预测第二天的肌酐值。我希望像这样的模型有一天可以集成到电子健康记录(EHR)中,以动态预测未来的肌酐(和 AKI 风险)。这将为医生提供实时临床决策支持,使他们能够提前解决肾损伤问题,而不是治疗它。

参考

  1. MIMIC-III,一个免费的重症监护数据库。Johnson AEW,Pollard TJ,Shen L,Lehman L,Feng M,Ghassemi M,Moody B,Szolovits P,LA 和 Mark RG。科学数据(2016)。DOI: 10.1038/sdata.2016.35。可在:【http://www.nature.com/articles/sdata201635获得
  2. 约翰逊,阿利斯泰尔 EW,大卫 j .斯通,利奥 a .切利和汤姆 j .波拉德。"模拟代码库:在危重病研究中实现再现性."美国医学信息学协会杂志(2017): ocx084。

预测 PetFinder 的采用速度

原文:https://towardsdatascience.com/predicting-adoption-speed-for-petfinder-bb4d5befb78c?source=collection_archive---------28-----------------------

我们的团队目前是一家咨询机构,代表 PetFinder 工作,pet finder 是一家非营利组织,包含一个动物数据库,旨在通过与相关方的合作来改善动物福利。这个项目的核心任务是预测一只宠物被收养需要多长时间。

商业理解

鸣谢:宠物发现者基金会

根据 pet finder 2018 年的财务报告,其获得的公共支持和获得的收入总额中约有 70%将用于其公共福利项目,包括这个动物收养项目。我们定义的业务问题是“当新宠物进来时,新宠物被收养的估计时间是什么时候。”根据每只宠物的不同特征,我们可以根据我们创建的模型来估计宠物被收养需要多长时间。因此,通过采用我们的模型,该公司可以指导通过该渠道发布动物信息的收容所和救援人员估计新动物的采用速度。一旦很好地预测了宠物收养速度,就可以实施更有效的资源分配,以提高整体收养性能,并随后降低庇护和寄养的成本。最终 PetFinder 将获得更多的资金支持,为全球动物福利做出更大的贡献。

数据准备

这个数据集最初由14993 个观测值24 个变量组成。所有数据都基于马来西亚地区,所以我们的分析是针对特定国家和文化的。我们删除了变量名,因为我们认为它与宠物的收养速度无关。出于同样的原因,除了 Name,我们还删除了 State、PetID 和 RescuerID。此外,一些列(如 Breed1 和 Type)被编码为数字,并提供了额外的参考电子表格。出于澄清的原因,我们将类型和性别转换为字符串:我们将“1”编码为“狗”,将“2”编码为“猫”;对于性别,我们将“1”编码为“男性”,“2”编码为“女性”,“3”编码为“混合型”。混合代表宠物的性别。我们还把分类变量变成了虚拟变量。此外,我们进行卡方检验来检验颜色 1、颜色 2 和颜色 3 之间的相关性,结果表明它们是相互依赖的。因此,我们计划保留颜色 1,删除其他两个。最后,考虑到只有 0.38%的记录具有 Breed2,为了简单起见,我们删除了 Breed2。

此外,考虑到数据集包含一个描述列,我们对该列应用了文本分析。根据分析,我们选择了 10 个最常出现的词,并根据这些热词创建了另外 10 个列。我们检查每只宠物的描述是否包含这 10 个单词。如果描述中有匹配的词,我们在该列下指定“1”。如果不匹配,我们指定“0”。这 10 个词是:爱,小猫,小狗,营救,健康,活跃,可爱,火车,母亲,善良。最后,我们都同意描述的长度可能也是一个重要的因素。由于描述越详细,领养者挑选宠物的时间就越少。从逻辑上讲,如果可用信息更丰富,采纳者往往会更快做出决定。因此,我们的最终数据集由14993 条记录29 个变量组成。

数据探索

文本分析

基于文本分析,我们首先创建了一个文本云来捕获描述列中最常见的单词。结果发现,“领养”出现的频率最高,其次是“小猫”、“小狗”和“可爱”等词。从单词 cloud 中,我们可以总结出数据集中这些宠物的主要特征。

接下来,我们创建二元模型来捕获文本中的更多模式。最常见的二元结构是“一个月前”,我们挑选了 10 个最有趣的词,并把它们绘制成柱状图。

从这两幅图中我们可以看出,救援人员和避难所在描述中倾向于使用很多描述性的词语,如积极、善良、可爱等。如上所述,为了测试这些词的有效性,我们挑选了 10 个热词,并将其转换为 10 个分类变量。我们没有选择二元模型的原因是二元模型是由词干组成的,所以软件可能很难在描述中检测到这些二元模型。

品种与采用速度

此外,从马来西亚最知名的宠物网站之一 Perro Market 网站上,我们了解到了马来西亚最受欢迎的 10 个猫狗品种。出于数据探索的目的,我们选择缅因猫和波斯猫作为猫,狮子狗作为狗。

猫收养速度的平均值为 2.40,标准偏差为 1.21。相比之下,缅因州的平均采用速度为 1.97,波斯语的平均采用速度为 1.95。即使他们的平均值低于平均值,他们仍然在第一标准差范围内。基于这一事实,我们不能得出结论,流行的猫品种,如缅因州和波斯猫往往有较短的收养期比其他品种。

另一方面,狗的平均收养速度为 2.62,标准差为 1.14。值得注意的是,贵宾犬的平均认养速度为 1.97。同样,即使平均收养速度小于整个群体的平均速度,它仍然落在 1 个标准差范围内,所以我们不能得出结论,受欢迎的狗品种导致较短的收养期。

然而,从下面的图表中,我们发现热门品种的宠物数量远远高于其他品种。品种 179 是狮子狗,品种 285 是波斯狗,而品种 276 是缅因狗。

基于这一初步分析,我们的结论是,受欢迎的品种决定了该品种下的宠物数量,但不一定意味着较低的领养速度。

接种疫苗与收养速度

接种疫苗为“1”表示宠物接种疫苗,“2”表示宠物未接种疫苗,“3”表示不确定。与直觉相反,接种疫苗的宠物比没有接种疫苗的宠物显示出更高的时间跨度中值,而对于那些报告未知的宠物,它们有更高的时间跨度等待被收养。跨物种的领养速度和疫苗接种之间也没有明显的相关性(-0.06)。

建模

由于目标变量 AdoptionSpeed 是一个具有 4 个级别的分类变量,我们决定该项目的核心任务是分类:当一只新宠物进来时,模型将根据它被分类到哪个级别的采纳速度来确定它将被采纳多长时间。由于其多类的特点,我们选择了三种模型来实现目标,包括随机森林SVM多项逻辑回归。所有这三个模型都根据新动物提供的属性来预测新动物的采用速度,从而帮助解决我们的业务绩效问题。通过与公司分享我们的预测,公司可以对当前资源的分配有更好的计划,特别是将更多的资源分配给预测收养期较长的动物,以加快它们的收养速度。

随机森林

随机森林由大量单独的决策树组成,这些决策树作为一个整体运行。随机森林中的每棵树都给出一个类别预测,拥有最多票数的类别成为我们模型的预测。随机森林的一个优点是,在处理高度相关的变量时,它是去相关的。一个缺点是它限制了预测因子中可包含的分类变量的数量。在我们的项目中,我们排除了描述,因为在一个变量中有超过 14000 个级别,并且它已经分割成具有高频率和描述长度的单词。

支持向量机(SVM)

我们使用的另一个模型是支持向量机(SVM)模型,用于创建最佳超平面,以便在我们的测试数据集中对新记录进行分类。除了描述之外,我们包括来自清理过的训练数据集中的所有变量。通过将复杂数据转换为高维分析,SVM 很容易被用于解决多类分类问题,从而使类容易分离。该模型本身具有良好的计算特性,但它并不试图模拟概率。与随机森林相比,SVM 只能用于预测类别,而不能估计不同类别的概率。从这个角度来看,随机森林可以让我们更全面地了解测试数据集的类别预测。

套索和后套索多项式逻辑回归

我们也使用多项逻辑回归来预测我们的目标变量。然而,由于在多项逻辑回归中可以包含的变量数量的限制,我们使用 Lasso 来选择每一类采用速度的相关变量。基于最小λ和 1 个标准误差λ,我们建立了 4 个带有套索和后套索的多项式 logistic 回归模型。选择变量后,模型消除了过度拟合问题,并可能做出更好的预测。然而,Lasso 选择的变量在不同的自举模型中可能有所不同,它们很难被解释。

估价

为了评估每个模型的性能,我们进行了三重交叉验证,并选择了混淆矩阵平衡准确度作为我们的样本外准确度测量。根据上面的图表,我们所有的六种型号都具有相似的精度性能,范围从 0.5 到 0.6。随机森林达到了最高水平的 OOS 准确率为 59%。使用最小λ的套索多项式逻辑回归是第二高的,具有 56%的 OOS 准确度。考虑到 OOS 准确性是分类模型的一个重要指标,我们选择随机森林作为预测新宠物收养速度的最佳模型。为了研究特定的分类精度,我们进一步评估了随机森林和 SVM 的混淆矩阵,其中一个具有最高的 OOS 精度,另一个具有最低的精度。

从混淆矩阵中,我们可以得出结论,Random Forest 对宠物在 1 个月内实际被收养(AdoptionSpeed = 2)和上市 100 天后没有被收养(AdoptionSpeed = 4)的预测更准确。随机森林并没有显示出倾向于某一特定类别的趋势。相比之下,SVM 倾向于将宠物分为收养速度 2 级。

该模型的一个可能的限制是采用速度为 0 的数据点太少,因此很难评估其分类精度。另一方面,在随机森林的上述限制下,如果 PetFinder 增加了一个超过 100 个级别的新分类变量,则使用最小λ的多项 Lasso 逻辑回归而不是随机森林将是对新来宠物的采纳速度进行分类的更好选择。

当我们尝试将我们的模型应用到现实生活中的业务时,我们应该开发一个业务案例来确定预测是否准确,以及业务是否可以利用预测来优化其资源规划,从而提高采用性能。通过根据我们的预测模型分配资源,企业可以将以前的采用绩效与未来的采用绩效进行比较。收养绩效的提高可以通过同一时期内被收养动物数量的增加来证明。此外,企业应该分析预测收养时间长的动物是否可以在较短的时间内被收养,以查看资源分配的变化是否有效率。

部署

通过评估每个模型的 OOS 精确度,我们得出结论,随机森林生成的 OOS 精确度最高,是 PetFinder 的最佳选择。每当有新宠物进来,PetFinder 只需输入宠物的特征,就能预测它被收养需要多长时间。更准确地估计收养时间将使我们能够改善动物的状况,这对加快收养速度至关重要,并随后节省庇护成本。

为了更深入地了解哪些具体特征对需要更长时间才能被采用的宠物有重大影响,我们使用最小λ检验了通过多项逻辑回归和 Lasso 选择的变量。由于变量选择在数据的每个折叠中都不同,我们取 3 个折叠中变量选择的交集,发现在采用速度的四个级别中,年龄、品种、上传的照片数量和上传的视频数量都很重要。具体来说,对于领养速度较慢的宠物,人们更关注它们的健康状况:是否接种疫苗、驱虫、绝育。另外,描述的长度在收养速度较慢的宠物的简介中起着更重要的作用。如果宠物被归类为可能需要更长时间才能被收养,PetFinder 应该鼓励收容所优先考虑宠物的健康,并增加简介的描述长度。

一个重要的伦理考虑是,是否应该根据宠物的预测收养速度来区别对待它们。在没有预测模型的情况下,我们假设所有宠物都接受同等水平的治疗。然而,如果我们建议企业将更多资源分配给预测收养速度较低的动物,我们将导致资源分配不均。如果我们的预测不准确,一些宠物会受到负面影响,更不可能被收养。从这个角度来看,企业改善全球动物福利的目标可能无法完全实现。

我们的模型的一个可能的风险是,我们目前对宠物的实际收养速度等级为 0 的预测不准确。如果这些宠物被预测为 3 级或 4 级,企业将分配更多资源来推广它们,从而导致有限资源的浪费。为了降低风险,我们应该经常更新和改进我们的模型,因为我们有更多的记录,尤其是实际采用速度为 0 的记录。

用 GCP 的预言家预测空气污染

原文:https://towardsdatascience.com/predicting-air-pollution-with-prophet-on-gcp-42ceb1625818?source=collection_archive---------52-----------------------

使用 EPA 的公共数据进行时间序列预测

GCP 提供了一套云技术和全面管理的无服务器解决方案,使处理,存储和分析数据变得容易。该分析将利用 BigQueryGeo VizAI 平台

GCP 向新用户提供 300 美元的试用积分。此外,BigQuery 每月提供 1TB 的免费处理。本演示使用了这些配额的一部分。

BigQuery 是一个无服务器的数据仓库和分析工具,具有熟悉的 SQL 接口。它具有地理空间分析的地理信息系统能力,这使它成为任何环境评估的理想工具。此外,BigQuery 提供了许多公开可用的数据集,包括 EPA 的历史数据。

美国环保署维持着一个全面的监测网络,监测许多有害的空气污染物,包括臭氧(O₃)、氮氧化物和颗粒物。该网络确保空气质量符合国家空气质量标准,并协助分析和模拟空气污染模式。

我们将把重点放在每日臭氧摘要上,这在 BigQuery 上很容易获得。这个数据集可能很难处理,因为来自全国各地监视器的大量信息包含每日记录。

抽取、转换、加载至目的端(extract-transform-load 的缩写)

第一件事是在 BigQuery 中创建一个数据集来保存我们将在表中处理的数据,将数据集命名为 EPAO3

接下来,我们查询 EPA 的每日臭氧,并按县、州和月对每日最大臭氧进行最大聚合。我们将这些数据与 2016 年美国人口普查中的县几何数据相结合,以使这些数据在 Geo Viz 中可见。查询结果作为一个新表存储在我们的数据集中,名为 o3monthlymax

按县汇总的月最大臭氧量表的创建

这个查询运行了 37 秒,处理了 627.8 mb 的数据。消耗的槽时间,总 CPU 时间,是 9 分 37 秒。与传统的单一处理数据库相比,BigQuery 能够显著提高查询速度。创建的新表有 2.26gb 的数据和 33K 行。

健康影响与急性接触相关联,使得每日最大一小时臭氧值成为健康影响的合理替代值。

数据可视化

既然我们已经处理了数据,我们可以在 BigQuery Geo Viz 中检查它。让我们做一个时间跨度上的最大聚合,以使 Geo Viz 中的可视化更容易。

o3max_v 视图用于 Geo Viz

我们将把它保存为一个新视图,而不是运行查询。调用视图 o3max_v 。在 EPAO3 数据集中找到新视图,突出显示导出,并选择使用 Geo Viz 进行探索。您需要授权 Geo Viz 访问您的数据。我们可以使用默认的查询 Geo Viz 来访问我们的数据

地理 Viz 查询

几何图形应自动选择为几何图形列。移动到样式和填充颜色。选择数据驱动选项,并在字段选择器中滚动到 O3 。这里选择线性作为函数,但是间隔也可以工作。添加一些领域的限制,并发挥范围内的颜色,直到你满意的结果。

按县划分的最大 1 小时臭氧 Geo Viz 地图

请注意,一些县在监测网络中有很好的代表性,而另一些县则没有监测员。例如,内布拉斯加州和堪萨斯州很少有臭氧监测器。

时间数列预测法

接下来我们将使用 Prophet 进行空气污染预测。Prophet 是由脸书开发的开源时间序列预测工具。它基于一个附加模型,其中非线性趋势适用于各种时间窗口和假期趋势。

我们将使用 GCP 的人工智能平台创建一个虚拟机来运行 Prophet,该平台具有适合机器学习的虚拟机。在 AI 平台中创建一个新的笔记本实例,这里使用的是定制的 n1-standard-1 机器类型,这有助于最小化成本。AI 平台上的 Notebook 实例已经过身份验证,可以访问同一个项目中的 BigQuery。

一旦虚拟机被配置好,你就可以直接从 GCP 控制台打开 jupyterlab 。从那里创建一个 Python 3 笔记本或者上传到 github repo 中。

人工智能平台 Jupyter 笔记本使用 BigQuery 上的数据预测未来的臭氧

BigQuery 客户端库提供了 cell magic,它可以运行 SQL 查询并以 Pandas DataFrame 的形式返回结果,从而使 python 查询变得容易。

洛杉矶县臭氧预测。监控值以黑点显示。预测用蓝线显示。

臭氧往往在夏季达到峰值,因为它依赖于温度。Prophet 在捕捉臭氧的季节性变化方面做了合理的工作,并提供了现成的参数。

摘要

我们能够使用 GCP 平台和开源软件上包含的工具,在几个步骤中完成复杂的地理空间时间序列分析。

感谢

感谢爱德华·克鲁格道格拉斯·富兰克林审阅本文。

预测里斯本 AirBnB 的价格:树木和随机森林

原文:https://towardsdatascience.com/predicting-airbnb-prices-in-lisbon-trees-and-random-forests-336d19cdf5a2?source=collection_archive---------32-----------------------

安德烈亚斯·布吕克尔在 Unsplash 上的照片

在这篇小文章中,我们将快速启动一个预测模型,预测里斯本 AirBnB 的夜间价格。本指南希望通过使用真实数据和开发真实模型,为机器学习数据分析提供简单实用的介绍。

它还假设对 Python 和机器学习库 scikit-learn 有基本的了解,并且是在运行 Python 3.6 和 sklearn 0.21 的 Jupyter 笔记本上编写的。数据集和笔记本都可以在我的 Github 账户上获得,或者通过谷歌的数据集搜索获得。

1.数据探索和清理

作为第一步,我们从加载数据集开始。下载文件后,用 Pandas 打开并解析它是很简单的事情,并提供一个我们可以从中期待的快速列表:

Index(['room_id', 'survey_id', 'host_id', 'room_type', 'country', 'city', 'borough', 'neighborhood', 'reviews', 'overall_satisfaction', 'accommodates', 'bedrooms', 'bathrooms', 'price', 'minstay', 'name', 'last_modified', 'latitude', 'longitude', 'location'], dtype='object')

尽管我们可以确认数据集已被正确加载和解析,但对数据统计描述的快速分析可以让我们快速了解其本质:

从这个表中,我们实际上可以推断出每个参数的基本统计观察值。因为我们的模型打算根据我们将提供给它的任何一组输入来预测价格,所以我们可以检查例如:

  • 每晚价格的平均值约为 88 欧元
  • 价格从最低 10 欧元4203 欧元不等
  • 价格的标准偏差约为 123 欧元(!)

价格分布可以表示如下:

如我们所见,我们的价格分布集中在 300 欧元区间下,有一些条目对应 4000 欧元的值。绘制出大部分价格所在的位置:

从上面的描述中我们可以清楚地看到,在里斯本住一晚的大部分价格在 0-150 欧元之间。

现在,让我们窥探一下实际数据集,以便了解我们将要处理的参数类型:

从上面的描述中,我们应该能够推断出一些关于数据性质的统计数据。除了分布参数集(我们现在不寻找),我们清楚地确定了两组相关的见解:

  • 有空列:countryboroughbathroomsminstay
  • host_idsurvey_idroom_idnamecitylast_modifiedsurvey_id这样的条目可能与我们的价格预测器不太相关
  • 有一些分类数据,我们最初无法添加到价格回归中,例如room_typeneighborhood(但我们稍后会回到这两个数据)
  • location现在可能是多余的,因为我们既有latitude又有longitude,我们可能需要进一步推断该字段格式的性质

然后,让我们继续将数据集分为:

  • 一个向量 Y 将包含数据集的所有真实价格
  • 在矩阵 X 上,包含我们认为与我们的模型相关的所有特征

这可以通过下面的代码片段来实现:

有了新的子集,我们现在可以尝试了解这些参数在最常见价格范围内的总体满意度方面的相关性:

上述图表允许我们检查所有单个变量的分布,并试图推断它们之间的关系。我们可以根据我们选择的每个参数的审核值自由应用色调。上图中一些简单易懂的例子,来自可能表示正相关的关系:

  • 对于住宿较少的房间,评论的数量更常见。这可能意味着大多数评论的客人都租了较小的房间。
  • 大多数评论都是针对价格较低的房间的
  • 考虑到黄色的视觉优势,大多数评论实际上是 5 分。要么这意味着大多数住宿实际上是非常令人满意的,或者最有可能的是,大量的人实际上审查,这样做是为了给 5 分的评级。

一个奇怪的观察是,位置严重影响价格和评级。绘制经度和纬度时,我们可以获得里斯本沿线评级的准地理/空间分布:

然后,我们可以将这些数据添加到里斯本的实际地图上,以检查分布情况:

正如预期的那样,大多数评论都是关于市中心的,一些评论已经与最近的 Parque das Na es 相关。北部更多的次城区,尽管它有一些分散的地方,但评论没有中心那么高和普遍。

2.分割数据集

现在我们的数据集已被正确清除,我们将首先把它分成两部分:

  • 将负责训练我们的模型的集合,因此称为训练集合
  • 一个验证集,它将被用来验证我们的模型

这两个集合基本上都是 XY 的子集,包含租赁空间及其相应价格的子集。然后,在训练我们的模型之后,我们将使用验证集作为输入,然后推断我们的模型在归纳成除了用于训练的数据集之外的数据集方面有多好。当一个模型在训练集上表现很好,但不能很好地推广到其他数据时,我们说该模型对数据集过度拟合

有关过度配合的更多信息,请参考https://en.wikipedia.org/wiki/Overfitting

为了避免我们的模型对测试数据的这种过度拟合,我们将使用 sklearn 的一个名为https://sci kit-learn . org/stable/modules/generated/sk learn . model _ selection . train _ test _ split . html的工具,该工具基本上将我们的数据分割成一系列随机的训练和测试子集:

Training set: Xt:(10183, 6) Yt:(10183,) 
Validation set: Xv:(3395, 6) Yv:(3395,) 
- 
Full dataset: X:(13578, 6) Y:(13578,)

现在我们已经有了数据集,我们现在可以继续创建一个简单的回归模型,根据我们选择的参数,尝试预测里斯本 AirBnb 的每夜费用。

3.种植决策树

作为最简单的监督 ML 模型之一,决策树通常用于通过从所有可用的特征数据中学习和推断决策规则来预测结果。通过获取我们的数据参数,这些树可以学习一系列有知识的“问题”,以便以某种方式划分我们的数据,我们可以使用得到的数据结构对分类数据进行分类,或者简单地为数值创建回归模型(就像我们对价格的情况一样)。

一个可视化的例子,取自维基百科,可以是围绕泰坦尼克号乘客生存预测的决策树:

基于这些数据,树建立在根上,并且将通过将每个节点分成两个子节点来(递归地)划分。这些生成的节点将根据我们向模型提供的统计数据推断出的决策进行拆分,直到我们达到数据拆分产生最大信息增益的点,这意味着我们可以根据我们迭代创建的类对所有样本进行正确分类。我们称之为“叶子”的末端顶点。

在上面的维基百科示例中,遵循决策过程是微不足道的,因为存活概率是这里的估计参数,所以我们可以很容易地获得当“他没有兄弟姐妹”时,“9.5 岁以上的男性”存活的概率。

(为了更深入地理解决策树是如何为回归构建的,我推荐由 StatQuest 制作的名为决策树的视频。

然后让我们通过利用 sklearn 实现来创建我们的决策树回归:

DecisionTreeRegressor(criterion='mse', max_depth=None, max_features=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, presort=False, random_state=42, splitter='best')

为了便于说明,我们可以在下图中验证树是如何构建的:

在这里找到生成树的图形表示 @ Github。

我们还可以显示预测的片段,以及训练数据集样本的相应参数。所以对于以下住宿:

我们获得以下价格:

array([ 30., 81., 60., 30., 121.])

在将我们的模型拟合到训练数据之后,我们现在可以对验证集运行预测,并评估我们的模型的当前绝对误差,以评估当不针对它所测试的数据运行时它的概括程度。

为此,我们将使用平均绝对误差 (MAE)度量。我们可以将这一指标视为预测集中的平均误差幅度。它可以这样表示:

它基本上是我们的模型预测(y)和实际观测值( y-hat )之间差异的平均值,考虑到所有个体差异具有同等的权重。

然后,让我们使用 Scikit Learn 实现将这一指标应用于我们的模型:

42.91664212076583

这一结果基本上意味着,当暴露于测试数据时,我们的模型给出的绝对误差约为每间客房 42.935 欧元,而我们在初始数据探索期间收集的平均值为 88.38 欧元

要么是因为我们的数据集太小,要么是因为我们的模型太天真,这个结果并不令人满意。

尽管这在这一点上看起来令人担忧,但总是建议尽快创建一个生成结果的模型,然后开始迭代优化。因此,现在让我们继续尝试改进我们模型的预测。

目前,我们确实为测试数据的过度拟合而痛苦。如果我们想象正在构建的决策树,由于我们没有为要分割的决策指定限制,因此我们将生成一个决策树,该决策树一直深入到测试特征,而不是在任何测试集上很好地概括。

由于 sklearn 的DecisionTreeRegressor允许我们指定叶节点的最大数量作为超参数,因此让我们快速尝试评估是否存在降低 MAE 的值:

(Size: 5, MAE: 42.6016036138866) 
(Size: 10, MAE: 40.951013502542885) 
(Size: 20, MAE: 40.00407688450048) 
(Size: 30, MAE: 39.6249335490541) 
(Size: 50, MAE: 39.038730827750555) 
(Size: 100, MAE: 37.72578309289501) 
(Size: 250, MAE: 36.82474862034445) 
(Size: 500, MAE: 37.58889602439078) 250

然后,让我们尝试生成我们的模型,但包括计算的最大树大小,然后用新的限制检查其预测:

36.82474862034445

因此,通过简单地调整我们的最大叶节点数超参数,我们就可以获得模型预测的显著增加。我们现在已经改进了我们模型的平均误差(42.935 - 36.825 ) ~ 6.11 欧元

4.分类数据

如上所述,即使我们能够继续优化我们非常简单的模型,我们仍然放弃了两个可能的相关字段,它们可能(也可能不会)有助于我们模型的更好的泛化和参数化:room_typeneighborhood

这些非数字数据字段通常被称为分类数据,通常我们可以通过三种方式接近它们:

1)下降

有时,处理分类数据最简单的方法是…将其从数据集中删除。我们这样做是为了快速建立我们的项目,但是我们必须一个案例一个案例地去推断这些字段的性质,以及它们是否有意义被删除。

这就是我们到目前为止分析过的场景,MAE 为:36445

2)标签编码

所以对于标签编码,我们假设每个值被分配给一个唯一的整数。我们还可以考虑任何可能与数据相关的顺序/数量级(例如,评级、浏览量等)来进行这种转换。让我们使用 sklearn 预处理器检查一个简单的示例:

array([3, 3, 1, 0, 2])

通过分配拟合数据的数组索引来评估LabelEncoder正在进行的转换是很简单的:

array(['double room', 'shared room', 'single room', 'suite'], dtype='<U11')

然后,让我们将这种预处理技术应用于分类数据,并验证这如何影响我们的模型预测。因此,我们的新数据集将是:

我们的分类数据在 panda 的数据帧上表示为一个object,可以通过以下方式提取:

['room_type', 'neighborhood']

现在我们有了列,接下来让我们在训练集和验证集上转换它们:

现在,让我们用转换后的数据来训练和拟合模型:

35.690195084932355

然后,我们改进了我们的预测器,对我们的分类数据进行编码,将我们的 MAE 降低到 ~ 35.69 欧元

3)一键编码

一次性编码不是枚举字段的可能值,而是创建新的列来指示编码值是否存在。让我们用一个小例子来展示这一点:

array([[0., 0., 0., 1., 0., 0., 1.], [0., 1., 0., 0., 0., 1., 0.]])

从上面的结果我们可以看到,二进制编码在每个特性数组实际启用的特性上提供了1,在不存在时提供了0。然后,让我们尝试在我们的模型上使用这种预处理:

所以上面的结果乍一看可能很奇怪,但是对于 26 个可能的类别,我们现在有一个二进制编码来检查它的存在。我们现在将:

  • 添加回转换过程中丢失的原始行索引
  • 从原始集合train_Xvalidation_X中删除原始分类列
  • 用包含所有 26 个可能类别的新数据框架替换删除的列

现在,我们可以继续在模型中使用新的编码集:

36.97010930367817

通过对我们的分类数据使用一个热编码,我们获得了 MAE to ~ 36.97EUR

这个结果可以证明,当与标签编码相比较时,对于我们的分类参数以及同时对于这两个参数来说,一键编码不是最佳的。然而,这个结果仍然允许我们将分类参数包括在初始 MAE 的减少中。

5.随机森林

从上一节我们可以看到,使用决策树,我们总是在以下两者之间保持平衡:

  • 一棵有很多叶子的深树,在我们的例子中,每片叶子上只有很少的 AirBnB 位置,对我们的测试集来说太多了(它们呈现了我们所说的高方差
  • 一棵浅树,叶子很少,无法区分一个项目的各种特征

我们可以将“随机森林”想象为决策树的集合,为了试图减少上述差异,决策树以允许算法以减少误差的方式选择剩余树的方式生成树。如何创建随机森林的一些示例如下:

  • 用不同的数据子集生成树。例如,根据上面分析的我们的参数集,将生成仅具有它们的随机集的树(例如,仅具有“评论”和“卧室”的决策树,另一个具有除“纬度”之外的所有参数
  • 通过对不同的数据样本进行训练来生成其他树(不同的大小,训练和验证数据集之间的不同划分等等)

为了减少方差,增加的随机性使得生成的单个树的误差不太可能相关。然后,通过组合不同的决策树预测,从所有预测的平均值中提取预测,这具有甚至消除一些错误的有趣效果,从而降低整个预测的方差。

更深入地解释该算法的原始出版物可以在本文末尾的参考书目部分找到。

然后,让我们使用随机森林来实现我们的预测器:

33.9996500736377

我们可以看到,当使用随机森林时,我们的 MAE 显著降低。

6.摘要

尽管决策树是机器学习中非常简单(可能是最简单)的回归技术,我们可以在我们的模型中使用,但我们希望演示一个分析数据集以生成预测的样本过程。很明显,通过小的优化步骤(如清理数据、对分类数据进行编码)和将单棵树抽象为随机森林,我们可以显著降低模型预测的平均绝对误差。

我们希望这个例子作为机器学习的实践经验变得有用,如果我可以澄清或纠正上面演示的一些内容,请不要联系我。在未来的一些文章中,我们还计划使用其他方法和工具进一步优化我们对这个特定数据集的预测,敬请关注:)

7.进一步阅读

请在下面找到一些资源,它们对于理解一些公开的概念非常有用:

欢迎随时联系我@https://Jose . tapadas . eu

使用 PyTorch 和 Apache Mxnet 的分层注意力网络预测亚马逊评论分数

原文:https://towardsdatascience.com/predicting-amazon-reviews-scores-using-hierarchical-attention-networks-with-pytorch-and-apache-5214edb3df20?source=collection_archive---------19-----------------------

这篇文章和这里的代码是一个更大的回购的一部分,我有(非常创造性地)称为“NLP-stuff”。顾名思义,我在回购项目中包括我所做的项目和/或我的想法——只要有与这些想法相关的代码——都与 NLP 相关。在每个目录中,我都包含了一个 README 文件和一系列解释笔记本,我希望它们有助于解释代码。我打算在 2020 年继续添加项目,不一定是最新和/或最流行的版本,而只是我觉得有趣和有用的论文或算法。特别是这篇帖子相关的代码在目录Amazon _ reviews _ class ification _ HAN

首先,让我们从感谢那些努力工作的相关人员开始。本帖及配套回购基于论文“用于文档分类的分层注意网络”(杨子超等,2016 )。此外,在我的实现中,我还使用了“正则化和优化 LSTM 语言模型”中的结果和代码( Stephen Merity,Nitish Shirish Keskar 和 Richard Socher,2017 )。我在回购中用于此实验和其他实验的数据集是亚马逊产品数据 ( J. McAuley 等人,2015R. He,J. McAuley 2016 ),特别是服装、鞋子和珠宝数据集。我强烈建议看一看这些论文和其中的参考资料。

1.网络架构

完成后,让我们从描述我们将在此实施的网络体系结构开始。下图是Figure 2杨子超等人的论文。

图 1(他们论文中的图 2)。分层注意网络

我们考虑一个由 L 个句子st5】ᵢ组成的文档,每个句子包含tt11】ᵢt13】个单词。 w_it 带 T∈【1,T】,代表第 i 个句中的词。如图所示,作者使用了一个单词编码器(一个双向 GRU, Bahdanau 等人,2014 ),以及一个单词注意机制,将每个句子编码成一个向量表示。这些句子表示通过具有句子注意机制的句子编码器,产生文档向量表示。该最终表示被传递给具有相应激活函数的全连接层以进行预测。单词“层次化在这里指的是首先从单词编码句子,然后从句子编码文档的过程,自然遵循文档中的“语义层次化”。

1.1 注意机制

假设一个人熟悉 GRU 公式(如果不是看这里的),所有理解注意力机制所需的数学都包括在下面。我在这里包括的数学表达式指的是注意机制这个词。句子注意机制相同,但在句子层面。因此,我相信解释下面的表达式,以及下面的代码片段,将足以理解整个过程。前三个表达式非常标准:

方程组 1(直接从论文中提取):GRU 输出

其中 x_it 是单词 t 在句子 i. 中的单词嵌入向量,向量h_ it是来自双向 GRU 的前向和后向输出特征,它们在应用关注之前被连接。注意机制的公式如下:

方程组 2(直接从论文中摘录):字注意。句子注意相同,但在句子级别

首先, h_it 特征通过一个带有双曲正切函数的单层 MLP。这导致了一个隐藏的表示 h_it,u_it。然后,将每个单词的重要性度量为 u_it 与上下文向量 u_w 的点积,得到所谓的归一化重要性权重 α_it 。之后,基于归一化的重要性权重,计算句子向量 s 作为 h_it 特征的加权和。更多详情,请阅读论文第 2.2 节"等级注意"如前所述,句子注意机制是相同的,但在句子层面。

单词和句子的注意力可以编码为:

Pytorch:

片段 1。Pytorch 的单词和句子注意机制

Mxnet:

片段 2。Mxnet 的单词和句子注意机制。

其中inph_ith_i 分别为单词和句子注意。

可以看出,Mxnet 的实现与 Pytorch 中的几乎相同,尽管有一些细微的差别。这将是贯穿整个韩实施的情况。不过我想补充几行澄清一下:这是我第二次“认真”潜入 Mxnet 和胶子。我用得越多,我就越喜欢它,但是我很确定我可以写出更好、更有效的代码。记住这一点,如果你,读者,是一个 Mxnet 用户,并有建议和意见,我很乐意听到他们。

1.1.1 字编码器+字注意

一旦我们有了AttentionWithContext类,编码WordAttnNet(单词编码器+单词注意力)就简单了。下面的代码片段是回购的简化版本,但包含了主要组件。完整版请看回购中的代码。

Pytorch

代码片段 3:单词编码器+单词注意力模块(又名单词注意力网络)的 Pytorch 实现

Mxnet

代码片段 3:单词编码器+单词注意力模块(又名单词注意力网络)的 Mxnet 实现

您将注意到 3 个与信号丢失相关的参数:embed_dropweight_droplocked_drop。我将在第 2 节中详细描述它们。目前,让我们忽略它们,将注意力集中在模块的其余组件上。

简单地说,输入令牌(X)通过嵌入查找表(word_embed)。得到的令牌嵌入通过双向 GRU ( rnn)和 GRU 的输出到达AttentionWithContext ( word_attn),后者将返回重要性权重(α)、句子表示( s )和隐藏状态 h_n

注意,返回隐藏状态是必要的,因为文档(这里是 amazon 评论)由一系列句子组成。因此,句子 i+1 的初始隐藏状态将是句子 i 的最后隐藏状态。我们可以说,我们将把文档本身视为“有状态的”。我将在稍后的文章中回到这个话题。

1.1.2 句子编码器+句子注意

假设我们不需要句子编码器的嵌入查找表,SentAttnNet(句子编码器+句子注意)简单来说就是:

Pytorch

代码片段 5:句子编码器+句子注意模块(又名句子注意网络)的 Pytorch 实现

Mxnet

代码片段 6:句子编码器+句子注意模块(又名句子注意网络)的 Mxnet 实现

这里,网络将接收WordAttnNet ( X)的输出,该输出然后将通过双向 GRU ( rnn),然后通过AttentionWithContext ( sent_attn)。

至此,我们拥有了编码 HAN 的所有构件。

1.1.3 分层注意网络(HANs)

Pytorch

代码片段 7: Pytorch 实现的分层注意力网络(HAN)

Mxnet

代码片段 8:分层注意力网络(HAN)的 Mxnet 实现

我认为在这里用一些与张量在网络中导航时的维数相关的数字来说明网络中的数据流可能是有用的。让我们假设我们使用批量大小(bsz)为 32,令牌嵌入为 dim ( embed_dim ) 100,GRUs 为隐藏大小(hidden_dim ) 64。

X之前的片段中对HierAttnNet的输入是 dim (bzs, maxlen_doc, maxlen_sent)的张量,其中maxlen_docmaxlen_sent是每个文档的最大句子数和每个句子的最大字数。我们假设这些数字是 5 和 20。所以,X在这里是 dim (32, 5, 20)的张量。

我们做的第一件事是改变坐标轴,得到一个 dim (5, 32, 20)的张量。这是因为我们将以“有状态”的方式,一次处理一个句子,将一个句子的最后一个隐藏状态作为下一个句子的初始隐藏状态。这将发生在向前传球的循环中。

在这个循环中,我们将一次处理一个句子,也就是说,一个 dim (32, 20)的张量包含批处理中所有 32 个评论的第个到第个句子。然后将这个张量传递给wordattnnet,简单来说就是前面所说的单词编码器+单词注意力。在那里,它将首先通过嵌入层,产生一个 dim 张量(32, 20, 100)。然后通过双向 GRU,产生 dim 张量(32, 20, 128),最后通过注意机制,产生 dim 张量(32, 1, 128)。这最后一个张量是杨子超等人论文中方程 7 中的,对应于第 I 个句子的向量表示。

运行该循环后,我们将得到沿第二维连接的 dim (32, 1, 128)maxlen_doc(即 5 个)张量,从而得到 dim (32, 5, 128)(bsz, maxlen_doc, hidden_dim*2)的张量。这个张量再经过sentattnnet,就是前面说的简单的句子编码器+句子注意。在那里,它将首先通过双向 GRU,产生一个 dim 张量(32, 5, 128),最后通过注意力机制,产生一个 dim 张量(32, 128)。这最后一个张量将是他们论文中方程 10 中的 v

最后v然后通过全连接层和 Softmax 函数进行预测。

2。嵌入、锁定和重量损失

当我开始运行实验时,我注意到模型在训练过程中过早地过度拟合。最佳验证损失和准确性发生在最初的几个时期内,或者甚至在第一个时期之后。出现过度拟合时,有多种选择:

  • 降低模型复杂性:我通过运行一些具有少量嵌入和/或隐藏大小的模型来探索这一点。
  • 提前停止:通常通过early_stop功能使用。
  • 附加正则化,如剔除、标签平滑( Christian Szegedy 等人,2015 年)或数据增强。我写“附加”是因为我已经使用了重量衰减。

在本练习中,我没有探讨标签平滑或数据扩充。如果你想更深入地了解如何在 Pytorch 中实现标签平滑,看看这个 repo 。在 Mxnet 的情况下,gluonnlp API 有自己的 LabelSmoothing 类

关于数据扩充,事实是我还没有尝试过,也许我应该尝试一下。不仅因为它通常会在模型泛化方面带来显著的改进,而且因为我已经从另一个实验中获得了大部分代码,在那里我实现了 EDA:用于提高文本分类任务性能的简单数据增强技术 ( Jason Wei 和邹凯 2019 )。然而,一个人必须在某个地方停下来,我决定专注于探索不同的辍学机制。

我在这里使用的 3 种不同形式的辍学是:嵌入辍学,锁定辍学和重量辍学。我使用的代码直接取自AWD-LTSM 协议( Merity,hirish Keskar and Socher,2017 )实施对应的 salesforce 回购。在这一节中,我将重点讨论 Pytorch 的实现,但是我也将包括关于 Mxnet 实现的信息。请注意,这些退出机制最初是在语言模型的环境中考虑和实现的。然而,没有理由为什么它们不应该在这里工作(或者至少没有理由为什么我们不应该尝试它们)。

2.1 嵌入脱落

这将在第 4.3 节中详细讨论。基于 Gal & Ghahramani (2016) 的工作。没有人比作者自己更好地解释它了。用他们自己的话说:“这相当于在单词级别上对嵌入矩阵执行丢弃,其中丢弃在所有单词向量的嵌入中传播。[……]"**

代码(以下代码是原* 回购 )中的简化版本😗

嵌入丢失的简化(即不完整)实现。来自 Merity,Shirish Keskar 和 Socher 2017: 规范和优化 LSTM 语言模型

基本上,我们沿着嵌入张量的第一维(“单词维)创建 0 和 1 的掩码,然后我们沿着第二维(“嵌入维)扩展该掩码,相应地缩放剩余的权重。正如作者所说,我们放弃文字。

2.2 锁定脱落

这也是基于Gal&Ghahramani(2016)的工作。再次用作者的话来说:“[…] 在第一次调用时只对二进制丢失掩码进行一次采样,然后对正向和反向传递中的所有重复连接重复使用锁定的丢失掩码”。

在代码中:

锁定辍学的实现。来自 Merity,Shirish Keskar 和 Socher 2017: 规范和优化 LSTM 语言模型

简单地说,LockedDropout将接收一个三维张量,然后它将沿第二维生成一个掩码,并沿第一维扩展该掩码。例如,当应用于像(batch_size, seq_length, embed_dim)这样的张量时,它将创建一个模糊(1, seq_length, embed_dim)的遮罩,并将其应用于整批。Mxnet 的nn.Dropout模块有一个axes参数,直接实现这种类型的退出。

最后…

2.3。重量下降

这在他们论文的第二部分讨论。再一次,用他们自己的话说:“我们建议在递归隐藏到隐藏权重矩阵上使用 DropConnect (* 万等人,2013**),这不需要对公式进行任何修改。”*

代码(以下代码是原* 回购 )中的简化版本😗

重量下降的简化(即不完整)实现。来自 Merity,Shirish Keskar 和 Socher 2017: 规范和优化 LSTM 语言模型

WeightDrop将首先复制并注册带有后缀_raw 的隐藏到隐藏的权重(或一般意义上的List权重中的权重)(第 14 行)。然后,它将应用 dropout 并将权重再次分配给module (如果variational为第 25 行,否则为第 27 行)。如代码片段所示,variational选项与之前讨论的嵌入丢失的情况相同,即沿张量的第一维生成一个掩码,并沿第二维扩展(或广播)。

这种实现有几个缺点。首先,给定一些输入权重,最终的模型将包含原始权重(称为weight_name_raw)和那些丢失的权重(称为weight_name),这不是很高效。其次,它更改了参数的名称,在原来的名称上添加了'module'。

老实说,这些根本不是主要的缺点,但是我可以把它们作为一个借口来介绍另外两个可能更好一点的实现(当然是基于原来的实现)。一个是[fastai](https://github.com/fastai/fastai)库中伟大的text API 中的实现。我想在这一点上每个人都知道这个库,但是如果你不让我在这里写几行。我发现这个库非常优秀,不仅因为它提供的高级 API,或者巧妙的默认设置,还因为在源代码中隐藏了很多小宝石。如果你对图书馆不熟悉,试一试,没有回头路。

另一个不错的实现是 Mxnet 的 gluonnlp API 中的函数apply_weight_drop,我在这里使用了它。事实上,在他们的[AWDRNN](https://gluon-nlp.mxnet.io/_modules/gluonnlp/model/language_model.html#AWDRNN)语言模型的实现中,这个函数被用于嵌入和隐藏到隐藏的权重丢失。可通过他们的utils模块获得:

*from gluonnlp.model.utils import apply_weight_drop*

就实现而言,就是这样。是时候做些实验了。

3。结果和可视化注意力

3.1。结果

我最终记录了 59 个实验(我又运行了几个),其中 40 个使用 Pytorch 实现,19 个使用 Mxnet。在整个实验中,我使用了不同的批量大小、学习速率、嵌入维数、GRU 隐藏大小、辍学率、学习速率调度器、优化器等。都显示在笔记本04 _ Review _ Score _ Prediction _ results . ipynb的表 1 和表 2 中。下表显示了每个实现的测试数据集上的最佳结果,以及我从使用 tf-idf 以及 LightGBM 和 Hyperopt 进行分类和超参数优化任务的先前尝试中获得的最佳结果。

表 1。将 HANs 与 Pytorch 和 Mxnet 以及 tf-idf+LightGBM 配合使用可获得最佳结果。更多详情请参见回购

首先,值得重申的是,我只对 Mxnet 实现进行了 19 次实验。部分原因是,正如我在本文前面提到的,我在 Pytorch 上的经验比 Mxnet 和 Gluon 多,这影响了相应的实验。因此,很有可能我错过了对 Mxnet 模型的一个小的调整,这个调整会导致比表中的结果更好的结果。

除此之外,我们可以看到 HAN-Pytorch 模型在所有准确度、F1 分数和精确度的测试数据集上比彻底调整的 tf-idf +LighGBM 模型表现得更好。因此,下一个最直接的问题是:使用 HAN 而不是 tf-idf+LightGBM* (或者您最喜欢的分类器)值得吗?答案是,就像生活中的大多数事情一样,“这要看情况”。*

确实汉族表现更好,但是涨幅比较小。一般来说,抛开亚马逊评论的特例不谈,如果在你的业务中,3%左右的 F1 分数很重要(即导致收入、节约或其他一些好处的大幅增加),那么毫无疑问,人们会使用 DL 方法。最重要的是,注意力机制可能会给你一些额外的有用信息(比如文本中导致某种分类的表达),而不仅仅是通过使用 tf-idf (或主题建模)等方法获得的关键词。

最后,我的 HANs 实现效率很低(见下一节)。即使在这种情况下,表中显示的结果也总是在不到 10 个时间段内获得,每个时间段在 Tesla K80 上运行约 3 分钟(或更短,取决于批次大小)。因此,这当然不是一个计算量很大的训练算法,而且性能很好。总的来说,我认为在执行文本分类时,HANs 是一个很好的算法。

3.2 观想注意力

现在让我们来看看注意力权重,特别是单词和句子的重要性权重(α)* 。*

图二。已被正确分类的评论的注意力图,包括正面(顶部)和负面(底部)评论。颜色强度对应于重要性权重的值(本文第 2 组等式中的αs 或他们论文中的等式 6 和 9)。

图 2 显示了两个被正确分类的评论的单词和句子的注意力权重。xxmaj记号是由 fastai 记号赋予器引入的特殊记号,表示下一个记号以大写字母开始。此外,值得一提的是,在原始数据集中,评论得分从 1-5 星不等。在预处理过程中,我将带有 1 和 2 starts 的评论合并到一个类中,并将这些类重新标记为从 0 开始(详见这里的)。因此,最终的类数为 4: {0,1,2,3}。

该图显示了在预测评论分数时,韩如何关注短语和结构,如“fit is perfect”、“ very superior ”或“rub[…]error places”,以及孤立的词,如“buyed”或“ not ”。此外,我们可以看到,在上面的图中,相对于其他 3 个句子,第 3 个句子受到了更多的关注。

图 3。除了分类错误之外,与图 2 相同。

图 3 显示了两个被错误分类的评论的单词和句子的注意力权重。最高评价被预测为 0,而真实分数为 3(原始数据集中的真实分数为 5)。有人发现这些靴子“恶心”、“令人失望”和“糟糕”,却给了他们 5 颗星的评分。底部的评论被预测为 3,而真实分数为 0(原始数据集中的真实分数为 1)。这就很容易理解为什么韩把这篇评论错误地归类为第一句话,而第一句话是最受重视的。

尽管如此,这些数字表明,注意力机制运作良好,捕捉评论中的相关片段,从而导致某种分类。笔记本05 _ Visualizing _ attention . ipynb包含了我用来生成这些图的代码。

4。讨论

在这一阶段,有几条意见值得提出。首先,我手动运行了所有实验(使用一个 bash 文件),这不是优化模型超参数的最佳方式。理想情况下,人们希望将训练和验证过程封装在一个目标函数中,并使用 Hyperopt,正如我在 repo 中对所有其他侧重于文本分类的实验所做的那样。在不久的将来,我将包含一个.py脚本来完成这个任务。

另一方面,观察图 2 和 3,可以看到注意力通常集中在孤立的单词或结构和短语或 2 或 3 个单词上。因此,有人可能会认为使用非 DL 方法和 n-grams 可能会改善表中的结果。我实际上在这个笔记本中做了,使用或不使用 n 元模型(特别是通过[gensim.models.phrases](https://radimrehurek.com/gensim/models/phrases.html)的二元模型)之间的差异可以忽略不计。

其他值得讨论的问题与模型的泛化和效率有关。例如,我已经提到,可以使用标签平滑和数据扩充来增加正则化。事实上,即使增加了一些遗漏,最好的验证损失和度量仍然在训练的早期获得,而且在 Mxnet 实现的情况下。这不一定是不好的,可能只是反映了这样一个事实,即模型在几个时期后就达到了最佳性能。然而,还需要更多的探索。

另外,如果你看一下我的实现细节,你会发现输入张量有很多不必要的填充。从这种填充中不会学到任何东西,但仍然必须进行处理,即这对于 GPU 来说是低效的。为了补救这种情况,可以将相似长度的评论分组到桶中,并相应地填充,从而减少处理文档所需的计算。此外,可以根据文档长度调整学习速率和批量大小。所有这些方法都已经被用于构建语言模型(例如,参见这个演示)并且在 gluonnlp API 上很容易获得。在这一点上,我只是触及了这个 API 的皮毛,我期待着在不久的将来进行更多的实验。

5.总结和结论

我已经使用 Pytorch 和 Mxnet 实现了“用于文档分类的分层注意力网络”(杨子超等人,2016 )来预测亚马逊评论得分,并将结果与之前不涉及深度学习的实现进行了比较。HANs 在所有评估指标上都表现得更好,相对容易实施,训练也更快。因此,我相信这是一个值得在文本分类任务中使用的算法。

除此之外,一如既往,我希望这篇文章对你有用。

任何意见,建议,请发邮件给我:jrzaurin@gmail.com 或更好地在回购问题。

参考文献

Dzmitry Bahdanau,KyungHyun Cho,Yoshua Bengio 2016。通过联合学习对齐和翻译的神经机器翻译。https://arxiv.org/abs/1409.0473

2015 年邹斌·格拉马尼·亚林加尔。递归神经网络中基于理论的丢包应用。https://arxiv.org/abs/1512.05287。**

毁了何,朱利安·麦考利 2016。起伏:用一类协同过滤模拟流行趋势的视觉演变。https://arxiv.org/abs/1602.01585

朱利安·麦考利、克里斯托弗·塔吉特、秦风、史和安东·范·登·亨格尔 2015。基于图像的风格和替代品建议。https://arxiv.org/abs/1506.04757

Stephen Merity,Nitish Shirish Keskar,Richard Socher 2017。规范和优化 LSTM 语言模型。【https://arxiv.org/abs/1708.02182】T5T6

克里斯蒂安·塞格迪、文森特·范霍克、谢尔盖·约菲、黄邦贤·施伦斯、兹比格涅夫·沃伊纳 2015。重新思考计算机视觉的初始架构。https://arxiv.org/abs/1512.00567

李万,马修泽勒,张思欣,杨乐村,罗布弗格斯 2013。使用 DropConnect 正则化神经网络。http://proceedings.mlr.press/v28/wan13.html

贾森·魏,邹凯 2019。EDA:用于提高文本分类任务性能的简单数据扩充技术。https://arxiv.org/abs/1901.11196

杨子超,杨迪一,,何晓东,亚历克斯·斯莫拉,爱德华·霍维 2016。用于文档分类的分层注意网络。https://www.cs.cmu.edu/~./hovy/papers/16 hlt-hierarchical-attention-networks . pdf

使用机器学习预测和防止高价值客户流失

原文:https://towardsdatascience.com/predicting-and-preventing-the-churn-of-high-value-customers-using-machine-learning-adbb4a61095d?source=collection_archive---------22-----------------------

** 简短的代码片段和可视化将在这篇文章中分享,但该项目的所有代码都可以在这个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)对每个因素对客户流失概率的影响进行排序。

感谢阅读!!

预测动画电影表现的数据管道

原文:https://towardsdatascience.com/predicting-animated-film-performance-5d25748b7481?source=collection_archive---------40-----------------------

实施线性回归预测动画电影表现的技术演示。

这是 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')

从热图中,我可以收集到与票房表现高度相关并且会严重影响我的模型的主要特征是:

  1. 平均运行周数
  2. 剧院数量
  3. 生产预算
  4. 续集/翻拍
  5. 元得分
  6. 标题长度(标题中的字母数)
  7. 运行时间
  8. 国内生产总值水平环比

有意思的是,随着年限的增长,收益反而下降。这也可能与不得不削减数据集以包含准确的元得分有关。为了探索这些特征和票房表现之间的数学关系,我进一步观察了一个配对图。代码和结果如下:

sns_plot = sns.pairplot(numeric_df, height=4, aspect=1);
sns_plot.savefig(“pairplot.pdf”)

从配对图中(在 pdf 上放大很多倍后),我可以进一步理解这些关系,并看到一些更有影响力的特征:

  1. 平均运行周数

这个特征与票房有直接关系,斜率很小,截距大于零。

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 和迭代的数量,但也令人欣慰的是知道人类对模型的输入和模型本身一样重要。我期待将线性回归应用于无数的问题。

预测动画电影的表现

原文:https://towardsdatascience.com/predicting-animated-film-performance-fc32e3611c71?source=collection_archive---------18-----------------------

这是 METIS 正在进行的五个数据科学项目中的第二个,旨在使用线性回归来预测动画电影的票房表现。

Shutterstock 获得授权的吉卜力动画工作室角色

动机

我喜欢动画电影——大多是吉卜力工作室的,但有时,迪士尼/皮克斯制作的东西我不介意看无数遍。我希望看到更多伟大的作品,但我知道动画电影的制作成本近年来大幅增加。我想帮助制片人和电影制作人更早地了解投资回报:

  • 动画电影制片人想知道投资哪部动画电影能获得最高回报。
  • 动画电影制作人想知道电影中的简单变化是否能提高电影的回报。

目标

  • 了解哪些因素会产生最高的国内票房回报
  • 在电影上映前预测国内票房收入

数据

  1. 分销战略、资金、绩效—“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 名预发行

  1. 生产预算:美元美元

2.分布:影院数量,周数

3.关键审查:预发布关键接收+

4.上映日期:夏季/12 月

5.标题长度名称:越短越好

6.续集:表现最好的电影是续集

  • 有趣的是,流派、语言数量和制作国家对票房表现没有显著影响。

我深入研究了下面的具体数字、分布和临界值:

Anupama Garla 绘制的配对图

1 预测因素:生产预算

投入电影的钱越多,电影产生的钱就越多。这可能部分是因为如今制作如此精美的动画所需的计算和人力。

Anupama Garla 的配对图

2 预测因素:分销战略和广度

这些对票房收入有重大影响。接触到广泛的观众,并在关键的剧院首演中击败竞争对手是非常值得努力的。

Anupama Garla 绘制的配对图

第三大预测因素:Metascore

批评性评论可以从无用的东西中发现宝石,然而,它本身并不是票房收入的良好指标。

Anupama Garla 绘制的配对图

4 最大的预测因素:发布月份

人们倾向于在假期和家人一起看更多的电影。高性能电影往往在五月、六月、七月、十一月和十二月上映。

Anupama Garla 绘制的配对图

第五大预测因素:电影名称中的字母数

虽然片名长度本身并不是一个预测因素,但大多数票房超过 4 亿美元的高性能电影都有 15 个字母以下的片名。

结论

线性回归模型能够充分预测票房表现。然而,该模型将受益于更多捕捉方差的特征——也许是量化明星效应或情节特征的特征。

虽然投入的资金直接反映了电影的表现,但发行和评论紧随其后。较短的标题更好,也许是因为它们更吸引人,续集往往会大获全胜!

预测德国的公寓租金价格

原文:https://towardsdatascience.com/predicting-apartment-rental-prices-in-germany-d5635197ab00?source=collection_archive---------31-----------------------

使用随机森林预测租赁价格

Unsplash 上由 Wiktor Karkocha 拍摄的照片

T 通过这篇文章,我试图使用包含德国租金价格的公寓租金数据集来预测租金价格。该数据集由从德国最大的房地产平台之一收集的数据组成。这里的主要目的是研究和理解数据,并利用这些知识构建一个基本预测模型来预测基础租赁价格(在德国通常称为“Kaltmiete”)。

原始数据集由 268850 个公寓(行)* 49 个要素(列)组成,但是缺失值和不平衡值的组合意味着在当前上下文中只有 14 个要素对我有用。这些列包含以下信息:

  1. 公寓所在的联邦州。
  2. 供暖类型:公寓使用的供暖系统类型。
  3. 阳台:列表示公寓是否有阳台。
  4. 建造年份: 公寓建造的年份。
  5. hasKitchen: 列表示公寓是否有厨房。
  6. 地窖:表示公寓是否有地窖的栏。
  7. 基本租金:不包括电费和取暖费的租金。
  8. 居住空间:以平方米为单位的居住空间。
  9. 状况:持平的状况。
  10. 电梯:表示公寓是否有电梯的栏目。
  11. typeOfFlat: 户型。
  12. noRooms: 公寓房间总数。
  13. 花园:一栏表示公寓是否有花园。
  14. regio2: 公寓所在城市。

数据框架一览(1/2)

数据框架一览(2/2)

探索性数据分析:

由于该数据集是通过网络抓取创建的,因此它远非干净。因此,挑战之一是摆脱极端和空值。例如,有几排居住空间超过 60 平方米。在€10-€30 的范围内,这是明显的异常值。还有几个房间总数超过 100 间的公寓。清理后研究得出以下结论:

1.德国平均房租最高的城市是慕尼黑,这并不奇怪,因为这座城市以生活成本高而闻名。慕尼黑市内及周边地区(用 München_Kreis 表示)也位列前十。有趣的事实是,紧随法兰克福排名第三的施塔恩堡是德国最富有的城镇。我很惊讶没有在名单上找到杜塞尔多夫和波恩。

各城市的平均租金

2.)汉堡是平均租金最高的联邦州,其次是柏林和拜仁(巴伐利亚)。东北部的萨克森-安哈尔特州和图林根州的价格最低。

各州平均租金

3.)应该是,居住空间的大小和基础租金价格似乎或多或少是正相关的。看起来像离群值的价格高的小(尺寸)公寓是位于市中心(柏林市中心,法兰克福)的公寓,这解释了成本。

总租金与居住空间

4.)德国最常见的基本租金价格在€300-€400 之间。

德国的租金分配

5.中央供暖系统似乎是德国家庭中最常见的供暖系统,远远超过其他任何一种。

6.)大多数出售的公寓都有 3 个房间,属于“公寓”类型。

每套公寓的房间数

租赁类型

模型开发:

在创建原型模型之前,转换数据集是很重要的。在将数据集输入模型之前,对数据集执行了以下预处理步骤。

  1. ‘条件’栏中的七个独特值(‘保持良好’,‘翻新’,‘第一次使用’,‘完全翻新’,‘全新状态’,
    ,‘第一次使用’,‘翻新后’,‘现代化’,‘可协商’,【T5’,‘需要翻新’,‘适合拆除’),被分成三个等级‘新’,‘旧’和‘中’公寓。这样做是为了获得更清晰的界限。
  2. 根据列值是真还是假,列【T6’‘阳台’,‘厨房’,‘地窖’,‘电梯’和【T8’‘花园’中的数据被编码为 1 或 0。
  3. 使用 sklearn 的 MinMaxScaler()对连续值变量 'baseRent ',' livingSpace' 和' noRooms '进行标准化。虽然在处理基于树的算法时,这不是一个必要的步骤,但是它简化了可解释性,并且使得与其他模型的性能比较更加容易。
  4. 分类变量使用一个热编码进行编码,通过熊猫的 get_dummies 变得容易。
  5. ‘base rent’被选为目标变量,其余为预测变量。
  6. 在应用上述步骤后,使用 sklearn 的 train_test_split 将数据集分成训练集(70%的数据)和测试集(30%的数据)。

我选择随机森林来开发原型,因为它是一个强大的模型,可以很好地处理连续变量和分类变量。

使用 RandomForestRegressor()对训练集拟合模型。使用测试集来检查模型的性能,获得了以下结果。

模型结果

该模型约占模型中数据的 83.4%,或者说该模型的预测能力为 0.83(最好为 1.0),考虑到该模型是使用默认参数运行的且未进行调整,这已经相当不错了。MSE 和 MAE 也较低。

结论:

这种模式还能改进吗?是的,当然!。这个模型远远不是最好的模型。我的第一种方法是使用网格搜索技术进行超参数调整和交叉验证,以找到理想的参数。第二,原始数据集包含许多缺少数据的列,我选择从模型中排除这些数据,这意味着丢失了相当多的信息。使用领域知识的智能插补技术可以帮助解决这个问题。原始数据集还包含描述公寓设施和描述的列。通过使用 NLP 技术,可以从这些列中获得更多的信息。较重的特征工程也会有所帮助。不用说,我将使用这些步骤作为线索来提高模型的性能。

我很想听到你对此的反馈。如果您有任何问题或建议,可以联系 me 。感谢您的阅读。

用脸书的预言家预测苹果公司的股价

原文:https://towardsdatascience.com/predicting-apple-inc-stock-prices-using-facebooks-prophet-54ed6e91dbda?source=collection_archive---------43-----------------------

时间序列预测的最新方法

亚历克斯·哈尼在 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 年以来的股价数据。

照片由芙罗莉丝·安德烈亚Unsplash 上拍摄

接下来,我们需要下载先知包。

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)

股票价格的交互式图表

尝试为不同的数据集实现该模型,看看它是否对您有益。

来自《走向数据科学》编辑的提示: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

预测新冠肺炎时代的苹果股票

原文:https://towardsdatascience.com/predicting-apple-stock-in-times-of-coronavirus-ca434bd2f788?source=collection_archive---------21-----------------------

简单是关键。

介绍

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()

为了融合商业新闻,我们需要:

  1. 与我们的目标相关的有用的新闻数据
  2. 将它融合到我们的数据中,使消息与第二天的价格“变化”(这样模型就可以学习预测第二天的价格)
  3. 将它转换成数字特征,这样它就可以遍历一个 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%

需要做的是根据情况优先考虑正面或负面建议

几天后,我将发表一篇后续文章,介绍一个模型的结果,该模型的根据增加或减少多长时间来最大化回报,在正/负建议之间切换。

用神经网络预测苹果股票价格

原文:https://towardsdatascience.com/predicting-apple-stock-prices-with-neural-networks-4aefdf10afd0?source=collection_archive---------26-----------------------

如何使用递归神经网络预测股票价格?

克里斯·利维拉尼在 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 天之间对下降做出反应。然后它赶上了上升趋势。

有许多方法可以尝试改进该模型的性能。您可以通过调整获得更好的结果:

  • 层数
  • 一层中的节点数
  • 时间步数
  • 辍学率
  • 时代数
  • 批量

感谢您的阅读。如果您有任何反馈,请告诉我。

使用公共房地美数据预测不良住房贷款——使用不平衡数据的教程

原文:https://towardsdatascience.com/predicting-bad-housing-loans-using-public-freddie-mac-data-a-tutorial-on-working-with-imbalanced-d2852c003996?source=collection_archive---------26-----------------------

机器学习能阻止下一次次贷危机吗?

房地美(Freddie Mac)是一家美国政府支持的企业,购买单户住房贷款,并将其打包作为抵押贷款支持证券出售。二级抵押贷款市场增加了新住房贷款的资金供应。然而,如果大量贷款违约,这将对经济产生连锁反应,就像我们在 2008 年金融危机中看到的那样。因此,迫切需要开发一种机器学习管道来预测贷款发放时贷款是否会违约。

在这个分析中,我使用了来自房地美单户贷款级别数据集的数据。数据集由两部分组成:(1)贷款发放数据,包含贷款开始时的所有信息;以及(2)贷款偿还数据,记录贷款的每次支付以及任何不利事件,如延迟支付甚至抛售。我主要使用还款数据来跟踪贷款的最终结果,使用原始数据来预测结果。原始数据包含以下几类字段:

  1. 唯一标识符:贷款 _ 序列号
  2. 借款人财务信息:信用评分、首次购房者标志、原始债务收入比(DTI)、借款人数、居住状况(主要住所、投资或第二套住房)
  3. 贷款信息: First_Payment (date),Maturity_Date,MI_pert (%抵押担保),原始 LTV(贷款与价值)比率,原始组合 LTV 比率,原始利率,原始未付余额,PPM(提前还款罚金抵押)标志,贷款目的(购买与再贷款),原始贷款期限,超符合标志
  4. 房产信息:单元数量,房产类型(公寓,独栋住宅等。)
  5. 位置: MSA_Code(大都市统计区),属性 _ 州,邮政编码
  6. 卖家/服务商信息:渠道(零售、经纪等。)、卖家名称、服务商名称

传统上,次级贷款被定义为信用分数为 600 或 650 的任意分界点。但这种方法是有问题的,即 600 的临界值仅占不良贷款的约 10 %, 650 仅占不良贷款的约 40%。我的希望是,原始数据的附加特征会比信用评分的硬性限制表现得更好。

按好贷款与坏贷款分组的信用评分累积直方图

因此,该模型的目标是根据贷款发放数据预测贷款是否为坏账。 在这里,我定义“好”贷款是指已经全部还清的贷款,“坏”贷款是指因任何其他原因而终止的贷款。为简单起见,我只检查 1999 年至 2003 年间产生的贷款,这些贷款已经终止,因此我们不必处理中间状态的持续贷款。其中,我将使用 1999-2002 年的贷款作为训练集和验证集;以 2003 年的数据作为测试集。

这个数据集的最大挑战是结果有多不平衡,因为不良贷款仅占所有终止贷款的大约 2%。在这里,我将展示解决这个问题的四种方法:

  1. 欠采样
  2. 过采样
  3. 把它变成一个异常检测问题
  4. 使用不平衡集成分类器

让我们开始吧:

过度/欠采样前后的不良贷款计数

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上联系我。

预测华盛顿特区的自行车共享需求(下)

原文:https://towardsdatascience.com/predicting-bike-sharing-demand-in-washington-d-c-part-2-56af211585a2?source=collection_archive---------81-----------------------

马库斯·温克勒在 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%的预测。

这就是我第二部分的内容。尽管如此,仍有许多东西可以考虑,新的工具可以使用,但这将是另一个时间。

用线性回归预测波士顿房价

原文:https://towardsdatascience.com/predicting-boston-house-prices-using-linear-regression-3c6107c662e5?source=collection_archive---------25-----------------------

线性、多元回归和正则化(LASSO、岭回归)

线性回归:理论与应用

来源: Pixabay 经【pexels.com】T2

介绍

什么是线性回归?它是一种预测性建模技术,可以发现自变量和因变量(连续变量)之间的关系。自变量(iv)s 可以是分类的(如美国,英国,0/1)或连续的 (1729,3.141 等),而因变量(dv) s 是连续的。底层函数映射 ivdv 可以是线性、二次、多项式或其他非线性函数(如逻辑回归中的 sigmoid 函数),但本文讨论的是线性技术。

回归技术在房地产价格预测、金融预测、交通到达时间(ETA)预测中被大量使用。

来源:阿尤什·潘特TowardsDataScience.com

变量的类型

分类:取不同的值:垃圾邮件/非垃圾邮件、糖尿病+ve/-ve

连续:可以取无限个值,如金钱、时间、重量。

依赖:实验结果,本博客房屋价值

独立变量:与研究者的行为无关的变量。面积、位置、卧室数量等。

如需更多参考,请查看: statistichowto

线性回归技术

1.普通最小二乘法(OLS)

OLS 中,目标是通过数据点找到最佳拟合线。最佳拟合线通过最小化距离预测线的数据平方距离的总和获得。这是一个无偏估计(尽管方差没有最小化),因为它最小化了该观察空间中数据集的偏差。

最小二乘法的目标

关键假设:

(一)OLS 假设 dviv 成线性关系。

(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 库在几行代码中实现线性回归。

  1. 获得最佳拟合线的普通最小二乘法在许多情况下效果很好,而且非常直观。
  2. 然而,当数据遭受多重共线性或异方差时,我们需要使用正则化技术来执行回归。
  3. VIF 是一种可用于检测预测变量中多重共线性的度量。
  4. 山脊线和套索线在执行回归建模方面做得很好。

快乐学习:)

附加源

  1. https://etav.github.io/python/vif_factor_python.html

用神经网络预测加州野火的规模(上)

原文:https://towardsdatascience.com/predicting-california-wildfire-size-with-neural-networks-building-a-machine-learning-project-from-db0e57dce4c9?source=collection_archive---------25-----------------------

从问题到解决方案构建机器学习项目

"你可以环游世界,但没有什么比得上黄金海岸."—凯蒂·佩里

加利福尼亚是个美丽的地方。

湾区起伏的群山(来源: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.0Node.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:

https://wild fire . Cr . USGS . gov/ArcGIS/rest/services/geomac _ dyn/MapServer/$ {year id}/query?其中=1%3D1 &外场= *&outSR = 4326&f = JSON

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://towardsdatascience.com/predicting-cardiovascular-disease-using-k-nearest-neighbors-algorithm-614b0ecbf122?source=collection_archive---------22-----------------------

用机器学习的力量预测和预防疾病

图片来源: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

数据标准化

为了确保数据在内部保持一致,以便于相互比较,对数据集中的数字数据进行了数据标准化。

分割数据集

数据分割在两种主要方法下进行,

  1. 将数据集分割为要素和标注
  • 标签——最终选择或需要预测的结果
  • 要素-用于预测标注的属性

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 值。

  1. 根据准确率选择 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(一种数字音乐服务)的用户流失

原文:https://towardsdatascience.com/predicting-churn-for-sparkify-a-music-streaming-service-59f2fd46b3a6?source=collection_archive---------62-----------------------

用 PySpark 构建客户流失预测模型。

Sparkify 是由 Udacity 创建的虚拟音乐流媒体服务

Sparkify 是一种虚构的数字音乐服务,由 Udacity 创建,旨在模拟 Spotify 或 Pandora 等现实世界的公司。在 Sparkify 上,用户可以播放免费计划或高级订阅计划的歌曲,这些计划提供了高级功能,并且没有广告。用户可以随时升级、降级或取消他们的服务。每当用户与服务交互时都会生成数据,包括播放歌曲、将歌曲添加到播放列表、用拇指向上或向下对歌曲进行评级、添加朋友、登录或注销、升级或降级等。根据经验,获得一个新客户比保留一个现有客户的成本更高,保持客户满意并识别那些有取消服务风险的用户是服务公司的高优先级任务。

因此,这个项目的目的是分析用户活动日志,并建立一个分类器来识别有可能流失的用户——取消了 Sparkify 音乐流媒体服务。此外,考虑到现实压倒性的流数据,我只使用完整 Sparkify 数据(12GB)的一小部分数据(98MB)进行数据探索和模型开发。最终的模型是使用 Spark 构建的,因此它可以扩展到在分布式集群环境中运行。

用户为什么会流失?

在假设中,用户有更多的互动与更少的摩擦应该是满意和积极的。因此,我们首先要考虑的是数据,churns 用户的行为是否与现有用户不同?

在开始回答业务问题之前,让我们探索一下日志中有哪些内容。

原始数据样本

在这里,我描述了我将用于切片和切块的主要功能:

  • userId :用户标识符
  • sessionId :日志所属的会话
  • 歌曲 :每个用户播放的歌曲
  • 注册 :用户注册时间戳
  • ts :给定事件的时间戳
  • 页面 :用户访问过的页面。
  • 等级 :免费或付费

页面字段显示用户可以在 Sparkify 上进行的活动

最后,我们需要定义流失并相应地标记流失用户。流失定义为点击了**cancellation confirmation** 页面的用户。

现在,我们将分而治之,看看搅动者用户的参与度是否低于现有用户。

下面我们深入探讨某些维度,看看流失群体和其他用户之间是否存在差异。

从上面的图表中,我们可以总结出:

  1. 流失用户在 Sparkify 上的参与度较低。
  2. 付费用户流失更多。这可能是因为付费服务不够好,或者高级功能让用户感到沮丧。
  3. 流失用户的社交联系(朋友)较少,降低了他们对平台的忠诚度。

建立机器学习模型来检测客户流失

特征工程

我们根据洞察力准备特征。关于工程过程的细节,请查看我的 Github 笔记本

创建新功能

  1. 收听的歌曲总数
  2. 竖起大拇指的次数
  3. 竖起大拇指的次数
  4. 自注册以来的总时间(总寿命)
  5. 每次会话播放的平均歌曲数
  6. 添加到播放列表的歌曲数量
  7. 朋友总数
  8. 降级(分类变量)

设置目标变量

  1. 搅拌

建模和评估

最后,我们将所有特征矢量化为一个向量,最重要的是,然后进行标准化,以避免一个较大规模的特征主导整个模型。

数据集分为 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 集群,如亚马逊 EMRIBM Watson Studio ,以利用分布式计算资源处理真实的完整数据集。

如果考虑更多的因素或添加更多的领域知识,这些特性还可以得到改进。它随着公司用户群的增长和从数据中挖掘更多洞察力而发展。

关于这个项目的更多细节,请查看我的 Github 可用这里

用 PySpark ML 预测客户流失

原文:https://towardsdatascience.com/predicting-churn-with-pyspark-ml-d65012e9ab7c?source=collection_archive---------31-----------------------

使用 Sparkify 订阅数据解决分类问题

弗兰基·查马基Unsplash 上拍摄的照片

留住客户对繁荣的企业至关重要。当我们正在享受一键订阅的数字服务时,一些公司正在拔头发,因为有人只是点击一下就退出了。如果我们能够确定哪些用户面临流失风险,那么企业就可以采取行动,并有可能留住他们。

为了实现这一点,我们需要不仅准确,而且足够强大的机器学习解决方案来快速处理大量数据。 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-302018-12-02。我们可以看到,付费层和免费层在开始时具有相似的用户会话数量和不同的用户,然后随着时间的推移,付费层的两个指标都增加了,而免费用户的指标则减少了。

一段时间内的用户活动

用户年龄(自注册后)

用户在 Sparkify 上停留多长时间后就会流失?从用户流失时的年龄直方图中,我们可以看到大多数流失发生在注册后的 100 天内。

流失时的用户年龄

特征选择

探索数据集后,选择了 11 个要素进行进一步分析:

用户信息:性别,用户 _ 年龄,付费 _ 用户,降级

活动测量:艺术家、歌曲、长度、互动、拇指向下、总时段、时段间隙

壮举直方图

相关性矩阵

  • 除了user_age之外cancelled没有明显的强预测因子
  • songs, interactions, thumbs_down, length, artists根据直方图非常相似。尽管它们都显示出彼此之间的高度相关性,但这可能是由小数据集(225 个用户)造成的。如果我们有更多的数据,我们可能会看到更多的用户行为差异。因此,我们将只排除songsartists ,因为它们总是与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 中。

参考

使用来自数字音乐流媒体应用的用户日志数据预测流失

原文:https://towardsdatascience.com/predicting-churn-with-user-log-data-from-a-digital-music-streaming-app-7c30d7206daf?source=collection_archive---------43-----------------------

当你不知道如何开始时,你应该考虑什么

照片由 @mantashesthavenUnsplash 上拍摄

预测客户流失是公司为了更好地了解客户和预测收入变化所能做的最有趣的事情之一。在这篇文章中,我将使用一个名为 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’]))

对未来的分析很有帮助的第二步是将 tsregistration 列转换成日期-时间格式,这样我们就可以读取日期和时间信息并执行一些日期操作。

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 个观察值,超调不会在结果中产生太大的差异。

在这篇文章中,我介绍了创建预测客户流失的机器学习模型的基本步骤:

  1. 问题动机
  2. 问题的定义和解决策略
  3. 基本数据清理
  4. 探索性数据分析
  5. 特征的创建
  6. 定义用于比较模型的指标
  7. 处理阶级不平衡
  8. 测试和选择模型
  9. 调整最终模型

因此,我们有一个分类模型,可以定期预测哪些注册用户更有可能取消他们的帐户,准确率为 79%。通过这种方式,Sparkify 可以在失去客户之前采取行动。

到目前为止,这是一个很好的结果,但是要改进这个模型还有很多工作要做。例如,我们可以在更大的数据集上训练分类器。如前所述,这些结果仅考虑全部数据的一小部分,随着新寄存器的加入,结果可能会发生巨大变化。

另一个改进是不仅预测注销账户的用户的流失,还预测从付费账户降级到免费账户的用户的流失。通过这种方式,Sparkfy 可以对其最重要的用户进行操作,这些用户是保持现金收入的用户。

这篇文章的详细代码可以在这个 git 仓库中找到。希望你喜欢它!

用决策树模型预测二氧化碳排放增长

原文:https://towardsdatascience.com/predicting-co2-emissions-growth-with-decision-tree-modeling-d4f588a8d8a2?source=collection_archive---------16-----------------------

基于化石/核能/可再生能源消费增长的二氧化碳增长预测

Python ETL 脚本、Tableau 探索性数据分析和 scikit-learn 决策树

二氧化碳排放量的增长是导致气候变化速度加快的一个主要因素。为了减少二氧化碳排放,各国必须发挥积极作用,遏制与排放增长最相关的能源消费活动。在当前的能源消费形势下,可再生能源(例如:风能、太阳能)的消费也越来越受到重视。为了优先考虑对减少二氧化碳排放影响最大的举措,各国必须配备高性能的未来排放预测工具。

拟议解决方案

在这个项目中,我们旨在提供这样一种工具,它使用决策树机器学习算法,根据一个州的能源消耗状况的理论变化来预测该州的排放量增长。

该工具使用 Python 脚本来提取、标准化和创建基于六个独立数据集的模型,这些数据集与州排放、经济和能源消耗概况相关。这里使用的主要 Python 库是:requests、pandas 和 scikit-learn。

该项目基于 2019 年秋季南加州大学维特比工程学院应用数据科学硕士项目 INF 550“大规模数据科学”课程的一项任务,由金善浩教授提供建议。我的搭档哈维尔布兰东也为这个项目做出了巨大贡献。

概念验证(POC)现已在我的 Github 页面-> 此处 上提供了用户友好的指南。

假设问题

我们希望为本项目提供指导的两个主要假设问题是:

  • 国家能源消耗或生产与排放有更高的关系吗?
  • 给定一个州的能源消耗增长,我们能很有把握地预测排放量是否会增长吗?

我们将使用清理数据集上的 Tableau 散点图来回答第一个问题。我们将使用 Python scikit-learn 处理转换后的数据来回答第二个问题。

ETL 和建模应用程序的结构

为了对 python 脚本和结果数据文件进行组织,我用两个子文件夹构建了存储库:

  • src —保存用于生成数据库的所有脚本,包括:驱动程序文件、python 模块需求、表格清理、线性回归和决策树脚本。这个驱动文件叫做‘Emissions _ data analysis . py’。应该从终端调用这个驱动程序,以运行所有的清理和建模脚本。
  • 数据 —保存已清洗的。csv 文件、线性回归和决策树可视化输出

src 文件夹的组织——驱动程序、清理和建模脚本位于此处

步骤 1:数据采集

该分析考虑了各州的历史排放、能源生产、能源消耗和经济数据。这些数据是从两个美国机构的网站上获得的——能源信息署 (EIA) 和经济分析局 (BEA) 。从这些 web 资源中,提取了六个表,并使用各自的 python 脚本对每个表进行了规范化。EIA 提供了涵盖 2000 年至 2016 年的国家排放、部门排放、能源生产和能源消费的数据集。这些数据发表在。该机构网站上的 csv 格式。

提取后,数据表被规范化并存储在本地。csv 文件

每个表都通过一个'-cleaning.py '脚本进行提取、转换和存储。x4 EIA 清理脚本指向。csv 文件,而 x2 BEA 脚本利用 BEA API 工具提取数据。

步骤 1:数据转换

为了实现排放、经济、能源生产和能源消耗表的连接,在写入之前,使用 python pandas 在内存中对数据进行了规范化。csv 文件到磁盘。这些数据集覆盖了不同的年份,并在不同的维度上扩展。一些数据集的属性是行,状态是列,而另一些则相反。每个脚本都必须适合数据源的原始格式,这样才能完成正确的转换。

标准化表格格式的过程是一个不可避免的障碍。然而,这一步是探索性数据分析(Tableau)和机器学习模型创建(Python)的基本先决条件。有了规范化的表格,现在可以将数据连接在一起,研究经济和环境指标之间的关系。

步骤 2:关系表的存储

清理完成后,每个数据集都作为存储库中的. csv 文件写入磁盘。我们使用的数据集相对较小,因此我们可以管理其中的存储。csv 文件在用户的机器上足够容易。

如果数据集非常大(千兆字节或兆兆字节),我们将在远程机器上实现已清理数据的存储。我们还希望使用分布式方法实现 python 数据清理,将工作分配给几个工人。

在应用程序的“数据”文件夹中存储已清理的数据文件

步骤 3:数据探索过程

在连接这些表之后, Tableau 用于探索针对假设问题的连接数据集的可视化。与假设一致,目标是揭示经济活动、能源消耗和排放之间的可预测关系。

双变量分析 —在此步骤中,探索了两个变量的许多组合,试图揭示预测关系。Tableau 用于快速构建二元可视化。在此步骤中,重点还在于回答与初始假设相关的两个问题:

每个观察代表 2016 年的一个州

1。能源生产或消费与排放的相关性更大吗? —为了探索这个问题,我们分析了 2016 年的数据,并构建了一个散点图矩阵,将生产和消费设为自变量,将源排放量(总&运输)设为因变量。这一形象化的分析清楚地表明了消费和排放之间存在着更强的联系。因为消费有很强的相关性,所以在分析的后面会对消费类型(化石燃料、核能、可再生能源)进行更深入的探讨。

“排放运输”关系中的噪音更少

2。哪些经济因素可以用来预测排放量?— 为了理解这个问题,我们选择了 2016 年的数据来创建另一个散点图矩阵,希望观察到线性关系。该散点图使用经济指标(实际国内生产总值、人口、个人收入、能源消耗)作为自变量,源排放量(总量、电力、交通)作为因变量。每个观察值反映了 2016 年的一个特定状态。为了保持这种关系,剔除了异常值,包括必须单独研究的较大状态。这些州异常值是加利福尼亚州、佛罗里达州、洛杉矶、纽约州和德克萨斯州。

从这个可视化结果来看,与运输排放的关联分数最为明显。由于强线性关系,这表明运输排放可能是使用线性回归线进行预测的强有力候选。

步骤 4:模型创建-线性回归

在观察到经济变量和运输排放之间的强线性关系后,正式定义了二元线性回归关系。这些回归使用了 2016 年的数据,并再次删除了必须单独研究的州异常值(加利福尼亚州、纽约州、德克萨斯州)。Python 脚本连接到了。csv 表并用于构建回归模型。Python 包 pandas、pyplot、matplotlib 和 scikit learn 用于模型和可视化。

每条回归线的 R 平方得分至少为 0.8659,这意味着这些线将解释因变量中至少 0.8659 的变异。如果没有行业标准的领域知识,很难相信这个度量的质量。然而,回归模型为预测运输排放提供了相对准确的工具。

从' emissions_regressions.py 创建的回归输出

步骤 5:模型创建—决策树

在确定了总排放量和能源消耗之间的关系后,工作重点转向进一步发展这种关系,寻找与排放量增加最相关的能源消耗类型(化石、核能、可再生能源)和化石燃料消耗类型(煤、天然气、石油)。Python pandas 用于数据转换,scikit-learn 用于算法和可视化。

决策树需要的数据转换,在'decision tree _ emis _ foster fuels . py

作为该分析的先决条件,必须转换数据以符合决策树分类输入要求。在此分析中,类别设置为排放量,属性设置为煤炭、天然气和石油消耗。然后,计算从 1990 年到 2016 年每个类别和属性的逐年增长。最后,每个增长指标被分类编码为 0 —减少,1 —无变化,2 —增加。对数据进行编码后,三个不同的决策树根据 1990 年至 2015 年的数据进行了训练(行数= 1250),并将增长限制在三个节点,以避免过度拟合。然后用 2015-2016 年的数据(行= 50)测试每棵树,并分析结果。

每个决策树的测试结果

在 python scikit-learn 包中, DecisionTreeClassifier 对象用于增长树并使用基尼不纯指数对数据节点进行分区。基尼系数显示了随机选择的元素被错误标记的频率。类似于使用最高信息增益的节点分裂,最小的 gini 杂质用于分裂树。此外,对于进一步的节点,DecisionTreeClassifier 对象考虑同一属性的较小分区的 gini 杂质,以最大化分类的准确性。

我们有最高的测试精度(0.94%),模型设置为预测“燃料类型”(化石、核能、可再生能源)的“所有排放”。在所述决策树(如下)中,第一个节点表明化石燃料消耗的增加对排放增加的影响最大。即使考虑到核能和可再生能源消费的增长(第二和第三节点),排放量增长预测主要反映了化石燃料的增长状况。这一观察结果反映出化石燃料的消耗与排放密切相关。然而,包括第二和第三节点(核能和可再生能源)增加了模型预测的准确性。

最高性能决策树的输出,来自'[decision tree _ emis _ all fuels . py【T1]'](https://github.com/mann-brinson/CO2Emissions_Predictive_Analysis/blob/master/src/decisiontree_emis_allfuels.py)

结论

这项研究证明:1)可以使用人口、国内生产总值和消费【线性回归】来预测州交通排放;2)减少化石燃料比可再生能源消费【决策树】对排放的影响更大。

这些都是重要的见解,因为它们为特定的行动过程提供了数据驱动的基础。例如,希望减少总体排放量的国家可以考虑鼓励减少化石燃料的消耗,而不是太阳能电池板等可再生能源的消耗。这个话题开启了关于设计减少国家二氧化碳排放的最有效途径的对话。

用模糊逻辑预测新冠肺炎感染

原文:https://towardsdatascience.com/predicting-covid-19-infection-based-on-fuzzy-logic-e434910d8809?source=collection_archive---------28-----------------------

如何利用模糊时间序列预测冠状病毒感染病例

约翰·利博特在 Unsplash 上的照片

介绍

使用时间序列预测方法是分析疫情感染率的常用方法。这将有助于我们创建更好的决策支持系统。我在这里所写的,是我在伊斯法罕科技大学 J-Asgari 教授的模糊系统课程中学到的一部分。所以我们先从时间序列的定义说起。

时间序列是在连续的、在大多数情况下是等距的时间周期/时间点对一个个体或集体现象的数量特征进行的一组有规律的时序观察[ 更确切地说是 ]。时间序列数据有两种主要的预测方法:

1-统计工具:阿玛 SARIMA 萨里玛[ 更多 ]
2-基于神经网络的智能工具,如 RNN 和 LSTM [ 更多

数据探索

我们已经查看了从这里下载的欧洲数据。此外,所有数据文件、源代码和笔记本都已上传到这个 Colab 笔记本上。让我们快速浏览一下数据集:

import pandas as pd
import warnings
import matplotlib.pylab as plt
%pylab inlinedf = pd.read_excel('COVID-19.xlsx')
df.head()

如上所示,我们必须按“continentExp”和“countriesAndTerritories”汇总数据:

#Aggregate by continentExp
continentExp = pd.pivot_table(df, values='cases', index=['dateRep'],columns=['continentExp'], aggfunc=np.sum, fill_value=0)#Aggregate by countriesAndTerritories
countriesAndTerritories = pd.pivot_table(df, values='cases', index=['dateRep'],columns=['countriesAndTerritories'], aggfunc=np.sum, fill_value=0)

按 continentExp 汇总

continentExp["Europe"].plot(figsize=(15,5), color=["green"], title='Europe')plt.show()

模糊时间序列预测

1965 年,扎德提出了模糊集的概念,作为检验未知隶属度的工具。许多模糊研究试图将这种方法作为理论框架,并广泛应用于自然科学和社会科学的研究领域,取得了良好的研究成果。模糊时间序列也是从模糊集概念中衍生出来的一种分析方法。由扎德提出的模糊集有许多表现形式,如模糊集、模糊决策分析和模糊时间序列。【1

pyFTS 库是什么?

这个软件包是为学生,研究人员,数据科学家,或谁想要利用模糊时间序列方法。这些方法提供了简单,易于使用,计算成本低,人类可读的模型,适用于统计外行专家。 Github

#install pyFTS
!pip install pyFTSCollecting pyFTS   Downloading [https://files.pythonhosted.org/packages/41/3a/c5ef1879b33fdf07dc5678e8484d9ea637924afd6c66f14d65001cb1cddf/pyFTS-1.6-py3-none-any.whl](https://files.pythonhosted.org/packages/41/3a/c5ef1879b33fdf07dc5678e8484d9ea637924afd6c66f14d65001cb1cddf/pyFTS-1.6-py3-none-any.whl) (175kB)      |████████████████████████████████| 184kB 3.3MB/s  Installing collected packages: pyFTS Successfully installed pyFTS-1.6

定义语言变量

对于语言变量,我们指的是其值为自然或人工语言中的单词或句子的变量。例如,年龄是一个语言变量,如果它的值是语言的而不是数字的,即年轻、不年轻、非常年轻、非常年轻、老、不太老和不太年轻[ 2 ]。

我们定义了 10 个变量“A0 — A9”,其中 A0 的感染度最低,A9 的感染度最高。然后进行模糊化,即通过最大化方法将每条记录集合成一个模糊集。

from pyFTS.partitioners import Griddata = data.valuesfs = Grid.GridPartitioner(data=data,npart=15)fig, ax = plt.subplots(nrows=1, ncols=1, figsize=[15,5])fs.plot(ax)

fuzzyfied = fs.fuzzyfy(data, method='maximum', mode='sets')pd.DataFrame(fuzzyfied).assign(values = list(data)).tail()

时间模式

这部分描述了考虑先例→结果逻辑已经生成的规则,例如,在 A0 先例之后,我们移动到 A0 和下一个时间步(t+1) A1。所以这里我们有:

from pyFTS.common import FLRpatterns = FLR.generate_non_recurrent_flrs(fuzzyfied)print([str(k) for k in patterns])output: 'A0 -> A0', 'A0 -> A1', 'A1 -> A1', 'A1 -> A2', 'A2 -> A2', 'A2 -> A3', 'A3 -> A3' ... ,'

规则生成

在生成模糊规则时,需要解决类之间的重叠。有两种解决重叠的方法:一种是在不考虑重叠的情况下生成模糊规则,然后通过调整模糊规则来解决重叠;另一种是在生成模糊规则的同时解决重叠。我们把前者的静态模糊规则生成和后者的动态模糊规则生成[ 更称为 ]。

根据我们上面讨论的模式,可以生成时间步长移动的规则。

from pyFTS.models import chenmodel = chen.ConventionalFTS(partitioner=fs)model.fit(data)print(model)

上述规则显示了每个语言变量的先例和后果,并生成规则。也就是说,在 A0 中发生的任何数据都有 A0 和 A1 的结果,这意味着在 A0 之后没有 A2 的数据。

模糊化和建模

模糊化就是将模糊域中的连续量分成几个层次,根据需要,每一个层次都可以看作一个模糊变量,并对应一个模糊子集或一个隶属函数[ more ]。

fuzzyfied = fs.fuzzyfy(18876, method='maximum', mode='sets')fig, ax = plt.subplots(nrows=1, ncols=1, figsize=[15,5])forecasts = model.predict(data)forecasts.insert(0,None)orig, = plot(data, label="Original data")pred, = plot(forecasts, label="fuzzified forecast")legend(handles=[orig, pred])

结论

ARIMA 时间序列预测中的方法可以预测平均误差。利用模糊时间序列中的公式,我们可以求出平均误差。模糊时间序列的误差值小于 ARIMA 时间序列的误差值。因此可以得出结论,模糊时间序列比其他时间序列模型有更好的结果。

参考

经合组织

静态模糊规则生成

使用 Prophet 和 SARIMA 模型预测新冠肺炎的推文量

科学指导

模糊时间序列的简短教程

使用邻域聚类预测德里的新冠肺炎密集区

原文:https://towardsdatascience.com/predicting-covid-19-intensive-zones-in-delhi-7e07f29a7231?source=collection_archive---------55-----------------------

对位置进行分析和分组,以制定最佳位置缓解策略

https://news.un.org/en/story/2020/02/1056562

编者注: 走向数据科学 是一份以研究数据科学和机器学习为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

1.介绍

1.1 背景

新冠肺炎是一种传染性疾病,它扰乱了地球上每个平民的日常生活,给现代世界带来了巨大灾难。该病毒主要影响肺部,全球已有 4,543,390 人感染,303,711 人因此丧生(截至 2020 年 5 月 15 日)。疫情迫使世界各国领导人采取严厉措施,如全国范围的封锁,以遏制病毒的传播。但是封锁阻碍了平民的工作和谋生,其影响不仅困扰着穷人,也困扰着社会的每一个部分,甚至政府本身。在这种情况下,经济下滑,国家可能走向衰退,人们可能被迫离开,与病毒一起工作和生活。这给像印度这样人口密度巨大的国家带来了巨大的风险。

1.2 问题

为了预见解除封锁的影响,我的研究和这本笔记本将帮助人们了解哪些社区可能会出现新冠肺炎病例激增。我将使用人口密度数据和热门地点(如热门市场)的位置数据来估计在特定地点发生的交互。这些社区将被分组,这样就可以建立共同有效的策略来处理类似的地方。我将主要关注我所在城市(印度首都德里)的预测。

1.3 利息

借此,我希望读者能够更好地了解潜在的危险区域,当局可以采取措施,事先对这些区域进行限制,以减少病毒的传播,从而减少平民生活的痛苦。

我希望并祈祷读到这封信的人平安无事。

2.数据

为了解决上述问题,我利用了以下数据:

德里的邻近地区(及其分割的基础)

德里有 9 个区,居民区都集中在其中一个区。

链接—https://en.wikipedia.org/wiki/Neighbourhoods_of_Delhi

请注意,这一数据是根据 2011 年人口普查得出的,根据目前的情况,人口普查公布了 9 个区,而不是 11 个区。因此,我将在南德里下增加东南德里的地方,在东德里下增加沙达拉的地方。

当我在地图上绘制结果时,这些数据将用于定义邻域。我借助谷歌地图中的“搜索”选项,计算出每个街区的大致坐标,并创建了自己的数据集。

热门地点的位置数据——由 Foursquare API 提供

Foursquare API 提供了与特定地点不同地点出现频率相关的数据。我将使用位置数据来识别人流密集的场所(如市场)附近的集群。这些区域将被识别为热点区域。

值得注意的是,Foursquare API 没有太多关于德里场馆的细节,因此这只是真实世界的一个大概图片。但我们可以肯定地说,这是一个很好的近似值,将满足我们的需要。

各地区的人口密度——2011 年人口普查数据

由于生活条件高度接近,人口密度数据将用于标记具有潜在高社区传播风险的地区。

链接—https://www . census 2011 . co . in/census/state/district list/Delhi . html

地区边界数据

我自己创建了一个数据集,里面有德里每个区的多边形坐标。我利用两个网站——http://nominatim.openstreetmap.org/http://polygons.openstreetmap.fr/index.py首先提取地图上一个地方的位置,然后分别提取其坐标。

3.方法学

为了预测德里的 COVID 密集区,我们将执行以下步骤:

  1. 查找每个街区的热门场地类别
  2. 使用 KMeans 聚类,根据流行的场所类别形成邻域的聚类。
  3. 叠加一层每个地区人口密度的 choropleth 图,以正确预测可能情况的严重性

最初,我开始想象社区和每个社区的活动场所。

根据社区对场地进行分组,我们看到只有 161 个社区被返回。这意味着在 177 个社区中,有 16 个没有场地结果。

现在,我创建了一个表,其中包含了在每个社区中找到的前两个场所类别。

根据找到的顶级场所,我使用 KMeans 聚类对相似的社区进行分组。我利用剪影分数比较来寻找 K 的最佳值(即聚类数)。

K 的最佳值为 6,然后用 K 均值聚类法将邻域分成 6 类。然后将结果合并到一个数据框中。

4.结果

在使用地区人口密度数据创建一个 Choropleth 地图时,我得到了这个。

此后,我将邻近区域的聚类添加到该地图上,这样我们就可以根据该地点的聚类属性和人口密度来了解邻近区域的聚类以及对它们的关注程度。

图例:

  • 最令人担忧的——红色、黄色
  • 适度关注—紫色、蓝色
  • 最不值得关注的——绿松石
  • 无关—绿色

邻域聚类属性有:

  1. 主要有“快餐店”和其他社交活动场所的社区。(最受关注)—黄色标记
  2. 有住宅区和日常平民活动区的社区。(中度相关)—蓝色标记
  3. 有许多日常生活相关场所的社区。(中度相关)—紫色标记
  4. 以“印度餐馆”为主的街区。(最受关注)—红色标记
  5. 只有基本需求场所的社区。(最不相关)—绿松石标记
  6. 场馆很少的街区。(无关)—绿色标记

5.讨论

在最终地图的帮助下,我们可以看到哪些地区容易受到病毒传播的影响,以及每个地区的哪些社区需要特别注意。

如果不及时采取措施,红色和黄色标记的地方(最受关注区域)尤其是像东北德里、北德里和中央这样的地区会使情况恶化。德里西南部和德里北部是人口稀少的地区,应该是德里最不受关注的地区。

在今后的研究中,可以进行以下改进:

  • 如前所述,Foursquare API 在用于收集关于德里的数据时并不提供非常详细的结果。在进一步的研究中,可以利用其他位置数据提供者来获得更高的准确性。
  • 此外,如果能够利用邻域边界并提取边界内的所有地点,而不是使用邻域的坐标,将会产生近乎完美的结果。
  • 该项目使用了 2011 年人口普查数据。今年是 2020 年,这意味着统计数据可能会发生很大变化。因此,根据最新的人口普查数据,当它发布时,可能会使结果更好。

6.结论

新冠肺炎在全球造成了严重破坏,现在地球上几乎一半的人都在抗击疫情。有了更好的战略和更有效的制度,我们应该能够以更好的方式解决这个问题,以便尽快解决这个问题,这不仅是为了全体人民的福利,也是为了保护经济。我希望我的这个项目有助于缓解战略的形成,以便我们都能赢得这场战斗,并尽早恢复正常生活。

我要感谢 Coursera、IBM 和所有参与数据科学专业证书课程的教师,他们向我介绍了数据科学,并使我具备了分析手头问题并得出结果所需的所有技能。最后但同样重要的是,我希望并祈祷我的读者们平安无事。

感谢您花费宝贵的时间阅读我的作品。

链接到我的笔记本—https://nb viewer . jupyter . org/github/NAND pop/Coursera _ Capstone/blob/master/Predicting % 20 covid % 20 intensive % 20 zones % 20-% 20 Delhi % 20% 28 notebook % 29 . ipynb

预测农作物产量:机器学习纳米级顶点项目

原文:https://towardsdatascience.com/predicting-crops-yield-machine-learning-nanodegree-capstone-project-e6ec9349f69?source=collection_archive---------9-----------------------

印度田间的农民— @nandhukumarndd

一.定义

简介、问题陈述和指标

训练机器来学习和产生未来预测模型的科学被广泛使用,这并不是没有意义的。农业在全球经济中发挥着至关重要的作用。随着人口的持续增长,了解世界范围内的作物产量对于应对粮食安全挑战和减少气候变化的影响至关重要。

作物产量预测是一个重要的农业问题。农业产量主要取决于天气条件(雨水、温度等)、杀虫剂。关于作物产量历史的准确信息对于做出与农业风险管理和未来预测相关的决策非常重要。

世界各地的烹饪有很大差异,但维持人类生存的基本成分非常相似。我们吃大量的玉米、小麦、大米和其他简单的农作物。在这个项目中,利用粮农组织和世界数据库的公开数据,机器学习方法被用于预测 10 种消费最多的作物。

回归分析是一种预测建模技术,调查因变量(目标)和自变量(预测值)之间的关系。用于本项目的回归模型:

  • 梯度推进回归器
  • 随机森林回归量
  • SVM
  • 决策树回归器

sk learn . metrics . R2 _ score函数计算 R(决定系数);它是可从自变量预测的因变量中方差的比例,它是一种介于 0 和 1 之间的统计度量,用于计算回归线与其拟合的数据的相似程度。如果是 1,模型 100%预测数据方差;如果它是 0,模型预测没有方差。

评估指标将是 R 分数,它将代表回归模型中项目(作物)方差的比例。默认的 SciKit-Learn 梯度推进回归器和随机森林回归器将用作基准。然后将探索几个模型来改进基准,包括决策树回归器和支持向量机(SVM)。

二。分析

收集和清理数据

数据收集是收集和测量相关变量信息的过程。粮农统计数据库提供了 300 多万个与粮食和农业有关的时序和跨部门数据。粮农组织的数据可以在 csv 格式(万岁!)。粮农统计数据库的核心数据集中包含 200 个国家和 200 多种初级产品和投入的数据。它提供国家和国际的食品和农业统计数据。首先要得到的是每个国家的农作物产量。

现在数据看起来整洁有序,但是删除了一些列,如区号、域、商品代码等,这些对分析没有任何用处。此外,将重命名为 hg/ha_yield ,以便更容易识别这是我们的作物产量产值。最终结果是一个四列的数据框架,包括:国家,项目,年份和作物产量。

使用 describe() 函数,很少能弄清楚数据框架,它从 1961 年开始,到 2016 年结束,这是粮农组织所有可用的最新数据。

气候因素包括湿度、阳光和涉及气候的因素。环境因素是指土壤条件。在这个模型中,选择了两个气候因素和一个环境因素,雨和温度。除了影响植物生长和发育的杀虫剂。

雨水对农业有着巨大的影响,除了每个国家的平均温度外,本项目的年降雨量信息也是从世界数据库中收集的。

平均降雨量的最终数据框架包括:国家、年份和年平均降雨量。数据框从 1985 年到 2017 年,另一方面,平均温度数据框包括国家、年份和平均记录温度。温度数据帧开始于 1743,结束于 2013。年份的变化会对收集的数据造成一定的影响,因为必须统一一个年份范围以不包含任何空值。

农药的数据是从粮农组织收集的,它从 1990 年开始,到 2016 年结束。将这些数据框架合并在一起,预计年份范围将从 1990 年开始,到 2013 年结束,这是 23 年的数据。

最终数据帧

上图描述了模型应用的最终数据框架和选定的特征。

正如预期的那样,数据框架从 1990 年开始,到 2013 年结束。确保没有空实体,我可以进入下一步。最后要注意的是,每一列的值的高方差,稍后我将说明这一点。

数据探索

按国家和项目分组,以便更好地理解数据集。数据框架中有 101 个国家,其中印度的农作物产量最高。此外,印度是木薯和土豆产量最高的国家。马铃薯似乎是数据集中的主要作物,在 4 个国家中最高。

现在,探索数据帧的列之间的关系,快速检查列之间的相关性的一个好方法是将相关性矩阵可视化为热图。从下面的热图可以明显看出,所有变量都是相互独立的,没有相关性。

数据帧中特征的相关热图

三。方法学

数据预处理

数据预处理是一种用于将原始数据转换成干净数据集的技术。换句话说,无论何时从不同来源收集数据,都是以原始格式收集的,这对于分析是不可行的。

在最终的数据帧中有两个分类列,分类数据是包含标签值而不是数值的变量。可能值的数量通常限于一个固定的集合,就像本例中的 items 和 countries 值。许多机器学习算法不能直接对标签数据进行操作,它们要求所有输入变量和输出变量都是数字。

这意味着分类数据必须转换成数字形式。一个热编码是一个过程,通过该过程,分类变量被转换成可以提供给 ML 算法的形式,以在预测中做得更好。为此,将使用一键编码将这两列转换为一键数字数组。

分类值表示数据集中条目的数值。这种编码将为每个类别创建一个二进制列,并返回一个包含结果的矩阵。

dataframe 的特征将类似于上面的 115 列。看一下上面的数据集,它包含的要素在量级、单位和范围上有很大差异。与低量值的要素相比,高量值的要素在距离计算中的权重要大得多。为了抑制这种效应,我们需要将所有的特征置于相同的量级。这可以通过用最小最大缩放器进行缩放来实现。

数据预处理的最后一步是训练和测试数据。数据集将被分成两个数据集,即训练数据集和测试数据集。数据通常倾向于拆分不等式,因为训练模型通常需要尽可能多的数据点。对于培训/测试,常见的拆分是 70/30 或 80/20。

训练数据集是用于训练 ML 算法以学习和产生正确预测的初始数据集。(70%的数据集是训练数据集)

型号比较和选择

在决定使用哪种算法之前,首先我们需要评估、比较并选择最适合这个特定数据集的算法。

通常,当使用给定的数据集处理机器学习问题时,我们会尝试不同的模型和技术来解决优化问题,并拟合最合适的模型,该模型既不会过拟合也不会欠拟合。

评估指标是基于 R(决定系数)回归得分函数设置的,它将代表回归模型中项目(作物)方差的比例。 R 分数显示了术语(数据点)与曲线或直线的拟合程度。

四款车型的研发结果

从上面的结果来看,决策树回归器的 R 值最高,为的 96%GradientBoostingRegressor次之,为的 89%。

我还将计算调整后的 R ,其中它也表示术语与曲线或直线的拟合程度,但会根据模型中的术语数量进行调整。如果你在一个模型中加入越来越多的无用变量,调整后的 r 平方将会减少。如果你增加更多有用的变量,调整后的 r 平方将会增加。调整后的 R 将始终小于或等于 R

R 和调整后的 R 结果。

四。结果

模型结果和结论

R 最常见的解释是回归模型与观测数据的拟合程度。对于示例,60%的 R 表明 60%的数据符合回归模型。通常,较高的 R 表示更适合该模型。从获得的结果来看,很明显,该模型与数据的吻合度达到了 96%。

特征重要性通过到达该节点的概率加权的节点杂质的减少来计算。节点概率可以通过到达节点的样本数除以样本总数来计算。该值越高,越重要,特性越重要。获得模型的 7 大重要特性:

特征重要性条形图

土豆这种作物在模型决策中具有最高的重要性,它是数据集中最高的作物。木薯也是如此,正如我们所料,我们看到了杀虫剂的影响,这是第三个最重要的特征,如果作物是红薯,我们会看到一些在数据集中特征重要性最高的作物。

如果作物生长在印度,这是有意义的,因为印度在数据集中有最大的作物总和。然后是降雨量和温度。关于这些特征的第一个假设是正确的,它们都显著影响模型中的预期作物产量。

下面的箱线图显示了每个项目的产量。土豆最高,木薯,红薯,山药。

动词 (verb 的缩写)结论和最终想法

上图包含了颠倒的决策树的图形,根在顶部,在这个例子中,根是条目 potatoes,因为它是顶部的特征。特征的重要性一目了然,关系也易于查看。

决策树算法已经成为 Kaggle 等竞赛以及商业环境中使用最多的机器学习算法之一。决策树既可以用于分类问题,也可以用于回归问题。

决策树通常从单个节点开始,分支成可能的结果。这些结果中的每一个都会导致额外的节点,这些节点又分支成其他的可能性。由正方形表示的决策节点显示要做出的决策,而结束节点显示决策路径的最终结果。一个节点代表一个输入变量(X)和该变量上的一个分割点,假设该变量是数值型的。树的叶节点(也称为终端节点)包含用于进行预测的输出变量(y)。

决策树通过对数据提出一系列问题来得出一个估计值,每个问题都会缩小我们的可能值,直到模型有足够的信心做出一个预测。问题的顺序及其内容由模型决定。另外,问的问题都是真/假的形式。决策树回归使用均方误差 (MSE)来决定将一个节点分割成两个或多个子节点。

根节点是 item potato,这是它在模型中最重要的特性。该模型会询问它是否是马铃薯,然后根据它的真假来跟踪分支。该算法首先选取一个值,并将数据分成两个子集。对于每个子集,它将分别计算 MSE。该树选择导致最小 MSE 值的值,直到它到达叶节点。

既然对分类项进行了编码,那么答案要么是 0,要么是 1,要么是,要么不是,那么深度为 1 的两个内部节点,如果遵循真分支,“是项木薯?< = 0.5”。另一个节点,会问“农药 _ 公吨< = 0.005 ”,跟随决策树到更深一层等等。

上图显示了预测的拟合优度,显示为一条线。可以看出 R 成绩优秀。这意味着我们已经找到了一个很好的拟合模型来预测某个国家的作物产量值。增加更多功能,如气候数据;风和污染,特定国家的经济状况等等可能会增强模型的预测。

那么,纳米学位值得吗?

嗯,某些部分,肯定是!如果部署部分更侧重于使用 Flask 而不是 Amazon SageMaker,我会更喜欢。

我设法在三周内完成了纳米学位,通过每个项目后的自律和满足感绝对值得。此外,可爱的升级项目专家徽章也值得你额外努力去完成每一件事。#UdacityLevelUp

(链接代码: 机器学习-顶点-项目)

参考

sci kit-learn 和 Spark 中决策树、随机森林和特征重要性的数学运算

决策树回归器深入讲解

联合国粮食及农业组织

世界银行公开数据

决策树回归

预测电信行业的客户流失

原文:https://towardsdatascience.com/predicting-customer-churn-in-the-telecommunications-industry-99a369317e91?source=collection_archive---------21-----------------------

使用特征重要性通过降维来简化问题,并为不平衡分类移动阈值。

授权 Leo Siu-Yin 通过 Shutterstock 获取图像

为什么要预测客户流失?

获得新客户比留住现有客户要昂贵得多。一些研究表明,获得一个新客户的成本是保持一个现有客户的六到七倍。

BeyondPhilosophy.com:

忠诚的客户会降低与消费者教育和营销相关的成本,尤其是当他们成为你组织的净推广者时

因此,能够主动确定最有可能离开的客户并通过了解他们的需求和提供积极的客户体验来采取预防措施非常重要。

Sharon McCutcheonUnsplash 上拍摄的照片

方法论

该项目分为 3 个阶段:

  1. 数据清理和探索性数据分析。
  2. 模型选择和阈值调整。
  3. 结果解释。

数据清理和探索性数据分析

数据来自 Kaggle,IBM 数据集。数据集有些不平衡,流失率为 26.5%。

首先检查数据的唯一客户 ID。空格被替换为 0,列在适用时被更改为数字类型。

进行 EDA 是为了理解数据。像性别这样的特征对流失影响不大,会被去掉。

使用热图绘制要素间的相关性,并丢弃彼此高度相关的要素(如下所示,相关性> 0.6)。

然后对分类特征进行一次热编码。并且通过使用算法的特征重要性属性的随机森林分类来选择前 11 个特征。

减少输入要素的数量将简化正在建模的问题并加快建模过程。

模型选择和阈值调整

使用四种模型对最终数据进行建模:逻辑回归、C-支持向量分类、K 近邻分类器和随机森林分类器。

GridSearchCV 用于调整超参数,并为每个模型找到最佳超参数。

基于阈值 0.5 的 1 类分类,发现逻辑回归模型具有最高的 ROC-AUC 得分、最低的对数损失、最高的 F1 得分和最高的回忆得分。因此,选择逻辑回归模型作为最终模型来进一步微调阈值,以提高我们数据的召回分数。

ROC-AUC 评分

原木损失

F1 分数

精确

回忆

精度是相关实例在检索到的实例中所占的比例,召回(也称为敏感度)是实际检索到的相关实例总数的比例。

在预测客户流失时,较高的召回率优于较高的精确度,因为能够预测哪些客户流失的风险较高是最理想的。然而,调整阈值以获得更高的召回率是以降低精确度为代价的。因此,需要实现平衡。在这个项目中,我选择使用 F1 分数作为衡量标准来选择我的阈值。

分类算法的工作原理是在概率被映射到类别标签之前预测概率。这是通过使用诸如 0.5 的阈值来实现的,其中等于或大于阈值的所有值被映射到一个类,而所有其他值被映射到另一个类。

由于数据具有类别不平衡,默认阈值会导致较差的分类。因此,调整用于将概率映射到分类标签的阈值非常重要。

在默认阈值为 0.5 时,逻辑回归模型给出的 F1 值为 0.58。基于 0.62 的最大 F1 分数,阈值结果是 0.36。这个新的阈值将回忆分数从 0.55 提高到 0.78。

结果解读

基于逻辑回归模型,电信公司可以专注于前两项功能,并通过以下方式减少客户流失:

  1. 与客户签订长期合同。
  2. 提高客户的在线安全性。

这里有一个链接到我的 GitHub,你可以在那里找到我的代码和演示幻灯片。也可以通过 LinkedIn 联系我。

使用逻辑回归预测客户流失

原文:https://towardsdatascience.com/predicting-customer-churn-using-logistic-regression-9543c60f6d47?source=collection_archive---------22-----------------------

我第一次接触逻辑回归算法

Unsplash 上由 Austin Distel 拍摄的照片

什么是客户流失?

流失率,也称为损耗率客户流失率,是客户停止与实体做生意的比率。它通常表示为在给定时间段内停止订购的服务用户的百分比。高客户流失率表明公司正在以惊人的速度流失客户。客户流失可归因于无数原因,公司需要通过客户数据中的模式和趋势来发现这些原因。

现代企业如今采用复杂的算法来预测最有可能流失的客户,即离开公司的客户。通过使用这种算法,公司可以提前知道最有可能放弃公司服务的客户,并因此提出客户保留策略来减轻公司可能面临的损失。

问题陈述

在前面的段落中描述客户流失的原因是因为我的下一个机器学习项目的目标是开发一种算法,可以准确预测最有可能流失的客户。

作为一个额外的挑战,我试图发现客户流失的趋势,并确定客户决定终止合同时的主要因素。在我所掌握的各种可视化库的帮助下,我能够找出控制客户流失决策的可能参数。这些因素将在本博客的后续章节中讨论。

工作流程

电信行业客户流失预测是一个机器学习问题。因此,为这个项目获取数据非常简单。我从 Kaggle 下载了数据集,并将其加载到我的 jupyter 笔记本上。此外,我还导入了完成这个项目所必需的库。现在需要的唯一任务是分析数据,清理数据,并使用清理后的数据集训练 ML 模型。

数据探索和数据工程

步骤 1:检查缺失值。

探索数据集时最重要的步骤之一是搜索缺失值。缺失值能够阻碍 ML 算法的训练过程,并影响训练模型的准确性。在数据集上使用 pandas 的 isnull()函数后,我发现数据集中没有缺失值。因此,我进入了数据探索步骤。

要素列表以及缺失值的计数。(图片由作者提供)

第二步:数据探索。

因为我现在确信我的数据集中没有丢失的值,所以我可以将注意力转向研究手头的数据。数据探索是至关重要的一步,因为它使我能够熟悉数据集中存在的不同特征以及每个特征列包含的值的类型。下面列出了我在数据探索阶段发现的数据要点。

  • 总共有 17 个分类特征和 4 个连续特征。
  • 除了“老年人”、“任期”和“每月费用”,所有其他特征都是数据类型对象。
  • 最后,数据集包含 1,869 条有过交易的客户记录和 5,163 条没有交易的客户记录。

步骤 3:数据可视化

数据可视化是任何机器学习或数据科学项目的一个关键方面。可视化通常提供数据的鸟瞰图,允许数据科学家或 ML 工程师从手头的数据中辨别趋势和模式。我使用 seaborn library 的 countplot 函数来绘制分类特征,然后试图发现客户流失的趋势。上述可视化任务的输出可以在下图中看到。

(图片由作者提供)

从上面的图片中,我能够挑出一些有趣的点,这些点在流失的客户中很普遍。以下列出了相同的内容:

  • 男性和女性的流失率几乎相当。
  • 老年人的流失率很低。
  • 拥有电话服务的客户流失率更高。
  • 有合作伙伴和家属的客户的流失率低于没有合作伙伴和家属的客户。
  • 与其他支付方式相比,使用电子支付方式的客户流失率更高。
  • 没有互联网服务的客户流失率较低。
  • 光纤互联网服务的流失率要高得多。

这种可视化通常有助于公司发现客户流失的可能原因。例如,以电子方式付款的客户更有可能流失,这可能是因为他们在进行电子付款时面临一些不便,公司可以对此进行调查,或者选择光纤互联网服务的客户对公司的流失率有很大影响,这可能暗示客户对公司提供的光纤互联网服务不满意,公司可以调查此事并尽早解决问题。数据可视化是重要的一步,因为它提供了可操作的见解,并帮助公司做出明智的决策。

步骤 4:数据工程

由于数据探索阶段现在已经完成,并且我对数据集有了很好的理解,所以我继续进行项目的数据工程部分。首先,我去掉了“客户 Id”列,因为它不会影响我们的 ML 模型的预测能力。接下来,我将所有分类特征转换成一次性编码特征。最后,数据集被分成训练和测试数据,以促进 ML 模型的训练。

机器学习模型创建和评估

第一步:训练一个机器学习模型。

随着数据探索和工程阶段的完成,我继续训练我的机器学习模型。客户流失预测是一个分类问题,因此,我使用逻辑回归算法来训练我的机器学习模型。在我看来,逻辑回归是一个相当容易实现、解释和训练非常有效的算法。此外,它在数字数据上工作得非常好。最后,可以通过逻辑回归实现的【L1】【L2】正则化技术防止模型过度拟合。

我从 sklearn 库中导入了逻辑回归模型,并对训练数据使用了“fit”函数。拟合操作一完成,我就进入下一步,评估我的 ML 模型的性能。

步骤 2:评估模型性能。

这是我的机器学习项目的最后一步,就是测试我的 ML 模型的性能。这一步至关重要,因为我可以根据看不见的客户数据来衡量我的 ML 模型的准确性。为了确定我的 ML 模型的性能,我使用了测试数据,并计算了预测标签的准确度分数以及混淆矩阵。逻辑回归模型的准确度得分为 81.5%。共有 1148 个标签被准确预测,而 259 个标签被错误预测。

结论

这个关于客户流失预测的机器学习项目给我提供了一个新的学习体验。它允许我使用各种可视化库,并让我意识到数据可视化的重要性。这也让我有机会使用一种新的 ML 算法,即逻辑回归。这个项目是机器学习在现实世界中的一个主要例子,在这个项目中工作帮助了我,磨练了我在机器学习领域的技能。

我为这个项目遵循的工作流程可以在我的Github个人资料中找到。我希望你喜欢看我的博客。

使用逻辑回归预测客户流失

原文:https://towardsdatascience.com/predicting-customer-churn-using-logistic-regression-c6076f37eaca?source=collection_archive---------5-----------------------

第 2 部分:构建模型

在我之前的帖子中,我们完成了一个客户流失分析数据集的探索性数据分析过程。我们的数据来源于 Kaggle,以客户流失率为中心,商业客户将离开他们目前是电信公司 Telco 的(付费)客户的商业平台。现在 EDA 流程已经完成,我们对数据在处理前告诉我们的东西有了很好的认识,我们可以继续构建一个逻辑回归分类模型,它将允许我们预测客户是否有从电信平台流失的风险。

完整的 GitHub 知识库和笔记本以及数据浏览可以在这里找到。

Austin DistelUnsplash 上拍摄的照片

逻辑回归

当处理我们累积到二元分离的数据时,我们希望将我们的观察结果分类为客户“会流失”或“不会流失”平台。逻辑回归模型将试图猜测属于一个或另一个群体的概率。逻辑回归本质上是线性回归的扩展,只有预测的结果值在[0,1]之间。该模型将确定我们的目标特征、流失和我们的剩余特征之间的关系,以应用概率计算来确定客户应该属于哪个类别。我们将使用 Python 中的“ScikitLearn”包。

概括数据

提醒一下,在我们的数据集中,我们有 7043 行(每行代表一个唯一的客户)和 21 列:19 个特征,1 个目标特征(客户流失)。数据由数字和分类特征组成,因此我们需要分别处理每种数据类型。

目标:

  • 客户流失—客户是否流失(是,否)

数字特征:

  • 任期——客户在公司工作的月数
  • 月度费用—每月向客户收取的费用
  • 总费用——向客户收取的总费用

分类特征:

  • CustomerID
  • 性别—男/女
  • 老年人—客户是否是老年人(1,0)
  • 合作伙伴—客户是否有合作伙伴(是,否)
  • 受抚养人——客户是否有受抚养人(是,否)
  • 电话服务—客户是否有电话服务(是,否)
  • 多条线路—客户是否有多条线路(是,否,无电话服务)
  • 互联网服务—客户的互联网服务类型(DSL、光纤、无)
  • 在线安全—客户是否有在线安全插件(是、否、无互联网服务)
  • OnlineBackup —客户是否有在线备份插件(是、否、无互联网服务)
  • 设备保护—客户是否有设备保护附件(是、否、无互联网服务)
  • 技术支持—客户是否有技术支持附加服务(是、否、无互联网服务)
  • 流媒体电视—客户是否有流媒体电视(是,否,无互联网服务)
  • 流媒体电影—客户是否有流媒体电影(是,否,无互联网服务)
  • 合同—客户合同的期限(每月、1 年、2 年)
  • 无纸账单—客户是否有无纸账单(是,否)
  • 支付方式—客户的支付方式(电子支票、邮寄支票、银行转账(自动)、信用卡(自动))

为建模预处理我们的数据

在 EDA 过程中,我们移动了一些数据,但是预处理主要是为了便于使用和消化,而不是为了模型的功能。为了进行逻辑回归,我们必须以不同的方式对数据进行预处理,特别是为了适应数据中的分类特征。让我们再看一下我们的数据信息,了解一下我们正在做什么。

我们没有任何丢失的数据,我们的数据类型是有序的。请注意,我们的大部分数据是“对象”类型,即我们的分类数据。这将是我们在预处理步骤中关注的主要领域。在数据的顶部,我们看到两个不必要的列,“未命名:0”和“客户 id”。这两列与我们的数据无关,因为前者没有任何重要的值,而后者是客户的唯一标识符,这是我们不想要的。我们通过快速熊猫切片从数据帧中快速删除这些特征:

df2 = df.iloc[:,2:]

下一步是解决我们的目标变量,流失。目前,该特性的值为“是”和“否”。这是一个二元结果,这是我们想要的,但我们的模型将无法以其当前的字符串形式有意义地解释这一点。相反,我们希望用数字二进制值替换这些变量:

df2.churn.replace({"Yes":1, "No":0}, inplace = True)

接下来,我们必须处理剩余的分类变量。虚拟变量是将名义变量作为二进制值合并到回归中的一种方式。这些变量允许计算机将分类变量的值解释为高分(1)或低分(0)。因为变量现在是数字,模型可以评估变量的方向性和重要性,而不是试图找出“是”或“否”的意思。当添加虚拟变量时,将添加新的二进制特征,其值为[0,1],我们的计算机现在可以解释。Pandas 有一个简单的函数来执行这一步。

dummy_df = pd.get_dummies(df2)

注意:当分类变量有多于二进制值时,注意“drop_first”参数是非常重要的。我们不能使用分类变量的所有值作为特征,因为这将引发多重共线性问题(计算机将对冗余信息赋予错误的意义)并破坏模型。我们必须留下一个类别作为参考类别。

我们新的数据框架特征如上,现在包括虚拟变量。

分割我们的数据

我们现在必须将数据分为目标特征和预测特征。

# Establish target feature, churn
y = dummy_df.churn.values# Drop the target feature from remaining features
X = dummy_df.drop('churn', axis = 1)# Save dataframe column titles to list, we will need them in next stepcols = X.columns

特征缩放

我们的数据几乎完全经过预处理,但还有一个更突出的问题需要解决,即缩放。我们的数据现在全是数值型数据,但是都是不同的单位。将“streamingtv_Yes”的二进制值 1 与“monthlycharges”的连续价格值进行比较不会给出任何相关信息,因为它们具有不同的单位。这些变量对模型的贡献是不一样的。为了解决这个问题,我们将通过重新调整原始变量来标准化我们的数据值,使其与其余变量具有相同的范围和方差。出于我们的目的,我们将使用最小-最大缩放 [0,1],因为标准化值将位于二进制范围内。

# Import the necessary sklearn method
from sklearn.preprocessing import MinMaxScaler# Instantiate a Min-Max scaling object
mm = MinMaxScaler()# Fit and transform our feature data into a pandas dataframe
X = pd.DataFrame(mm.fit_transform(X))

训练-测试-分离

我们现在进行标准的训练测试分割,将我们的数据分成训练集和测试集。

from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, test_size = .25, random_state = 33)

构建模型

现在可以相对快速地建立模型,我们选择一些参数:

from sklearn.linear_model import LogisticRegression# Instantiate a logistic regression model without an intercept, arbitrarily large C value will offset the lack of interceptlogreg = LogisticRegression(fit_intercept = False, C = 1e12, solver 
= 'liblinear')# Fit the model to our X and y training sets
logreg.fit(X_train, y_train)

既然我们的模型已经建立,我们必须预测我们的未来值。

y_hat_train = logreg.predict(X_train)
y_hat_test = logreg.predict(X_test)

此时,我们的模型实际上已经完全构建好了,尽管我们没有看到输出。让我们来看看评估我们的表现。

评估模型性能

分类器在训练集上正确的次数是多少?

因为我们试图预测一个客户是否会离开,有什么比看看它多长时间是正确的更好的方法来检查我们的模型性能!为此,我们将采用实际训练数据和预测训练数据之间的剩余距离,以及实际测试数据和预测测试数据之间的剩余距离。

# Find residual differences between train data and predicted train data
resiudals = np.abs(y_train, y_hat_train)# Print the number of times our model was correct ('0') and incorrect ('1')
print(pd.Series(residuals).value_counts()# Print normalized amount of times our model was correct (percentage)
print(pd.Series(residuals).value_counts(normalize = True)

非标准化训练结果:

  • 正确:4270
  • 不正确:1012

归一化训练结果:

  • 正确:. 8084
  • 不正确:1916

这挺好的!在我们的第一次测试中,80%的正确率是一个很大的数字。请记住,100%的准确性实际上会是一个问题,因为我们的模型会完全超出我们的数据。让我们检查我们的测试数据(执行与上面相同的代码块,使用 y_test 和 y_hat_test 作为剩余参数。

非标准化测试结果:

  • 正确:1409
  • 不正确:352

归一化测试结果

  • 正确:. 8001
  • 不正确:1999 年

再次,积极的结果!我们的测试集和训练集大小不同,因此归一化的结果在这里更有意义。事实上,我们的模型在我们的训练和测试集上表现得差不多,这是一个积极的迹象,表明我们的模型表现良好。

混淆矩阵

混淆矩阵是评估我们的分类器性能的一个非常强的方法。混淆矩阵是一种直观表示,它告诉我们四个重要分类指标的程度:

  • 真阳性(TP): 模型预测客户会流失(1)并且他们确实会流失(1)的观察次数
  • 真否定(TN): 模型预测客户不会流失(0),而他们实际上没有流失(0)的观察次数。
  • 误报(FP): 模型预测客户会流失的观察次数(1),但在现实生活中他们不会流失(0)。
  • 假阴性(FN): 模型预测客户不会流失的观察次数(0),但在现实生活中他们会流失(1)。

混淆矩阵的一个轴将代表真实值,而另一个轴将代表预测值。在这一步,拥有业务领域知识是非常重要的。某些度量对我们的模型来说更普遍。例如,如果我们对一个病人是否患有疾病进行建模,那么大量的假阴性会比大量的假阳性更糟糕。如果有许多假阳性,那么这仅仅意味着一些患者需要进行一些不必要的测试,可能还需要一两次烦人的医生检查。但是,高假阴性意味着许多患者实际上已经患病并被诊断为健康,这可能会产生可怕的后果。为了达到客户流失的目的,当客户实际流失时,预测客户不会流失对我们来说更糟糕,这意味着我们的假阴性更值得关注。

from sklearn.metrics import confusion_matrix# Pass actual test and predicted target test outcomes to function
cnf_matrix = confusion_matrix(y_test, y_hat_test)

混淆矩阵:

我们在 1761 次观察中有 224 次是假阴性。这比我们想要的略大,但仍然是一个有希望的数字。为了从混淆矩阵中获得真正的意义,我们必须使用这四个指标来产生更具描述性的指标:

  1. 精确度:预测的精确度
  • 精度= TP/PP
  • “在模型预测客户会流失的所有次数中,客户实际流失了多少次”

2。Recall: 表示我们感兴趣的类实际上被模型捕获的百分比

  • 召回= TP/(TP + FN)
  • “在我们看到的所有实际流失的客户中,我们的模型正确识别为‘将会流失’的客户占多少比例

3。准确性:度量模型获得正确预测的总数,包括真阳性和真阴性

  • 准确度= (TP + TN)/(TP + FP + TN + FN)
  • "在所有的预测中,有百分之多少是正确的?"

4。F1 得分:精确度和召回率的调和平均值—精确度和召回率的一个强有力的指标(在没有强有力的模型支持的情况下,不可能有高的 F1 得分)

  • F1 = 2(精度*召回)/(精度+召回)
  • 如果模型偏向于精确或召回,则严重惩罚模型
  • 通常最常用的模型性能指标

这些指标可以通过更长的路径手工计算,但对我们来说幸运的是,Sklearn 有一些模块可以为我们计算这些指标。我们要做的就是传递我们的目标数据集和我们预测的目标数据集。

from sklearn.metrics import precision_sore, recall_score, accuracy_score, f1_scoreprecision_train = precision_score(y_train, y_hat_train)
precision_test = precisoin_score(y_test, y_hat_test)recall_train = recall_score(y_train, y_hat_train)
recall_test = recall_score(y_test, y_hat_test)accuracy_train = accuracy_score(y_train, y_hat_train)
accuracy_test = accuracy_score(y_test, y_hat_test)f1_train = f1_score(y_train, y_hat_train)
f1_test = f1_score(y_test, y_hat_test)

精度:

  • 火车:0.6615
  • 测试:0.6666

回忆:

  • 火车:0.5558
  • 测试:0.5333

精度:

  • 火车:0.8084
  • 测试:0.8001

F1 得分:

  • 火车:0.6041
  • 测试:0.5926

我们的结果令人鼓舞,但并不完全令人满意。我们的查全率和查准率分数比我们预期的要低一点,但是我们的查准率分数是最强的指标,也是一个非常好的标志,尤其是在第一次尝试的时候。请记住,构建模型是一个迭代过程,因此第一次的高分是令人鼓舞的!

ROC 曲线和 AUC

另一种评估我们模型性能的综合方法和混淆矩阵的替代方法是 AUC 度量和 ROC 曲线图。

ROC 曲线——受试者操作者特征曲线

这个直观的图表将说明我们的分类器的真阳性率(召回率— TPR)与假阳性率(FPR)。表现最好的模型将有一个 ROC 曲线,它紧挨着图表的左上角。这意味着我们对积极因素的正确分类要比错误分类多得多。下图中的蓝色虚线表示 1:1 的线性关系,代表一个坏的分类器,因为模型每猜对一个就猜错一个,这比扔硬币好不了多少!

AUC —曲线下面积

AUC 将为我们提供一个单一的数字指标进行比较,而不是直观的表示。AUC = 1 表示完美的分类器,AUC = 0.5 表示只有 50%精度的分类器。这一指标量化了我们的分类器模型的总体准确性。

获取指标的编码如下:

from sklearn.metrics import roc_curve, auc# Calculate probability score of each point in training set
y_train_score = model.decision_function(X_train)# Calculate false positive rate(fpr), true pos. rate (tpr), and thresholds for train set
train_fpr, train_tpr, train_thresholds = roc_curve(y_train, y_hat_train)# Calculate probability score of each point in test set
y_test_score = model.decision_function(X_test)# Calculate fpr, tpr, and thresholds for test set
test_fpr, test_tpr, test_thresholds = roc_curve(y_test, y_hat_test)

绘制 ROC 曲线的代码:

# Plot the training FPR and TPR
plt.plot(train_fpr, train_tpr, label = 'ROC Curve')# Plot positive sloped 1:1 line for reference
plt.plot([0,1],[0,1])
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xticks([i/20.0 for i in range(21)])
plt.yticks([i/20.0 for i in range(21)])
  • 训练 AUC = 0.8517
  • 测试 AUC = 0.8388

这些指标看起来很棒!请注意,我们的测试和训练曲线都紧挨着左上角,并且具有非常强的 AUC 值。有了这样强大的模型,我们现在可以将目光转向调整一些模型参数/超参数来慢慢提升我们的分数。

结论

我们为第一轮建造了一个非常坚固的模型。构建任何机器学习模型都是一个迭代的过程,分类建模本身就有几种类型的模型。在接下来的一些帖子中,我将探索这些其他方法,如随机森林、支持向量建模和 XGboost,看看我们是否可以改进这个客户流失模型!

用 PySpark 预测客户流失

原文:https://towardsdatascience.com/predicting-customer-churn-with-pyspark-6a4526cdc0b7?source=collection_archive---------57-----------------------

Sparkify 是一种虚构的流行数字音乐服务,类似于 Spotify 或 Pandora。使用 Sparkify,许多用户可以通过这项服务播放他们最喜欢的歌曲,并可以通过在歌曲之间放置广告的免费层或使用高级订阅模式来这样做。用户可以随时升级、降级或取消他们的服务,所以确保用户喜欢这项服务非常重要。

每当用户与该服务进行交互时,无论他们是在播放歌曲、注销、竖起大拇指喜欢一首歌、听广告还是降低服务等级,它都会生成数据。所有这些数据都包含了让用户满意和帮助企业发展的关键见解。

通过 Udacity 的 Nanodegree 项目提供的这个项目,我将利用这些数据来预测哪些用户有流失的风险,要么降低他们的服务级别,要么完全取消服务。通过能够在用户离开服务之前准确识别用户,Sparkify 可能会提供折扣和激励措施,并可能为企业节省数百万美元的收入。

下面是我在这个项目中采取的一些步骤,以探索数据集,并为预测客户流失的机器学习模型做准备。

正在加载火花数据

作为任何项目的第一步,我首先需要将我的项目加载到我的环境中。我将 128MB 的数据集读入一个 spark 数据帧,首先检查我的数据集包含多少行和列以及模式。

正如您在下图中看到的,我的数据集包含 286,500 行和 18 列。大多数列被表示为 string 类型,只有少数列被表示为 long 类型。

现在让我们看看实际数据是什么样的:

通过查看数据,我可以开始了解在我的探索性数据分析步骤中哪些列可能是相关的。

清理火花数据

当我开始探索我的数据时,我知道我需要清理我的数据,以便它可以准备好构建机器学习模型。

下面我提供了一个我为这个项目经历的清洁步骤的快速总结。

  1. 检查缺少用户标识的记录
  2. 检查 sessionId 为空的记录
  3. 检查缺少性别输入的记录
  4. 检查列的分布,以删除任何可能没有变化的列(单值列)
  5. 将 ts 列转换为正确的时间戳格式
  6. 将注册转换为正确的时间戳格式
  7. 将“位置”列拆分为两个新列——用户城市和用户州
  8. 删除用户代理、方法、位置列,因为它们似乎与我的分析无关

需要注意的一点是,我当然可以采取更多的步骤来进一步清理我的数据,但是这取决于每个数据科学家决定他们何时认为他们的数据足够干净。执行完这些步骤后,我得到了比原始数据集更清晰的数据集。

现在我的数据比以前干净了,我可以开始进一步研究我的数据了。

探索性数据分析

当我开始研究我的数据时,我知道我想要找出那些正在搅动的用户。我意识到目前的数据不能直接为我提供这个答案,所以我需要首先提取这个答案,这样我就可以进一步探索我的数据。

在上一步中,我查看了数据中的每一列,并打印出了列中每个值的计数。

对于页面列,我能够找到我正在寻找的确切细节,用户在那里进入取消确认页面,用户在那里点击以便实际取消他们的会员资格。在下面我可以找到所有用户所在的页面。

现在,我已经找到了我要寻找的细节,以找出哪些用户正在翻腾,我可以把它变成自己的列

提取客户流失信息后,我可以进一步探索我的数据。

让我们根据播放的歌曲来探索 Sparkify 的整体活动。

总的来说,许多用户与这项服务互动很多,听了很多歌曲!看起来 ID 为 39 的用户总共听了大约 8000 首歌!

我知道我的数据集有相同用户的各种数据点,所以我将确保现在只查看每个唯一用户的数据。我将从客户流失列开始,了解我的数据集中有多少用户流失了。

看起来在这个包含 225 个用户的数据集中,大约有 52 个用户受到了影响。

被搅动的用户如何因他们来自哪里而不同?总的来说,我不认为这是完全相关的,但它肯定可以用来理解国家在某一时期是如何参与的。(也许在冬季,来自美国北部各州的用户听更多的音乐,因为他们可能更经常在家,并且喜欢播放音乐来娱乐,等等)

就目前而言,这并不太令人惊讶,因为加州、纽约州和佛罗里达州的人口往往更密集,我们通常可以预期更高的流失率和更高的整体参与度。由于我只有 Sparkify 数据的一个子集,我也许可以通过完整的数据集确定更多。

让我们来看看被搅动的用户在他们的订阅账户级别和性别方面是如何变化的。

对于帐户级别,它肯定表明免费层用户可能比付费订阅用户更容易流失。此外,付费用户可以简单地将他们的帐户降级为免费,而不是完全取消他们的订阅。一些可以用完整数据集进一步探索的东西。

那么,当只看被搅动的用户时,与之前可视化中的总量相比,他们听了多少首歌?

正如你所看到的,ID 为 29 的用户听了最多的歌曲,总共有 3028 首!

总的来说,数据集无疑告诉了我们很多关于通过免费或付费订阅选项订阅 Sparkify 的用户的信息。我们当然可以进一步探索数据,但对于这个项目,我已经有了下一步该做什么的想法。

数据建模

因此,我最终想用这个数据集建立各种模型来预测客户流失,但我不确定哪种预测模型最好。

对于这个项目,我将测试 2 个不同的模型。逻辑回归模型和梯度推进树分类器模型。对于建立的每个模型,我将基于准确性和 F1 分数对它们进行评估。

以下是每个型号的结果。

逻辑回归模型

https://spark . Apache . org/docs/latest/API/python/pyspark . ml . html # pyspark . ml . classification . logisticregression

梯度增强树分类器模型

https://spark . Apache . org/docs/latest/API/python/pyspark . ml . html # pyspark . ml . classification . gbt classifier

比较基本型号时,我得到以下结果:

从上面训练的模型来看,看起来 GBT 分类器在准确性和 F1 分数之间有更多的平衡。此外,对于我的下一步调整,GBT 分类器有几个选项供我调整,并可能比逻辑回归模型更多地增加我的指标。

调整我的模型

我已经选择调整 GBT 分类器模型。这些是我将调整和评估的参数:

maxIter (10,20,30)
maxDepth (3,5,10,20)
minInfoGain(0)
minInstancesPerNode(1)

通过调整超参数,我能够改进 GBT 分类器模型!这花了几个小时,但我能够改进我的模型的指标,并实现了大约 0.73 的精确度和大约 0.68 的 F-1 分数。

这些是调优后最适合我的 GBT 分类器的参数。
maxIter(20)
max depth(3)
minInfoGain(0)
minInstancesPerNode(1)

现在我有了一个已经建立和调整的模型,可以用来评估未来的用户是否会在 Sparkify 服务上流失。

结论

在这个项目中,我能够实现一个 python 笔记本,它可以加载、探索和清理客户数据,然后用于构建一个可以预测客户流失的机器学习模型。在用于预测模型的数据集中,我有 9 个特征(不包括流失特征和用户 Id)。

我能够建立两个机器学习模型。逻辑回归模型和 2。GBT 分类器模型。在比较了每个模型的准确性和 F1 值后,我确定 GBT 分类器模型是预测客户流失的最佳平衡模型。

丰富

我认为这个实现肯定可以做一些改进。在这个特定的项目中,我只使用了数据的子集(12MB)。完整的数据集为 12GB,这肯定会产生巨大的差异,并使我能够更好地了解哪些功能值得认真研究,哪些功能在创建预测模型时可能更重要。虽然 12MB 的数据肯定足以满足这个初始模型,但可能会有一些可能被忽略的不准确之处。此外,在我创建的模型中,我只是使用了一些我认为与我的模型相关的特定特征,尽管我肯定可以在最终的数据集中使用更多或所有的特征,并可能获得更好的模型。我还可以对模型的超参数进行更多的调整,尽管这会花费更多的时间和计算能力。

反射

我喜欢完成这个项目,因为它反映了一个非常真实的例子。这肯定是所有类型的客户都会经历的事情,他们希望确保他们能够真正更好地了解他们的客户,并能够在客户离开时采取主动的方法,而不是被动的方法。正如在 Udacity Nanodegree 项目之前的课程中所解释的那样,该项目以及任何其他具有大量数据的项目最重要的方面是探索和预处理数据。为了真正拥有在现实世界示例中有用的模型,需要对如何预处理数据进行大量思考,以确保您可以创建一个可用于训练模型的数据集。如果预处理不好,创建的模型可能不会像您希望的那样有效。

Github 项目

你可以在下面找到与这篇博文相关的 github 项目。

https://github . com/lrod rig-IBM/uda city-Capstone-spark ify-Project

致谢

感谢 Udacity 提供基于真实世界经验的相关数据集和数据科学纳米学位项目

预测危机期间的需求

原文:https://towardsdatascience.com/predicting-demand-during-a-crisis-4cb5f0a0259c?source=collection_archive---------50-----------------------

在不确定的世界中做出更好的需求计划决策

Fikri Rasyid 在 Unsplash 上拍摄的照片

鉴于我们全球供应链的脆弱状态,预测制造什么、运输什么、储存什么在今天比在最近的记忆中更重要。鉴于过去三周我们看到的购买行为的转变,确保消费者能够在当地杂货店找到他们需要的产品极其困难:

  • 新冠肺炎封锁彻底改变了我们生活的方方面面,包括我们购物的内容、方式、地点、时间和原因
  • 经过十多年的持续增长后,我们正在进入衰退
  • 许多人做出购买决定是出于恐惧而不是需求

随着供应链重新成为焦点,许多企业都在努力理解为什么他们的需求计划流程不起作用,以及他们可以做些什么来修复它们。以下是我和别人谈过这个问题后的看法。

短期内,预测应该退居二线

在封闭的世界中,消费者需求有着根本的不同:历史数据和基于这些数据的建模基础设施不再代表我们今天生活的世界。某些产品类别将比其他类别更能感受到这种转变的影响,但我们可以假设 2020 年 2 月之前大多数产品商店的观察是有偏差的。许多人问,其他危机事件是否可以代表我们当前的情况(例如,飓风或暴风雪使人们在室内呆了一周;12 月/1 月来自中国的早期观察),但这些事件和今天持续的全球封锁之间有太多的差异,我们无法相信这是事实。

不幸的是,留给我们的代表性数据样本非常少。集合模型(如 XGBoost)在如此小的样本量下可能会欠拟合,而时间序列模型(如 ARIMA)在零售商过去两周观察到的极端销售差异下会过拟合。在这种情况下能做些什么?

鉴于我们的观测数据如此之少,而形势发展如此之快,我们不应指望在短期内可靠地预测未来。这个疫情带来的文化和经济挑战才刚刚开始:我们现在开发的任何点估计都将非常不准确。即使我们在建模阶段很幸运,我们也没有足够的观测值来可靠地测量样本外误差。在我们有足够的数据来验证我们的预测方法之前,我们最好把时间花在别的地方。

在不确定性中做出明智的决策

鉴于我们无法再做出准确的预测,问题就变成了“在一个不确定的世界里,我们如何做出更好的供应链决策?”。

首先,我们应该强调未来几周我们将做出的许多艰难决定没有“正确”的答案。“完美是好的敌人”当然适用于这种情况:减少偏见,保持开放的心态,保持敏捷比在这个阶段纠结于数据更重要。

第二,我们应该有目的地调整我们的心智模式来进行需求规划。历史数据和稳定的预测应该打折扣,以利于新近加权模型、实时分析和已经在管理层得到验证的明智假设。我们衡量成功的方式可能必须改变,以 a)保持货架上关键消费品的可用性,b)避免可能影响我们核心业务的现金流问题。像这样的选择需要权衡,嵌入式数据科学团队非常适合就每个决策的相关风险提出建议。

最后,我们可以建立专家系统和 ML 基础设施来提醒我们何时应该重新考虑我们的假设。特别是像[帕累托/NBD 和帕累托/GGG](http://Resample your data) 这样的生成模型,可以讲述看似不稳定的购买行为背后丰富的故事。通过可视化它们随时间的后验分布,并观察它们的移动和形状变化,我们可以观察需求的转折点,并推断美国各地商店的真实情况。这些概率模型也不会给我们精确的点估计,但没关系:查看概率分布将有助于规划者自信地约束他们的决策。所有型号都是错的,但是我们的还可以用。

随着封锁解除,我们的生活变得更加确定,我们可以用短期贝叶斯预测、定制损失函数和新冠状病毒相关特征来改进我们的集合模型。在那之前,我们会做出明智的决定,将破产的风险降到最低。

预测全球难民署关注人员的人口趋势

原文:https://towardsdatascience.com/predicting-demographic-trends-for-global-unhcr-persons-of-concern-86dc4b8b920d?source=collection_archive---------37-----------------------

利用回归模型设计更好的社会支持系统

保加利亚的难民营|图片来源:论坛报达卡

介绍

在过去的十年里,难民和流离失所者的数量激增,使我们陷入了有史以来最大的难民危机。与此同时,像美国这样的国家正在接受数量少得可怜的 T2 难民,同时大力发展机构服务和支持网络。我们必须立即纠正这些侵犯人权的行为,并对我们已经看到的大规模移民进行更好的规划。

尽管数据科学和机器学习技术在历史上一直被用来对付边缘化群体,而不是增强他们的能力(只需看看凯西·奥尼尔的数学毁灭武器,如果使用正确,它们也可以用来帮助实现公平。在流离失所的背景下,我们可以开始实现预测人口迁移趋势的崇高目标。通过不仅从总人口规模的角度来看人们来自哪里,而且从人口本身的构成来看,政府和组织可以在搬迁过程中将自己置于支持流离失所者的最佳位置。显然,知道一个群体中有 70%是 4 岁以下的儿童,比不得不假设各年龄层之间的分布相等要好。

联合国难民署(UNHCR)在被归类为关注人群的个人中收集人口统计数据。这可以作为一个示例数据集来构建一个用于预测全球近期人口趋势的框架。具体来说,该工具将使用回归技术来预测八个人口统计桶中的总人数。请注意,使用这种方法可以而且应该用于更具体的人口统计数据集(按年龄、非二元性别身份等)。

方法学

预处理:就本项目而言,难民署的数据需要在国家一级进行标准化和汇总,因此可以采用一些简单的数据清理步骤,如去除星号、按国家分组、合并不总是被视为单独类别的人口统计数据,以及重命名国家,以便从中提取纬度和经度。我们也不能对只有一年数据的国家进行回归,所以这些值必须被删除。

机器学习:主模型利用简单线性回归进行预测。构建函数是为了在数据集中指定一个国家,并为特定的人口统计创建线性回归对象。然后在 test_train_split sklearn 功能中对多个测试规模应用回归,以通过 R 最大化线性回归。对于所有国家和人口统计数据,线性回归对象被转换为数据框架,以便在预测分析中轻松计算。

可视化: 用两种不同的可视化来检验预测的数据。第一幅图清楚地展示了特定年份的历史数据、回归拟合和预测值,而第二幅图则提供了以对数色标绘制的地理点地图。

支架开发

我不会在本文中讨论数据清理,但是如果你对细节感兴趣的话,可以看看我的 github。对于这个框架,我创建了三个函数,指定一个国家来获取数据,创建回归模型,并通过在 train/test/split 中迭代不同的测试规模来最大化基于 R 的回归。在这里,线性回归函数可以用其他回归模型来代替,如果它们能产生更好的拟合的话。

对柬埔寨人口统计“女性 5-17 岁”进行测试,我们得到:

现在,可以在清理后的数据集中对每个国家和人口进行迭代。显然,一些 R 值比其他值更好。稍后会详细介绍。

形象化

如上所述,该工具的可视化有两种形式——国家级和全球级。第一个是给定人口统计和国家的简单线性回归图,包括历史数据、相关回归线(R 最大化)和图表上显示所选年份预测值的特定点。第二个可视化显示了一个对数彩色比例的世界地理图,蓝色代表极少数流离失所者(0-10),红色代表特定人口和年份的大量流离失所者(1,000,000-10,000,000)。有了这个图,你可以点击任何数值,得到那个国家的预测。

可视化开发如下所示。注意,第二个函数获取输入地址的纬度和经度。

可视化示例如下所示:

结果和讨论

建立这一模型是为了更好地预测总人口中流离失所者的具体人口数量,以便更好地准备必要的服务来支持受关注的人,但结果显然缺乏统计刚性。

这项研究最大的败笔是对大量公开数据的预测能力。每个国家最多有 18 个数据点,自 2001 年以来每年一个。有了这么少量的数据和流离失所的难以置信的不稳定性,这个工具的实际预测可行性非常低-如果有的话,它只能提供方向性的答案,即我们将在哪里看到特定人口的流离失所。每次回归运行时,R 会根据国家的不同而有很大的变化,尽管是最大化的。这在人口流离失所率低的国家尤其普遍。有了更长时间的数据收集和更具体的指标,算法支架会更成功。

该工具预测能力的一个改进领域是根据趋势不可变的特定因果数据进行映射。例如,利用围绕气候变化所做的大量预测工作是有意义的,气候变化已经迫使个人流离失所,而不是试图预测特定的战争是否会爆发。这并不是说后者更重要或更不重要,而是说如果模型除了完全基于总人口流动的历史趋势进行预测之外,还智能地引入因果因素,它将得到更好的装备。本质上,流离失所趋势是复杂的,因此获得有用的信息需要引入因果数据,并利用更先进的回归模型。然而,这可以为加载、清理和转换复杂的数据集提供一个支架,以构建和分析必要的学习算法。

尽管所使用的数据集存在统计学上的缺陷,但我们还是可以收集到一些推论。基于详细描述流离失所者预测人数的对数图,我们得到了基于历史趋势的预期结果。具体来说,预计最大的人口通常来自撒哈拉以南非洲、中东、中美洲和东南亚部分地区。

一些意想不到的国家出现了我们原本没有预料到的高数据,比如德国。然而,研究通常会指出这些数字存在的原因。例如,不仅有许多流离失所者前往德国,而且政府还驱逐了其中的许多人。由于靠近许多正在经历难民危机的地区,人数不幸变得相当多。

同样显而易见的是,即使在同一个国家,人口趋势也有很大差异——如果你自己摆弄数据,你会发现一些人口随着时间的推移在下降,而另一些人口则在上升(例如,阿富汗的老年男性与年轻男性)。

有关如何利用数据科学为难民创造更加公平的环境的更多信息,请参见 Bansak、 et al. (2018)。

如有任何想法或问题,请随时联系我们,完整代码请参见 my Github 。非常感谢 Madeline Hardt 为这个项目提供咨询。

马尼拉奎松市 Barangay 预测登革热

原文:https://towardsdatascience.com/predicting-dengue-by-barangay-in-quezon-city-manila-afef0a89c03d?source=collection_archive---------42-----------------------

菲律宾奎松市——图片来自https://www . zocalopubicsquare . org/2020/05/07/letter-from-Quezon-City-Philippine-coronavirus-新冠肺炎/ideas/dispatches/

登革热是菲律宾的一个长期问题。由于热带气候和漫长的雨季,菲律宾成为携带病毒的蚊子的良好滋生地。不幸的是,登革热是无法治愈的,对于少数不幸被严重病毒感染的人来说,这可能是致命的。

预测病例数本身有助于为可能即将爆发的疫情做准备。然而,一个地方政府特别感兴趣的问题可能是:哪里我们确切地预计会有大量病例?通过定位登革热热点,官员们可以优先考虑进行蚊子存在测试和死水检查的地区,这将有助于降低爆发的可能性。

语境

一个是菲律宾最小的地理单位——大致相当于美国的一个县。初级卫生服务(据推测)是由每个镇的卫生站提供的,而镇很小,足以提供一个很好的图片,以准确地指导登革热干预措施。

换句话说,我回答了“我们在哪里预测登革热的爆发?”,通过回答“我们预测登革热在哪个镇爆发?”

方法

登革热数据来自 2016-2018 年 PhilHealth 从 Wilson Chua 先生和蚊子实时普查跟踪项目获得的记录(查看!).使用 Google API 对地址进行地理标记,然后映射到从 PhilGIS 获得的 barangay shapefiles。

特性

【NDWI】

水通常是蚊子的良好滋生地——这可能使它成为一个很好的预测器。这是使用 NDWI 量化的,它使用光吸收和反射的波长之间的差异来绘制高浓度和低浓度水的区域。使用谷歌地球引擎和 Sentinel-2 数据,对每个镇的 NDWI 值进行平均,并计算 2016 年至 2018 年期间每个月的 NDWI 值。

被吸收的光合有效辐射的分数【FAPAR】

像水一样,植被也是蚊子的良好滋生地——这可以使用 FAPAR 进行量化。它使用与 NDWI 相同的原理工作,但具有水反射和吸收的其他光谱带。还从谷歌地球引擎和 Sentinel-2 获得并处理了数据。

人口和密度

人口和人口密度值由 barangay 使用 PSA 的 2015 年数据获得。

日期变量

月份和年份用作模型的输入特征。

目标变量

利用菲律宾健康中心的数据,我们统计了每个镇每月的登革热病例数。生成了三个二元目标变量:

  • 低风险:当月,镇上至少有 1 例登革热病例
  • 中等风险:当月,镇上至少有 10 例登革热病例
  • 高风险:当月,镇上至少有 20 例登革热病例

这些值是任意的,选择这些值是为了探索模型对不同目标的预测准确性。

型号

对数据的初步扫描显示,登革热的发生相对异常——在 4825 份记录中,25%至少有 1 例登革热病例,12%至少有 10 例,4.4%至少有 20 例。

考虑到这一点,使用 SMOTE 平衡数据集,SMOTE 通过取当前数据的中点来生成新数据。这产生了一个数据集,其中一半的行是登革热阳性,一半的行是阴性。通过平衡数据,我们训练的模型不会偏向于预测一种结果而不是另一种结果。

然后,我们实施了梯度推进——一种机器学习模型,它迭代地重新加权输入,以便调整模型来分类模型以前无法分类的行。这使得它可以集中于最初可能无法正确分类的异常数据,并对这些条目进行加权,从而将模型调整到能够正确分类先前错误分类的镇的程度。

我们研究了梯度增强的三种变体:正常梯度增强、XGBoost 和轻型 GBM。

结果

这些模型在预测出现登革热病例的高风险地区时表现最佳。在三个模型中,LGBM 在预测高风险区域(97.47%的准确率)方面表现最好,而 XGBoost 在预测中等(93.67%)和低风险(80.84%)区域方面表现更好。将这些结果与纯粹的随机猜测(50.00%)进行对比——表明模型的表现并不太差。

为什么模型在高危情况下表现更好?

没有登革热病例的镇和有 1 例登革热病例的镇之间的 NDWI 或人口密度可能没有明显差异,这使得模型更难将一个镇分类为低风险或无风险。然而,一个没有病例的乡镇和 20 个病例的乡镇之间可能存在更大的差异——这使得模型更容易预测高风险地区,所达到的更高准确性就是证明。

但是,值得注意的是,大量数据被估算(实际上是创建)以创建平衡的数据集,尤其是在中高风险区域。因为这些数据是生成的,所以它遵循现有数据的模式,并且不包含来自真实世界数据的噪声——这反过来可能会使模型更容易生成更好的预测。这对我们来说意味着,虽然高风险模型在我们生成的数据上表现良好,但我们不确定它在未来的真实世界数据上表现如何。

哪些变量对将一个镇归类为有(或没有)登革热风险的影响最大?

使用 SHAP 图,我们可以看到哪些变量对模型的决策过程贡献最大,从而将镇划分为有登革热风险的镇。SHAP 值表示某个变量将模型的预测转变为支持或反对将某个镇归类为登革热阳性的程度。

读图:变量的分布表明它对模型预测的影响范围。价差越大,一个变量的影响就越大。如果红点在右边,蓝色值在左边,这意味着该变量与更高的登革热发病率正相关。右边的蓝点和左边的红点表示该变量与登革热呈负相关。

由于我们使用了二元指标(0 表示没有登革热,1 表示有登革热),一个镇的人口变量的 SHAP 值为 0.50,表明该镇的人口发生登革热的预测概率增加了 50%。

具有 XGBoost 的中等风险登革热模型的 SHAP 值

结果:人口对一个镇的登革热风险评分影响最大。正如所料,这是正相关的:人越多,患登革热的风险就越高。月份变量(从 1 到 12,每个月)也显示出正相关,这与雨季的趋势一致。一年中较早的月份相对干燥,因此“低”月份值(2 月至 5 月,标记为 2 至 5)与登革热的低风险相关,而潮湿和“高”月份值(7 月至 10 月,标记为 7 至 10)与登革热的高风险相关。

评论:结果相当令人惊讶——我预计 FAPAR、NDWI 和人口密度会产生最大的影响,因为它们直接量化了降雨量、植被和人口密度,而这些都与蚊子的繁殖和生长直接相关。然而,事实证明人口和月份的影响要大得多。这可能与 FAPAR、NDWI 或 density 的数据质量问题有关,或者它们可能不像我想象的那样具有预测性!

那又怎样?

在这个项目中,我们着眼于使用一个镇的信息来预测其发生至少 1 例登革热病例、10 例以上登革热病例和 20 例以上登革热病例的概率。然后我们发现人口多的镇在一年的后几个月最容易患登革热。对于奎松市来说,这意味着在选择实施登革热缓解计划的地方时,他们应该优先考虑人口最多的镇,并在雨季开始时这样做。

代码和谢谢

查看这里的代码:https://github.com/ljyflores/Dengue-Prediction.git

非常感谢 Wilson Chua 先生的指导和指引,以及耶鲁大学科学和社会科学信息中心的 Miriam Olivares 和 TC Chakraborty 对特征工程的帮助。

机器学习如何预测你想要购买的钻石的价格

原文:https://towardsdatascience.com/predicting-diamond-prices-using-basic-measurement-metrics-bc8ba821c8f6?source=collection_archive---------48-----------------------

使用基本测量指标预测钻石价格。

Unsplash 上的 chuttersnap 拍摄

介绍

我想一有足够的钱就给我妈妈买一枚钻石戒指。前几天,我在谷歌上搜索了它的价格,但我不知道是什么指标推动了这些价格。因此,我决定应用一些机器学习技术来找出是什么推动了一枚完美无瑕的钻石戒指的价格!

目标

构建一个 web 应用程序,用户可以在其中查找他们想要的钻石的预测价格。

数据

对于这个项目,我使用了 GitHub 上 pycaret 的 dataset 文件夹中的一个数据集,执行了数据预处理转换,并建立了一个回归模型,以使用基本的钻石测量指标来预测钻石的价格(326 美元至 18,823 美元)。数据集中的每颗钻石都有一个价格。钻石的价格由 7 个输入变量决定:

  1. 克拉重量:0.2 千克-5.01 千克
  2. 切割:一般、良好、非常好、优质、理想
  3. 颜色:从 J(最差)到 D(最好)
  4. 清晰度 : I1(最差)、SI2、SI1、VS2、VS1、VVS2、VVS1、IF(最好)
  5. 波兰 : ID(理想)、EX(优秀)、G(良好)、VG(非常好)
  6. 对称性 : ID(理想),EX(优秀),G(良好),VG(非常好)
  7. 报告 : AGSL(美国宝石协会实验室)、GIA(美国宝石学院)

👉任务

  1. 模型训练和验证:使用 Python ( PyCaret )训练、验证模型,并开发用于部署的机器学习管道。
  2. 前端 Web 应用:构建一个基本的 HTML 前端,带有自变量(克拉重量、切工、颜色、净度、抛光度、对称性、报告)的输入表单。
  3. 后端 Web 应用:使用烧瓶 框架。
  4. 部署 web 应用程序:使用 Heroku ,一旦部署,它将公开可用,并且可以通过 Web URL 访问。

💻项目工作流程

机器学习工作流程(从培训到 PaaS 部署)

任务 1 —模型训练和验证

使用 PyCaret 在 Python (Jupyter 笔记本)中进行模型训练和验证,以开发机器学习管道并训练回归模型。我使用 PyCaret 中的默认预处理设置。

from **pycaret.regression import** *s2 = setup(data, target = 'Price', session_id = 123,
           normalize = **True**,
           polynomial_features = **True**, trigonometry_features = **True**, feature_interaction=**True**, 
           bin_numeric_features= ['Carat Weight']

数据集中转换的比较

这改变了数据集,减少到 65 个用于训练的特征,而原始数据集中只有 8 个特征。

PyCaret 中的模型训练和验证:

# Model Training and Validation 
lr = **create_model**('lr')

线性回归模型的 10 倍交叉验证

在这里,均方根误差( RMSE )和平均绝对百分比误差( MAPE )受到了显著影响。

# plot the trained modelplot_model(lr)

线性回归模型的残差图

构建模型后,我将它保存为一个文件,该文件可以传输到其他应用程序并供其使用:

# save transformation pipeline and model 
save_model(lr, 'deployment_28042020')

保存模型会根据在 setup() 函数中定义的配置创建整个转换管道,并且会考虑到相互依赖关系。整个机器学习管道和线性回归模型现在保存在 save_model() 函数中。

任务 2 — 前端 Web 应用

CSS 样式表 CSS(层叠样式表)描述了用 HTML 编写的文档的呈现方式。它保存诸如颜色、字体大小、边距等信息。它被保存为链接到 HTML 代码的. css 文件。

<head>
  <meta charset="UTF-8">
  <title>Predict Diamond Price</title>
  <link href='[https://fonts.googleapis.com/css?family=Pacifico'](https://fonts.googleapis.com/css?family=Pacifico') rel='stylesheet' type='text/css'>
<link href='[https://fonts.googleapis.com/css?family=Arimo'](https://fonts.googleapis.com/css?family=Arimo') rel='stylesheet' type='text/css'>
<link href='[https://fonts.googleapis.com/css?family=Hind:300'](https://fonts.googleapis.com/css?family=Hind:300') rel='stylesheet' type='text/css'>
<link href='[https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300'](https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300') rel='stylesheet' type='text/css'>
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='./style.css') }}">

</head>

对于前端 web 应用程序,我使用了一个简单的 HTML 模板和一个 CSS 样式表来设计输入表单。下面是我们的 web 应用程序前端页面的 HTML 代码片段。

<body>
 <div class="login">
 <h1>Predict Diamond Price</h1><!-- Form to enter new data for predictions  -->
    <form action="{{ url_for('predict')}}"method="POST">
      <input type="text" name="Carat Weight" placeholder="Carat Weight" required="required" /><br>
     <input type="text" name="Cut" placeholder="Cut" required="required" /><br>
        <input type="text" name="Color" placeholder="Color" required="required" /><br>
        <input type="text" name="Clarity" placeholder="Clarity" required="required" /><br>
        <input type="text" name="Polish" placeholder="Polish" required="required" /><br>
        <input type="text" name="Symmetry" placeholder="Symmetry" required="required" /><br>
        <input type="text" name="Report" placeholder="Report" required="required" /><br>
        <button type="submit" class="btn btn-primary btn-block btn-large">Predict</button>
    </form><br>
   <br>
 </div>
 {{pred}}</body>

任务 3—后端 Web 应用程序

我使用 Flask 框架来构建后端 web 应用程序。下面是后端应用程序的 Flask 代码片段。

from flask import Flask,request, url_for, redirect, render_template, jsonify
from pycaret.regression import *
import pandas as pd
import pickle
import numpy as npapp = Flask(__name__)model = load_model('deployment_28042020')
cols = ['Carat Weight', 'Cut', 'Color', 'Clarity', 'Polish', 'Symmetry', 'Report'][@app](http://twitter.com/app).route('/')
def home():
    return render_template("home.html")[@app](http://twitter.com/app).route('/predict',methods=['POST'])
def predict():
    int_features = [x for x in request.form.values()]
    final = np.array(int_features)
    data_unseen = pd.DataFrame([final], columns = cols)
    prediction = predict_model(model, data=data_unseen, round = 0)
    prediction = int(prediction.Label[0])
    return render_template('home.html',pred='Price of the Diamond is ${}'.format(prediction))[@app](http://twitter.com/app).route('/predict_api',methods=['POST'])
def predict_api():
    data = request.get_json(force=True)
    data_unseen = pd.DataFrame([data])
    prediction = predict_model(model, data=data_unseen)
    output = prediction.Label[0]
    return jsonify(output)if __name__ == '__main__':
    app.run(debug=True)

任务 4— 部署网络应用

在训练了模型,建立了机器学习管道之后,我在 Heroku 上部署了 web 应用程序。我链接了一个 GitHub 库到 Heroku。这个项目的代码可以在我的 GitHub 库这里找到。

github.com/dhrumilpatel02/diamond-price-prediction

接下来,我在 Heroku 上部署了 web 应用程序,该应用程序发布在 URL:

https://diamond-price-prediction.herokuapp.com/

感谢 PyCaret 的创始人和主要作者, Moez Ali 。这个项目的过程灵感来自于他最近在的帖子

感谢阅读!

您可以通过以下方式联系到我:

  1. LinkedIn 这里关注/联系我。
  2. GitHub 这里关注我。
  3. 查看我的网站 这里

用随机森林回归预测电子商务销售额

原文:https://towardsdatascience.com/predicting-e-commerce-sales-with-a-random-forest-regression-3f3c8783e49b?source=collection_archive---------25-----------------------

使用真实生活数据的基础教程

rupixen.comUnsplash 上拍照

数据集

为了演示随机森林回归,将使用流行的在线零售商 Wish 的电子商务销售数据集。这些数据来自 Kaggle ,并且只展示了夏季服装的销售信息。这些属性包括产品描述、评级、是否使用了广告宣传、产品列表中是否添加了紧急文本以及售出的数量等。

为了显示随机森林回归的威力,将预测售出的单位数。不仅对于需要估计订购或生产多少产品的库存计划人员来说,而且对于需要了解产品在电子商务环境中如何移动的销售人员来说,做出良好、准确的预测都是非常宝贵的。

导入和清理数据

所有的数据导入和操作都将通过 python 以及 pandas 和 numpy 库来完成。

import pandas as pd
import numpy as np# import the data saved as a csv
df = pd.read_csv("Summer_Sales_08.2020.csv")

前两行只是导入 pandas 和 numpy 库。最后一行读取先前保存并重命名为“Summer_Sales_08.2020”的 CSV 文件,并创建一个数据框。

df["has_urgency_banner"] = df["has_urgency_banner"].fillna(0)df["discount"] = (df["retail_price"] - df["price"])/df["retail_price"]

查看数据时,“has_urgency_banner”列编码不正确,该列指示是否对产品列表应用了紧急横幅。当横幅没有被使用时,它只是留下空白,而不是使用 1 和 0。第一行代码用 0 填充这些空白。

第二行创建一个名为“discount”的新列,它计算产品相对于列出的零售价格的折扣。

df["rating_five_percent"] = df["rating_five_count"]/df["rating_count"]
df["rating_four_percent"] = df["rating_four_count"]/df["rating_count"]
df["rating_three_percent"] = df["rating_three_count"]/df["rating_count"]
df["rating_two_percent"] = df["rating_two_count"]/df["rating_count"]
df["rating_one_percent"] = df["rating_one_count"]/df["rating_count"]

原始数据集包括几个专用于产品评级的列。除了平均评级,它还包括评级总数以及五星、四星、三星、二星和一星评论的数量。因为已经考虑了评论的总数,所以最好将星级作为总评分的百分比来看,这样可以在产品之间进行直接比较。

上面几行简单地创建了五个新列,给出了数据集中每个产品的五星、四星、三星、二星和一星评论的百分比。

ratings = [
    "rating_five_percent",
    "rating_four_percent",
    "rating_three_percent",
    "rating_two_percent",
    "rating_one_percent"
]for rating in ratings:
    df[rating] = df[rating].apply(lambda x: x if x>= 0 and x<= 1 else 0)

虽然 pandas 在除以 0 时不会抛出错误,但在试图分析数据时会产生问题。在这种情况下,评分为 0 的产品在上一步计算时会产生问题。

上面的代码片段遍历所有新生成的列,并检查输入的值是否在 0 和 1 之间,包括 0 和 1。如果不是,它们会被替换为 0,这是一个合适的替代。

数据探索

import seaborn as sns# Distribution plot on price
sns.distplot(df['price'])

价格分布图。图由作者制作。

上面的代码生成了数据集中所有产品的价格分布图。最明显也是最有趣的发现是,没有任何产品花费€10 英镑。这可能是商家为了让他们的产品出现在“€10 岁及以下”名单上而故意做出的努力。

sns.jointplot(x = "rating", y = "units_sold", data = df, kind = "scatter")

收视率和销售量之间的散点图。图由作者制作。

上图显示,绝大多数销售都是在三星和四星半之间。它还显示,大多数产品的销量不到 2 万件,少数产品的销量分别为 6 万件和 10 万件。

作为一个旁白,散点图组织成线的趋势表明,销售单位更可能是一个估计,而不是硬数字。

sns.jointplot(x = "rating_count", y = "units_sold", data = df, kind = "reg")

收视率和销售量之间的散点图。图由作者制作。

这张图表展示了评级的另一面。评级的数量和产品销售的可能性之间有一种松散但积极的关系。这可能是因为消费者在考虑购买时会同时考虑总体评分和评分数量,或者是因为高销量的产品自然会产生更多的评分。

如果没有关于购买时间和评级发布时间的额外数据,如果没有额外的领域知识,很难辨别相关性的原因。

什么是随机森林回归?

简而言之,随机森林回归是一系列决策树的平均结果。决策树就像一个流程图,它提出一系列问题,并根据这些问题的答案做出预测。例如,试图预测网球运动员是否会去球场的决策树可能会问:正在下雨吗?如果是,球场在室内吗?如果没有,玩家能找到伴侣吗?

一个简单的决策树。图由作者制作。

决策树将在做出预测之前回答每一个问题。虽然容易理解,而且根据一些专家的说法,比其他机器学习技术更好地模拟实际的人类行为,但它们经常过度拟合数据,这意味着它们经常可以在类似的数据集上给出非常不同的结果。

为了解决这个问题,从相同的数据集中取出多个决策树,打包,并返回结果的平均值。这就是所谓的随机森林回归。

一个简单的随机森林。图由作者制作。

它的主要优势是对高度非线性的数据做出准确的预测。在愿望数据集中,在评级中可以看到非线性关系。没有一个很好的,容易看到的相关性,但低于三颗星和高于四颗半的截止点是显而易见的。随机森林回归可以识别这种模式,并将其纳入结果中。然而,在一个更传统的线性回归中,它只会混淆它的预测。

此外,随机森林分类器是高效的,可以处理许多输入变量,并且通常做出准确的预测。这是一个非常强大的工具,并且不需要太多代码来实现。

实现随机森林回归

from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor# Divide the data between units sold and influencing factors
X = df.filter([
    "price",
    "discount",
    "uses_ad_boosts",
    "rating",
    "rating_count",
    "rating_five_percent",
    "rating_four_percent",
    "rating_three_percent",
    "rating_two_percent",
    "rating_one_percent",
    "has_urgency_banner",
    "merchant_rating",
    "merchant_rating_count",
    "merchant_has_profile_picture"
])Y = df["units_sold"]# Split the data into training and testing sets
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.33, random_state = 42)

在运行任何模型之前,前两行导入相关的库。下一组行创建两个变量 X 和 Y,然后将它们分成训练和测试数据。测试大小为 0.33,这确保了大约三分之二的数据将用于训练数据,三分之一将用于测试数据的准确性。

# Set up and run the model
RFRegressor = RandomForestRegressor(n_estimators = 20)
RFRegressor.fit(X_train, Y_train)

接下来,模型实际上被初始化并运行。注意,参数 n_estimators 表示要使用的决策树的数量。

predictions = RFRegressor.predict(X_test)
error = Y_test - predictions

最后,新拟合的随机森林回归被应用于测试数据,并且取差来产生误差阵列。这就是全部了!

结论

Wish 数据集提供了一个数字游戏场,可用于解决现实世界的问题。通过最少的数据操作,随机森林回归被证明是分析这些数据并提供实际结果的无价工具。

用 Keras 和 Python 预测停电

原文:https://towardsdatascience.com/predicting-electricity-outage-with-keras-and-python-fbd1b299a24e?source=collection_archive---------34-----------------------

知道你所在的城市什么时候、什么地方会停电,会停电多长时间

在本文中,我们将探索我和我的团队开发一个 web 应用程序来预测班加罗尔停电的概率的过程。只要能收集到足够的数据,结果可以在任何城市重现。

第 1 部分:整合数据

我们从 BESCOM 的网站上找到了公开的非计划停电数据。虽然这不是一个优雅的解决方案,但由于网站一次加载所有 50,000+行,一个简单的 Ctrl+A,Ctrl+CCtrl+V 到一个 excel 表中,使我们免于编写复杂的废弃代码。

显示从 BESCOM 网站“复制”的数据的 Excel 表格

将它加载到我们的 python 代码中相当简单。我们的文件被保存为BESCOM-electricity-data-orange . xlsx .

 Sl. No.    ...     Updated By
0      1.0    ...         Sushma
1      2.0    ...         Sushma
2      3.0    ...         Sushma
3      4.0    ...         SUSHMA
4      5.0    ...      Devaraj R[5 rows x 12 columns]

为了查看所有单独的列,我们使用

array(['Sl. No.', 'Circle', 'Division', 'Subdivision', 'Substation',
       'From', 'To', 'LC Duration', 'Feeders', 'Areas Affected',
       'Reason For LC', 'Updated By'], dtype=object)

由于这些属性中的大多数并没有为我们的理解增加很多信息,为了使我们的任务更简单和更容易可视化,我们将只保留列 Sl。号,分割,从LC 持续时间。

 Division                From     LC Duration
0          HSR Division 2019-11-06 21:07:00  0 days 1 hours
1          HSR Division 2019-11-06 16:00:00  0 days 2 hours
2  Koramangala Division 2019-11-06 14:00:00  0 days 2 hours
3          HSR Division 2019-11-06 14:29:00  0 days 1 hours
4           Indiranagar 2019-11-06 13:00:00  0 days 2 hours

接下来,我们需要添加关于某一天是否是假日的数据。直觉告诉我们,节假日的用电量会增加,因此停电的可能性更大。为此,我们首先找到数据集中包含的最早和最早的日期。

Timestamp('2019-11-06 21:07:00')
Timestamp('2014-05-05 02:40:00')

现在,我们找到该范围内的所有公共假日,并将它们添加到单独的 excel 表 holidayData.xlsx.

所有假期的列表

下一步是将这些假期映射到我们现有的数据集中。为此,我们在数据集中创建另一个名为 Holiday 的列,并将所有行赋值为零。查看日期,我们将列更新为“1 ”,即出现在 holidayData.xlsx 中的日期。

Holiday  Division   From  LC Duration   Date                                   
    0.0     16136  16179        16179  16179
    1.0      1116   1117         1117   1117

接下来,我们将绘制各个分区的人口图,人口越多的分区理论上遭受停电的几率就越高。

首先,我们找到独特的部门列表

array(['HSR Division', 'Koramangala Division', 'Indiranagar',
       'Shivajinagar', 'Hebbal', 'Whitefield', 'Malleshwaram',
       'Rajaji Nagara Division', 'Jayanagar', 'Jalahalli',
       'Kengeri Division', 'R R NAGAR', 'Vidhanasoudha',
       'Peenya Division', nan], dtype=object)

我们现在找到了这些地区的估计人口。这项任务的准确性因数据是否公开而异。在我们的例子中,上一次人口普查是在 2011 年进行的,所以我们必须推断人口数来反映班加罗尔当前的总人口。由于只有 14 个区域,我们将在字典中输入这些值,而不是将这些数据添加到另一个 excel 文件中。然后,我们在数据集中创建另一个名为人口的列,并为其分配与部门相同的值。然后我们使用 python 中的替换函数,用 div_pop_dict 中的替换 Population 中的

0    105265.0
1    105265.0
2     63987.0
3    105265.0
4     58830.0
Name: Population, dtype: float64

接下来,我们发现了之前提到的日期范围内的每日最低和最高温度。这些数据存储在 weather_data_max_min.xlsx 中。我们将加载数据集并将 datetime 值更改为日期。

 Date  Max Temp  Min Temp
0  2014-01-01      18.7      14.8
1  2014-01-02      27.3      15.4
2  2014-01-03      27.7      13.1
3  2014-01-04      29.5      12.0
4  2014-01-05      29.6      14.1

现在,我们遵循与人口数据集相同的流程,即创建一个包含日期和温度值的字典,并用最低/最高温度替换断电日期。

 Max Temp Min Temp
0     34.3     15.3
1     34.3     15.3
2     34.3     15.3
3     34.3     15.3
4     34.3     15.3

这些都是我们将在这个例子中使用的特性。

现在,我们需要为分类创建标签。现在我们已经详细了解了产生和中断的特征组合。然而,我们需要将关于哪些条件不会导致断电的数据输入到模型中,以便正确理解区别并相应地制定规则。

我们将如何处理这个特殊的问题是通过选择每一行,其中我们有断电发生的时间和地点的日期和时间,并将其标记为断电的日期和时间。对于所有其他持续时间,除了时间之外的完全相同的特征组合的标签被标记为‘0’表示不停机。为了进一步说明这一点,我们举一个例子:

假设选择了下面的行:

然后将断电标记为‘1】,如下所示:

请注意,这一特定停机发生的时间大致在2100-2200 小时之间。因此,我们可以得出结论,在0000–2100 和 2200–0000 之间的持续时间内可能没有断电。因此,我们可以复制具有这些持续时间的行,并将它们标记为‘0’表示不中断。获取:

作为训练前的最后一步,我们需要将一键编码的值。这意味着,划分(英迪拉那加,科拉曼加拉,HSR 布局……)对计算机来说毫无意义。因此,我们为这些划分中的每一个划分形成单独的列,每行可以有 0/1。例如,假设为 Indirangar 的分部形成了一行,行中的值 0 将意味着该特定行没有 Indiranagar 作为其分部,而值 1 将表明它是。这让计算机用自己的术语理解数据,并形成更好的模式。为了更深入地理解一键编码,你可以阅读这篇文章。

这给出了下面的列,我们可以注意到,在每一行中,只有一列的值为“1 ”,表示分部。

一个热编码分区

第 2 部分:训练数据

在训练数据之前,我们需要对其进行缩放。这意味着不同的特征具有不同的取值范围,而神经网络通常工作得最好的是作为其输入的值在 -1 到+1 或 0 到 1 的范围内。因此,我们在单个特征自身的尺度上对其进行缩放,以降低给定范围内的所有值,同时保持其内在差异。

这通过找到列的平均值和标准偏差,然后转换列,使缩放器适合数据。当另一个数据集需要被缩放以提供给神经网络进行预测时,我们应该不要再次拟合缩放器,而只是将其转换并馈入神经网络。

缩放数据

接下来,我们需要将数据集分割成一个训练和测试集。训练集用于训练模型,测试集用于评估模型的准确性。

现在是我们定义神经网络模型的时候了。我们为我们的工作选择了一个具有 3 个隐藏层的序列模型。

定义模型后,我们的艰苦工作就完成了,现在是时候满意地观看我们的模型火车了:

*Epoch 1/20
81987/81987 [==============================] - 3s 35us/step - loss: 0.4935 - accuracy: 0.7443
Epoch 2/20
81987/81987 [==============================] - 3s 33us/step - loss: 0.4333 - accuracy: 0.7874
Epoch 3/20
81987/81987 [==============================] - 3s 33us/step - loss: 0.4259 - accuracy: 0.7900
Epoch 4/20
81987/81987 [==============================] - 3s 31us/step - loss: 0.4186 - accuracy: 0.7923
Epoch 5/20
81987/81987 [==============================] - 3s 32us/step - loss: 0.4147 - accuracy: 0.7949
Epoch 6/20
81987/81987 [==============================] - 3s 31us/step - loss: 0.4121 - accuracy: 0.7977
Epoch 7/20
81987/81987 [==============================] - 3s 32us/step - loss: 0.4097 - accuracy: 0.7983
Epoch 8/20
81987/81987 [==============================] - 3s 31us/step - loss: 0.4080 - accuracy: 0.7988
Epoch 9/20
81987/81987 [==============================] - 3s 32us/step - loss: 0.4058 - accuracy: 0.8007
Epoch 10/20
81987/81987 [==============================] - 3s 31us/step - loss: 0.4041 - accuracy: 0.8015
Epoch 11/20
81987/81987 [==============================] - 3s 31us/step - loss: 0.4039 - accuracy: 0.8020
Epoch 12/20
81987/81987 [==============================] - 3s 32us/step - loss: 0.4020 - accuracy: 0.8024
Epoch 13/20
81987/81987 [==============================] - 3s 32us/step - loss: 0.4004 - accuracy: 0.8043
Epoch 14/20
81987/81987 [==============================] - 3s 31us/step - loss: 0.3989 - accuracy: 0.8046
Epoch 15/20
81987/81987 [==============================] - 3s 32us/step - loss: 0.3984 - accuracy: 0.8056
Epoch 16/20
81987/81987 [==============================] - 3s 31us/step - loss: 0.3974 - accuracy: 0.8057
Epoch 17/20
81987/81987 [==============================] - 3s 31us/step - loss: 0.3964 - accuracy: 0.8062
Epoch 18/20
81987/81987 [==============================] - 3s 31us/step - loss: 0.3952 - accuracy: 0.8067
Epoch 19/20
81987/81987 [==============================] - 3s 32us/step - loss: 0.3944 - accuracy: 0.8075
Epoch 20/20
81987/81987 [==============================] - 3s 31us/step - loss: 0.3934 - accuracy: 0.8080*

测试训练好的模型:

*20497/20497 [==============================] - 1s 34us/step
Out[80]: [0.38760558974482917, 0.7936800527572632]*

我们已经实现了大约 80%的训练准确率和大约 79%的测试准确率。这可以通过调整神经网络架构来改善。

这篇文章就到这里吧各位!感谢您的阅读,如果您觉得这对您有用,请发表评论。这也是我的第一篇中型文章,所以任何关于我无意中出错的事情的指点都是非常感谢的!

你可以在 GitHub 上找到完整的项目。在 Linkedin 上与我联系,或者查看我的网站。

* [## 卡尔潘·慕克吉

我是一名 20 岁的信息科学与工程专业的学生,是一名有抱负的软件开发人员,住在班加罗尔…

卡尔潘.代码](https://kalpan.codes)

别忘了给我你的👏!

*

预测能源产量

原文:https://towardsdatascience.com/predicting-energy-production-d18fabd60f4f?source=collection_archive---------58-----------------------

使用深度学习神经网络模型

作为为 AI4IMPACT 的深度学习 Datathon 2020 创建的,团队默认创建了一个基于神经网络的深度学习模型,用于预测法国的能源生产需求。该模型是使用 Smojo 在 AI4IMPACT 创新的基于云的学习和模型部署系统上创建的。

我们的模型能够达到 0.131 的测试损失,这大大超过了 0.485 的持续性损失。

一些背景

随着全球能源市场变得越来越自由化,自由开放的市场已经看到了优化能源需求的上升和重要性。新的和现有的进入者转向数据和各种方法来预测能源消耗,希望能够获得利润。

这对于寻求转换和采用清洁/可再生能源发电以减少碳足迹、满足监管标准或干脆不投资碳捕获技术的国家尤其重要。因为太阳不会整天照耀,风也不会吹,所以预测能源需求比以往任何时候都更有助于防止短缺和停电。

随着人工智能(AI)和机器学习的出现,零售商和贸易商已经利用人工神经网络的潜力来优化能源需求,从而优化产量。

照片由 Unsplash 上的khaméo Vilaysing拍摄

任务

我们项目的目标是使用神经网络深度学习模型为我们的客户最大化利润,该模型预测未来 18 小时的能源需求。

该模型将于 7 月 21 日至 7 月 29 日实时运行,在此期间,利润和排行榜排名将被实时跟踪。该模型将建立在 AI4IMPACT 开发的 AI 开发工具 Autocaffe 上。

我们的目标是获得 T+18 小时的能量预测,每小时。目标是利用你的能源产量预测和给定的交易算法为你的客户实现利润最大化。

以下参数起作用:

  1. 你的客户每向电网出售一千瓦时可获得 10 欧分。你只能向电网出售你对该日期的预测。
  2. 如果实际发电量超过预测,超出部分将被电网吸收,但您的客户不会因此得到补偿。
  3. 如果实际发电量低于预测,您必须从现货市场购买能源(每千瓦时 20 欧分)供应给电网。

前 18 个小时(称为“热身”)不进行任何交易。每小时预热后,您需要生成一个 T+18 小时的能源产量预测。这就是所谓的“交易期”。交易在周末和公共假日继续,24x7。交易在评估期结束时结束。

开始时你会得到 10,000,000 欧元的现金。您需要在评估期结束时返还该金额。剩下的是你的客户的利润,这是你的工作最大化。****

数据

使用了 2 个数据集:风能产量和风速

风能生产的来源来自法国能源传输管理局。

近实时风能实际值来自 RTE 的在线数据库,我们将其平均并标准化为 1 小时的时基。

  • 提供了从 2020 年 1 月 1 日到 2020 年 7 月 19 日每天和每小时的数据。
  • 发电量值以千瓦时为单位。
  • 数据集被标准化为 1 小时的值

初步分析(季节性/趋势)

总体趋势

以每日分辨率查看整个日期范围,我们可以拟合一条简单的递增多项式阶 2 线,并观察能量需求随时间的逐渐增加。

总体趋势

月度趋势

按季度分析数据,我们发现不同的季度有不同的能源需求。趋势似乎是,它在第一季度(1 月、2 月和 3 月)达到最大值,并在其余月份持续下降,直到从第三季度开始增加到第二年的第一季度。

每月趋势

每周趋势

以每周一次的分辨率检查数据,我们观察到了几周内能源需求的差异。通过计算一天的平均能量产出,我们注意到能量产出往往在周一最高,周二最低。

似乎趋势是能源需求在周二开始处于低位,周三增加,周六减少,然后在周日和周一增加。

每周趋势

数据预处理

从下面的数据集可以看出,这些值具有季节性趋势,每年 11 月至 3 月期间产生的能量更多。此外,根据风电场信息,2017 年 8 月和 2019 年 7 月新增风电场。为了确保我们能够以最小的漂移获得足够大的数据集,我们决定从 2019 年 1 月 1 日到现在获取数据集。

随着时间推移产生的能量

我们只考虑从 2019 年 1 月 1 日开始的发电量数据的 3 位小数作为我们的第一列数据,并获取不同位置的风速值,计算风速的平均值作为我们的第二列数据。

smojo 配置

下图显示了从 2019 年 1 月 1 日开始的能源和风速图表。这两个变量之间有明显的密切相关性。可以作出的进一步推论是,在增加新的生产者之后,通常能量生产率更高。风向对发电量也没有太大的贡献,因此被忽略。

一段时间内的发电量和风速

使用 autocaffe,我们计算了所考虑的两个变量的统计数据。以下数据是用于两个变量标准化的值。我们还发现持续性值为 0.485,在开发我们的交易模型时,我们必须打破这个值。

数据集统计

训练/测试分割

数据集的 70:30 训练/测试分割用于确保足够的训练。趋向于比率平衡的比率可能导致测试和进一步的新数据的欠拟合。

利润基准

为了找出可获得的最大利润,我们采用了从 2019 年 1 月 1 日到现在产生的能量总和 x10 美分 x 0.3 来说明训练/测试分割。基准测试的原因将允许我们测试利润。我们在整个期间能够获得的最大利润将是 9.972E+08 美分。

特征选择和模型构建流程

下面是团队为得出最终模型所经历的迭代过程的总结。下面详细介绍了各个迭代

模型迭代摘要

#1 幼稚网络

击败比分: 485 /击败利润:9.972E+08 欧分

型号#1 配置

模型#1 结果

首先,我们从一个简单的网络开始,用数据来测试我们的第一轮结果。该能量窗口包括从 T-24 到 T-0 小时平均值和标准偏差值的特征。风速窗口仅包括 T-0 到 T+18 小时的数据。我们的神经网络有 3 种不同的大小,分别是 32、64 和 128 个节点。我们选择的求解器类型是 Adam,在神经网络中有 3 个隐藏层。第一次运行将不包括超参数调整。

下面我们从第一次测试运行中获得的结果表明,我们的最佳测试损失是 0.388224。我们这次的利润总计为 3.354E8 欧分,这只是可获得的最大利润的 33.6%。我们的实际与测试预测图也非常分散,这很糟糕,因为这表明我们的模型不可靠且不准确。滞后峰值也在 18,这很糟糕。

#2 更多功能

预期得分:0.38824 /预期利润:3.354E8 欧分

型号#2 配置

模型#2 结果

我们得出结论,可以向我们的模型中添加更多的特征,以确保更好的结果和准确性。因此,我们添加了更详细的特征,包括 T-24 至 T-0 小时的平均值和标准差、最小值和最大值、偏斜度、差异值以及更多来自能量的过去数据,如 T-168 至 T-0 小时和 T-336 至 T-0 小时的平均值、标准差和偏斜度值。

至于风速数据,我们包括了从 T+15 到 T+18 小时的未来值。到目前为止,网络还没有其他变化。记住之前最好的测试亏损 0.38824,盈利 3.354E8 欧分。运行新的模型,我们获得了更好的测试损失 0.137427,以及利润新高 6.514E8 美分,这是我们最大可能利润的 65.3%。至于我们的实际与测试预测图,我们可以看到 2 个值之间有更好的相关性,我们的滞后峰值为 0,这是一个好迹象,表明我们的模型正在改善。

#3 超参数

预期得分:0.137427 /预期利润:6.514E8 欧分

型号#3 配置

模型#3 结果

基于上一个实验的知识,更多的隐藏层被添加到模型中。具体来说,添加了 0.01、0.001、0.0001 的辍学率,以减少训练数据集的过度拟合。类似地,添加 0.01、0.001 和 0.0001 的权重衰减值以减少过拟合。L2 正则化被包括以减少训练期间神经网络权重的量值。

获得的最佳测试损失为 0.135409,利润为 6.467E8,比之前的更差。我们注意到,实际数据和测试预测变得更加相关,滞后相关峰值略高。性能最好的设置是 NN-size = 256,dropout = 0.0001,decay = 0.001。

#4 使用 2019 年 7 月的数据

预期得分:0.135409 /预期利润:6.514E8 欧分

模型#4 结果

接下来,我们重复了相同的神经网络配置,但仅使用 2019 年 7 月的数据,结果如下图所示。运行该模型使我们获得了更好的测试损失,为 0.100719,超过了我们从 2019 年 1 月开始的数据集的测试损失。然而,我们从这款更新更近的车型中获得的利润仅为 2.439E8 欧分,仅为我们应实现的 8.016E8 欧分预期利润的 30.4%。****

#5 扩展

预期得分:0.100719 /预期利润:6.467E8 欧分

动量和力损失的预测结果

最后,我们测试了在模型上添加动量、力损失和自动编码器的概念。在附加动量和力损失的情况下,获得的最佳试验损失为 0.158881,利润为 6.157E8。我们观察到预测中的噪声增加,导致预测不太准确。

启用自动编码器的预测结果

在自动编码器下,最佳测试损失为 0.129414,利润为 6.647E8。这使得模型的训练时间明显延长,导致测试结果更加多样化。

最终模型

我们的最终模型是一个简单的模型,它使用设置#3,重复 20 次,并采用最佳设置。

使用的特征包括 3 个时间框架的平均值、标准差、偏斜度和差异:T-24、T-168 和 T-336。此外,我们使用过去的数据来预测从 T-0 小时(T-0 到 T-18 小时)的未来 18 小时,并使用值对来表示从 T-(-24)到 T-0 的 18 个差异。这导致模型中总共有 14 个独立的特征。

该模型具有以下特点:

最终模型配置

决赛成绩

最终模型的最终测试损失为 0.132 欧元,利润为 6.501 欧分。作为对比,持续性损失= 0.485,盈利基准= 9.972E+08。模型的训练和测试损失、实际和测试预测以及滞后相关图如下所示。

最终模型结果

进一步的潜在改进

  1. 利用额外特征,如风向

虽然我们试图保持输入的准确性并符合我们的直觉,但将风向作为额外输入的潜力可能会被证明是有用的。​

2.配置

测试了进一步的改进,并偏离了之前的配置;当观察到一个普遍趋势时,团队就去追求它,而不考虑另一个完全不同的设置。​

类似于神经元权重的“随机初始化”的想法,该团队可以“初始化”一个新的起点,这可以提供前所未有的洞察力。​

3.附加原始数据

如果对 2019 年之前最初被忽略的数据进行进一步清理和归一化,以符合 2019 年及以后的数据的相同归一化范围,则可以利用这些数据。有了更多的数据,模型会学得更好。​

总结和回顾

该团队认为,复杂的模型不一定等同于更好的结果,因为它可能倾向于陷入次优解决方案。因此,我们的方法从一个直观的简单模型开始,并通过分析趋势和试错法建立在它的基础上。毕竟,一个我们可以理解的模型是可以客观而非盲目改进的。

凭借目前良好的结果,我们满怀信心地进入现场测试阶段。

认识团队:)

**[## 许伟文-企业联络主任-南洋理工大学学生会

目前就读于南洋理工大学(NTU),攻读机械工程学士学位,辅修…

www.linkedin.com](https://www.linkedin.com/in/koh-wei-wen-927044120/)** **[## Anders Choo -新加坡南洋理工大学| LinkedIn

在全球最大的职业社区 LinkedIn 上查看安德斯·周的个人资料。安德斯的教育列在…

www.linkedin.com](https://www.linkedin.com/in/anders-choo/)** ** [## Gabriel Tan -新加坡国立大学学生大使| LinkedIn

查看 Gabriel Tan 在全球最大的职业社区 LinkedIn 上的个人资料。加布里埃尔有 4 份工作列在他们的…

linkedin.com](http://linkedin.com/in/gabriel-tan-223a631a0) [## 韩德-大数据实习生-雷蛇公司| LinkedIn

在世界上最大的职业社区 LinkedIn 上查看韩德·c 的个人资料。韩德有一份工作列在他们的…

www.linkedin.com](https://www.linkedin.com/in/dehan-c-948045177/)

这里还有一篇文章给你!

[## 用 python 创建一个垃圾短信分类器

使用 scikit 的自然语言处理基础-学习

towardsdatascience.com](/create-a-sms-spam-classifier-in-python-b4b015f7404b)**

预测虚假招聘信息—第 1 部分(探索性分析)

原文:https://towardsdatascience.com/predicting-fake-job-postings-part-1-data-cleaning-exploratory-analysis-1bccc0f58110?source=collection_archive---------28-----------------------

当心这种虚假的“现在招聘”标志

由于新冠肺炎·疫情对各大洲的经济造成损害,我们正生活在一个前所未有的时代。失业率每天都在增加,据美国报道,约有 2600 万人申请失业救济,这是其漫长历史上的最高记录,英国有数百万人被解雇,世界各地有数千人被解雇。以下是联合国副秘书长阿米娜·穆罕默德的一句话,用一句话概括了当前的形势。

正当世界全力应对疫情新冠肺炎冠状病毒前所未有的影响时,我们正面临一场前所未有的人道主义危机,我们的社会结构和凝聚力正面临压力。

在这个绝望的时代,成千上万的人在寻找工作,这为网络骗子利用他们的绝望情绪提供了一个绝佳的机会。我们看到这些虚假的招聘信息每天都在增加,这些信息看起来很合理,通常这些公司也会有一个网站,他们的招聘流程与业内其他公司相似。

如果一个人足够努力,他们可以发现这些假帖子和真帖子之间的差异。大多数情况下,这些帖子上没有公司的标志,公司的第一反应是来自一个非官方的电子邮件帐户,或者在面试中,他们可能会要求您提供个人机密信息,如您的信用卡信息,说他们需要这些信息进行人员验证。在正常的经济条件下,所有这些都是公司可疑之处的明显暗示,但这不是正常的经济条件。这是我们一生中见过的最糟糕的时期,在这个时候,绝望的人只需要一份工作,这样,这些人就直接落入了这些骗子的手中。以下是丹尼尔·林斯基的一段话,他是波士顿警察局的前局长

警察部门没有调查这些事件的资源,在联邦当局介入之前,这必须是一个数百万美元的诈骗,所以骗子们只能继续逍遥法外。

通过这两部分的系列媒体文章,我希望让求职者意识到这一问题的严重性,以及如何通过机器学习模型来预测一个职位发布是否具有欺诈性。在本系列的第 1 部分,我将探索这些数据,并深入了解哪些行业受到的影响更大,以及哪些关键的危险信号会泄露这些虚假帖子。在第二部分,我将应用机器学习模型来预测我们如何检测这些伪造的帖子。

我将在分析中使用的数据是由爱琴海大学信息与通信系统安全实验室(http://emscad.samos.aegean.gr/)编制的 18000 份工作描述的数据集。这个数据集包含 800 个虚假的职位描述。

数据集具有以下变量:

  1. 标题:招聘广告条目的标题。
  2. 位置:招聘广告的地理位置。
  3. 部门:法人部门。
  4. 薪金 _ 范围:指示性薪金范围。
  5. Company_profile:简要的公司描述。
  6. 描述:招聘广告的详细内容。
  7. 要求:空缺职务的登记要求。
  8. 福利:由雇主提供的福利。
  9. 远程办公:适用于远程办公的职位。
  10. Has_company_logo:如果公司徽标存在,则为 True。
  11. Has_questions:如果存在筛选问题,则为 True。
  12. 就业 _ 类型:全职、兼职、合同等。
  13. 要求 _ 经验:高管、入门级、实习生等。
  14. 要求 _ 学历:博士、硕士、学士等。
  15. 行业:汽车、IT、医疗保健、房地产等。
  16. 职能:咨询、工程、研究、销售等。
  17. 欺诈性的(目标变量):如果是假的,则为 1,否则为 0。

数据清理

我在我的系统上导入了 Jupyter 笔记本上的数据,并在 Python 3 上工作。由于我希望这一部分更多的是关于洞察力而不是代码,所以我没有在这里附上任何代码要点,但是任何对查看数据清理代码感兴趣的人都可以随意查看我的 GitHub 库—【https://github.com/sharad18/Fake_Job_Posting

最初的数据集包含 18,000 个帖子。清理后,新数据有大约 11,000 个帖子。在本系列的第 2 部分,我将研究机器学习模型来预测哪些帖子可能是假的。我将干净的数据导入到 Tableau 中进行探索性分析,这将在下一节中详细描述。

探索性分析

目标变量的分布

我们首先需要看的是数据的分布,这是非常不平衡的,只有 249 个虚假发布,涉及 11,023 个良好的职位发布,这是预计会出现这样的问题。欺诈性的广告张贴很普遍,但数量上超过了真正的广告。这些招聘广告已经发布在 LinkedIn、Glassdoor 和其他求职网站上,这些网站都有其欺诈检测团队。该数据集通过这些网站的高精度算法发现隐藏得很好的虚假网站。

非常不平衡的目标变量

数据集中其他变量的分布

在下图中,我们看到了要求的教育程度、就业类型和要求的经验等变量的分布。对于第一个变量,我们可以看到数据中的大多数代表是高中毕业生和大学毕业生,这在当前每个公司都在削减成本的情况下是可以理解的。最残忍的方法是解雇比大多数人挣得多的人,用级别较低的人取代他们。从这里,我们可以得到一个年龄组的估计,可能在 20 岁到 35 岁之间。此外,研究生级别的工作和博士级别的工作数量较少,这表明求职者受教育程度越高,他们对某个角色的要求就越复杂,因此与受教育程度较低的人相比,为他们创建工作岗位具有挑战性。

中高级职位在数据集中最常见。

第二幅图更符合一个共识,即在任何时候,对全职职位的需求总是比临时职位多,因为对公司来说,长期投资于个人仍是更好的投资。

在不止一个场景中,最后一个情节与第一个情节相矛盾。要求学历是大专学历,但要求经验是中高级水平。这表明,对于任何角色来说,过去在特定行业或企业界的技能都比教育更受重视。一个典型的刻板印象是,对于高级职能来说,研究生学位是必须的,但数据并不同意这一点。大多数高管都是通过网络招聘的,这一数据与此相符,因为这是发布招聘广告最不需要的经历。

工作职能和行业分布

接下来,我们将看看哪些工作职能和行业最容易受到骗子的攻击。在下图中,我们看到像信息技术和工程这样的技术功能位于顶部,随后是销售和客户服务。由于大部分招聘信息都围绕这些工作职能,他们最容易受到虚假招聘信息的影响。随着我们往下看,我们看到功能变得越来越具体,因此,欺骗这些人变得越来越困难,因为这些功能对他们的行业来说是如此的特殊。

信息技术和工程主宰了招聘信息。

在接下来的情节中,我们可以看到前面结果的延续。像 IT、计算机软件和互联网这样的技术行业在招聘信息中占主导地位。这两个数字清楚地表明,专业工作最容易受到这种虚假职位的影响,因为目前这些人的需求很大。即使有这么多的招聘信息,供应仍然少于市场,这就创造了一个完美的局面,骗子可以介入并剥削这些求职者。

排名前三的行业都是技术性的。

虚假招聘信息分析

在接下来的章节中,我们将深入分析这些虚假招聘广告的一些特殊特征,这些特征将它们与官方招聘广告区分开来。区分这两者的关键之一是招聘过程。

45%的招聘广告没有经过任何招聘程序

左图显示,45%的欺诈案例甚至没有面试。这是这些骗局中最大的漏洞,一份工作没有经过任何筛选就被提供了。在大多数情况下,工作邀请之后会询问银行或信用卡详细信息等机密信息,这是这些虚假招聘信息欺骗你的主要方式。

在下图中,查看在没有筛选过程的情况下,这些骗子瞄准的经验水平。这些骗子通常以入门级工作的求职者为目标。这些大多是应届大学毕业生,他们正在寻找自己在行业中的第一个角色,而当前的经济形势,最容易成为骗子的目标。随着我们级别的降低,资历级别增加,这表明随着个人获得更多的经验,他们可以区分假职位和真职位。

入门级的工作最容易被骗子盯上

虚假招聘广告的地理分布

在这里,我们可以看到这些假币是如何在世界各地传播的。我们知道美国的病例最多。这种情况是如此之多,以至于它让世界其他地方黯然失色,不得不创造一个独立的数字。在第二幅图中,我们可以看到英国、加拿大、印度和澳大利亚也有大量此类骗子。

美国的虚假招聘数量最多。

在上图中,我们看到美国是欺诈案件最多的国家,其次是英国。接下来,我们将在城市一级看到更全面的分析。即使在美国,东海岸比西海岸更频繁,这与我们早期的发现相矛盾。我们看到,最脆弱的行业是技术行业,它集中在美国西部,但大多数欺诈案件都发生在对面的海岸。英国和欧洲其他地区的主要金融和技术中心也有大量此类索赔。印度、东南亚和澳大利亚的主要中心遵循同样的模式。

美国城市占据了虚假招聘的主导地位。

词云可视化

在这里,创建了欺诈性职位发布和非欺诈性职位发布的两个词云。我们可以从这两个词云中看到的一个区别是,非欺诈词云对所做的工作有更具体的要求和描述。在欺诈类中,最常见的词是无处不在的词,这些词不能反映工作是关于什么的,需求是什么,只是围绕着一般的概念。这些广告大多很好地运用了文字游戏。LinkedIn 和 Glassdoor 等网站上的过滤器通常会搜索这些通用术语,而不是特定术语,因此这些帖子有时会通过这些网站的欺诈检测算法。这些发现让我们得出结论,也许仅仅是职位描述并不是一个很好的预测变量,我们需要更多的信息。

虚假招聘信息的 Word cloud。

因此,诸如招聘流程、公司标志、广告的在线位置等信息,以及围绕该招聘信息的许多此类外部因素变得至关重要,无法从职位描述中推断出来。在本系列的第 2 部分中,我将更仔细地研究这些变量,以及它们如何影响这个问题的预测性能。

真实招聘信息的 Word cloud。

在这一部分中,我们看到了一个深入的探索性分析,即假职位与真职位有何不同。在当前的经济形势下,我理解尽快找到工作的绝望,但我们需要对这种骗子的损失有所不同。这个问题是求职群体的道德责任,如果发现此类虚假招聘信息,他们应该互相帮助并向有关部门举报。

在当前的经济环境下,虚假招聘是一个严重的问题。随着情况的恶化,我们可以看到越来越多的这种欺诈性帖子到处涌现。我在这篇文章中提出了这个问题的一些趋势和分析,我希望这有助于你下次申请下一份工作时更加注意。

下一部分,我会开发一个机器学习算法,把职位描述作为输入,预测是不是假的。所以非常感谢你看完这一部分,敬请期待下一篇!

参考资料:

https://www . the balances careers . com/list-of-fake-job-scam-examples-2062 168

https://www . weforum . org/agenda/2020/04/新冠肺炎-行动-呼叫-8-apr/

作者注:

你可以在 LinkedIn 上联系我—【https://www.linkedin.com/in/sharad-jain/

预测虚假招聘信息—第二部分(预测分析)

原文:https://towardsdatascience.com/predicting-fake-job-postings-part-2-predictive-analysis-3119ba570c35?source=collection_archive---------30-----------------------

预测哪些招聘信息是假的。

在这个由两部分组成的系列文章的第一部分中,我做了一个详细的探索性分析,分析了虚假的招聘信息与真实的招聘信息有什么不同。下面是第 1 部分的链接,我强烈建议您在继续之前先阅读该部分!

[## 预测虚假职位发布—第 1 部分(数据清理和探索性分析)

COVID19 及其带来的经济低迷导致了许多虚假的招聘信息。这里有一个详细的…

towardsdatascience.com](/predicting-fake-job-postings-part-1-data-cleaning-exploratory-analysis-1bccc0f58110)

前一部分的一些重要见解—

  1. 虚假的招聘信息大多针对全职职位,这些职位的最低要求是学士学位和中高级工作经验。
  2. 这些职位主要面向在技术部门寻找工作的个人。
  3. 45%的帖子甚至没有问一个问题就把工作给了候选人(这是虚假帖子的一个重要标志)。
  4. 没有经过筛选的职位大多是初级职位。
  5. 这些虚假帖子主要来自美国,其次是英国、加拿大和印度。
  6. 创建词云后发现,招聘启事有类似的行为内容,但正版的更具体到角色。

基于这些见解,我们现在知道,有可能发现哪些招聘信息是假的,哪些不是。但在这个前所未有的时代,每天都有数百人被解雇,求职者感到绝望。骗子们正利用这种绝望情绪发布越来越多的虚假招聘广告。因此,我们需要在 LinkedIn、Glassdoor 等求职网站上使用更多这样的算法和工具,以便过滤掉这些虚假的帖子,让求职者只看到真实的帖子。

在接下来的部分,我将对上次使用的数据使用机器学习技术,并从真实的招聘信息中预测虚假的招聘信息。

数据

因此,到目前为止,我们在分析中使用的数据是由爱琴海大学信息与通信系统安全实验室(http://emscad.samos.aegean.gr/)编制的。该数据集包含 800 个 fak 职位描述。

我已经在本系列的第 1 部分中定义了作为数据集一部分的变量。我会提到完整列表中的变量。我将在下一节中使用进行分析。

数据清理

我在我的系统上导入了 Jupyter 笔记本上的数据,并在 Python 3 上工作。由于我希望这一部分更多的是关于洞察力而不是代码,所以我没有在这里附上任何代码要点,但是任何对查看数据清理代码感兴趣的人,都可以随意查看我的 GitHub 库—【https://github.com/sharad18/Fake_Job_Posting

最初的数据集包含 18,000 个帖子。清理后,新数据有大约 11,000 个帖子。

我将用于预测分析的变量子集是—

  1. 标题:职位发布的标题。
  2. 描述:职位描述+公司简介+要求
  3. 远程办公:远程办公职位的 Tru。
  4. Has_company_logo:如果公司徽标存在,则为 True。
  5. Has_questions:如果存在筛选问题,则为 True。
  6. 就业 _ 类型:全职、兼职、合同等。
  7. 要求 _ 经验:高管、入门级、实习生等。
  8. 要求 _ 学历:博士、硕士、学士等。
  9. 行业:汽车、IT、医疗保健、房地产等。
  10. 职能:咨询、工程、研究、销售等。
  11. 欺诈性的(目标变量):如果是假的,则为 1,否则为 0。
  12. 城市:招聘启事中提到的城市。
  13. Country_name:职位发布中提到的国家的名称。

让我们开始处理这些干净的数据吧!

导入库和读取数据

我暂时导入了以下库,它们是任何人在 Python 中执行分析所需的基本库,

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
pd.set_option('display.max_columns', None)

让我们看看数据,

df = pd.read_csv('Clean_data.csv')
df.head()

正在使用的数据的预览。

现在,我们试着详细研究“描述”一栏。在我导入的已清理数据文件中,“描述”列是“描述”+“要求”和“公司简介”的组合“描述”中的数据看起来像什么的一个例子—

“描述”列中的单个条目。

接下来,我们将试着看看 20 个最常用的单词,它们既出现在虚假招聘中,也出现在好的招聘广告中。

import spacy
nlp = spacy.load('en_core_web_lg')
import base64
import string
import re
from collections import Counter
from nltk.corpus import stopwords
stopwords = stopwords.words('english')punctuations = string.punctuationdef cleanup_text(docs, logging = False):
    texts = []
    for doc in docs:
        doc = nlp(doc, disable = ['parser', 'ner'])
        tokens = [tok.lemma_.lower().strip() for tok in doc if tok.lemma_ != '-PRON-']
        tokens = [tok for tok in tokens if tok not in stopwords and tok not in punctuations]
        tokens = ' '.join(tokens)
        texts.append(tokens)return pd.Series(texts)

对于虚假的招聘信息,

Fraud_1 = [text for text in df1[df1['fraudulent'] == 1]['description']]
Fraud_1_clean = cleanup_text(Fraud_1)
Fraud_1_clean = ' '.join(Fraud_1_clean).split()
Fraud_1_counts = Counter(Fraud_1_clean)
Fraud_1_common_words = [word[0] for word in Fraud_1_counts.most_common(20)]
Fraud_1_common_counts = [word[1] for word in Fraud_1_counts.most_common(20)]fig = plt.figure(figsize = (20, 10))
pal = sns.color_palette("cubehelix", 20)
sns.barplot(x = Fraud_1_common_words, y = Fraud_1_common_counts, palette=pal)
plt.title('Most Common Words used in Fake job postings')
plt.ylabel("Frequency of words")
plt.xlabel("Words")
plt.show()

虚假招聘中的前 20 个词。

对于真实的招聘信息,

Fraud_0 = [text for text in df1[df1['fraudulent'] == 0]['description']]
Fraud_0_clean = cleanup_text(Fraud_0)
Fraud_0_clean = ' '.join(Fraud_0_clean).split()
Fraud_0_counts = Counter(Fraud_0_clean)
Fraud_0_common_words = [word[0] for word in Fraud_0_counts.most_common(20)]
Fraud_0_common_counts = [word[1] for word in Fraud_0_counts.most_common(20)]fig = plt.figure(figsize = (20, 10))
pal = sns.color_palette("cubehelix", 20)
sns.barplot(x = Fraud_0_common_words, y = Fraud_0_common_counts, palette=pal)
plt.title('Most Common Words used in Genuine job postings')
plt.ylabel("Frequency of words")
plt.xlabel("Words")
plt.show()

真实招聘启事中的前 20 个单词。

在上面的两个图中,最常用的词几乎是一样的,很难区分两者。因此,变量“描述”本身不能帮助我们预测,因此完整的变量集是有意义的。更值得一提的是,当一个人在互联网上看到招聘信息时,我在“数据清理”部分提到的这些附加功能并没有直接提供。这些变量仅在职位发布被举报为欺诈后获得。在这种情况下,当务之急是,如果发现这种虚假招聘,他们必须通知有关当局以及他们网络中的其他求职者。

将数据分为训练和测试

在分割数据之前,我们需要对数据做一些最后的修改,之后我们将分割数据。必须将‘description’列清理成令牌。这是在空间nltk 库的帮助下完成的。在下面这段代码中,' description' '列已经被转换成标记,这些标记已经被用来使用 sklearn 的 CountVectorizer 创建一个热列。此外,类似于‘就业类型’,‘必需教育’,‘必需经验’,‘行业’,和’功能’的分类列已经被转换成一个热点向量。

STOPLIST = set(stopwords.words('english') + list(ENGLISH_STOP_WORDS))
SYMBOLS = " ".join(string.punctuation).split(" ")def tokenizetext(sample):
    text = sample.strip().replace("\n", " ").replace("\r", " ")
    text = text.lower()
    tokens = parser(text)
    lemmas = []
    for tok in tokens:
        lemmas.append(tok.lemma_.lower().strip() if tok.lemma_ != "-PRON-" else tok.lower_)
    tokens = lemmas
    tokens = [tok for tok in tokens if tok not in STOPLIST]
    tokens = [tok for tok in tokens if tok not in SYMBOLS]
    return tokensvectorizer = CountVectorizer(tokenizer = tokenizetext, ngram_range = (1,3), min_df = 0.06)
vectorizer_features = vectorizer.fit_transform(df1['description'])vectorized_df = pd.DataFrame(vectorizer_features.todense(), columns = vectorizer.get_feature_names())
df_final = pd.concat([df1, vectorized_df], axis = 1)df_final.drop('description', axis = 1, inplace = True)
df_final.dropna(inplace=True)columns_to_1_hot = ['employment_type', 'required_experience', 'required_education', 'industry', 'function']for column in columns_to_1_hot:
    encoded = pd.get_dummies(df_final[column])
    df_final = pd.concat([df_final, encoded], axis = 1)columns_to_1_hot += ['title', 'city', 'country_name']
df_final.drop(columns_to_1_hot, axis = 1, inplace = True)

接下来,我们把数据分成训练和测试两部分—

target = df_vectorized['fraudulent']
features = df_vectorized.drop('fraudulent', axis = 1)X_train, X_test, y_train, y_test = train_test_split(features, target, test_size = 0.1, stratify = target, random_state=42)print (X_train.shape)
print (y_train.shape)
print (X_test.shape)
print (y_test.shape)

我们得到以下输出—

(10144, 857)
(10144,)
(1128, 857)
(1128,)

我们现在万事俱备了。先说机器学习吧!

机器学习算法

我们将在后续章节中使用的库—

from sklearn.model_selection import GridSearchCVfrom sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNearestNeighbors
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.neural_network import MLPClassifierfrom sklearn.metrics import accuracy_score, confusion_matrix, classification_report, roc_auc_score

1.逻辑回归

log_reg = LogisticRegression()
c_values = [0.00001, 0.0001, 0.001, 0.01, 0.1, 1, 10, 100, 1000, 10000]
penalty_options = ['l1', 'l2']param_grid = dict(C = c_values, penalty = penalty_options)grid_tfidf = GridSearchCV(log_reg, param_grid = param_grid, cv = 10, scoring = 'roc_auc', n_jobs = -1, verbose=1)grid.fit(X_train, y_train)log_reg_pred = grid.predict(X_test)print (roc_auc_score(y_test, log_reg_pred))
print (classification_report(y_test, log_reg_pred))

我们得到以下结果—样本 roc_auc 得分= 0.7795,对于分类报告,我们得到—

逻辑回归的样本外结果。

用最基本的模型进行预测,逻辑回归,给我们一个 0.7795 的 ROC-AUC 分数,考虑到数据的不平衡,这是一个很好的分数。在随后的章节中,我们将看到更复杂的模型。

2.k-最近邻(KNN)

knn = KNeighborsClassifier()
k_range = list(np.arange(2, 23, 2))
param_grid_knn = dict(n_neighbors = k_range)
print (param_grid_knn)grid_knn = GridSearchCV(knn, param_grid_knn, cv = 10, scoring = 'roc_auc', n_jobs = -1, verbose = 1)grid_knn.fit(X_train, y_train)knn_pred = grid_knn.predict(X_test)print (roc_auc_score(y_test, knn_pred))
print (classification_report(y_test, knn_pred))

KNN 的样本外 ROC-AUC 得分为 0.5995。对于分类报告,我们得到—

KNN 的样本结果。

从左图中,我们可以看到,与逻辑回归相比,KNN 的表现非常差。

3.支持向量机(SVM)

svc = SVC()
kernel = ['linear', 'rbf']
param_grid_knn = dict(kernel = kernel)
print (param_grid_knn)grid_svc = GridSearchCV(svc, param_grid_knn, cv = 10, scoring = 'roc_auc', n_jobs = -1, verbose = 2)grid_svc.fit(X_train, y_train)svc_pred = grid_svc.predict(X_test)print (roc_auc_score(y_test, svc_pred))
print (classification_report(y_test, svc_pred))

这里报告的样本外得分为 0.8195 ~ 0.82。分类报告如下—

SVC 以 0.82 的分数获得了迄今为止最好的成绩,这明显优于后两种方法。

4.随机森林

rf = RandomForestClassifier()
n_estimators_range = [1, 2, 4, 8, 16, 32, 64, 100, 200]
param_grid_rf = dict(n_estimators = n_estimators_range)
grid_rf = GridSearchCV(rf, param_grid_rf, cv = 10, scoring = 'roc_auc', n_jobs = -1, verbose = 1)grid_rf.fit(X_train, y_train)
print (grid_rf.best_score_)
print (grid_rf.best_params_)rf_pred = grid_rf.predict(X_test)
print (roc_auc_score(y_test, rf_pred))
print (classification_report(y_test, rf_pred))

对于随机森林模型,报告的 ROC-AUC 得分为 0.74。分类报告如下—

的分类报告

说实话,我预计随机森林的表现会比 SVC 好,但到目前为止,SVC 的结果最好。

5.Sklearn 的神经网络 MLP 分类器(solver = 'sgd ')

mlp = MLPClassifier(solver = 'sgd', activation = 'relu', hidden_layer_sizes = (100, 50, 30), max_iter = 1000)
mlp.fit(X_train, y_train)mlp_pred = mlp.predict(X_test)print (roc_auc_score(y_test, mlp_pred))
print (classification_report(y_test, mlp_pred))

在这种情况下,ROC-AUC 得分为 0.7786。分类报告—

MLP 分类器的分类报告(solver = 'sgd ')

带有“sgd”解算器的 MLP 分类器的性能略好于随机森林模型,但仍比 SVC 报告的要差。

6.Sklearn 的神经网络 MLP 分类器(solver = 'adam ')

mlp = MLPClassifier(solver = 'adam', activation = 'relu', hidden_layer_sizes = (100, 50, 30), max_iter = 1000)
mlp.fit(X_train, y_train)mlp_pred = mlp.predict(X_test)print (roc_auc_score(y_test, mlp_pred))
print (classification_report(y_test, mlp_pred))

该模型的样本外 ROC-AUC 值为 0.8595 ~ 0.86。分类报告如下—

MLP 分类器的分类报告(求解器= 'adam ')

这是迄今为止报道的最高分,基于这个模型,我们将能够在 86%的情况下正确预测招聘信息是否是假的。

模型比较

所有模型之间的比较。

从上图中,我们可以看到 Sklearn 基于神经网络的 MLP 分类器与' adam' optimizer 表现最好,其次是同一模型与'【SGD '解算器和支持向量机分类器。因此,基于 MLP 分类器的样本外性能指标 ROC-AUC 得分,我们可以有把握地说,我们可以在 86%的时间里预测一个职位发布是否是假的。

这种预测分析对于 LinkedIn 和 Glassdoor 这样的求职网站非常有用,可以帮助他们过滤这种虚假的招聘信息。

结论

目前,我们生活在一个我们谁都没有预料到的时代。冠状病毒不仅给各国带来了突发卫生事件,还加速了即将到来的经济衰退。每天都有许多员工被解雇,对工作的需求远远超过了市场上的职位数量。

通过这一系列文章,我试图提出一个正在就业市场蔓延的问题。动荡和混乱是骗子的完美支持者,目前,网络诈骗攻击正在上升。在上一部分,我详细分析了如何区分虚假和真实的招聘信息,以及欺诈性招聘信息的特征。在这一部分中,我提供了一个详细的分析,说明我们如何应用机器学习来预测这种虚假帖子的出现。

正如我在这两部分中提到的,作为互联网用户和求职者,我们有责任让当局和我们的网络知道我们是否遇到了这种虚假的招聘信息,而不是任何模型或分析。

谢谢你看了这两部分。我希望每个人都有美好的一天&请保持社交距离,这样我们可以更快更有效地度过这样的时光!

作者注:

参与这个项目对我来说是一次很好的学习经历。希望你们都觉得它很有帮助,很有启发性。

这篇文章的全部代码都在我的 GitHub 存储库中,在 https://github.com/sharad18/Fake_Job_Posting进行分析。我很想在评论区听到你的反馈。

你也可以在 LinkedIn 上联系我—https://www.linkedin.com/in/sharad-jain/

利用卫星图像预测赞比亚的粮食不安全状况

原文:https://towardsdatascience.com/predicting-food-insecurity-in-zambia-using-satellite-imagery-272ffecbbce5?source=collection_archive---------18-----------------------

通过可视化我们的模型预测,我们能够识别作物和水可及性的高风险区域。

气候变化预计将通过更高的温度、更大的降雨量波动以及可能对作物和淡水供应产生毁灭性影响的极端天气,在 21 世纪增加营养不良的发生率。在义神星,我们专注于将机器学习应用于卫星图像,并开发了一个名为 EarthAI 的地理空间机器学习平台,以处理遥感图像的数量和复杂性。在我们的作物分类项目中,我们训练了一个模型,使用遥感图像对作物和水进行分类,并使用这些预测来研究赞比亚食物和淡水可获得性的变化,赞比亚在 2018 年全球饥饿指数中排名第五,属于“令人担忧”的类别。⁵ 60%的赞比亚人口生活在贫困中,40%的儿童因营养不良而发育不良。⁴通过这项研究,我们能够发现自然资源可获得性的变化,并跟踪作物可用性和轮作情况,从而了解该地区的粮食不安全状况。

“作为一家福利公司,将个人和组织与他们改善周围世界所需的信息联系起来对我们来说非常重要。几乎有无限多的方法可以做到这一点,但在无法获得信息或技术的项目中工作真的很有意义。让地球关注赞比亚的食品短缺对我们公司来说是一个鼓舞人心的挑战。”

~首席执行官布兰登·理查森

数据

由于它的全球覆盖范围和长期的免费和公开可用数据的存档,我们决定在这个项目中使用 Landsat 8 图像。这颗卫星大约每 16 天重访地球上的同一个地点,并在可见光、近红外和短波红外光谱中产生空间分辨率为 30 米的图像。

对于世界上的大部分地区,很难找到地面实况地理参考作物数据集,但幸运的是,自 2008 年以来,美国农业部(USDA)每年都会为美国大陆制作一个地面实况地理参考作物数据集。这个名为 CropScape 的数据集以 30 米的分辨率标注了 92 种不同的作物和 25 种土地覆盖类型。我们使用 CropScape 数据集在美国训练我们的模型,然后将这个模型推广到赞比亚。

图一。来源: Landsat 8 影像作物景观农田数据层

感兴趣区域

赞比亚享有长期的和平与稳定,但受到气候变化的严重影响。⁴我们特意选择了一个政治稳定的国家来控制混淆变量,如战争或经济制裁,以便粮食不安全问题是由气候变化引起的极端天气造成的,随着时间的推移,气候变化会慢慢影响作物,而不是由动荡的政治环境或其他超出遥感数据分析能力的无形变量造成的。

在赞比亚,农业支撑着 population,⁶85%的人口的生计,但赞比亚是一个内陆国家,大多数农民依靠降雨来灌溉作物,因此特别容易受到气候变化引起的天气波动的影响。⁴由于这些因素以及赞比亚种植的作物与美国的作物非常匹配,赞比亚是模型外推的一个简单选择。

利用赞比亚作物生产的一些基本统计数据(非洲数据粮农组织国家报告赞比亚数据门户),我们根据 2015 年和 2016 年种植的公顷数和每种作物的产量确定了赞比亚最常见的作物。总之,我们在模型中包括了九种作物类型:玉米、小麦、小米、马铃薯、杂豆、花生、甘蔗、烟草和棉花。

光谱特征工程

用于训练我们的分类模型的特征是来自 Landsat 8 的原始波段(红色、绿色、蓝色、近红外、两个短波红外和一个沿海波段)和一组派生的水、植被和土壤指数。由于不同作物的植被指数在不同时间达到峰值,因此包含一个时间序列的特征值以区分不同作物非常重要。

归一化差异植被指数(NDVI)是用于测量植物健康的近红外和红色波段的比率。⁷较高的 NDVI 值表明植物更健康。⁷图 2 向您展示了 NDVI 时间序列如何区分作物。玉米的 NDVI 在 6 月和 7 月初达到高峰;棉花、花生、小米和烟草在 8 月达到高峰;干豆在九月达到高峰。

图 2:按作物和月份划分的平均 NDVI 时间序列图。

建模

义神星 EarthAI 平台建立在 Apache Spark 和亚马逊网络服务(AWS)基础设施之上。因为我们需要为这个建模工作处理的图像量几乎是 1tb,所以我们使用 EarthAI 以及时和分布式的方式来执行建模。我们的流程概述如下。

  1. 读入 Landsat 8 影像和 ground truth CropScape 数据,并通过重新投影和重新采样 ground truth 数据以匹配遥感数据,在空间上连接这两个栅格数据集。
  2. 从原始的 Landsat 8 波段导出水、植被和土壤指数。
  3. 将栅格数据分解为像素,因此数据集中的每一行都是一个像素,每一列都是不同的波段。
  4. 使用 Landsat 8 质量评估(QA)波段过滤掉不良数据,如被云覆盖的像素。
  5. 通过按月平均每个光谱特征来创建时间序列特征。
  6. 将数据分成训练集和测试集。
  7. 训练和评估分类模型。
  8. 在 2015 年和 2016 年对赞比亚的模型进行评分。
  9. 对模型的预测执行分类后更改检测。

图 3:使用 EarthAI 平台建模工作流。

因为我们选择的九种作物的作物日历并不同步,所以我们决定为夏季和冬季作物建立两个独立的模型。在美国,甘蔗、小麦和马铃薯是冬季作物,在夏末秋初种植,第二年夏天收获;而玉米、棉花、花生、小米、干豆和烟草是夏季作物,在早春种植,秋季收获。在赞比亚的⁸,由于半球不同,作物日历是相反的。⁹

对于夏季和冬季生长季节,我们表现最好的模型是梯度促进树木(GBT)模型。GBT 夏季模型的总体准确度为 0.876,F1 值为 0.792。类别度量如图 4 所示。与其他类相比,小米的召回率很低,因为我们的训练集不平衡,而且我们的此类示例太少。

GBT 冬季模型的总体准确度为 0.956,F1 值为 0.895。较少的班级和贫瘠的冬季景观使得这些班级比夏季班级更容易建模。类别度量如图 5 所示。

图 4:测试集的夏季模型度量。

图 5:测试集的冬季模型度量。

调查结果

我们对赞比亚两年的夏季和冬季模型进行了评分,并对赞比亚境内的区域进行了分类后变化检测。我们能够检测自然资源可用性的变化,如图 6 所示,2015 年至 2016 年间,塔米山淡水水库水位显著下降。

图 6:2015 年和 2016 年叠加在赞比亚姆库西区米塔丘陵大坝上的模型预测。

我们还能够跟踪作物的可用性和轮作时间,如图 7 所示的例子,显示了粮食作物向经济作物的转移。在需要的时候,经济作物会产生更多的收入,因为它们是为了销售而不是消费而种植的。

图 7:2015 年和 2016 年赞比亚农业区的模型预测。

通过可视化我们的模型预测,我们能够识别粮食不安全和水可及性的高风险区域。及时分享这些信息可以加快预防饥饿和营养不良的干预努力。

挑战

当试图将一组特定数据上训练的模型外推至一组新数据时,概化将是一个挑战。我们的模型是根据美国的影像进行训练的,因为我们在赞比亚找不到地面实况地理参考作物数据。美国幅员辽阔,并非所有州都表现出与赞比亚相似的特征,因此我们分析并选择了在气候、天气、土壤、生物群落、生态区域和作物可用性方面与赞比亚最相似的美国各州,以创建最具代表性的训练集。

这个项目的另一个挑战是需要处理的大量遥感数据以及我们完成特征工程的速度。幸运的是,义神星 EarthAI 的使用缓解了这些问题以及处理地理空间数据源的所有隐藏的复杂性。

“将地球观测(EO)数据纳入数据科学的主要挑战之一是处理不同的地图投影和坐标系统。另一个挑战是数据的巨大规模。我们从头开始设计义神星 EarthAI 来处理这两个挑战,对数据科学家几乎没有影响。EarthAI 的“栅格连接”功能就是一个例子,通过该功能,来自全球各地的大型数据集可以在空间和时间上与平台管理的复杂性相连接。”

~研发副总裁 Simeon Fitch

我们在这个项目中使用的遥感数据的大小约为 1tb,在 EarthAI 中聚合和过滤数据后,数据减少到 11GB。尺寸显著减小的部分原因是我们使用光学数据,并且必须应对云。如果一朵云在整个生长季节的任何时候覆盖了一个特定的像素,那么这个像素就会从我们的数据中删除,这对于我们的数据中已经很少见的作物(如豆类和小米)来说是不可取的。因此,我们开始研究减少缺失数据的不同方法,最有前途的方法之一是将合成孔径雷达(SAR)数据源整合到我们的模型中。

合成孔径雷达是一种雷达,它通过向地球发射微波脉冲来工作。当脉冲与物体接触时会被反射或散射,然后返回到卫星,在卫星上,传感器根据返回的回波生成图像。与需要阳光照射物体的被动光学传感器不同,SAR 可以在白天和晚上进行感知,从而产生更多的图像。SAR 的另一个优势是微波脉冲能够穿透云层,因此 SAR 即使在阴天也能产生图像。我们已经有了一些有希望的初步结果,将 SAR 和光学图像结合起来对作物进行分类,如图 8 所示。

图 8:有和没有 SAR 数据的模型预测的比较。

通过利用员工的数据科学专业知识和义神星 EarthAI 平台的可扩展处理能力,我们开发了一个模型,能够跟踪一个面临粮食不安全风险的国家的水和作物可用性。随着气候变化继续改变天气模式,受影响的国家将不得不适应不同的生长季节和水模式,因此,一个允许人们可视化作物和水分布随时间变化的模型将有助于各国适应并确定粮食不安全的高风险地区。

如有疑问或意见,请访问我们的网站:www . astrea . earth

撰写考特尼 ,资深数据科学家

非常感谢义神星大学参与这个项目的其他数据科学家:
金伯利·斯科特博士,联合创始人&数据科学副总裁
杰森·布朗,高级数据科学家
埃里克·库伯特森,数据科学家

参考文献

  1. http://agris.fao.org/agris-search/search.do? recordID=GB2013200329
  2. https://en.wikipedia.org/wiki/Landsat_8
  3. https://www . NASS . USDA . gov/Research _ and _ Science/wh 田/sarsfaqs 2 . PHP # section 1 _ 1.0
  4. https://www . concern USA . org/story/worlds-ten-hungriest-countries/
  5. https://www . concern USA . org/WP-content/uploads/2018/10/GHI-2018 . pdf
  6. http://www.yieldgap.org/zambia
  7. https://medium . com/regen-network/remote-sensing-indexes-389153 e3d 947
  8. https://downloads . USDA . library . Cornell . edu/USDA-esmis/files/VM 40 xr 56k/dv 13 zw 65 p/w 9505297d/planning-10-29-2010 . pdf
  9. http://www.fao.org/giews/countrybrief/country.jsp?code=ZMB

用张量流预测 GCP 森林覆盖类型及模型部署

原文:https://towardsdatascience.com/predicting-forest-cover-type-with-tensorflow-and-model-deployment-in-gcp-fbce9c047dcc?source=collection_archive---------43-----------------------

通过 Kaggle 竞赛开始使用 Tensorflow 并了解如何在 GCP 部署模型

迪皮卡·巴德利用张量流进行森林覆盖类型分类

在这篇文章中,我将分享:

  1. 我如何开始使用 Tensorflow
  2. 用深度学习解决一个卡格竞赛
  3. 在 GCP 部署模型
  4. 在 GCP 为曼梯·里建一条管道

本项目使用的数据来自森林覆盖类型的 Kaggle 竞赛。虽然这不是 Kaggle 上的一个活跃的竞争,但这正好符合我的数字/分类数据标准,可以很容易地进行预测,因此我们可以专注于在 Tensorflow 中建立模型,并为 GCP 建立一个小管道。数据的详细信息在其数据描述页面上提供。数据由美国地质调查局和 USFS(林务局)提供。本问题将预测七种森林覆盖类型:

1 —云杉/冷杉
2 —黑松
3 —黄松
4 —杨木/柳树
5 —白杨
6 —花旗松
7 —克鲁姆霍尔茨

我将通过以下步骤来解决这个问题:

  1. 正在加载数据集
  2. 预处理数据集
  3. Tensorflow 入门
  4. 创建张量流数据集
  5. 用 Keras 建模
  6. 训练模型
  7. 测试模型
  8. 向 Kaggle 提交结果
  9. 在 GCP 部署模型

1.正在加载数据集

从上述 Kaggle 竞赛中下载数据,并将其存储在您的 google drive 或本地的适当文件夹中。将文件夹路径设置为FOLDER_NAME变量。在我的例子中,我将数据存储在 google drive 中,并使用 Google Colab 读取输入文件。如果你想在 Kaggle 笔记本上写代码,你可以按照我在 Kaggle和本文一起发表的代码来写。这些变化仅发生在 Kaggle 笔记本电脑加载和存储数据的情况下。

让我们从安装驱动器开始使用 Google Colab:

这将给出一个链接,以获取代码,你需要输入到输入框出现。一旦完成,我们就可以在 dataframe 中加载数据了。

输出:

部分输出

训练数据集有 15120 行。从描述表中可以看出,土壤类型 7 和 15 具有恒定的 0 值,因此应将其移除。除了分类列(Soil_TypesWilderness_Areas)之外,一些具有数值的列应该被规范化以获得更好的结果。在下一步中,我们将执行所有的预处理步骤,以便为预测准备好数据。

2.预处理数据集

所有土壤类型的类别数据列将从一个热编码表合并为一列,类似的荒野区域列也将被转换。

输出:

土壤类型 8 和 25 每种类型只有一行,因此它们被转换成另一列,标有 NA 下标。这是可选的,您也可以删除这些列。

对于数字列,MinMaxScaler是将被应用来获得标准化列的转换器。在此之前,我们需要将数据分为训练、测试和验证,以便对这些数据进行标准化。

将数据分为训练、val 和测试

数据将分为训练、验证和测试。培训占 60%,测试占 20%,验证占 20%。

输出:

一旦数据被分割,归一化可以应用如下:

3.Tensorflow 入门

Tensorflow 是谷歌基于 Theano (Python 库)的开源深度学习库,用于研究和生产。你需要知道的一些核心组件是张量和图形。张量是一个 n 维向量或矩阵,用于存储数据和执行功能。Graph 是描述节点之间所有操作和连接的地方,可以在多个 CPU 或 GPU 上运行。

在这篇文章中,我将解释我如何使用 Tensorflow 创建我的第一个模型,而不是 tensorflow 的基础知识。如果你有兴趣学习,可以从这里过基础教程。我必须承认浏览 Tensorflow 文档不像 PyTorch 那么容易。使用 PyTorch,我能够在一周内构建我的第一个模型,但使用 Tensorflow 文档,很难理解加载数据本身的正确方式,此外,函数格式之间存在冲突,并且它与其他版本的向后兼容性也存在问题。因此,接下来的教程将会导致其他不容易解决的错误。

在你的机器或谷歌 Colab 中安装 tensorflow。我用过 Google Colab 搭配 GPU 运行时。这个问题用的是 Tensorflow 2。

!pip install tensorflow

4。创建张量流数据集

在所有的处理之后,我们将把数据放入 tensorflow 数据集。这将有助于构建模型的输入管道。对于数据集,必须定义 batch_size,这是可以成批而不是一次访问数据的大小。你也可以随意调整行。

输出:

输出的一部分(水平方向的列名无法放入一个屏幕截图中)

5.用 Keras 建模

将使用具有前馈神经架构的 tensorflow Keras 构建模型。使用 tensorflow Keras layers.DenseFeatures构建要素图层。分类列和数字列被分别处理,以创建代码中所示的输入层。模型在build_model 函数中定义,具有 100 和 50 两个隐藏层,后面是包含输出神经元数量为 8 的输出层。它是 8,因为类型是从 1 到 8 的整数值,而不是 0 到 7。在混淆矩阵中,我们忽略了类 0。使用优化器adam和激活功能relu。建筑模型和管线的代码如下:

6.训练模型

对于训练,我们为模型的拟合函数提供训练和验证数据集。验证损失使得在训练期间更容易发现模型的过度拟合。模型被训练 100 个纪元。

输出:

部分输出

在输出中,很明显,网络是基于随着验证精度增加的训练精度来学习的。如果在某个点上,验证准确性在增加,而训练准确性在增加,那么这就是模型过度拟合的点。这样你就能知道在那个时候停止纪元。如果它是随机的,那么这个模型没有学到任何东西。有了设计好的架构,我在训练集和验证集上的准确率分别达到了 85%和 84%。

在模型摘要中,您可以看到每一层的参数数量。在第一个隐藏层中,51 个输入特征连接到 100 个隐藏节点,对于完全连接的网络具有 5100 个权重,对于每个节点具有 100 个偏差参数,总计 5200 个参数。在下一层中,100 个节点连接到 50 个节点,具有 5000 个连接,第二隐藏层中的每个节点具有 50 个偏置参数,构成 5050 个参数。类似地,计算下一批参数。这就是你阅读模型摘要的方式。它显示最后学习了多少个参数。最后模型被保存到一个目录中。

7.测试模型

为了测试模型如何处理测试数据,我们将对 sklearn 的报告进行分类。分类报告将显示每种森林覆盖类型的精确度、召回率和 f1 分数以及平均精确度等。

输出:

该模型的平均准确率达到了 80%左右。对于前馈神经网络的简单结构,这是足够好的结果。现在,我们可以使用模型获得 kaggle 测试数据集的结果,并将其提交给 kaggle。

8.向 Kaggle 提交结果

我们需要预测 kaggle 上给出的测试数据的封面类型。该数据与第一步中下载的数据位于同一文件夹中。预期的输出是包含IdCover_Type列的 csv 文件。对训练数据进行的类似转换必须对测试数据进行。以下代码显示了如何获取测试数据的结果:

输出:

一旦你准备好了文件,你可以把它上传到 Kaggle 竞赛页面的我的提交部分。一旦提交,你可以在一段时间后看到分数。提交后,我在测试数据上得到了~62%的准确率。你可以用不同的实验做尽可能多的提交,努力提高这个分数。就这些,你可以开始参加不同的比赛,用不同种类的数据集做实验。我从有数字/分类数据的简单预测问题开始。我的目标是通过一个真实世界的例子来学习张量流,所以我从 Kaggle 竞争数据集开始,该数据集并不活跃,但有简单的问题需要处理。

9.在 GCP 部署模型

谷歌人工智能平台

前一节中保存的模型可用于部署在 google cloud 中,以便您拥有的任何应用程序都可以访问它。我认为你对谷歌云有基本的了解,并且在这方面有所建树。正如我不会解释的那样,如何开始学习 GCP(你可以在 coursera / GCP Qwiklabs 上学习很多入门课程)。

先决条件:

你可以创建一个免费的谷歌云账户,如果你还没有的话,它有 300 美元的免费信用。在接下来的步骤中,我们需要这一点。同时在你的电脑上安装 GCP 软件开发工具包。如果没有项目,在 Google Cloud 中创建一个项目。确保在 IAM 中下载一个服务帐户密钥,并存储在环境变量中。(关于通过命令控制台与 GCP 交互的基本设置,请参考谷歌云文档)

export GOOGLE_APPLICATION_CREDENTIALS=<PATH TO KEY JSON FILE>

运行以下命令,使用 Google Cloud 帐户进行身份验证,并根据输出中的给定说明设置项目。

gcloud auth login

第一步,将前面章节中的文件夹forest_model_layer_100_50_epoch_100上传到谷歌云存储中。我创建了一个 bucket forest-cover-model并在那个位置上传了文件夹。

一旦完成,您就可以部署模型了。

gcloud components install beta

这在部署模型之前是必需的。

gcloud beta ai-platform versions create v7 \--model ForestPredictor \--origin gs://forest-cover-model/forest_model_layer_100_50_epoch_100/ \--runtime-version=2.1 \--python-version=3.7

v7 版本是在我做了一些实验后有效的版本。可以以 v1 作为版本名。这样,您可以保留模型的不同版本。合适的运行时版本可以在这里找到。Origin 参数是存储模型的 google 存储路径的路径。

最初我计划用预处理类等定制预测例程。但不幸的是,在创建了所有这些之后,在部署的时候,我才知道它只适用于tensorflow>=1.13,<2。它正在发展,所以它可能会在未来支持,检查这里的更新。(自定义管道的代码存在于我的库中,我已经分享给感兴趣的人)

要测试部署的模型,可以浏览到 AI Platform > Models,在模型名称下点击想要测试的版本号。有测试和使用选项,你可以给自定义输入。输入格式如下,使用下面的例子进行测试。

{
   "instances":[
      {
         "Elevation":0.4107053527,
         "Aspect":0.9833333333,
         "Slope":0.2121212121,
         "Horizontal_Distance_To_Hydrology":0.0,
         "Vertical_Distance_To_Hydrology":0.2235142119,
         "Horizontal_Distance_To_Roadways":0.3771251932,
         "Hillshade_9am":0.7716535433,
         "Hillshade_Noon":0.842519685,
         "Hillshade_3pm":0.6141732283,
         "Horizontal_Distance_To_Fire_Points":0.9263906315,
         "Wilderness_Areas":"Wilderness_Area1",
         "Soil_Types":"Soil_Type33"
      }
   ]
}

您可以看到如下输出:

输出给出了输入的每种覆盖类型的概率。

一旦这些都工作正常,您就可以使用该模型对任何输入数据进行预测。我已经在 Github 资源库中分享了代码。文件forest_classification.py包含调用模型和输入管道的代码。

我将输入数据分成小块,因为它不能一次返回所有行的结果。这些是你需要在应用程序中管理的东西。如果您有兴趣探索如何为部署在 GCP 的模型创建管道,您可以参考该文档。

Tadaa!您已经准备好在实际解决方案中使用该模型,并为各种实验维护版本控制,并在此基础上跟踪性能。在现实世界中,除了只是建立一个模型,这些技能是非常重要的。有趣的是,如果您愿意的话,您可以尝试看看这些管道在其他云环境中是如何构建的。如果您希望尝试如何使用各种参数或其他优化函数来优化模型,那么您可以参考我以前的文章,在那里我提出了在深度神经网络中构建模型的改进/其他机会。尽管这是针对 PyTorch 的,但是无论您使用哪种框架,更改架构和参数的基础都是相同的。你必须找到在其他库中定义和做同样事情的方法。希望这能帮助你开始学习 GCP 和 Kaggle 以及 Tensorflow 框架!

一如既往—愉快的实验和学习:)

用机器学习工作流预测森林覆盖类型

原文:https://towardsdatascience.com/predicting-forest-cover-types-with-the-machine-learning-workflow-1f6f049bf4df?source=collection_archive---------9-----------------------

内森·安德森Unsplash 上拍照

机器学习

又名神奇的树:在哪里找到,如何检测它们🌲

在本文中,我将解释如何使用端到端的工作流来处理多类分类监督机器学习(ML)问题(或项目)。

  • 监督:特征(生成预测的变量)和目标(待确定的变量)在数据集中可用。
  • 多类分类:有七个离散的类别来区分目标。

该项目基于机器学习社区中一个著名的数据集,称为森林覆盖类型,可在 UCI 机器学习知识库中下载。

来自原始数据集的分层样本用于应用工作流和独立测试集以生成最终预测,被用作 Kaggle 中初学者友好型竞赛的一部分。

项目(和竞赛)的目标:以最佳精度预测北科罗拉多州罗斯福国家森林四个不同荒野地区的七种不同覆盖类型。

四个荒野地区是:

  • 1:拉瓦
  • 2:纽塔
  • 3:科曼奇峰
  • 4: Cache la Poudre

Cache la Poudre 荒野地区(来源)

Cover_Type栏中从 1 到 7 的七个类别,待分类:

  • 1:云杉/冷杉
  • 2:黑松
  • 3:美国黄松
  • 4:杨木/柳木
  • 5:阿斯彭
  • 6:道格拉斯冷杉
  • 7:克鲁姆霍尔茨

目标(封面类型)的名字让我想起了神奇的野兽,所以我称它们为神奇的树,以增加项目的想象力🙃。

端到端机器学习工作流程步骤:为了对封面类型进行分类并回答发起的问题,在哪里找到奇异的树以及如何检测它们,将遵循以下步骤:

  1. 理解、清理和格式化数据
  2. 探索性数据分析
  3. 特征工程和选择
  4. 比较几种机器学习模型
  5. 对最佳模型执行超参数调整
  6. 解释模型结果
  7. 用测试数据评估最佳模型(回答初始问题)
  8. 总结和结论

我将在本文中提供该项目的亮点,项目背后的全面分析和完整代码可在 Kaggle 笔记本GitHub 中获得。

对于数据角力和可视化 numpypandasmatplotlibseaborn;为了建立机器学习模型 xgboost ,lright GBMscikit-learn;为了执行预处理步骤,将使用 scikit-learn

1.理解、清理和格式化数据

让我们加载训练数据并创建trees数据框:

trees = pd.read_csv("/kaggle/input/learn-together/train.csv")

我总是发现查看第一行和最后一行很有用:

数据集的第一列和第一行

数据集的最后一列和最后一行

第一个观察结果是,Vertical_Distance_To_Hydrology列中有一些负值。我将在检查异常&异常值部分对此进行更详细的检查。

为了理解trees数据框架,让我们看看数据类型和描述性统计。使用 pandas info方法,我们可以列出非空值和数据类型:

**Data columns (total 56 columns):
Id                                    15120 non-null int64
Elevation                             15120 non-null int64
Aspect                                15120 non-null int64
Slope                                 15120 non-null int64
Horizontal_Distance_To_Hydrology      15120 non-null int64
Vertical_Distance_To_Hydrology        15120 non-null int64
Horizontal_Distance_To_Roadways       15120 non-null int64
Hillshade_9am                         15120 non-null int64
Hillshade_Noon                        15120 non-null int64
Hillshade_3pm                         15120 non-null int64
Horizontal_Distance_To_Fire_Points    15120 non-null int64
Wilderness_Area1                      15120 non-null int64
Wilderness_Area2                      15120 non-null int64
Wilderness_Area3                      15120 non-null int64
Wilderness_Area4                      15120 non-null int64
Soil_Type1                            15120 non-null int64
Soil_Type2                            15120 non-null int64
Soil_Type3                            15120 non-null int64
Soil_Type4                            15120 non-null int64
Soil_Type5                            15120 non-null int64
Soil_Type6                            15120 non-null int64
Soil_Type7                            15120 non-null int64
Soil_Type8                            15120 non-null int64
Soil_Type9                            15120 non-null int64
Soil_Type10                           15120 non-null int64
Soil_Type11                           15120 non-null int64
Soil_Type12                           15120 non-null int64
Soil_Type13                           15120 non-null int64
Soil_Type14                           15120 non-null int64
Soil_Type15                           15120 non-null int64
Soil_Type16                           15120 non-null int64
Soil_Type17                           15120 non-null int64
Soil_Type18                           15120 non-null int64
Soil_Type19                           15120 non-null int64
Soil_Type20                           15120 non-null int64
Soil_Type21                           15120 non-null int64
Soil_Type22                           15120 non-null int64
Soil_Type23                           15120 non-null int64
Soil_Type24                           15120 non-null int64
Soil_Type25                           15120 non-null int64
Soil_Type26                           15120 non-null int64
Soil_Type27                           15120 non-null int64
Soil_Type28                           15120 non-null int64
Soil_Type29                           15120 non-null int64
Soil_Type30                           15120 non-null int64
Soil_Type31                           15120 non-null int64
Soil_Type32                           15120 non-null int64
Soil_Type33                           15120 non-null int64
Soil_Type34                           15120 non-null int64
Soil_Type35                           15120 non-null int64
Soil_Type36                           15120 non-null int64
Soil_Type37                           15120 non-null int64
Soil_Type38                           15120 non-null int64
Soil_Type39                           15120 non-null int64
Soil_Type40                           15120 non-null int64
Cover_Type                            15120 non-null int64
dtypes: int64(56)
memory usage: 6.5 MB**

describe方法,我们可以观察到描述性统计:

第一列的描述性统计

info法提供了一些有价值的信息:

  • 数据是格式化的和干净的:没有任何空值,所有要素都是数字。
  • 一个热编码栏(在原始笔记本中验证):土壤类型和荒野面积。

检查异常&异常值:

观察到的第一个异常是Vertical_Distance_To_Hydrology列中的负值。定义是:

到最近地表水特征的垂直距离

通过一些研究和使用逻辑,负值表明最近的地表水低于该数据点或低于海平面。两种情况都有道理,所以我要保留负值。

为了帮助未来的 ML 模型掌握数据中的模式,我将搜索异常值并使用极端异常值方法来确定它们。

如果数据点位于第一个四分位数以下或第三个四分位数以上的四分位数间距的 3 倍以上,则数据点将被删除。

*# loop through all columns to see if there are any outliers*
for column in trees.columns:
    if outlier_function(trees, column)[2] > 0:
        print("There are {} outliers in {}".format(outlier_function(trees, column)[2], column))

知道了荒野面积和土壤类型列是一次性编码的,我们就可以专注于其余部分:

**There are 53 outliers in Horizontal_Distance_To_Hydrology
There are 49 outliers in Vertical_Distance_To_Hydrology
There are 3 outliers in Horizontal_Distance_To_Roadways
There are 7 outliers in Hillshade_9am
There are 20 outliers in Hillshade_Noon
There are 132 outliers in Horizontal_Distance_To_Fire_Points**

山体阴影列是特定时间阴影的 RGB 颜色表示,因此范围已经固定在 0 到 255 之间。

考虑到Horizontal_Distance_To_Firepoints具有最大数量的异常值和最宽的数据范围【0,6993】,我将只删除该列中的异常值。

trees = trees[(trees['Horizontal_Distance_To_Fire_Points'] > outlier_function(trees, 'Horizontal_Distance_To_Fire_Points')[0]) &
              (trees['Horizontal_Distance_To_Fire_Points'] < outlier_function(trees, 'Horizontal_Distance_To_Fire_Points')[1])]

2.探索性数据分析

EDA 是该工作流中的第一步,在该步骤中,针对特征选择启动决策过程。通过观察目标的分布、特征与目标的关系以及特征之间的联系,可以获得一些有价值的见解。

我的偏好是从查看目标开始,然后检查特征及其与目标的关系。

目标分布:

奇异的树/标签/覆盖类型的分布

数据集具有平衡的标签,导致每个类别的封面类型数量几乎相等。当我们应用 ML 算法时,这将是一个优势,因为模型将有很好的机会学习所有类的模式,而不需要进一步的平衡策略。

荒野地区——覆盖类型:

为了了解这种关系,荒野区域列将被反向热编码。

trees['Wilderness_Area_Type'] = (trees.iloc[:, 11:15] == 1).idxmax(1)

不同荒野地区覆盖类型的 KDE 样地

荒野区域是确定Cover_Type的显著特征。

荒野地区—土壤类型—覆盖类型:

反向一热编码将使用以下函数应用于土壤类型列。因此,将添加一个具有 1 到 40 之间的离散数字的列Soil_Type

不同荒野地区土壤类型和覆盖类型散点图

不同的荒野地区由一些特定的树木组成。有趣的是,有一种奇妙的树,棉白杨/柳树,特别喜欢生长在 Cache la Poudre(荒野区域 4)。虽然云杉/冷杉、黑松、白杨和花旗松可以在任何土壤类型中生长,但其他覆盖类型可以在特定的土壤类型中生长。

连续特征之间的关系:

土壤类型和荒野区域列是离散的,并且都是一个分类要素的一个热编码版本。

其余要素被视为连续要素:高程、坡向、坡度、水平距离水文、垂直距离水文、水平距离道路、山体阴影上午 9 点、山体阴影中午 3 点、水平距离火灾点。

为了用一个函数将它们可视化,将绘制 Seaborn 的PairGrid,以提供用不同的图调整上下对角线的灵活性:

连续特征的成对网格

上半部分显示了具有皮尔逊系数的 KDE 图,下半部分显示了散点图。对角线是特定特征的直方图。正如所料,山体阴影特征是共线的:

  • 山体阴影中午-山体阴影下午 3 点
  • 山体阴影下午 3 点—山体阴影上午 9 点

这些对为模型提供相同的输入,为了更好的可解释性,其中一个将在特征工程&选择中被删除。

特性和目标的皮尔逊系数:

作为 EDA 的最后一步,当观察特征和目标的 Pearson 系数时,只有 1%的 one-hot-encoded 土壤类型列在确定Cover_Type时是有效的(本文未显示,但在笔记本这里)。因此,它们将被排除,皮尔逊系数将被重新使用连续特征、一个热编码的荒野区域、Soil_TypeCover_Type

continuous_variables = trees.columns[1:11].tolist()wilderness_areas = sorted(trees['Wilderness_Area_Type'].value_counts().index.tolist())all_features_w_label = continuous_variables + wilderness_areas + ["Soil_Type"] + ["Cover_Type"]trees_w_numeric_soil = trees[all_features_w_label]

cover_type 数据集的皮尔逊系数热图

深色代表强烈的相关性。不幸的是,最后一列由浅色组成,导致特征相对于目标的弱皮尔逊系数,在[-0.22,0.12]的范围内。

标签编码的 Soil_Type列与Cover_Type有更强的相关性。

Hillshade_9am在确定Cover_Type时最不重要。因此,它将在下一节中被删除。

3.特征工程和选择

在已有特征的基础上提取新特征,用一些方法和算法消除特征,称为特征工程&选择。

水文要素有水平距离和垂直距离,两者的欧几里德距离相加闪烁。

trees_w_numeric_soil['Euclidian_Distance_To_Hydrology'] = (trees_w_numeric_soil['Horizontal_Distance_To_Hydrology']**2 +                                                        trees_w_numeric_soil['Vertical_Distance_To_Hydrology']**2)**0.5

此外,添加数字特征的线性组合是特征工程中的常见做法。对于一些数字特征,两个变量的平均值相加:

trees_w_numeric_soil['Mean_Elevation_Vertical_Distance_Hydrology'] = (trees_w_numeric_soil['Elevation'] +                                                               trees_w_numeric_soil['Vertical_Distance_To_Hydrology'])/2trees_w_numeric_soil['Mean_Distance_Hydrology_Firepoints'] = (trees_w_numeric_soil['Horizontal_Distance_To_Hydrology'] +                   trees_w_numeric_soil['Horizontal_Distance_To_Fire_Points'])/2trees_w_numeric_soil['Mean_Distance_Hydrology_Roadways'] = (trees_w_numeric_soil['Horizontal_Distance_To_Hydrology'] +                                                   trees_w_numeric_soil['Horizontal_Distance_To_Roadways'])/2trees_w_numeric_soil['Mean_Distance_Firepoints_Roadways'] = (trees_w_numeric_soil['Horizontal_Distance_To_Fire_Points'] +                              trees_w_numeric_soil['Horizontal_Distance_To_Roadways'])/2

另一种常见的做法是对数字特征执行对数和平方根变换。再添加 5 个特征后,对正特征应用平方根变换:

for col **in** trees_w_numeric_soil.columns:
    if trees_w_numeric_soil[col].min() >= 0:
        if col == 'Cover_Type':
            next
        else:
            trees_w_numeric_soil['sqrt' + col] = np.sqrt(trees_w_numeric_soil[col])

在重新访问皮尔逊系数之后,如果新添加的特征显示出与目标更强的相关性,则保留该新添加的特征,而丢弃原始特征。此外,Hillshade_9am因与Hillshade_3pm密切相关而被剔除。

特征工程后的皮尔逊系数

最后的特点是:

*# final list of features*
transformed_features = ['sqrtHorizontal_Distance_To_Hydrology', 'sqrtMean_Distance_Hydrology_Roadways', 'sqrtEuclidian_Distance_To_Hydrology', 
'Mean_Elevation_Vertical_Distance_Hydrology', 'Mean_Distance_Firepoints_Roadways', 'Mean_Distance_Hydrology_Firepoints']all_features =  (['Elevation', 'Aspect', 'Slope', 'Vertical_Distance_To_Hydrology', 'Horizontal_Distance_To_Roadways', 
'Hillshade_Noon', 'Hillshade_3pm', 'Horizontal_Distance_To_Fire_Points' ] + 
wilderness_areas + ['Soil_Type'] + transformed_features)trees_training = trees_w_numeric_soil[all_features]
labels_training = trees_w_numeric_soil["Cover_Type"].as_matrix()

为了比较 ML 模型并建立基线,trees_traininglabels_training数据帧被分成训练集和验证集。

X_train, X_valid, y_train, y_valid = train_test_split(trees_training, labels_training, test_size=0.2, random_state=1)
  • 训练集用作输入,以便机器学习模型可以捕捉特征中的模式,并利用它们来区分目标。
  • 验证集用于评估 ML 模型的性能,并量化其将模式归纳到新数据集的能力。

创建基线度量:

在深入研究 ML 分类算法之前,我将计算一个常识基线。常识基线可以定义为了解该领域的人如何在不使用任何 ML 技巧的情况下解决问题。它可以用人类的直觉以及一个虚拟或简单的算法来计算,只需要几行代码。

我将使用 scikit-learn 库中的一个虚拟算法。使用该算法,我将建立一个具有准确性的基线度量,即所有覆盖类型中正确预测的覆盖类型的百分比。准确性是本次竞赛的评估标准,将在整个项目中使用,记住它对于某些分类问题来说不是最有效的标准

基线指标在某种程度上很重要,如果机器学习模型不能击败人的简单直观预测或算法的猜测,那么原始问题需要重新考虑或训练数据需要重新构建。

*# Create dummy classifer*
dummy = DummyClassifier(strategy='stratified', random_state=1)*# train the model*
dummy.fit(X_train, y_train)*# Get accuracy score*
baseline_accuracy = dummy.score(X_valid, y_valid)
print("Our dummy algorithm classified {:0.2f} of the of the trees correctly".format(baseline_accuracy))
**Our dummy algorithm classified 0.14 of the of the trees correctly**

现在,我期望以下 ML 模型击败 0.14 的准确度分数!

4.比较几种机器学习模型

有时很难知道哪种机器学习模型将有效地解决给定的问题。所以,我总是尝试几种机器学习模型。

一项研究显示,基于树和基于距离的算法在分析的 165 个数据集上优于其他最大似然算法。

机器学习算法性能比较(来源)

我将比较一个基于距离的算法和四个基于树的算法的准确性。

基于距离:

  • k-最近邻分类器(使用欧几里德距离来聚类标签;之前需要进行规范化,并在原始笔记本中的处应用。)

基于树:

(型号后面的代码是这里是。)

与研究结果不同,额外树分类器优于其他分类器。所有模型都优于基线度量,表明机器学习适用于森林覆盖类型的分类。

我们最好的模型,额外树分类器,是一个基于集合树的模型。sci kit-learn 库中的定义如下:

该类实现了一个元估计器,它在数据集的各个子样本上拟合多个随机决策树(也称为额外树),并使用平均来提高预测精度和控制过度拟合。

与随机森林算法的主要区别在于:

  1. 不是为节点中的特征寻找最有区别的分裂值,而是完全随机地选择分裂作为阈值。
  2. 子样本取自整个训练集,而不是训练集的引导样本。

因此,该算法对于过拟合变得更加鲁棒。

5.对最佳模型执行超参数调整

寻找模型参数的最佳组合被称为超参数调整,它可以极大地提高模型的性能。我将使用交叉验证的随机搜索算法进行超参数调整:

  • 随机搜索:在一个范围内定义一组 ML 模型的参数,并输入到 sklearn 的T0。该算法随机选择一些参数组合,并将定义的score(精确度,对于这个问题)与迭代进行比较。可以用参数n_iter控制随机搜索运行时间和迭代次数。
  • K-Fold 交叉验证:一种用于评估超参数在整个数据集上的性能的方法。(目测此处)。不是将数据集分成训练集和验证集的两个静态子集,而是对于给定的 K,数据集被均等地划分,并且随着迭代,不同的 K-1 个子集被训练,并且用不同的子集测试模型。

使用以下一组参数和 5 重交叉验证,RandomizedSearchCV将寻找最佳组合:

*# The number of trees in the forest algorithm, default value is 100.*
n_estimators = [50, 100, 300, 500, 1000]

*# The minimum number of samples required to split an internal node, default value is 2.*
min_samples_split = [2, 3, 5, 7, 9]

*# The minimum number of samples required to be at a leaf node, default value is 1.*
min_samples_leaf = [1, 2, 4, 6, 8]

*# The number of features to consider when looking for the best split, default value is auto.*
max_features = ['auto', 'sqrt', 'log2', None] 

*# Define the grid of hyperparameters to search*
hyperparameter_grid = {'n_estimators': n_estimators,
                       'min_samples_leaf': min_samples_leaf,
                       'min_samples_split': min_samples_split,
                       'max_features': max_features}*# create model*
best_model = ExtraTreesClassifier(random_state=42)

*# create Randomized search object*
random_cv = RandomizedSearchCV(estimator=best_model,                          param_distributions=hyperparameter_grid,
                               cv=5, n_iter=20, 
                               scoring = 'accuracy',
                               n_jobs = -1, verbose = 1, 
                               return_train_score = True, 
                               random_state=42)*# Fit on the all training data using random search object*
random_cv.fit(trees_training, labels_training)
random_cv.best_estimator_

以下是参数的最佳组合:

  • n_estimators = 300
  • max_features =无
  • min_samples_leaf = 1
  • min_samples_split = 2

当我将它们输入额外的树分类器时:

**Accuracy score in the previous extra random forests model: 0.8659106070713809
Accuracy score after hyperparameter tuning: 0.885923949299533**

导致精确度增加 2 个点。

另一种搜索方法是GridSearchCV,与RandomizedSearchCV相反,搜索是在给定参数的每一个组合上进行的。(此处应用和讨论【原笔记本)

6.解释模型结果

混乱矩阵:

可视化分类模型结果的最常见方法之一是混淆矩阵。

奇异树混淆矩阵将是一个 7x7 矩阵。我将使用标准化的混淆矩阵,因此在该特定类别的所有猜测中,正确猜到的实际封面类型的百分比将出现在矩阵的对角线上。

非对角线元素将显示模型错误标记的元素。混淆矩阵对角线上的百分比越高、颜色越深越好,表明有许多正确的预测。

我将使用 scikit 中的函数——学习绘制它:

超参数调整的超随机森林分类器的混淆矩阵

该模型很好地检测了美国黄松、三叶杨/柳树、白杨、花旗松、克拉姆霍尔茨等奇异的树木,但似乎对检测云杉/冷杉和黑松(覆盖类型 1 和 2)有些混淆。

特征重要性:

另一种方法是查看具有feature_importances_的特征重要性:一个介于 0 和 1 之间的数字,显示每个特征对预测的贡献。数字越高,说明贡献越大。

利用当前选择的功能、额外的树分类器和参数,前 10 个功能是:

其中 5 个是在本项目范围内创建的。这个列表强调了特征工程和选择的重要性。

7.用测试数据评估最佳模型(回答初始问题)

如何检测奇异的树(生成最终预测):

Kaggle 为比赛提供单独的训练和测试设备。直到现在,我都在训练台上工作。尽管如此,测试集用于最终预测,所以我将测试集和训练集在这里对齐,并将其输入超参数调整的额外树分类器

成功检测奇异树,准确率 78%。

哪里可以找到神奇的树:

云杉/冷杉、Lodgepole Pine 和 Krummholz 喜欢在 Rawah、Neota 和 Comanche Peak 荒野地区出没。

Cache la Poudre 荒野区是种植黄松和棉白杨/柳树的最佳地点。

如果你看到一个白杨,怀疑你是在 Rawah 或 Comanche。

花旗松是一种容易相处的物种,适合任何荒野地区。

8.总结和结论

在本文中,我重点介绍了端到端的机器学习工作流在有监督的多类分类问题中的应用。我从使用 EDA 理解和可视化数据开始,并形成了对 cover 类型数据集的见解。利用 EDA 的输出,我进行了特征工程,在其中我转换、添加和删除了特征。

额外树分类器很好地匹配了这个分类问题的准确性度量。随着超参数的调整,通过调整n_estimators参数,模型的准确度分数增加了 2 个点。解释模型结果显示了最重要的特征以及如何进一步提高准确性(通过更好地区分封面类型 1 和 2)。

项目背后的综合代码:

https://github.com/cereniyim/Tree-Classification-ML-Model】Github 回购:T4

Kaggle 笔记本:https://www . ka ggle . com/cereniyim/fantastic-trees-where-to-find-how-detect-them/Notebook

感谢阅读,这种端到端的工作流程可以应用于任何机器学习问题,我鼓励你去尝试一下!

对于任何问题、评论或建设性反馈,您可以通过回复联系我, TwitterLinkedin

使用 Elo 评级预测一级方程式赛车结果

原文:https://towardsdatascience.com/predicting-formula-1-results-with-elo-ratings-908470694c9c?source=collection_archive---------26-----------------------

体育分析

通过模型、数据管道和蒙特卡洛模拟建立预测

达伦·努尼斯Unsplash 上拍摄的照片

一级方程式赛车比赛通常感觉是可预测的:梅赛德斯在 2020 赛季赢得了过去的 5 个冠军和前 9 个 gp 中的 7 个。网上当然不乏 f1 预测——从专业专家到自封的纸上谈兵的“专家”,任何人都经常热衷于分享他们的预测。我的目标是对这个问题进行更深入的分析:一级方程式比赛能被算法预测吗?

在过去的两年里,我一直致力于预测 f1 资格赛的结果。从一开始,我的目标也是预测比赛结果,但这比预期的要复杂。排位赛结果相对更容易建模:在一级方程式排位赛中,获胜者是创下最快时间的车手。因此,司机的表现可以被认为是独立于其他人的:他们与时间竞争,只是间接的相互竞争。这使得预测结果更容易:每个司机的预测结果可以直接与他们的成绩进行比较。一级方程式比赛的建模更加复杂,因为车手之间直接竞争。但是随着一个封闭的夏天的到来,我决定是时候尝试一下赛车模型了。两位伟大的开发人员 Raiyan 和 Philip 加入了我的行列,共同探索建立一个预测 f1 比赛结果的模型。

在 F1 比赛中,完成时间并不重要:无论你以 20 秒还是 0.1 秒的优势赢得比赛,你都可以获得相同的分数。我们决定将比赛建模为成对参与者之间的一系列独立的、面对面的比赛,最终一名参与者获胜或失败(或者未解决,如果一方或双方没有完成比赛)。该模型不考虑完成时间或获得的分数,而是检查参与者赢得了多少场比赛,以及它与他们的预期分数如何匹配。这种方法背后的一个主要好处是它在“反常”比赛中的相对弹性:例如,在一个只关注终点位置的模型中,大多数领先者没有完成的比赛将导致较弱的车手获得不合理的大收益。一个关于头对头比赛的推理模型不会将退役的车手考虑在内,从而导致对车手分数的现实调整。

这些车手之间的竞争可以用一个叫做 Elo ratings 的概念来模拟。Elo 评级最初是为国际象棋选手排名而开发的。在 Elo 系统中,战胜一个更强的对手比战胜一个统计上更弱的对手获得更多的分数。每位车手的 Elo 评分在比赛结束后会根据他们在每场比赛中的表现与预期分数的对比情况进行上调或下调。预期分数是通过比较两个参与者的 Elo 评级计算出来的,它是一个介于 1 和 0 之间的值。预期分数 1 意味着车手将永远赢得比赛,而预期分数 0.5 意味着他们将赢得一半的时间。一级方程式赛车比赛的“真实”分数总是 1 或 0,取决于车手是赢还是输(如果一名或两名车手没有完成比赛,比赛不计算分数)。实际分数和预期分数之间的差异将应用于每位驾驶员的分数,K 系数为 4。

f1 比赛因排位赛而变得更加复杂,排位赛规定了比赛的发车顺序。因为车手的发车位置对他们的预期完成位置有着重大影响,所以参与者的 Elo 分数会根据他们的发车位置上下调整。网格调整后的 Elo 分数(gaElo)是用于预测车手比赛成绩的分数。与排位赛模型一样,预测是通过蒙特卡洛模拟生成的,在模拟过程中,每个车手、建造商和引擎的 gaElo 分数都会随机上调或下调。这里还模拟了一名车手退出比赛的可能性。通过多次运行模拟,可以计算出每个车手完成位置的百分比概率。

如前所述,比赛模型的预测取决于给定的起始网格。除了在周六的排位赛中决定的发车,我们还可以使用排位赛模型的模拟排位赛结果来生成比赛预测。这被称为“资格前预测”,它往往比“资格后预测”具有更大的分数方差。这是可以理解的,因为定性前的预测包含两倍的不确定性。构建允许两个模型顺序运行的管道并不容易,但是结果是非常值得的!

比赛模型产生的预测与现有的排位赛模型一起出现在项目的网站上。对 2020 年德国 Eifel GP 的预测是由当前的模型生成的,而早期的预测是由实验模型生成的。

马克斯·维斯塔潘的比赛预测截图。图片作者:Ville Kuosmanen

该模型的性能是根据两个基准来衡量的:一个随机模型,随机预测结果;一个模型,总是预测结果与起始网格相同。我们的评估显示,该模型的性能优于基准测试,尽管与基于网格的模型相比,它的性能仅略胜一筹,这表明该模型在准确性方面还有很长的路要走。比赛模型尤其难以预测由于发车区处罚或排位赛中的问题而在场地后部起步的快速车手的成绩,这是我们希望在未来解决的问题。

比赛模式仍然有很多需要改进的地方。尽管如此,我不相信比赛模型能够匹配排位赛模型的表现:f1 比赛从本质上来说比排位赛更随机(这是否是真的还有待证明)。我们想做的下一个功能包括通过模拟未来的比赛来预测整个锦标赛。就像连接排位赛模型和正赛模型一样,这是一个工程问题,需要建设新的数据管道。我还想通过在网站上展示对模型内部工作的一些见解来提高模型的可解释性(这是我在推荐系统中写过的一个主题)。调查赛季前测试的数据也很有趣:比赛和排位赛车型往往在每个赛季开始时表现最差,因为制造商之间的力量平衡被打破了。

如果你有兴趣了解我们的一级方程式预测项目,你可以查看 GitHub 上的项目页面(完整的开源代码)。虽然作为一名工程师,我希望看到一个可以完美预测每场比赛结果的模型,但作为一名观众,每隔一段时间就有一场意想不到的比赛获胜者被证明是错误的,这令人耳目一新!

使用 NLP +深度学习预测欺诈性新闻文章

原文:https://towardsdatascience.com/predicting-fraudulent-news-articles-using-nlp-deep-learning-ffdf64f19537?source=collection_archive---------58-----------------------

利用 NLP、ML 和深度学习分析和预测欺诈性新闻文章。

乔·塞拉斯Unsplash 上的照片

生活在一个网上信息泛滥的时代,让我们容易相信欺骗性的新闻报道。这个问题在互联网上大量存在,其需求要求我们用机器学习和深度学习模型进行实验,以对潜在虚假的新闻进行分类。

这篇文章希望阐明“如何”利用自然语言处理、机器学习和深度学习来预测和识别欺诈性新闻文章。它还分享了从分析中得出的方法、结果和结论。

获取数据:

包含真假新闻文章的数据集是从 Kaggle 获得的。数据集的形状是 20800 行和 5 列。数据集中有 10413 篇真实文章和 10387 篇虚假文章,表明数据集是平衡的。“标签“栏表示该商品是真的还是假的; 1 表示假, 0 表示真。

图 1:数据快照。

清理数据:

由于文本数据是非结构化和杂乱的,因此需要进行文本预处理。一个助手函数被应用于数据,以移除换行符、新行、超链接、与符号、大于/小于符号、不间断空格、电子邮件、新行字符和分散注意力的单引号。创建了一个包含文章文本长度的新列“length”。

图 2:创建长度列后的数据集。

数据集还在“author”和“article_title”列中包含由“Unknown”替换的空值。长度少于 50 个字符的文章也被删除,理由是少于 50 个字符的文章不是文章。

探索性数据分析

名为‘text _ polarity’的列被添加到数据集中。使用 TextBlob 库的情感极性函数对‘文本’列返回文本的极性,从 1 到 1 表示从负到正。

观察真实文章和虚假文章之间文本极性的分布如何不同将是有趣的。下图 3A 和 3B 分别展示了真文和假文的文本极性分布。

左图 3A,右图 3B

这两类文章中文本极性的分布似乎是均匀的,有些文章是完全负面的,有些是完全正面的。

图 4 —相关矩阵

为了检查数据集中不同特征之间的相关性,使用了热图。数据集中不存在强相关,数据集中长度和标签之间的最大相关值为-0.12,表明非常弱的负相关。

使用 CountVectorizer 方法,绘制了去除和不去除停用词的前 20 个单字、双字和三元字。停用词指的是语言中最常见的词。在下面的例子中,图 5A 和 5B 显示了去除停用词后真实文章和虚假文章中的前 20 个三元模型。

左侧—图 5A,右侧—图 5B

推断统计分析:

接下来,进行单样本 t 检验,以检验总体平均值是否与某些假设值有显著差异。进行统计 t-检验以确定假文章的平均文本极性是否不同于所有文章的平均文本极性。

假设检验:是假的文章和全文字文章在文字极性的均值上有显著差异吗?

无效假设:无效假设将是假文章和所有文本文章之间的文本极性没有差异。

备选假设:备选假设将是假文章和所有文章之间的文本极性存在差异。

图 6

基于图 6 中的单样本 t-检验结果,所有文章的平均文本极性与虚假文章的平均文本极性之间存在显著差异。在 5%置信区间 0.0025 的低 P 值是拒绝零假设的良好指标。

建模

下一步,也是我们分析的关键,需要训练模型来预测一篇新闻文章是真是假。在训练模型之前,我们需要将文本转换成适合这些算法的输入。为此,我们将使用两种方法,称为计数矢量器和 TF-IDF(术语频率-逆文档频率)矢量器。

CountVectorizer 用于通过将文本语料库转换为表示相应语料库中字数的向量来对其进行标记化。它还允许我们删除文本中的停用词,并检查最流行的 N ' unigrams,bigrams 和 trigrams。

相反,TF-IDF 是通过检查语料库并计算“术语频率”和“逆文档频率”获得的词频分数。术语频率是术语在文档中出现的频率,逆文档频率为文档中常见的词分配低权重。因此,TfidfVecotrizer 获取一组文档,并将它们分配给一个 TF-IDF 特性矩阵。然后,这种矢量化形式可以用作训练模型的输入。

这两种方法都将作为多项式朴素贝叶斯分类器和逻辑回归分类器的输入。逻辑回归被用作基准模型。基准模型是一种用于参考的模型,用来比较其他模型相对于它的表现。

没有为逻辑回归执行超参数调整,并且使用 0.01 的 C 值 对其进行训练。或者,对于多项式 NB 模型,使用交叉验证执行超参数调整,并发现 alpha = 0.1 是计数矢量器和 TF-IDF 矢量器模型中的最佳值。

LSTM(长短期记忆)神经网络是一种特殊类型的递归神经网络。简单来说,LSTM 网络有一些内部情境状态细胞,充当长期或短期记忆细胞。LSTM 网络的输出由这些单元的状态调制。当我们需要神经网络的预测依赖于输入的历史背景,而不是仅仅依赖于最后一个输入时,这是一个非常重要的属性。”[1] 阿萨德·莫瓦德LSTM 神经网络的魔力 (2018)

创建 LSTM 模型时,每个文本中使用的最大字数等于 50,000, 最大字数 为 250。LSTM 模型的spatial drop out 1d值为 0.2, 脱落值 为 0.1, 经常性脱落值 为 0.1。

结果

为了检验结果,计算了不同输入(计数矢量器和 TF-IDF)和不同模型的准确性和 AUC-ROC 评分。在评估模型时,准确性本身可能是一个误导性的指标,因此还查看了 AUC-ROC 评分和 ROC 图。AUC-ROC 是一个很好的评估指标,因为它考察了模型正确分类的能力,也为我们提供了假阳性和假阴性的概念。如果 AUC 分数高,则模型在预测类别标签方面做得很好,即 0 表示 0,1 表示 1。在这种特殊情况下,如果 AUC 很高,这意味着模型预测真实的文章是真实的,而假文章是假的。

图 7A 显示了使用计数矢量器和 TF-IDF 转换数据的不同分类器的结果。图 7B 显示了相同分类器的 ROC 曲线。

**

左—图 7A,右—图 7B

用计数矢量器来表征数据的逻辑回归给了我们最好的结果。它实现了 95%的准确性和 95%的 AUC-ROC 评分。尽管 LSTM 模型获得了更高的 AUC-ROC 评分,但使用它可能会矫枉过正,因为逻辑回归在准确性方面表现更好,并且具有更高的 AUC-ROC 评分。此外,逻辑回归计算成本较低。

最差的模型性能也是通过用 TF-IDF 矢量器的逻辑回归实现的,准确度和 AUC-ROC 得分为 0.88。

模型评估

图 8A

图 8B

图 8C

除了仅使用准确性作为评估指标之外,我们还使用了 AUC-ROC 评分,它绘制了真阳性率与假阳性率的关系。我们还应该考虑假阳性和假阴性误差来评估我们的模型的性能。

假阳性(I 型错误):你预测文章是假的但却是真的。

假阴性(ⅱ型错误):你预测文章是真的但却是假的。

图 8A、8B 和 8C 显示了每个分类器的混淆矩阵和分类报告。

解释结果

重要的是,我们不仅要预测新闻文章是真是假,还要估计新闻文章是真是假的概率。这将允许我们标记假新闻文章,并显示它是假的概率。

用这种方法我们会遇到两种问题。首先,考虑新闻文章被模型预测为假的,但实际上,新闻文章是真实的。这被称为误报,这种错误可能代价高昂,因为它可能导致公司尴尬,还可能导致用户流失。不过,这可以通过建立一个机制来报告被错误标记为假的文章来快速纠正。这可能是这个项目发展的许多方向之一。

相反,考虑新闻文章被预测为真实但实际上是假的。随着越来越多的人接触到这篇假新闻,同时相信它是真实的,这篇文章将继续不受限制地被分享。这被称为假阴性,它有能力在敏感问题上播种不信任和分化在线用户。这对我们模型的有效性以及提供这些服务的公司的声誉更有害,因为它会导致人们不信任这个平台及其辨别真相和谎言的能力。为了缓解这个问题,可以建立一种机制,允许人们报告文章是否是假的,然后一个负责检查文章事实的团队根据他们的分析做出最终决定。这些只是一些可以实现的解决方案,它们既不意味着完美,也不声称是完美的。

你可以在这里找到代码为的完整笔记本。如果您有问题、可以提出的改进建议或想要讨论想法,请随时联系我们。**

用 Python 和机器学习预测未来股市趋势

原文:https://towardsdatascience.com/predicting-future-stock-market-trends-with-python-machine-learning-2bf3f1633b3c?source=collection_archive---------0-----------------------

利用集成建模和交叉验证准确预测股票市场趋势

注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

随着最近由于新冠肺炎疫情引起的股票市场的波动,我认为尝试和利用机器学习来预测股票市场的近期趋势是一个好主意。我对机器学习相当陌生,这是我的第一篇媒体文章,所以我认为这将是一个很好的开始和展示项目。

这篇文章讨论了关于数据科学的不同主题,即:数据收集和清理、特征工程,以及创建机器学习模型来进行预测。

注意:我之前在这篇文章的代码中使用了前瞻偏差,这产生了一些非常好的结果(非常好)。然而,它们是误导性的,我现在的目标是尝试用交叉验证来解决这个问题。

作者声明:本项目非财务或投资建议。这并不能保证它在大多数情况下都能提供正确的结果。因此,你应该非常小心,不要把它作为交易洞察力的主要来源。

你可以在我的 github 上的 jupyter 笔记本上找到所有代码:

[## Lucas rea/股票预测

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/lucasrea/StockForecast)

1.导入和数据收集

首先,我们包括了这个项目使用的所有库。我使用 yfinance API 收集了所有的历史股票市场数据。它直接取自雅虎财经网站,所以是非常可靠的数据。

然后我们定义一些用于数据检索和数据处理的常数。带有指示符号的列表有助于为我们的模型生成更多特征。

这里有一个链接,你可以在这里找到这些功能的实际名称。

[## 同行化学家/finta

熊猫实施的通用财务技术指标。这是正在进行的工作,错误是意料之中的,结果…

github.com](https://github.com/peerchemist/finta)

现在我们从 yfinance 中提取历史数据。我们没有太多可以使用的特性——除非我们找到一种方法来至少规范化它们或者从它们派生出更多的特性,否则这些特性不是特别有用。

“关闭”列中的数据

2.数据处理和特征工程

我们看到上面的数据是粗略的,包含了大量的时间序列峰值。它不是很平滑,模型很难从中提取趋势。为了减少这种情况的出现,我们希望在计算技术指标之前指数平滑我们的数据。

来自“Close”的数据,但已被平滑

我们可以看到数据平滑了很多。当计算技术指标时,有许多波峰和波谷会使它难以近似,或者难以提取趋势。它会让模型失控。

现在是时候计算我们的技术指标了。如上所述,我使用 finta 库结合 python 内置的 eval 函数来快速计算指标列表中的所有指标。除了正常的成交量,我还计算了一些不同平均长度的均线。

我去掉了像“开盘”、“高”、“低”和“收盘调整”这样的栏,因为除了指标之外,我们还可以用均线得到足够好的近似值。成交量已经被证明与价格波动有相关性,这也是我将其归一化的原因。

Index(['close', 'RSI', 'MACD', 'SIGNAL', '14 period STOCH %K','MFV', '14 period ATR', 'MOM', '14 period MFI', 'ROC', 'OBV_x', 'OBV_y', '20 period CCI', '14 period EMV', 'VIm', 'VIp', 'ema50', 'ema21', 'ema14', 'ema5', 'normVol'], dtype='object')

就在我们收集预测之前,我决定保留一点数据来预测未来的值。这一行捕获了与 7 月 27 日这一周的 5 天相对应的 5 行。

live_pred_data = data.iloc[-16:-11]

现在是这个项目最重要的部分之一——计算真值。如果没有这些,我们甚至无法训练一个机器学习模型来进行预测。

我们如何获得真理价值?这很直观。如果我们想知道一只股票何时上涨或下跌(希望赚一百万美元!)我们只需要展望未来,观察价格,以决定我们现在是应该买入还是卖出。嗯,有了这些历史数据,这正是我们能做的。

回到我们最初提取数据的表格,如果我们想知道 1993 年 3 月 29 日当天(收盘价为 11.4375)的买入(1)或卖出(0)决定,我们只需要向前看 X 天,看看价格是高于还是低于 1993 年 3 月 29 日的价格。因此,如果我们向前看 1 天,我们会看到价格上升到 11.5。因此,1993 年 3 月 29 日的真实价值是买入(1)。

由于这也是数据处理的最后一步,我们删除了指标和预测生成的所有 NaN 值,并删除了“close”列。

因为我们使用了 Pandas 的 shift()函数,我们从数据集的末尾丢失了大约 15 行(这就是为什么我在这一步之前捕获了 7 月 27 日这一周)。

3.模型创建

在训练我们的模型之前,我们必须将数据分成训练集和测试集。然而,由于时间序列的性质,我们需要小心处理这部分。如果我们随机化我们的训练测试集,我们可能会遇到前瞻偏差,这对于预测股票市场是不利的。这是因为你用模型已经看过的数据训练它。

为了防止这种情况,我们将使用一种称为交叉验证的不同技术来训练该模型。下图说明了我们将如何划分数据并测试模型的准确性。

时间序列中交叉验证的滑动窗口方法

首先,我们将使用多个分类器来创建一个集成模型。这里的目标是结合几个模型的预测,尝试提高可预测性。对于每个子模型,我们还将使用 Sklearn 的一个特性 GridSearchCV 来优化每个模型,以获得最佳结果。

首先,我们创建随机森林模型。

然后是 KNN 模式。

最后,我们创建投票分类器

一旦我们建立了模型,我们就可以把它和交叉验证放在一起。我们从编写一些代码开始,这些代码将允许我们用许多大小均匀的块来迭代我们的数据。

打印出我们的数据帧的索引,我们已经成功地分割了我们的数据,就像在滑动窗口图像中一样。

10 50
20 60
30 70
40 80
50 90
60 100
.
.
.
6820 6860
6830 6870

现在我们添加代码,将分区分成训练集和测试集。在 train_test_split 函数中设置 shuffle=False 非常重要——这是避免前瞻偏差的方法。

最后,我们合并我们的模型。

这样的样本运行看起来像…结果被夸大了。

rf prediction is  [1\. 1\. 1\. 0\. 0\. 1\. 1\. 1\. 1\. 1\. 1\. 1.]
knn prediction is  [1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1.]
ensemble prediction is  [1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1.]
truth values are  [1\. 1\. 1\. 0\. 1\. 1\. 1\. 1\. 1\. 1\. 1\. 1.]0.9166666666666666 0.9166666666666666 0.9166666666666666

最后的结果给了我们

RF Accuracy = 0.6732649071358748
KNN Accuracy = 0.67460899315738
Ensemble Accuracy = 0.6925708699902248

我们可以看到,通过使用集合建模,我们获得了更高的精度。与不使用交叉验证相比,结果的准确性要低得多。然而,这是解决这个问题的更正确的方法……大约 70%的准确率也不错!

4.结果验证

下一步,我们将使用预测模型预测 S&P500 的行为。我在 8 月 17 日的周末写这篇文章。因此,为了看看这个模型是否能产生准确的结果,我将使用本周的收盘数据作为预测的“真实”值。由于这个模型被调整为 15 天的窗口,我们需要输入 7 月 27 日这一周的数据。

七月二十七日->八月十七日

七月二十八日->八月十八日

七月二十九日->八月十九日

七月三十日->八月二十日

7 月 31 日-> 8 月 21 日

我们保存了将要在 live_pred_data 中使用的周。

live_pred_data.head()

以下是我们将要进行预测的五个主要日期。看起来模型预测价格每天都会上涨。

让我们用实际结果来验证我们的预测。

del(live_pred_data['close'])
prediction = ensemble_model.predict(live_pred_data)
print(prediction)[1\. 1\. 1\. 1\. 1.]

结果

7 月 27 日:322.78 美元——8 月 17 日:337.91 美元

7 月 28 日:321.74 美元——8 月 18 日:338.64 美元

7 月 29 日:323.93 美元——8 月 19 日:337.23 美元

7 月 30 日:323.95 美元——8 月 20 日:338.28 美元

7 月 31 日:325.62 美元——8 月 21 日:339.48 美元

正如我们从实际结果中看到的,我们可以确认模型的所有预测都是正确的。然而,决定股票价格的因素有很多,所以说这个模型每次都会产生相似的结果是幼稚的。然而,在相对正常的时间段内(没有导致股票市场波动的重大恐慌),该模型应该能够产生良好的结果。

5.摘要

总结一下我们在这个项目中所做的,

  1. 我们已经收集了用于分析和特征创建的数据。
  2. 我们已经使用熊猫来计算许多模型特征,并产生干净的数据来帮助我们进行机器学习。使用熊猫创建预测或真实值。
  3. 利用交叉验证来避免前瞻偏差。训练许多机器学习模型,然后使用集成学习将它们结合起来,以产生更高的预测精度。
  4. 确保我们的预测与真实世界的数据相符。

通过这个项目,我学到了很多关于数据科学和机器学习的知识,希望你也一样。作为我的第一篇文章,我喜欢任何形式的反馈来帮助提高我作为程序员和数据科学家的技能。

感谢阅读:)

预测未来战争

原文:https://towardsdatascience.com/predicting-future-wars-7764639f1d8d?source=collection_archive---------20-----------------------

Unsplash 上由 Stijn Swinnen 拍摄的照片。

来自开放数据和机器学习的见解

我知道你在想什么:战争是罕见而复杂的事件,人们不能指望考虑到它们的全部复杂性。你是对的,它们源于错综复杂的政治、经济和历史原因,但不要忘记厚厚的随机性外衣,因此应该谨慎对待。甚至政治专家也一直在争论是什么导致了冲突,有时是在事件发生几十年后。冲突可能是黑天鹅,本质上不可预测的改变游戏规则的事件(即使专家经常声称事后发现了明显的警告信号)。但这并不意味着我们不能通过使用机器学习来评估导致战争的氛围。

用经济指标来预测冲突并不是什么新想法,关于这个问题已经做了很多研究 。结果是有希望的,但他们使用给定年份的数据来预测同一年一个国家的状态,这有点违背直觉。如果你已经知道了国家的经济状况,那么为什么还需要“预测”它是否处于战争状态呢?信息已经有了。这迫使他们使用联合国等组织提供的预测来应用他们的模型。这使得他们的预测依赖于他们。在这里,只有过去和现在的数据被用来预测一个国家在不久的将来的状态。

使用的功能

为了将这些指标与冲突联系起来,使用了 UCDP/PRIO 武装冲突数据集 ,其中列出了 1946 年至 2018 年的所有武装冲突。根据冲突的致命程度和所反对的群体类型,冲突被分为不同的类型。就特征而言,采用了主要来自世界银行的年度时间序列形式的经济和社会指标。目标特征是通过增加表明一个国家在未来五年内是否会陷入冲突的变量而获得的。在这里,我们跳过预处理阶段,更详细的描述见报告。最终数据集包含 12 900 行(60 年* 215 个国家)。

分析因果关系

对于多变量时间序列,皮尔逊相关是不合适的,当前冲突状态可以是其他变量的过去值的函数。这就是应用格兰杰因果关系检验的原因。它决定了一个时间序列如何影响另一个时间序列。每年的汇总版本用于计算测试。

经济指标和冲突的格兰杰因果关系测量(X 影响 Y)。鸣谢:作者。

小冲突受到债务、账户余额和自然资源租金的强烈影响。总的来说,冲突受到婴儿死亡率的强烈影响,婴儿死亡率是贫困引发冲突的一个指标。国家间的冲突是由国内生产总值和账户余额引发的。外国直接投资与新冲突的爆发或出现之间也有着密切的联系。这些观察表明,经济是有影响的,但是经济的不同方面与不同类型的冲突有关。

模型

最好的结果不是通过特定于时间序列的模型(VAR 模型)获得的,而是通过将每个国家的每一年作为一个数据点。一个有 100 棵树并且最大深度为 15 的随机森林获得了如下所示的结果。

随机森林模型的结果:准确率为 92%,F1 值为 74%,精确度为 71%,召回率为 76%。鸣谢:作者。

用于区分的特征如下所示。

根据辨别能力对每个特征进行排序。鸣谢:作者。

对该模型最有影响的特征是腐败、婴儿死亡率和自然资源租金。这意味着该模型的预测基于政权类型(腐败)、贫困(婴儿死亡率)和对资源的依赖(自然资源)。

预言

最后,有趣的部分是,最近几年(2018 年和 2019 年)的数据被输入到模型中,以查看世界上哪个国家将在未来五年(2019 年至 2024 年)陷入新的冲突。结果如下图所示。

我们的模型给出的每个国家在 2019-2024 年经历新冲突的概率。鸣谢:作者。

许多更有可能面临新冲突的国家已经经历了动荡。但像巴基斯坦、印尼这些相对稳定的国家,近期爆发新冲突的概率很大。伊朗最近因制裁和最近的政治气氛而承受巨大压力,与其他国家相比,它也很有可能陷入新的冲突。

如果只考虑主要的冲突,即战争,我们会得到这些预测。

我们的模型给出的每个国家在 2019-2024 年面临新的重大冲突的概率。鸣谢:作者。

在这种情况下,只有叙利亚和索马里这两个已经处于非常不稳定状态的国家很有可能在未来几年面临新的战争。

尽管战争远不是一个确定性的系统,但机器学习是评估一个国家历史上关键时期的有用工具。

完整的项目可以在这里访问

从好书到名著

原文:https://towardsdatascience.com/predicting-great-books-from-goodreads-data-using-python-1d378e7ef926?source=collection_archive---------38-----------------------

使用 python 来预测是什么让书籍变得伟大

艾德·罗伯森Unsplash 拍的旧书照片

什么

这是 2020 年 7 月 30 日从 Goodreads 的 API 中提取的前 50,000 个图书 id 的数据集。几千个 id 没有通过,因为图书 id 被更改,URL 或 API 被破坏,或者信息以非典型格式存储。

为什么

从读者的角度来看,书籍是一种多小时的学习和休闲的承诺(他们不会称之为好的免费阅读)。从作者和出版商的角度来看,书是一种生活方式(也有一些学习和休闲)。在这两种情况下,知道哪些因素解释和预测伟大的书籍将节省您的时间和金钱。因为虽然不同的人有不同的品味和价值观,但了解一本书的总体评价是一个明智的起点。你可以随时更新它。

环境

在虚拟环境中工作是很好的实践,一个有自己的库和版本的沙箱,所以我们将为这个项目制作一个。有几种方法可以做到这一点,但是我们将使用 Anaconda 。要使用 Python 3.7 创建并激活名为“gr”(Goodreads)的 Anaconda 虚拟环境,请在您的终端或命令行中运行以下命令:

装置

您应该在提示符的左侧看到“gr”或您命名的环境。如果是这样,请运行以下命令。Anaconda 将自动安装这些包的任何依赖项,包括 matplotlib、numpy、pandas 和 scikit-learn。

进口

数据收集

我们使用由 Michelle D. Zhang (代码和文档在这里)制作的 Goodreads API 的轻量级包装器提取前 50,000 个图书 id 及其相关信息,然后将每个 id 作为字典写入名为book_data的 JSON 文件。

数据清理

我们将在下面定义和描述一些关键函数,但是我们稍后将在一个大的 wrangle 函数中运行它们。

威尔逊下界

基于 20 条评论的 4 星评价和基于 20000 条评论的 4 星评价是不相等的。基于更多评论的评级具有较少的不确定性,因此是对“真实”评级的更可靠的估计。为了正确定义和预测伟大的著作,我们必须通过惩罚不确定性来改变average_rating

我们将通过计算威尔逊下限来实现这一点,其中我们估计特定评级的置信区间,并将其下限作为新的评级。基于数万条评论的评级几乎不会受到影响,因为它们的置信区间很窄。然而,基于更少评论的评级具有更宽的置信区间,并且将被降低更多。

:我们修改了公式,因为我们的数据是从 5 分制计算的,而不是 Wilson 描述的二进制。具体来说,我们将average_rating减 1,作为真实非膨胀评级的保守估计,然后将其归一化。如果这个惩罚太重或太轻,随着时间的推移,更多的评级将分别提高或降低该书的评级。换句话说,随着更多的信息,这种调整是自我纠正的。

流派

Goodreads 的 API 返回了“书架”,它包含了像“科幻小说”这样的真实类型和像“阅读”这样的用户创建的类别。在提取数据时,我们只提取了 5 个最受欢迎的货架,以限制这种清理;在这里,我们会完成任务。

经过一些检查,我们看到这些子串代表了非流派书架的主体。我们将使用正则表达式过滤掉它们。注意:我们在正则表达式中使用了两个字符串,所以这一行不会被切断。圆括号内的相邻字符串在编译时连接在一起。

多功能一体清洗

现在,我们将构建并运行一个函数来处理数据集。这样,清理更具可重复性和可调试性。

比较未调整和调整后的平均评分

从数字上看,平均值(蓝色)和中值(绿色)趋势的中心度量值略有下降,方差显著下降。

视觉上,我们可以看到评级调整在更平滑和更宽的分布中(尽管注意 x 轴被截断)。这是因为消除了没有评级或评级很少的异常书籍,并缩小了具有高度不确定性的评级。

作者图片

Unadjusted mean: 3.82
Unadjusted median: 3.93
Unadjusted variance: 0.48

作者图片

Adjusted mean: 3.71
Adjusted median: 3.77
Adjusted variance: 0.17

数据泄露

因为我们的目标来源于评级,使用评级来训练我们的模型实际上是用目标来训练。为了避免扭曲模型,我们必须删除这些列。

也有可能review_count有点漏,但它似乎更像是流行度的代理,而不是伟大,就像流行(ular)歌曲通常不被认为是经典一样。当然,如果它的排列重要性高得可疑,我们会重新考虑这个问题。

分割数据

我们将进行 85/15 的训练测试分割,然后重新分割我们的训练集,使验证集与测试集的大小大致相同。

(20281, 12) (20281,) (4348, 12) (4348,) (4347, 12) (4347,)

评估指标

对于这种不平衡的分类,准确性(正确预测/总预测)可能会产生误导。对于这个分数来说,没有足够的真阳性作为模型性能的最佳度量。因此,我们还将使用 ROC AUC,曲线下的受试者操作者特征面积。这是一张彩图,由马丁·托马斯提供。

Martin Thoma 绘制的 XKCD 风格的 ROC AUC 图,在知识共享 CC0 1.0 通用公共领域专用下提供

ROC 曲线是分类模型的真阳性率(TPR)与其假阳性率(FPR)的关系图。ROC AUC 是从[0,1]到该曲线右下方的面积。因为最佳模型性能使真阳性最大化,假阳性最小化,所以这个 1x1 图中的最佳点在左上角,曲线下面积(ROC AUC) = 1。

对于像great这样的不平衡类,ROC AUC 作为一个指标优于准确性,因为它更好地反映了真阳性和假阳性之间的关系。它还描述了分类器在其所有值上的性能,为我们提供了更多关于模型何时何地改善、停滞或受损的信息。

适合模型

预测名著是一个二元分类问题,所以我们需要一个分类器。下面,我们将对一个线性模型(逻辑回归)和两个基于树的模型(随机森林和 XGBoost)进行编码、估算和拟合,然后将它们相互比较并与多数基线进行比较。我们将计算它们的准确性和 ROC AUC,然后进行可视化。

多数类基线

首先,从结构上来看,great的书是 Wilson 调整后排名前 20%的书。这意味着我们的多数类基线(没有书是伟大的)有 80%的准确性。

第二,这个“模型”不会改进、停滞或受损,因为它从一开始就没有洞察力。随机选择的阳性和随机选择的阴性将被同等对待。在其他研究中,其 ROC AUC = 0.5。

Baseline Validation Accuracy: 0.8
Baseline Validation ROC AUC: 0.5

逻辑回归

现在,我们将使用交叉验证拟合线性模型,重新计算评估指标,并绘制混淆矩阵。

Baseline Validation Accuracy: 0.8
Logistic Regression Validation Accuracy: 0.8013
Baseline Validation ROC AUC: 0.5
Logistic Regression Validation ROC AUC: 0.6424

逻辑回归混淆矩阵

作者图片

随机森林分类器

现在我们将使用基于树的模型和 bagging 做同样的事情(BootstrapAGGregation)。

Baseline Validation Accuracy: 0.8
Logistic Regression Validation Accuracy: 0.8013
Random Forest Validation Accuracy: 0.8222

Majority Class Baseline ROC AUC: 0.5
Logistic Regression Validation ROC AUC: 0.6424
Random Forest Validation ROC AUC: 0.8015

随机森林混淆矩阵

作者图片

XGBoost 分类器

现在,我们将使用另一个基于树的模型做同样的事情,这次使用 boosting。

Baseline Validation Accuracy: 0.8
Logistic Regression Validation Accuracy: 0.8013
Random Forest Validation Accuracy: 0.8245
XGBoost Validation Accuracy: 0.8427

Majority Class Baseline ROC AUC: 0.5
Logistic Regression Validation ROC AUC: 0.6424
Random Forest Validation ROC AUC: 0.8011
XGBoost Validation ROC AUC 0.84

XGBClassifier 在准确性和 ROC AUC 方面表现最佳。

绘制并比较模型的 ROC AUC

下面,我们看到逻辑回归在获得高 ROC AUC 方面远远落后于 XGBoost 和 Random Forests。在前两者中,XGBoost 最初优于 RandomForest,然后两者大致收敛在 FPR=0.6 左右。然而,我们在右下方的图例中看到,XGBoost 的 AUC 最高,为 0.84,其次是随机森林,为 0.80,逻辑回归为 0.64。

用不太专业的语言来说,XGBoost 模型最擅长将好书归类为好书(真阳性),而不将不太好的书归类为好书(假阳性)。

作者图片

排列重要性

一个直观的识别某样东西是否重要以及重要到什么程度的方法是看当你拿走它时会发生什么。在不受时间和金钱约束的情况下,这是最好的。

但是在有实际约束的现实世界中,我们可以用置换来代替。我们不是通过删除列值来消除它们,而是通过随机化来消除列的信号。如果该列真的是一个预测特性,那么它的值的顺序就很重要,如果不破坏关系的话,将它们移动会大大削弱关系。因此,如果特征的预测能力没有真正受到伤害,或者随机化甚至有所帮助,我们可以得出结论,它实际上并不重要。

让我们仔细看看 XGBoost 模型的排列重要性。我们将不得不改装它以与 eli5 兼容。

排列重要性分析

作者图片

正如我们在开始时假设的那样,review_count很重要,但并没有高到令人怀疑的程度。这似乎没有上升到数据泄露的程度。这意味着,如果你想知道下一本书该读什么,一个有用的指标是它有多少评论,代表有多少人读过它。

我们看到genres是 XGBoost 模型中 ROC AUC 的第二个最重要的特征。

author排在第三,这令人惊讶,或许也有点令人担忧。因为我们的测试集并不大,这个模型可能只是识别出按 Wilson-adjusted 术语评价最高的作者,比如 J.K .罗琳和苏珊·科林斯。更多的数据将有助于检验这一理论。

第四个是num_pages。我认为这个数字会更高,原因有二:

  1. 很长的书的评分似乎有一点向上的倾向,因为愿意开始和完成它们的人会给它们更高的评分。冗长的篇幅筛选掉了不太感兴趣的边缘读者,他们可能一开始就不会给这本书很高的评价。
  2. 阅读并炫耀你正在阅读或已经阅读了长篇大论是社会地位高的标志。典型的例子:无限的玩笑。

外卖食品

我们已经看到了如何收集、清理、分析、可视化和建模数据。一些可操作的要点是,什么时候和谁出版一本书并不重要,但它的评论数很重要——评论越多越好。

为了进一步分析,我们可以分解genresauthors来找出哪些被评为最高。现在,快乐阅读。

用随机森林预测幸福

原文:https://towardsdatascience.com/predicting-happiness-using-random-forest-1e6477affc24?source=collection_archive---------51-----------------------

使用机器学习探索影响人们幸福水平的因素

迈克·彼得鲁奇在 Unsplash 上的照片

为什么我们试图预测幸福?能够预测幸福意味着我们能够操纵或试图改善某些因素,以增加我们自己的幸福,也可能增加政府的国民幸福。我发现随机森林(RF)是最简单和最有效的软件包,所以让我们开始吧!

内容:

  1. 数据
  2. 随机森林模型
  3. 数据清理
  4. 培训和测试
  5. 特征重要性
  6. 修改变量的数量
  7. 评估模型

数据:

#WorldValuesSurvey 获得的数据包含了> 290 个问题&在去除了缺失的幸福水平数据后,由大约 69k 个回答组成。是跨年度的跨国调查,问卷可以在网站上找到。特别是,我们将关注 2017 年至 2020 年的数据集。数据集的大小使其成为机器学习的最佳选择。

随机森林模型:

首先,我们将使用 RF 分类器*,因为我们希望机器能够预测群体的幸福水平(非常幸福、相当幸福、不太幸福、一点也不幸福)。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn import metrics

数据清理:选择数据

让我们先从问题栏开始,去掉 Q46 关于幸福水平的回答中的负值。

var="Q46"
df=df[df.columns[32:349]]
df=df[df[var]>0]

*负值表示受访者表示不知道、没有答案、没有被问到或回答缺失。这些值将使机器更难对它们进行分类,因为它增加了类别的数量,而不是我们所寻找的。

剩余的数据集如下所示:

进一步的数据清理:

下一个问题是,我们必须处理其他列中缺失的值。有 3 个选项可供考虑:

  1. 用 0 替换丢失的值
  2. 用平均值替换缺失的值
  3. 删除缺少值的行(数据集变为空)。

由于第三个选项不可行,我们必须检查选项 1 或 2 中哪一个会给出最高的精度。在这种情况下,我发现用 0 替换会更准确。

df.fillna(0, inplace=True)

准备列车标签:

现在,我们为机器设置“标签”,以识别我希望它预测的特征,并将数据分为训练集和测试集。

train_labels = pd.DataFrame(df[var])
train_labels = np.array(df[var])
train_features= df.drop(var, axis = 1)
feature_list = list(train_features.columns)
train_features = np.array(train_features)
train_features, test_features, train_labels, test_labels = train_test_split(train_features, train_labels, test_size = 0.25, random_state = 42)

训练并测试模型:

培训和测试的过程很简单。为了提高预测能力和/或模型速度,我们可以简单地修改 RF 分类器中的参数。

增加精度:

n_estimators —多数表决前算法构建的树的数量

max _ features 随机森林考虑分割节点的最大要素数

min _ sample _ leaf 分割内部节点所需的最小叶子数。

增加速度:

n_jobs —允许使用的处理器数量。如果= 1,只使用一个处理器。If =-1,无限制

random _ state 使模型的输出可复制,即给定相同的超参数和训练数据,总是产生相同的结果

oob_score:随机森林交叉验证方法

rf=RandomForestClassifier(n_estimators = 1000, oob_score = True, n_jobs = -1,random_state =42,max_features = “auto”, min_samples_leaf = 12)
rf.fit(train_features, train_labels)
predictions = rf.predict(test_features)
print(metrics.accuracy_score(test_labels, predictions))

该模型需要 1.3 分钟来训练~52k 训练行和> 290 列,并需要 1 秒来测试。准确率为 63.70% 。如果我们选择用平均值来填充缺失值,精确度将是 63.55% 。但重要的是找出是什么影响了机器的预测,因为这些是我们想要研究的变量。我们当然不能指望每个人都回答 290 多个问题,或者试图在所有 290 个方面努力提高幸福感(这将花费很多)。因此,我们将着眼于特性的重要性。

特性重要性:

如果您还记得,feature_list 包含除 Q46 之外的所有其他变量的列。目标是了解影响预测的变量。

importances = list(rf.feature_importances_)
feature_importances = [(feature, round(importance, 2)) for feature, importance in zip(feature_list, importances)]
feature_importances = sorted(feature_importances, key = lambda x: x[1], reverse = True)
[print('Variable: {:20} Importance: {}'.format(*pair)) for pair in feature_importances]
x_values = list(range(len(importances)))# Make a bar chart
plt.bar(x_values, importances, orientation = 'vertical', color = 'r', edgecolor = 'k', linewidth = 1.2)
# Tick labels for x axis
plt.xticks(x_values, feature_list, rotation='vertical')
# Axis labels and title
plt.ylabel('Importance'); plt.xlabel('Variable'); plt.title('Variable Importances');

特征重要性总和为 1,我们注意到,与其他变量相比,某些变量对预测的影响更大,几乎每个变量都有某种形式的影响,尽管由于变量太多而非常小。接下来的事情是继续改进我们的模型,让我们更好地理解幸福。

修改变量数量:

让我们来看看前 20 个特征,并用这 20 个变量(+ var 本身)建立一个新模型。我们将重复数据清理和相同的 RF 模型。我得到了 64.47%的准确率。如果我们选择用平均值替换缺失值,则精确度将为 64.41% 。这里令人惊讶的是,随着变量数量的减少,模型变得更加精确(从 63.70%64.47% )。这可能是因为其他变量在模型中产生噪声,导致模型不太准确。

让我们再来看看特性的重要性:

这一次,可以更清楚地看出哪些变量更重要。你可以参考 WVS 网站上的调查问卷了解更多详细信息。我将总结一下这些问题所涉及的主题。

评估模型:

让我们看看前 200 个测试值的实际值与预测值的图表。为了更好地了解整个测试集,让我们简单地计算一下预测值和实际值之间的差异(预测值减去实际值)。

该模型在预测幸福水平方面似乎是消极的多于积极的,但在其他方面仍然被认为是平衡的!

感悟:

我所做的是检查 WVS 中 290 多个与幸福水平更相关的关键问题。这将意味着我们在研究幸福时可以试着特别关注这些方面。

在调查问卷中,我们还会注意到 Q261 和 Q262 是同一个东西(年龄和出生年份),因此我们可以删除其中一个以包含另一个特征。对于问题 266,267,268(回答者和父母的出生国),它们似乎是重复的,但并不完全相同,因为移民/跨文化婚姻可能会发生。尽管如此,我们可以考虑删除其中两个,因为这种情况很少发生。

一般话题有:

个人层面:
生活满意度、健康、财务、自由、年龄、安全、宗教、婚姻、家庭。
国家层面:
国家、对腐败的看法、民主/政治影响力、民族自豪感

特别是,健康、财务和年龄是机器认为最重要的特征。从这个意义上说,个人层面的因素比国家层面的因素对一个人的幸福水平有更大的影响。

然而,我注意到 WVS 没有关于睡眠时间的数据,这是我在之前的文章中观察到的一个关键因素。尽管如此,它仍然非常有用,因为我们可以考虑这些方面进行进一步的分析!我会带着对这些方面和幸福之间的相关性的更多见解回来,以确定我们如何才能提高我们的幸福水平。在那之前,记得保持快乐!

预测危险的地震颠簸第二部分:训练和调整监督最大似然分类器和模型性能分析

原文:https://towardsdatascience.com/predicting-hazardous-seismic-bumps-part-ii-training-supervised-classifier-models-and-8b9104b611b0?source=collection_archive---------43-----------------------

本文演示了使用不同的监督分类器预测危险的地震颠簸、调整模型超参数、准确性悖论以及理解“业务问题”对性能评估的重要性

肖恩·麦克伦登在 Unsplash 上的照片

介绍

在我的上一篇文章中,关于来自 UCI 数据档案库的地震颠簸数据集,我应用了特征工程的基本数据分析技术和不平衡数据集的测试序列分割策略。在本文中,我展示了如何应用监督机器学习算法(KNN、随机森林和 SVM)进行预测,并调整超参数(使用 GridSearchCV)以获得最佳结果。性能评估的结果也清楚地展示了准确性悖论,我将在下面的章节中详细阐述。此外,它还展示了为什么理解“业务问题”对于选择最佳模式至关重要

完整的笔记本可以在我的 GitHub 库中找到

照片由丹妮尔·麦金尼斯Unsplash 上拍摄

我从…

创建一个文件夹来保存我的模型。将多种算法用于数据时,最好在训练和调整后保存模型。为此,我使用 datetime python 模块创建了一个文件夹。

**import** **datetime****def** model_store_location():
    **return** "model-store-**{}**".format(datetime.date.today())model_store_location = model_store_location()
print(model_store_location)!mkdir {model_store_location}

每个性能最好的模型都将存储在该文件夹中。

接下来,我建立了一个基线

这是一个二元分类任务,我选择了最简单的分类模型,K-最近邻(KNN)来开始预测建模。KNN 是最简单的分类器之一,它基于前 K 个相似的可见实例中标签的最大数量来将标签分配给不可见实例。

为了改进模型,需要一个基线,随后的模型将与该基线进行比较。因此,它被称为“基线模型”。因此,对于基线模型,我使用默认参数初始化了 KNN 分类器:

model = KNeighborsClassifier()

接下来,我首先检查了性能,使用 10 次分割的 StratifiedKFold,保持评分标准“准确性”。

skf = StratifiedKFold(n_splits=10)

作者图片

对于所有的折叠,精确度在 0.92 到 0.93 之间,并且数值的接近性通过分数的标准偏差来显示。

这里的准确率真的很高。现在,让我们在训练数据中拟合模型,并检查模型的性能—

model.fit(X_train, y_train)
y_pred = model.predict(X_test)

我添加了一个数据框来保存每个模型的超参数和性能,如下所示:

df_results = pd.DataFrame(index = ['scoring_technique', 
                                   'algorithm', 'n_neighbors',
                                   'weights', 'leaf_size', 
                                   'accuracy', 'precision', 
                                   'recall', 'f1-score'])

并添加了我的基线模型的性能:

**from** **sklearn.metrics** **import** accuracy_score, precision_score, recall_score, f1_scoredf_results['Baseline'] = ['None', model.algorithm,
                          model.n_neighbors, 
                          model.weights, 
                          model.leaf_size,
                          accuracy_score(y_test, y_pred), 
                          precision_score(y_test, y_pred), 
                          recall_score(y_test, y_pred), 
                          f1_score(y_test, y_pred)]

作者图片

这就是 KNN 的表演看起来超越了准确性。这是一个典型的准确性悖论的例子。由于大多数地震凸起是无危险的,因此真负值(TN)比 TP、FP 和 FN 的总和要大得多, 从而在数字上提高了准确性,并创造了预测正确的假象 ,但正如精度和召回率所示,危险地震凸起识别率低于 30%。

二元分类性能指标—

= TP+TN/(TP+FP+TN+FN)

精度 = TP / (TP + FP)

回忆 = TP / (TP + FN)

F1-Score= 2 * Precision x Recall/(Precision+Recall)= 2TP/(2TP+FP+FN)**

因此,基于基线性能度量,只有 25%的预测危险隆起是正确的,只有 5%的实际危险地震隆起被模型正确识别。93%的数据实际上包含无危险的地震隆起,因此cross_val_score 中的精确数字是有意义的,也在 93%左右。

然而,正如您所看到的,精确度和召回率都受到了影响,让我们看看如何使用GridSearchCV来调优超参数

GridSearchCV 用于调整 KNN 超参数

马库斯·温克勒在 Unsplash 上拍摄的照片

GridSearchCV 是一个函数,它接受超参数的可能值或范围,运行指定的超参数值的所有组合,并根据提到的评分标准计算性能。这个评分标准应该基本上与业务价值或您的目标一致。

要查看提供了哪些评分标准,此代码有助于:

***import** **sklearn**
sorted(sklearn.metrics.SCORERS.keys())*

该代码将生成可用评分方法的完整列表。

接下来,我为 KNN 定义了超参数,如下面的代码所示,并创建了一个名为param_grid 的字典,其中包含 KNN 超参数的参数,如 Scikit-Learns 关于 KNN 的文档中所定义的键,而值包含相应的值列表。

*n_neighbors = [1, 2, 3, 4, 5] 
weights = ['uniform', 'distance'] 
algorithm = ['ball_tree', 'kd_tree', 'brute'] 
leaf_size = [10, 20, 30 , 40, 50]  #param_grid = dict(n_neighbors=n_neighbors, 
                  weights=weights, 
                  algorithm=algorithm, 
                  leaf_size=leaf_size)*

接下来,我使用模型、最佳超参数搜索的网格、交叉验证类型、作为精度的评分度量来初始化 GridSearchCV,并且我还使用了refit参数来确保最佳评估的估计值作为best_estimator_可用,这是当训练集可用于进行预测时的拟合模型。Verbose决定您希望在屏幕上显示多少日志信息。

*grid = GridSearchCV(estimator=model, 
                    param_grid=param_grid, 
                    cv=StratifiedKFold(shuffle=**True**), 
                    scoring=['precision'],
                    refit='precision',
                    verbose=10)*

我调用 fit 方法来启动超参数调优过程。

*grid_result = grid.fit(X_train, y_train)*

基本上,grid_result包含了所有的输出,从拟合时间到个人得分,以及基于传递的参数评估的最佳模型。grid_result.best_estimator_包含最佳拟合模型的超参数的选定值,根据评分标准进行优化。

我试验了不同的scoring

型号 1 — scoring:精度

型号 2 — scoring:召回

型号 3 — scoring : f1

以下是模型性能的总结:

作者图片

如果您在此网格中注意到,每个模型的评分指标的最佳可能结果属于在整个网格中指定的相应scoring指标,即,当参数为“precision”时,任何其他模型的“precision”性能都不如模型 1。同样,对于“召回”,网格中的最佳由模型 2 和模型 3 共享。其实他们的表现是一样的。

在模型 1 中,其精度为 50%,即 50%的预测的危险地震颠簸是正确的,有可能评论说该模型只不过是掷硬币。但是抛硬币是公平的,而我们的数据集却不是,它是一个不平衡的数据集。在一次公平的掷硬币中,正面和反面同样可能发生,但是对于这个数据集,危险的和非危险的地震颠簸不会发生。

在模型 2 和模型 3 中,召回率最高,可以解释为正确识别的实际危险地震碰撞的 14%。精度也是 16%。f1 的成绩远远好于 Model 1,相当不错。模型 1 的低 f1 分数是因为 2%的不良回忆,这意味着该模型只能预测实际危险地震颠簸的 2%,这是 no bu eno。

随机森林分类器能赢得这场挑战吗?

卢卡·布拉沃Unsplash 上拍摄

我选择的下一个模型是随机森林分类器,竞赛获奖的 ML 模型。这是一个健壮的 ML 模型,其中构建了多个决策树来集成它们的输出。最终预测是所有单个决策树预测的函数。这就是随机森林模型表现更好的原因。

我从初始化随机森林分类器开始:

*from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier()*

接下来,我构建了一个网格来寻找最合适的参数:

*param_grid = {
 ‘bootstrap’: [True],
 ‘max_depth’: [80, 90, 100, 110],
 ‘max_features’: [2, 3, 4],
 ‘min_samples_leaf’: [3, 4, 5, 6],
 ‘min_samples_split’: [8, 10, 12],
 ‘n_estimators’: [100, 200, 300, 500]
}*

我还再次为“得分”选择了“精确度”。以下是完整的代码:

*from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier()param_grid = {
 ‘bootstrap’: [True],
 ‘max_depth’: [80, 90, 100, 110],
 ‘max_features’: [2, 3, 4],
 ‘min_samples_leaf’: [3, 4, 5, 6],
 ‘min_samples_split’: [8, 10, 12],
 ‘n_estimators’: [100, 200, 300, 500]
}grid = GridSearchCV(estimator=model, 
                    param_grid=param_grid, 
                    cv=StratifiedKFold(shuffle=True), 
                    scoring=['precision'],
                    refit='precision',
                    verbose=10)
grid_result = grid.fit(X_train, y_train)file_name = 'seismic_bump_rf_model.sav'
joblib.dump(model, model_store_location + file_name)print(grid_result.best_estimator_)*

由此得出的模型是—

然而,在预测测试集时,精度为零。

作者图片

训练和调整支持向量机

由于随机森林模型真的让我失望,我想到了使用支持向量机(SVM)。支持向量机属于分类算法的核方法组,用于拟合决策边界。分类基于决策边界的哪一侧是数据点。

支持向量机的计算开销很大,可以通过以下网格搜索设置进行演示:

*from sklearn.svm import SVC 
model = SVC()param_grid1 = {'C': [0.1, 1, 10, 100, 1000],  
              'gamma': [1, 0.1, 0.01, 0.001, 0.0001], 
              'kernel': [ 'linear', 'poly', 'rbf', 'sigmoid']}*

安装这个网格花了超过 10 个小时,实际上我不得不中断。我检查了多边形内核有更好的结果。所有线性核都很快,但精度为零。总的来说,这个网格相当于 500 次拟合,每 100 个候选对象 5 次折叠(5 * 5 * 4)。

因此,我构建了一个新网格,如下所示:

*param_grid2 = {'C': [1],  
              'gamma': [1], 
              'kernel': ['poly', 'rbf', 'sigmoid']}*

这个网格总共有 15 次拟合,花了大约 3.5 个小时来完成调整过程。

现在,按照同样的过程,我看了看最适合的模型,如下所示:

*grid_result.best_estimator_***Output:
SVC(C=1, gamma=1)****

默认的核是“rbf”或径向基函数(RBF)。要了解更多关于内核函数的信息,请参考 Scikit-learn 文档

*grid_result.best_estimator_.kernel***Output:
rbf****

以下是 SVM 的最终性能结果:

作者图片

就精度而言,这看起来比迄今为止所有其他模型都要好。然而,召回只是稍微好一点。

现在,我们来对比总结一下…

每个分类器的最佳精度(图片由作者提供)

在上表中,SVM 的精确度略好,但精确度有了很大的提高,67%的危险地震隆起的实际数量被正确预测。然而,召回率是 6%,即实际危险的地震颠簸中只有 6%是正确的。KNN 车型的 f1 得分低于 SVM 车型。

总的来说,由于无法识别危险的地震碰撞带来的风险因素,该问题陈述需要更好的回忆。召回中唯一表现较好的模型是 KNN,其权重一致,n _ neighbours 为 1,leaf_size 为 10。

业务需求的重要性因情况而异。有时回忆是首选(像这里),有时精确是首选。如果对预测的结果采取行动是有成本的,那么精确度就很重要,也就是说,你会想要更少的假阳性。当成本与每个假阴性相关联时,需要更高的召回率。在两者都重要的情况下,f1 分数,即精确度和召回率的调和平均值,变得重要。

参考:

[1]西科拉·m .、弗罗贝尔·l .:规则归纳算法在煤矿地震灾害监测系统收集的数据分析中的应用。采矿科学档案,55(1),2010,91–114。

感谢您的来访。我希望你喜欢阅读这个博客!

有关使用 SMOTE 处理不平衡类的更多信息,请参考这篇由 CathL 及其团队撰写的博客:

* [## 预测危险的地震颠簸第三部分:改善不平衡数据集的模型性能

新手评估试用机器学习模型进行分类和数据扩充,以更好地支持…

medium.com](https://medium.com/womeninai/predicting-hazardous-seismic-bumps-part-iii-improving-model-performance-for-imbalanced-datasets-88fa64b4d622)*

本笔记本的 GitHub 链接:

* [## royn5618/Medium_Blog_Codes

github.com](https://github.com/royn5618/Medium_Blog_Codes/blob/master/Predicting Hazardrous Seismic Bumps/Predicting_Seismic_Bumps.ipynb)*

我的链接: |LinkedIn|GitHub

预测危险的地震碰撞第一部分:EDA,不平衡数据集的特征工程和训练测试分裂

原文:https://towardsdatascience.com/predicting-hazardous-seismic-bumps-using-supervised-classification-algorithms-part-i-2c5d21f379bc?source=collection_archive---------30-----------------------

本文展示了探索性数据分析(EDA)、特征工程以及使用 UCI 数据档案中的地震颠簸数据集对不平衡数据进行分割的策略。

张秀坤·万尼Unsplash 上的照片

简介:

地震冲击数据集是一种鲜为人知的二进制分类数据集,它使用长壁煤矿中的地震和地震声学系统来捕捉地质条件,以评估它们是否容易发生导致地震灾害的岩爆。

https://archive.ics.uci.edu/ml/datasets/seismic-bumps】链接到数据集:

这是一个很好的数据集,它实际展示了不平衡数据集,处理不同类型的数据分割,并评估分类器的性能指标,包括展示准确性悖论

关于该数据集的另一件事是,它既有分类又有数字特征,这为争论和尝试不同的特征转换方法提供了一个平台。

这篇文章代码不多,但是在理解什么是对的和错的方面更直观一点!代码可以在我的 GitHub 库中找到。

注意——我没有详细说明 EDA 和功能工程步骤中的每个功能,因为它们是重复的。我只有这个博客和 中的样本,完整的代码可以在 GitHub 的这个链接 中找到。

探索性数据分析

照片由安德鲁·尼尔Unsplash 上拍摄

数据事实:

该数据集有 19 列 2584 个实例,其中有 4 个分类特征、8 个离散特征和 6 个数值特征。最后一个是标签列,包含 0 表示无危险,0 表示无危险的地震碰撞。为了便于使用,我将特性名称分类并保存如下:

**col_list_categorical** = ['seismic', 'seismoacoustic', 'shift', 'ghazard']
**col_list_numerical** = ['genergy', 'gpuls', 'gdenergy', 'gdpuls', 'energy', 'maxenergy']
**col_list_discrete** = ['nbumps', 'nbumps2', 'nbumps3', 'nbumps4', 'nbumps5', 'nbumps6', 'nbumps7', 'nbumps89']
**label** = 'class'

属性信息[ 来源:
1 .地震:通过地震方法获得的矿山工作中的移位地震危险评估结果(a-无危险,b-低危险,c-高危险,d-危险状态);
2。地震声学:通过地震声学方法获得的矿山开采中的移位地震危险性评估的结果;
3。班次:有关班次类型的信息(W —采煤,N—准备班次);
4。地震能量:监测长壁的
地震检波器中最活跃的地震检波器(GMax)在前一个班次内记录的地震能量;
5。gpuls:GMax 在前一个班次内记录的脉冲数;
6。gdenergy:GMax 在前一个班次中记录的能量与前八个班次中记录的平均能量的偏差;
7。GD puls:GMax 在前一次移位中记录的脉冲数与前八次移位中记录的平均脉冲数的偏差;
8。ghazard:根据仅来自 GMax 的注册,通过地震声学方法获得的矿山作业中的移位地震危险评估结果;
9。nbumps:前一个班次内记录的地震颠簸次数;
10。nbumps2:前一个班次内记录的地震颠簸次数(能量范围[1⁰,1⁰]);
11。nbumps3:前一个班次内记录的地震颠簸次数(能量范围[1⁰,1⁰⁴]);12。nbumps4:前一次移动中记录的地震颠簸次数(能量范围[1⁰⁴,1⁰⁵]);
13。nbumps5:在最后一次移动中记录的地震颠簸次数(能量范围[1⁰⁵,1⁰⁶]);14。nbumps6:前一个班次内记录的地震颠簸次数(能量范围[1⁰⁶,1⁰⁷]);15。nbumps7:前一个班次内记录的地震颠簸次数(能量范围[1⁰⁷,1⁰⁸]);16。nbumps89:前一个班次内记录的地震颠簸次数(能量范围[1⁰⁸,1⁰⁰]);17。能量:前一次移动中记录的地震冲击的总能量;18。最大能量:前一次移动中记录的地震冲击的最大能量;19。类别:决策属性—“1”表示高能地震冲击发生在下一个班次(“危险状态”),“0”表示在下一个班次(“非危险状态”)没有高能地震冲击发生。

目标类别分布

在 2584 份记录中,只有 6.5%的危险事件。换句话说,50 次地震中有 3 次是危险的。

sns.countplot(x=label, data=df, palette=colors)
plt.xlabel('CLASS')
plt.ylabel('COUNT')

分类特征

首先,我查看了分类特征,以了解它们与标签类别之间是否存在关系偏差。为此,我使用 pandas.crosstab 函数构建了列联表,并评估了分类特征中每个类别的内容相对于类别标签的比率和比例,以确定是否存在偏差。

data_crosstab = pd.crosstab(df['seismoacoustic'], df[label], colnames=['class'])

类别 1 到类别 0 的每个地震声学类别的比率约为 0.06,没有表现出任何强偏差。特征“地震”和“移动”包含一些分布偏差。“地震”特征中的“b”类包含更多的危险地震碰撞,而“shift”特征中的“W”类包含的地震碰撞比“N”类多。这些分类特征的列联表如下:

左侧——针对“班次”与“等级”的列联表;中心——地震与等级的应变表;右侧——针对“ghazard”与“Class”的列联表

数字特征

接下来,我查看数据并挑选出数字列,以理解它们的描述性统计、相关性和分布图。

  • 描述性统计

在 Pandas 中, 描述 方法仅提供计数、平均值、最小值、最大值、标准值和百分位数,我们可以从这些值中评估数据在某种程度上的偏斜度。为了更好地理解它们的分布,视觉效果是必不可少的,如分布图和直方图。

df[col_list_numerical].describe()

  • 相关性&热图

我用熊猫评估了这些特征之间的相关性。DataFrame.corr 并使用 seaborn.heatmap 可视化。

df_corr = df[col_list_numerical].corr()
plt.figure(figsize=[8, 8])
sns.heatmap(data=df_corr, vmin=-1, vmax=1, cmap=’gist_earth_r’, annot=True, square=True, linewidths=1)
plt.xticks(rotation=90)
plt.yticks(rotation=0)

  • 来自描述性统计和相关性的观察:

能量和最大能量的分布看起来很相似。genergy 看起来右倾。为了更好地理解分布,我使用了 seaborn.distplot 来可视化每个特性,如下所示。

在热图中,很明显 genergy 和 gpuls、gdenergy 和 gdpuls 之间有很强的相关性。能量和最大能量几乎是完全相关的。在 EDA 的后面部分,我试图为这些高度相关的对构建散点图,并可视化它们在每个目标类中的分布。

  • 更多 EDA 可视化:分布图&散点图

就像我说的,我想将分布可视化如下,很明显 genergy 是右偏的,就像所有其他数字特性一样(如 Github Notebook 所示)。

sns.distplot(df['genergy'], hist=True)

genergy 的更多实例在 0 到 200000 的范围内,并且分布随后向更高的能量值逐渐减少。所有其他数值特征的模式相同,但 gdenergy 和 gdpuls 的范围小于其他数值特征。

此外,我使用散点图来可视化相关系数大于 0.70 的相关特征。我构建了散点图来查看这些数值是如何分布在每个目标类中的。

plt.figure(figsize=[10, 8])
sns.scatterplot(x='genergy', y='gpuls', hue='class', data=df)

左侧 genergy 与 gpuls 的散点图;右侧—能量与最大能量的散点图

在左图中,地震凸起更集中在较高的 gpuls 和 genergy 值处。右侧散点图中观察到的能量与最大能量的线性关系也很强,如描述性统计数据、它们的散点图和此散点图所示。

离散特征

“nbumpsX”是包含从 0 到 9 的整数的离散特征。这里可以看到,‘nbumps 6’全是零,与‘nbumps 7’和‘nbumps 89’相同。此外,它们都是右偏或正偏分布。

我使用下面的代码删除了“nbumps6”、“nbumps7”和“nbumps89”。其他一切看起来都很好,但是任何 ML 模型都很有可能将‘nbumpsX’信息视为序数。

df.drop(columns=['nbumps6', 'nbumps7', 'nbumps89'], inplace=True)

我还使用以下代码再次构建了列联表,以查看 nbumpsX 如何与目标类联合分布:

for each_col in col_list_discrete:
    data_crosstab = pd.crosstab(df[each_col], df[label], colnames=['class'])
    print(data_crosstab)
    print('-----'

在表中,危险和非危险情况的分布没有明显的差异。在所有这些分立特性中,它们在 nbumpsX 计数中按比例出现。

因为所有这些看起来都很好,所以我转到了下一节“特性工程”,在这里我处理了分类和数字特性。

特征工程

我一次性编码了分类变量,并转换了数值列以缩小范围。我保持了独立的特征不变。

  • 分类特征的一键编码

我将所有两个类别的分类特征编码成一个包含 0 和 1 的特征,同时将两个以上类别的特征转换成每个类别的二进制列。这个 one-hot encoded feature 列表示该实例是否包含该特定类别。

例如,地震声学特征包含三个类别——a、b 和 c(如左图所示),它们被转换为扩展的三个二元特征(如右图所示)。我使用 drop='first '来避免伪变量陷阱。

label_encoder = LabelEncoder()
onehot_encoder = OneHotEncoder(drop='first', sparse=False)
encoded_array = label_encoder.fit_transform(df[col_name])
encoded_array_reshaped = encoded_array.reshape(len(encoded_array),1)
one_hot_encoded_array = onehot_encoder.fit_transform(encoded_array_reshaped)
num_features = one_hot_encoded_array.shape[1]
new_enc_col_names = [col + '_enc_' + str(num) for num in range(0, num_features)] 
df_enc = pd.DataFrame(one_hot_encoded_array)
df_enc.columns = new_enc_col_names
df = pd.concat([df, df_enc], axis=1)
df.drop(columns=col, inplace=True)

  • 数字列的转换

然后,我使用对数变换来转换所有的数字特征。z 分数变换并比较原始分布的变换。分布现在看起来更“正常”,范围也更好了。参考下面的代码和可视化进行比较。

sns.distplot(**np.log**(df['genergy']), hist=True)
# Results in the figure on the right

左 genergy 的实际分布;右——遗传的对数变换分布

我基本上创建了一个字典来定义我希望在这些列上应用什么转换,然后循环遍历字典条目,如下所示:

def shifted_log_func(df_col):
    return np.log(1 + df_col)dict_num_cols_trnsfm = {'genergy': np.log,
                        'gpuls' : np.log,
                        'gdenergy': stats.zscore,
                        'gdenergy': stats.zscore, 
                        'energy': shifted_log_func}for col_names, transfm_func in dict_num_cols_trnsfm.items():
    df['scaled_' + col_names] = transfm_func(df[col_names])
df.drop(columns=col_list_numerical, inplace=True)
df[[col for col in df.columns if 'scaled_' in col]].describe()

由于两者的数据相似,删除 maxenergy 后,数值的最终描述性统计数据。

左侧-缩放数字要素的描述性统计数据;右-原始数值数据的描述性统计信息

左侧表格中的范围似乎不错。右边的表格包含一些能量和最大能量的零值。为了解决这个问题,我在“能量”栏中加了 1(因为我去掉了 maxenergy ),然后应用对数变换。

分割培训和测试数据

由于这是一个不平衡的数据集,我使用分层混洗分割来分割和按比例分配目标类。

stratified_split = StratifiedShuffleSplit(n_splits=1, test_size=0.20)for train_idx, test_idx in stratified_split.split(X, y):
    y_train= y[train_idx]
    X_train = X[train_idx]
    X_test, y_test = X[test_idx], y[test_idx]print("Training Set Target Class Distribution:")
print(y_train.value_counts()/len(y_train))
print("Test Set Target Class Distribution:")
print(y_test.value_counts()/len(y_test))

如果我没有使用这种技术,我可能会以稍微不平衡的比例结束危险的地震颠簸,如下图所示。机器学习算法将能够从更公平比例的类别标签中学习,而不是从随机分布中学习,在随机分布中,目标类别的较小类别可能太少而无法学习,因此降低了模型的性能。

(左)-使用 train_test_split with shuffle 进行拆分时的分布= False(右)-使用 train_test_split with shuffle 进行拆分时的分布=True

这些微小差异的影响可能会影响机器学习算法的性能,因此对于二进制和多类分类问题都是如此。因此,建议对分类问题使用分层分割,尤其是当存在不平衡数据集时,以保留每个类别的样本百分比并避免采样偏差。

感谢您的来访。我希望你喜欢阅读这篇博客。 下一篇文章 是这篇探索模型构建和性能指标比较的博客的继续。下面链接-

[## 预测危险的地震颠簸第二部分:训练和调整监督 ML 分类器和模型…

本文展示了预测危险的地震颠簸使用二元分类器,调整模型超参数…

towardsdatascience.com](/predicting-hazardous-seismic-bumps-part-ii-training-supervised-classifier-models-and-8b9104b611b0) [## 预测危险的地震颠簸第三部分:改善不平衡数据集的模型性能

新手评估试用机器学习模型进行分类和数据扩充,以更好地支持…

medium.com](https://medium.com/womeninai/predicting-hazardous-seismic-bumps-part-iii-improving-model-performance-for-imbalanced-datasets-88fa64b4d622)

本笔记本的 GitHub 链接:

[## royn5618/Medium_Blog_Codes

github.com](https://github.com/royn5618/Medium_Blog_Codes/blob/master/Predicting Hazardrous Seismic Bumps/Predicting_Seismic_Bumps.ipynb)

我的链接: |LinkedIn|GitHub

基于神经网络的 HDB 房价预测

原文:https://towardsdatascience.com/predicting-hdb-housing-prices-using-neural-networks-94ab708cccf8?source=collection_archive---------24-----------------------

实践教程

朱洪志Unsplash 上拍照

除了问你的房屋中介,你有没有想过你的 HDB 值多少钱?或者想知道对你的 HDB 有很大影响的主要特征是什么?看到超过 92.2%的新加坡人拥有 HDB,我相信这些是大多数新加坡人都有过的常见问题,如果我能使用数据分析来获得对新加坡政府住房市场的任何见解,那将是很好的。序列预测模型给出的平均绝对误差为 22,429 美元(+/- 571.83)

关于可视化的更多信息,请查看我的 tableau 公共简介。有关代码的更多信息,请查看我的 GitHub。所有数据均在data.gov.sg获得。

概观

data.gov 的所有数据都有。以下数据分析项目遵循典型的方法(CRISP-DM)。

  • 数据清洗+探索性数据分析
  • 顺序神经网络(3 层)
  • 估价
  • 结论
  • 未来的工作

在接下来的 EDA 阶段,我将致力于数据可视化方面的深入研究,为我的读者提供对新加坡 HDB 房地产市场的更深入的见解。

数据清理

该数据集包括从 1990 年到 2020 年的数据。总共有 677,114 行和 10 列。虽然数据集中没有空值,但也有一些异常值(例如,封顶与未封顶的要素等。).首先,由于我们考虑的是在 MOP(最短入住期)后出售的公寓,任何超过 95 年租约(剩余租约)的公寓都将被删除。

然而,在数据集中有大量的重复,它们已被删除。

目标功能概述

我们整个数据集的中值价格约为 35 万美元。另外我们可以看到,80 万以上的房子只有少数。有趣的事实:根据我们的数据,这些年来卖出的最贵的房子是 123.2 万英镑。

图一。房价分布

探索性数据分析

相关矩阵

图二。所有定量特征的相关矩阵

公寓类型和建筑面积

正如我们所知,在新加坡有多种类型的公寓,一室,两室,行政等。直觉上,我们认为更大的房子(更大的建筑面积)是价格的有力指标。我把两张图拼在一起,这样你就可以看到公寓类型/建筑面积和转售价格之间的强烈相关性。正如我们所想象的,房子越大,价格就越高。

图 3。建筑面积(平方米)与转售价格

图 4。建筑面积与转售价格中位数

越大=越好?简短的回答;是的。

故事范围

在数据集中,地板水平被给定为一个范围并被注册为一个字符串。(例如“01 至 03”、“03 至 05”等。).此外,还有一些从 01 到 05 的楼层范围,跨越两个特征。我根据这些特征的平均楼层对它们进行了编码,并相应地将它们从 1(最低楼层范围)到 17(最高楼层范围)进行了排序。

图 5。转售价格与楼层范围

根据转售价格对它们进行排序,我们注意到,与其他功能相比,故事范围从 01 到 05 具有更高的中值价格。而总的趋势显示,地板越高,转售价格越高。

同样,对于故事范围 15、16 和 17,它们转换为 43 到 45、46 到 48 和 48 到 51,差异是< $200,000 (1 Sigma). There aren't too many HDB in Singapore that has floor that are higher than 43 floors, deeper analysis shows that most apartments sold there are from here.

Flat Model/Flat Layout

Flat model essentially refers to the layout of the house. As HDB have a long history in Singapore housing market. some of these models are obsolete, as the land are getting scarcer, some flat models will never return (e.g. Masionette).

Figure 6. Resale Price VS Model Type, ranked according to mean

Date (Month & Year)

The date was split into month and years as I firmly believe that the months do not matter as much as compared to the years. Perhaps changing them into Q1Y19 would give a deeper resolution into how HDB resale price changes overtime.

显然,这几个月没有太大的区别。月份从最小的中间转售价格开始排序。

图 7。转售价格中位数与月数

图 8。几个月内售出的房产总数

我把几个月作为一个特征,因为它们不会对转售价格的变化产生很大影响。有趣的是,计数图显示,多年来,二月一直是不受欢迎的购房月份。我认为这是因为二月的天数最少。

年份(HDB 转售指数)

通过对历年(1990 年至 2020 年)转售价格的排名,我们可以看到 HDB 转售价格多年来有明显的趋势。

图 9。转售价格与年销售量

HDB 转售指数随时间波动,在 2013 年达到峰值,HDB 的平均售价约为 40 万美元。从 1997 年到 1998 年,一年中最大的年同比降幅约为 50,000 美元。

塑造转售指数的一些值得注意的事件是 1997 年和 2008 年房地产泡沫期间发生的亚洲金融危机。然而,我们看到,HDB 转售指数在 2008 年房地产危机期间并没有受到太大影响。相反,由于我不知道的原因,它在 2013 年至 2014 年期间出现了更严重的下降。我最初的假设是 SIBOR 利率上升,或者在 2013 年和 2014 年有更好的资产类别可以投资

镇(区)

我认为,我认识的大多数新加坡人对财产有一种近乎不健康的痴迷(包括我在内)。新加坡人几乎愿意花大价钱住在黄金地段/成熟地区,其中一个原因可能是因为连通性和良好的小学。不用进一步滚动,你大概就能猜出哪些区域会卖高价。

图 10。转售价格与城镇

令人惊讶的是,远离市中心的丰戈尔获得了最高的转售价格,然而,从数据来看,丰戈尔是最近 10 年才开发的,这意味着平均零售价格已经很高了。

另一方面,虽然璧山、中央区和武吉提马的平均价格较低,但与其他地区相比,它们的 75%销售价格都较高。

对于成熟的房地产,如皇后镇,芽笼,昂莫桥和大巴窑。虽然它们靠近中心区,被认为是成熟的住宅区,但它们的收入中位数较低。这可能是因为这些地区的房屋一般都比较旧,可能已经过了最佳剩余租期。

图 11。剩余租约与城镇

剩余租约

正如我们可以看到的密度图显示,大多数人在两点出售他们的房子。94 年(紧接着 5 年的 MOP)2。70-85 岁(又名升级者/降级者)。这很直观,因为新加坡的组屋租期为 99 年,最短入住期为 5 年。因此,一旦最低入住期结束,人们可能会升级。第二个最常见的销售期在 70-85 左右是因为房地产价格大幅上涨。

图 12。转售价格与剩余租赁的热图。

小学

对于大多数新加坡人来说,我们听说过父母搬家只是为了更接近一所更好的(主观的)小学。这是因为在投票时,居住在更靠近首选学校的新加坡公民和永久居民会得到优先考虑

学校首先根据其受欢迎程度排名。最后,学校被地理标记到各自的城镇(区),然后进行平均。形成新的特色(学校排名)。

如你所见,武吉提马、璧山和中部地区的平均排名非常高。林珠港没有学校,事实上,快速搜索谷歌会发现林珠港几乎没有任何组屋。

序列神经网络

部署了三层神经网络,因为当与 SGDregressor 和 XGBoost 比较时,它产生最佳结果。基于 MAE 对结果进行评估。

我们利用了一个简单的 3 层序列神经网络,所有特征都被归一化。使用 minmax scaler 将分类特征拆分到单独的列中。

重复 K 倍

使用重复的 K-fold 来评估模型的性能。重复的 K-fold 随机地将数据分成大小大致相等的 5 个块。每个块依次被排除,而另外 4 个块用于训练模型。预测保持的块,并且这些预测被总结为 MAE(平均绝对误差)和 RMSLE(均方根误差)。然后重复该过程 3 次,并对各自的性能指标进行平均。更多关于重复 k 倍的信息,我们可以参考这个

图 14。k 倍交叉验证,混洗数据集,重复该过程 3 次。

结果

图 15。历元数与 MAE(左)和 MSE(右)

随着时代数量的增加,我们的损失(MAE,MSE,MAPE)减少,除了 MAPE,我相信这是因为它是原始房价的函数。我相信我们还没有找到“最佳点”,因为我们看到,随着我们的训练和验证数据中的时期增加,我们的损失仍在继续减少。

评估指标

重复 k 折叠序列神经网络模型结果是,

平均汇率:22767.46 (+/- 571.83)

MAPE: 9.07% (+/- 0.35%)

均方根误差:0.017(+/- 0.006)

结论

总的来说,模型的表现比我预期的要好。我试图寻找 HDB 预测模型的基准,它徘徊在 0.09 到 0.03 RMSLE 之间。然而,神经网络缺乏可解释性。与线性回归模型相比,我们可以看到不同系数的具体权重。

沙普利值

由于神经网络在很大程度上是黑盒模型,利用 Shapley 值来解释哪些特征在确定价格方面贡献最大。Shapley 值显示了哪些特征对价格预测贡献最大。

图 16。平均 SHAP 值

特征年销售量对价格预测贡献最大,其次是户型(3 房和 4 房)和建筑面积平方米。这意味着销售年份在很大程度上影响了预测,其次是公寓类型是三房还是四房。

未来的工作

最初的数据分析表明,确实有某些特征有助于更高的转售价格。然而,我相信我们可以更多地使用街区号码和街道名称。如果我们能够地理定位每个地址的纬度和经度,我们就能够创建新的距离特征。

此外,我还将尝试不同的算法,为模型提供更好的解释能力。目前,我们无法看到不同的功能如何影响最终的预测价格。

第二部分:https://towards data science . com/predicting-hdb-prices-using-machine-learning-algorithms-part-2-614 c 54646998

预测新冠肺炎疫情所需的医院容量

原文:https://towardsdatascience.com/predicting-hospital-capacity-needed-for-covid-19-pandemic-af743d7c3210?source=collection_archive---------40-----------------------

预测疾病传播和住院需求,确定应对激增所需的床位数量。

在我的上一篇文章中,我使用时间序列预测了确诊病例的指数增长&应用了修正以考虑社会距离和其他类似的措施。在这篇文章中,我将使用一个简单的流行病学模型来关注传染病传播的建模。在文章的开始,我将简要介绍该模型如何工作的基础知识,并使用该模型预测传播和住院需求

请注意,本文仅用于数据分析目的,本文观点不应被解释为专业建议。

流行病模型是基于分室的模型,将人群分成不同的组。目标是模拟这些疾病如何从一个群体的一个成员传播到另一个群体。一个最简单的房室模型叫做 SIR ,它将种群分为 3 组:

  1. 可能被感染的易感人群
  2. 受感染的个人(一)
  3. 康复个体(R)。

请注意,术语“康复”指的是可能已经痊愈并产生免疫力的患者,或者可能已经去世的患者。他们不会再被感染,这在现实中还没有被证实。

SIR 模型基于当前观察到的局部参数,如患病率和倍增时间,提供了对未来疾病在人群中传播的洞察。请注意,传播对隔离政策、检测可用性和其他当地因素非常敏感。这个模型的目标是理解

  1. 疾病传播的速度有多快
  2. 有百分之几的人口会被感染?
  3. 有百分之多少的人康复了?
  4. 我们的医院容量应该是多少?

SIR 模型预测将被感染的潜在个体总数。该数字可用于进一步估计需要医院资源(如住院、ICU、通气等)的患者比例。请注意,该模型对所有人都一视同仁,而实际上,患有更多慢性病的老年人群似乎风险更高。

SIR 模型使用初始(当前)疾病流行参数预测未来感染,如

  1. 群体大小
  2. 恢复时间
  3. 传输速率

方案

我们举个简单的例子。假设我们有一个拥有 100 万人口的县/州,在那个镇上,有五个人被感染。目标是确定它能传播多少和多快。这取决于许多因素。

  • 我们是否在跟踪家中的避难所及其对感染者每天可感染人数的影响:每个感染者每天可联系或多或少的人,这取决于是否实行社交距离。假设每个人每天接触两个人。不是每个他/她接触的人都会被感染。存在传播的可能性(易感者和受感染者接触后的感染可能性)。比方说传输概率是 15%。

  • 这意味着,如果这个人每天遇到 6 个人,传播概率为 15%,他每天会感染 6 * 15 % = 0.9 人。这个数字被称为 beta (𝛃)又名传播率,代表一个感染者每天感染的人数。出于建模的目的,每天接触的人数可能低至 1 人,高至 10 或 15 人,传播概率在 5%至 15%之间。较高的传播概率可能与具有较高风险的人群(患有其他慢性疾病的老年人群)相关
  • 疾病可以从感染者身上传播的天数:我们已经知道这个感染者每天可以传染 0.9 人。这个人多少天会被感染,传播疾病?假设这个病人与人接触了 5 天。如果他/她每天感染 0.9 人,5 天就感染 0.9 * 5 = 4.5 人。这个数字被称为基本繁殖数,用来估计疾病在人群中传播的速度。这是一个感染者感染的总人数。这是一个需要理解的重要数字,因此让我们在下面对此进行更多的讨论。
  • 再现号 Ro 读作“R 零”这是一个数学术语,表示疾病的传染性。告诉你平均有多少人会从一个有传染性的人身上染上疾病。如果一种疾病的 Ro 为 6,只要没有人接种过疫苗或在他们的社区中已经对其免疫,感染者就会将该疾病传播给平均 6 个其他人。2009 年的猪流感或 H1N1 病毒的 Ro 值约为 1.5。由于疫苗和抗病毒药物的作用,影响并不大。在冠状病毒的情况下, R o 值估计在 1.5 到 3.5 之间,其中 1.5 到 2.5 用于良好的社交距离。

  • 痊愈率(ɣ)是单位时间内痊愈的感染者的比率。在这种情况下,感染持续了 5 天,⅕是伽马值,是目前每天恢复的感染人数。

这些参数可用于通过识别感染和康复人群的变化来定义传播。

随着时间的推移,易感人群的数量下降,被感染的人数上升。康复的人数也在上升。(𝛃)传染率是指一个人感染多少人。既然我们有我感染的人,那就是𝛃 我就是感染的力量。当我们将其乘以易感人群,即新感染人群。由于一些种群可能已经恢复,ɣ I 给出了恢复的种群数量。必须减去这个数字才能得到感染人数。这可以用一个简单的等式来描述,如下所示。我不打算在本文中解释这个公式的数学原理,但会解释它的实际用法。

使用 SIR 模型进行预测

预测一个州/县所需的医院床位

现在,我们将上述知识应用于拥有 100 万人口的县/州(如前所述)。假设这个县/州在 3 月 10 日左右宣布了 5 个病例。

这里要解决的问题是

  1. 疾病传播的速度(到达高峰的时间)
  2. 有百分之几的人口会被感染?
  3. 社交距离的影响?
  4. 对我们医院容量的影响?

截至 2010 年 4 月 20 日,美国主要一般统计数据的简要总结。这些是我们可以在计算中使用/参考的一些公开可用的统计数据。这些数据来源于世卫组织和疾病预防控制中心。

  1. 被测试人口的百分比相当低(< 1%).
  2. Out of the tests conducted, on an average anywhere from 10 to 20% of the people tested are becoming positive.
  3. Out of the individuals who have confirmed positive, 10 to 16% of those are hospitalized.
  4. Most states in the USA the number of beds range from 1.6 to 4.4 beds for every 1,000 people. The average for the USA is 2.4.

用于模拟的关键数字

  • 假设一个人感染了 5 天。如前所述,这意味着γ(回收率)是⅕ = 0.2。为了限制建模的范围,我保持伽玛为常数。在后续文章中,我可能会进一步阐述这种影响。
  • 从本文前面的讨论来看,对于新冠肺炎来说基本的再生数 R o 的范围是从 1.25 到 3.5。我们将使用 1.25 的 Ro ,1.5 的& 2 并比较结果。告诉你平均有多少人会从一个有传染性的人身上染上疾病。例如, R o 为 2 表示一个感染者会将疾病传染给另外两个人。如果 R o 值大于 1,则感染率大于恢复率,因此感染将在整个人群中增长。如果 Ro 小于 1,感染将很快消失,因为人们愈合的速度比传播的速度快。
  • 相同的β值将分别为( R o * gamma) 0.25,0.3 & 0.4。β代表一个感染者每天感染的人数。
  • 对于 SIR 模型,截至 3 月 10 日,最初的易感人群约为 100 万,其中有 5 人被感染。

下一节总结了这个模拟的结果。

Ro 1.5 的结果汇总

对于 Ro = 1.5,从下图可以看出,峰值出现在 3 月 10 日之后的 112 天。这将是 7 月初左右,高峰病例为 63,000 例。注意 y 轴表示人数(%),x 轴表示天数。

比方说,我们县每个病人有 2.1 张病床& 16%的检测呈阳性的人住院了(根据上面的统计)。让我们用那个计算来估计医院的容量。

从 3 月 10 日起的 112 天中,峰值病例为 63,000,相应的峰值住院需求为 10,080。

添加可用的医院容量,见下图。在现有床位为 2,100 张的情况下,要为 10,080 张床位的激增做好准备,需要通过增加医院容量以及练习社交距离来减少激增。在下一节中,我们将讨论将 Ro 从 1.5 降至 1.25 的影响。

社交距离的影响或缺乏社交距离

下图显示了范围从 1.25 到 2.0 的各种 Ro 值的影响。y 轴显示人数(%),x 轴显示天数。如果一个人做了很好的社交距离,我们可以看到 Ro = 1.25 时的行为。如果我们开始放松社交距离,你会看到更接近于 2.0(或者更高)的行为。这就是为什么社交距离、测试、追踪和隔离极其重要。

对于 Ro = 1.25,假设继续做好社交距离等隔离方式,197 天左右可以看到 21500 例。这是从 3 月 10 日开始的大约 7 个月,也就是 9 月底/10 月初。

让我们加上每 1000 个可用床位 2.1 张的计算结果(来自统计数据)& 16%(来自统计数据)测试呈阳性的人住院了。考虑到这些因素,所需床位计算如下。

相应的高峰住院需求为 3440 人,而容量仅为 2100 人。

预测不同 Ro 值的医院床位容量

下表总结了 3 个不同 Ro 值的建模结果。峰值表示自模拟开始(2020 年 3 月 10 日)以来可以找到的最大案例数,天数为天。

让我们加上每 1000 个可用床位 2.1 张的计算结果(来自统计数据)& 16%(来自统计数据)测试呈阳性的人住院了。考虑到这些因素,所需床位计算如下。

对于 Ro = 1.25,该模型预测高峰病例将在 197 天后发生,大约高峰日期为 9 月 23 日,需要医院床位 3440 张。假设每 1000 人 2.1 张床位,该县将短缺 1340 张床位。

类似地,对于 Ro = 1.5,该模型预测高峰病例将在 112 天后发生,大约高峰日期为 6 月 30 日,所需医院床位为 10,080 张。假设每 1000 人拥有 2.1 张床位,该县将缺少 7980 张床位..

如果我们假设需要住院治疗的检测呈阳性的人口百分比为保守估计的 10%,则以下是相应的所需医院床位容量。

对于 Ro = 1.25,该模型预测该县不会出现短缺。就 Ro 1.5 而言,预计短缺 4,200 个床位。

通过适当的管理,将 Ro 保持在 1.25 以下,并采取适当的谨慎措施,人们可以处理这一危机。

总结

使用 SIR 模型,我们预测了一个拥有 100 万人口的县的传播范围,该县截至 3 月 10 日有 5 例确诊病例,具有不同的 Ro 值。如果该县能够将 Ro 保持在 1.25 或以下,我们应该能够很好地控制病毒爆发。如果 Ro 达到峰值,那就是我们开始不知所措的时候。这表明了社会距离、接触者追踪和隔离的重要性。更重要的是,知道大概的高峰时间和潜在的住院需求,县可以通过增加适当的临时床位来帮助减少影响。

使用 InterpretML 预测酒店取消预订

原文:https://towardsdatascience.com/predicting-hotel-cancellations-using-interpretml-e4e64fefc7a8?source=collection_archive---------43-----------------------

可解释性是机器学习的一个被忽视但又必要的方面。

为了将模型部署到生产中,并使非技术受众能够理解研究结果,模型结果的可理解性或理解与准确性一样重要。

微软开发的 InterpretML 包的目的是允许增加黑盒机器学习模型的可理解性,同时保持强大的准确性性能。

下面是一个使用可解释助推机(EBM)预测客户是否会取消酒店预订的例子(1 =客户取消,0 =客户不取消)。

数据准备

H1 数据集用于训练目的,而 H2 数据集用于测试模型预测。

Antonio 等人的原始数据集和研究可以在本文末尾的参考资料中找到。以下是数据集的一个示例:

来源:使用数据科学预测酒店预订取消(Antonio 等人)

除了包含空值的变量(代理公司)以及 ReservationStatusDate 之外,数据集中的所有特征都包括在内。

最小最大缩放器用于将特征转换为 0 到 1 之间的比例。

假设未消除(0)的发生率比消除(1)多,SMOTE 过采样方法用于创建样本训练数据以模拟消除发生率的特征数据。

>>> counter = Counter(y_train)
>>> print(counter)Counter({0: 21672, 1: 8373})

最初, 0 有 21672 个条目,而 1 有 8373 个条目。

>>> oversample = SMOTE()
>>> x_train, y_train = oversample.fit_resample(x_train, y_train)
>>> counter = Counter(y_train)
>>> print(counter)Counter({1: 21672, 0: 21672})

0 和 1 的发生率现在相等。

可解释的助推分类器

可解释的提升分类器被用作训练模型。

>>> from interpret.glassbox import ExplainableBoostingClassifier
>>> ebm = ExplainableBoostingClassifier()
>>> ebm.fit(x_train, y_train)
>>> print("Accuracy on training set: {:.3f}".format(ebm.score(x_train, y_train)))
>>> print("Accuracy on validation set: {:.3f}".format(ebm.score(x_val, y_val)))Accuracy on training set: 0.907
Accuracy on validation set: 0.623

验证准确率达到 62%。

精确度与召回率和 f1 分数

当比较准确度分数时,我们看到在每个混淆矩阵中都提供了大量的读数。

然而,在精度召回之间存在一个特别重要的区别。

Precision = ((True Positive)/(True Positive + False Positive))Recall = ((True Positive)/(True Positive + False Negative))

这两个读数经常相互矛盾,也就是说,通常不可能在不降低召回率的情况下提高精确度,反之亦然。

对理想指标的评估很大程度上取决于所分析的具体数据。例如,癌症检测筛查出现假阴性(即表明患者没有患癌症,而事实上他们患有癌症)是一大禁忌。在这种情况下,召回是理想的衡量标准。

然而,对于电子邮件,人们可能更喜欢避免误报,例如,将一封重要的电子邮件发送到垃圾邮件文件夹,而实际上它是合法的。

f1 分数在设计一个更通用的分数时考虑了精确度和召回率。

哪个因素对预测酒店取消更重要?

从酒店的角度来看,他们可能希望更准确地识别出最终会取消预订的客户,这使得酒店能够更好地分配房间和资源。确定不打算取消预订的客户不一定会增加酒店分析的价值,因为酒店知道,无论如何,很大一部分客户最终都会坚持预订。

测试集上的性能

当在测试集(H2)上运行该模型时,以下混淆矩阵表明基于 f1 分数的总体准确性为 55% ,而取消类别的召回率为 87% (这意味着在所有取消预订的客户中,该模型正确识别了 87%):

[[14848 31380]
 [ 4437 28665]]
              precision    recall  f1-score   support 0       0.77      0.32      0.45     46228
           1       0.48      0.87      0.62     33102 accuracy                           0.55     79330
   macro avg       0.62      0.59      0.53     79330
weighted avg       0.65      0.55      0.52     79330

下面是生成的 ROC 曲线:

来源:InterpretML

确定了前 5 个特征。

来源:InterpretML

交付时间(功能 1 )、周末住宿(功能 5 )、所需停车位(功能 15 )、国家(功能 19 )和分配的房间类型(功能 23 )被确定为对客户是否会取消其酒店预订最有影响的五个因素。

让我们将混淆矩阵的准确性指标与使用相同功能运行的标准 XGBoost 模型的准确性指标进行比较:

[[12650 33578]
 [ 1972 31130]]
              precision    recall  f1-score   support 0       0.87      0.27      0.42     46228
           1       0.48      0.94      0.64     33102 accuracy                           0.55     79330
   macro avg       0.67      0.61      0.53     79330
weighted avg       0.70      0.55      0.51     79330

XGBoost 的召回率略高,为 94% ,而总体准确率保持在 55%

随机森林分类器

让我们看看 RandomForestClassifier 作为一个黑盒分类系统如何解决这个问题。

from sklearn.ensemble import RandomForestClassifier
from sklearn.decomposition import PCA
from sklearn.pipeline import Pipelinepca = PCA()
rf = RandomForestClassifier(n_estimators=100, n_jobs=-1)blackbox_model = Pipeline([('pca', pca), ('rf', rf)])
blackbox_model.fit(x_train, y_train)

让我们按照重要性顺序来看一下已确定的特性。

from interpret.blackbox import LimeTabular
lime = LimeTabular(predict_fn=blackbox_model.predict_proba, data=x_train, random_state=1)
lime_local = lime.explain_local(a_scaled[:5], b[:5], name='LIME')
show(lime_local)

来源:InterpretML

虽然功能的重要性与可解释的 Boosting 分类器有所不同,但所需的停车位和国家(功能 15 和 19 )仍然被确定为酒店取消的重要影响因素。

这是在测试集上生成的 ROC 曲线:

来源:InterpretML

以下是相关的混淆矩阵:

[[43711  2517]
 [17992 15110]]
              precision    recall  f1-score   support 0       0.71      0.95      0.81     46228
           1       0.86      0.46      0.60     33102 accuracy                           0.74     79330
   macro avg       0.78      0.70      0.70     79330
weighted avg       0.77      0.74      0.72     79330

基于 f1 分数的总体准确率要高得多,为 74%,而取消类的召回率要低得多,为 46%。在这方面,该模型在预测总体结果(取消和未取消)方面做得更好。

然而,如果我们希望具体预测哪些客户将取消他们的预订,那么可解释的提升分类器是一个更好的模型。

结论

如前所述,InterpretML 的重点是让模型结果既准确又易懂。从这个角度来看,这个库是一个非常有用的工具,它允许直观和可理解地显示结果。

非常感谢您的阅读,这个项目的 GitHub 库和相关代码可以在这里找到。

免责声明:本文是在“原样”的基础上编写的,没有担保。本文旨在提供数据科学概念的概述,不应以任何方式解释为专业建议。

参考

用线性回归预测房价

原文:https://towardsdatascience.com/predicting-house-prices-with-linear-regression-4fc427cb1002?source=collection_archive---------16-----------------------

以埃姆斯住房数据集为特色的项目

史蒂文·昂格曼在 Unsplash 上的照片

在学习数据科学时,许多学生将学习的第一个有监督的机器学习模型之一是线性回归。线性回归试图模拟预测变量 (X)和数字目标变量 (y)之间的线性关系。对于用模型评估的每个观察值,将目标的实际值(y)与目标的预测值(ŷ)进行比较,并且这些值的差被称为 residials。线性回归模型的目标是最小化残差平方和。多元线性回归的方程式如下所示。

图一。多元线性回归方程。在该等式中,β0 是 y 轴截距,x 的每个值都是预测变量。对于每个预测因子,如果所有其他特征保持不变,β系数描述了 x 增加一个单位时 y 的变化。随机误差用ε表示。

对于初学者来说,学习线性回归最常见的方法之一是建立一个模型,根据房子的具体特征来预测房子的价格。对于这个项目,使用了 Ames 住房数据集。该数据集包括 2006 年至 2010 年爱荷华州埃姆斯市出售的房屋信息。数据集中包含 2930 个观测值和 80 多个特征。

下面,我将描述我建立一个线性回归模型来预测房价的步骤。所有代码都托管在 GitHub 上。

步骤 1:导入库;获取和清理数据

埃姆斯住宅数据集是通过大会主办的 Kaggle 竞赛提供给我的。(然而,数据集也可以在这里公开。)在开始研究数据或建模之前,我导入了代码 1 中所示的库。我还清除了丢失的值,确保没有异常值,并且每个特性都是适当的数据类型。

代码 1。用于本项目的库

步骤 2:探索性数据分析(EDA)

之前的一篇文章中,我讨论了 EDA 对于在数据集中发现模式的重要性。对于这个项目,EDA 对于探索不同特征和目标(房屋销售价格)之间的关系同样重要。对于数字特性,我创建了一个相关矩阵,专门寻找相关系数的绝对值为 0.5 或更高的特性。这一步帮助我确定了与销售价格密切相关的几个特征,包括房子的整体质量、居住面积和车库的大小(就汽车数量和面积而言)。

代码 2 。数字特征的探索性数据分析

对于分类变量,理解不同类别和销售价格之间的关系要稍微复杂一些。总的来说,这个数据集包含超过 20 个分类特征,一些特征有超过 10 个不同的类别。为了降低模型的维度,我知道简单地对类别进行一次性编码是不可行的。为了解决这个问题,我为每个分类特征创建了条形图,以探索不同类别之间平均销售价格的差异。有趣的是,如下图所示,我开始注意到各种功能的一些类别开始聚集在一起。通过识别这些聚类,我能够设计特征来表示分类变量。

代码 3。具有分类特征的探索性数据分析条形图

图一。按条件 1 的销售价格。在这个用 Matplotlib 和 Seaborn 创建的条形图中,很明显,浅蓝色条形图和深蓝色条形图在销售价格和类别描述方面彼此相似。认识到这些相似性,这个具有九个类别的分类特征可以仅由两个二元特征来表示。

代码 4。将图 1 中的聚类转化为二元变量

第三步:模型准备

一旦我完成了对数据和工程特性的探索,就该为建模准备数据了。在这一步中,我使用pd.get_dummies()对任何感兴趣的分类变量进行虚拟化,并使用train_test_split()将我的数据分成训练集和测试集。

第四步:建模

建模是一个迭代的过程,在这个过程中,为了给我的最终模型提供信息,构建了几个模型。总共制造了六个模型。所有模型均采用 R2 评分进行评估。

代码 5。功能用于打印 R2 分数

模型 1: 该模型是使用DummyRegressor()创建的基线/空模型。当对每次观察的平均值进行预测时,进行研究以探索 R2 评分。

代码 6。虚拟回归模型

模型 2: 该模型是一个线性回归模型,使用在 EDA 过程中被识别为重要的特性。

模型 3: 在看到线性回归模型有改进的空间后,我将所有可能的特征放入一个模型中,以创建一个过拟合模型,然后可以将其正则化。

模型 4: 我尝试的第一种正则化是岭回归,它使用 L2 罚函数。

代码 9。缩放数据和岭回归

模型 5: 我尝试的第二种正则化是 LASSO 回归。

代码 10。套索回归

模型 6: 最终模型是线性回归,其特征在 EDA 和 LASSO 回归中被识别为重要。因为目标不是正态分布的,所以对于这个模型,它是对数变换的。

代码 11。最终线性回归模型。模型中有 47 个特征,包括:地段临街面、地段面积、整体质量、整体状况、建造年份、改造年份、砖石饰面面积、未完工地下室平方英尺、地上总房间数、车库大小(汽车)、车库面积、出售年份、总浴室数、可居住平方英尺、车库汽车 x 面积互动、邻里群 1、邻里群 2、1 层房屋(1946 年及以后)、2 层房屋(1946 年及以后)、1 层规划开发单元、靠近场外特征、靠近繁华街道、石材饰面、新销售、 房地产销售,良好的地下室,优秀的厨房,分区组 1,铺面街道,丘陵地带等高线,低土地等高线,水平土地等高线,复式,两户转换,联排别墅,联排别墅(末端单元),附属车库,地下室车库,内置车库,汽车港口,独立车库,无车库,一般外观质量,良好外观质量,一般外观质量,部分铺面车道,全铺面车道。

第五步:型号选择

在我建立了我的模型之后,我比较了训练和测试的 R2 分数来挑选最好的模型。

图二。基线、过度拟合、山脊、套索和最终模型的 R2 得分

对我来说,最好的模型与线性回归建立在 EDA 和 LASSO 中确定的特征。该模型解释了测试集销售价格变化的 87.8%。

第六步:模型评估

在选择了我的最佳模型后,我通过计算均方根误差(RMSE)和比较实际值与预测值来进一步评估它的性能。

均方根误差(RMSE)

代码 12。计算均方根误差

根据 RMSE 的值,线性回归模型对销售价格的预测可能会相差约 23,625.19 美元。这小于训练数据中销售价格的标准偏差的 1/3。虽然提高这个数字很好,但这是一个很好的起点。

销售价格的预测值与实际值相比如何?

图三。显示预测销售价格与实际销售价格的图表

通过将预测价格与实际价格进行对比,我发现这个模型在预测所有价格时表现得并不一样好。具体来说,该模型似乎擅长预测 90,000 美元至 225,000 美元范围内的房地产价格,但它在两个极端都做得不好。在最初的测试数据集中,75%的房屋价格在 214,000 美元或以下。由于这些情况下的训练数据不足,该模型在极端值下可能表现不佳。

结论

虽然这篇文章中创建的线性回归模型并不完美,但它能够解释大约 87.8%的房产销售价格变化,并且能够预测 23,625.19 美元以内的销售价格。对该模型残差的进一步研究揭示了该模型在预测极值方面的一个特定弱点。具体来说,预测的理想范围似乎在 90,000 美元到 225,000 美元之间。为了更好地预测这个范围之外的价格,可以对模型进行一些更改。改进的想法包括对数转换特征和将一些分类变量编码为序数。

你参加过艾姆斯住宅挑战赛吗?你有什么建议或窍门?

用 Scikit-Learn 的随机森林模型预测房价

原文:https://towardsdatascience.com/predicting-housing-prices-using-a-scikit-learns-random-forest-model-e736b59d56c5?source=collection_archive---------11-----------------------

图片来自 Getty Images

动机

拥有一个房价预测模型对买卖双方来说都是非常重要的工具,因为它可以帮助他们做出明智的决定。对卖家来说,它可以帮助他们确定出售房屋的平均价格,而对买家来说,它可以帮助他们找到购买房屋的正确平均价格。

目标

建立随机森林回归模型,能够预测房屋的中值。我们还将简要介绍一些探索性数据分析、特征工程和超参数调整,以提高我们的随机森林模型的性能。

我们的机器学习管道

图片作者:简单的机器学习管道

我们的机器学习管道可以概括为以下任务:

  1. 数据采集
  2. 数据预处理和探索性数据分析
  3. 创建基础模型
  4. 特征工程
  5. 超参数调谐
  6. 最终模型培训和评估

第一步:数据采集

我们将使用波士顿住房数据集:https://www.kaggle.com/c/boston-housing/data

#Importing the necessary libraries we will be using%load_ext autoreload
%autoreload 2
%matplotlib inlinefrom fastai.imports import *
from fastai.structured import *from pandas_summary import DataFrameSummary
from sklearn.ensemble import RandomForestRegressor
from IPython.display import displayfrom sklearn import metrics
from sklearn.model_selection import RandomizedSearchCV#Loading the DatasetPATH = 'data/Boston Housing Dataset/'
df_raw_train = pd.read_csv(f'{PATH}train.csv',low_memory = False)
df_raw_test = pd.read_csv(f'{PATH}test.csv',low_memory = False)

步骤 2:数据预处理和探索性数据分析(EDA)

2.1 数据缺失和异常值的检查和处理。

df_raw_train.info

作者图片

了解原始数据:

根据上面的原始训练数据集:

(a)共有 14 个变量(13 个自变量—特征和 1 个因变量—目标变量)
(b)数据类型要么是整数要么是浮点数
(c) 不存在分类数据
(d)我们的数据集中没有缺失值

2.2 作为 EDA 的一部分,我们将首先尝试确定因变量(MDEV)的分布。

#Plot the distribution of MEDVplt.figure(figsize=(10, 6))
sns.distplot(df_raw_train['MEDV'],bins=30)

作者图片:MEDV 分布

MEDV 的值遵循正态分布且平均值约为 22。右边有一些异常值。

2.3 接下来,试着确定:
(i)自变量本身
(ii)自变量与因变量
之间是否有相关性

为此,我们来做一个关联热图。

# Plot the correlation heatmapplt.figure(figsize=(14, 8))
corr_matrix = df_raw_train.corr().round(2)
sns.heatmap(data=corr_matrix,cmap='coolwarm',annot=True)

作者图片:相关热图

(i)独立变量之间的相关性 :
我们需要寻找多重共线性的特征(即彼此相关的特征),因为这将影响我们与独立变量的关系。

注意到 RADTAX 彼此高度相关(相关分数:0.92),而有几个特征彼此稍微相关,相关分数约为 0.70 (INDUS 和 TAX、NOX 和 INDUS、AGE 和 DIS、AGE 和 INDUS)。

(二)自变量与因变量之间的相关性 :
为了让我们的回归模型表现良好,理想情况下我们需要选择那些与我们的因变量(MEDV)高度相关的特征。

我们观察到 RMLSTAT 都与和 MEDV 相关,相关系数分别为 0.66 和 0.74。这也可以通过散点图来说明。

#Scatter plot to observe the correlations between the features that are highly correlated with MEDVtarget_var = df_raw_train['MEDV']plot1 = plt.figure(1)
plt.scatter(df_raw_train['RM'],target_var)
plt.xlabel('RM')
plt.ylabel('MEDV')plot2 = plt.figure(2)
plt.scatter(df_raw_train['LSTAT'],target_var)
plt.xlabel('LSTAT')
plt.ylabel('MEDV')

作者图片:RM 与 MEDV 散点图

作者提供的图片:RM 与 LSTAT 的散点图

从上面的散点图来看:
i) MEDV 随 RM 线性增加。这是有道理的,因为我们预计随着房间数量的增加,房子的中值价格会更贵。MEDV 随 LSTAT 线性下降。这也是有道理的,因为我们可以预期,在社会地位较低的地方,房子的中值价格通常会更便宜。

步骤 3:创建基础模型

停下来。在我们创建我们的基本随机森林模型之前,选择一个合适的评估标准是非常重要的。

图片来自 imgflip.com

3.1 选择正确的评估指标
选择正确的评估指标将有助于我们评估我们的模型性能是否良好。对于回归问题,最常用的评估指标是均方根误差(RMSE)均方根逻辑误差(RMLSE)

RMSE :这是我们的模型预测值和实际值之间的平方差。

均方根误差公式

其中 y:预测值,y:实际值

RMSLE :它是我们的模型预测的对数和实际值的对数之间的平方差的度量。

均方根逻辑误差

其中 y:预测值,y:实际值

RMSLE 可能是一个更好的评估指标,因为(1)它足够稳健,可以处理我们在数据集中看到的异常值(2) RMSLE 会因低估实际值而招致更大的损失。如果我们站在卖家的角度,我们不想低估价格,因为这会导致损失。然而,对于这个项目,我们不会站在任何一方,我们将选择 RMSE 作为评估指标,因为我们将使用不受异常值影响的随机森林模型。

3.2 创建我们的基础随机森林模型

下一步是首先创建一个基本模型,不进行任何特征工程和超参数调整。在我们完成特征工程和超参数调整之后,我们将使用这个模型的性能作为比较的基准。

我们选择的机器学习模型是随机森林回归模型,原因如下:

  1. 随机森林模型需要最少的数据准备。它能够轻松处理分类、数字和二进制特征,无需缩放或标准化。
  2. 随机森林模型可以帮助我们执行隐含的特征选择,因为它们提供了重要特征的良好指标。
  3. 随机森林模型不受离群值的影响,离群值存在于我们的数据中,它们完全忽略了统计问题,因为不像其他机器学习模型在标准化后表现得更好。

照片摄于 frontiersin.org

我们想创建一些有用的函数:

# A function to split our training data into a training set to train our  model and a validations set, which will be used to validate our model.def split_vals(a,n):
    return a[:n],a[n:]# Functions that will help us calculate the RMSE and print the score.def rmse(x,y):
    return math.sqrt(((x-y)**2).mean())def print_score(m):
    res =[rmse(m.predict(X_train),y_train),rmse(m.predict(X_valid),y_valid),m.score(X_train,y_train),m.score(X_valid,y_valid)]
    if hasattr(m,'oob_score_'):res.append(m.oob_score_)
    print(res)

进一步拆分我们的训练数据—用于训练随机森林模型的训练数据和用于验证模型性能的验证数据。

n_valid = 100
n_train = len(df_raw_train)-n_valid
X_train,X_valid = split_vals(df_raw_train.drop('MEDV',axis=1),n_train)
y_train,y_valid = split_vals(df_raw_train['MEDV'],n_train)
X_test = df_raw_test

在没有特征选择和超参数调整的情况下创建和拟合我们的随机森林模型

从我们的基本随机森林模型中,我们已经得到了一个非常不错的结果,其中训练 RMSE1.394 ,而验证 RMSE3.021 。但是,请注意,我们的模型似乎更适合,因为验证 RMSE 比训练 RMSE 大约高 3 倍。

因此,击败的基线分数是验证 RMSE 3.021** !**

步骤 4:特征工程

特征工程和超参数调整是机器学习管道中的基本步骤

4.1 确定重要特征
我们数据中的特征直接影响着我们的随机森林模型及其实现的结果(即,我们准备和选择的特征越好,我们实现的最终结果就越好!).因此,我们将通过确定哪些特性在之前的基础模型中被认为是重要的,来探索和微调我们的随机森林模型。

def feat_importance(m,df_train):
    importance = m.feature_importances_
    importance = pd.DataFrame(importance,index=df_train.columns,columns=["Importance"])
    return importance.sort_values(by=['Importance'],ascending=False)importance = feat_importance(m,X_train)
importance[:]

分级特征重要性系数

importance.plot(kind='barh')

分级特征重要性条形图

我们观察到在预测 MDEV 时最重要的特征是 LSTATRM 。回想一下,之前发现这两个参数与 MDEV 高度相关。

4.2 丢弃不重要的特征
下一步将尝试丢弃重要性系数小于 0.01 的特征,并使用它再次为我们的随机森林建模,以查看我们的预测结果是否有改进。

#Discarding features with feature coefficients less than 0.01to_keep = importance[importance['Importance'] > 0.01].index
df_raw_train_keep = df_raw_train[to_keep].copy()
df_raw_test_keep = df_raw_test[to_keep].copy()#Splitting data into training and validation setX_train,X_valid = split_vals(df_raw_train_keep,n_train)# Fitting our Random Forest Model after discarding the less important features.

我们的随机森林模型在移除了一些冗余功能(即 6 个功能)后,表现稍好!).我们已经获得了确定因变量 MEDV 的前 9 个最重要的特征(LSTAT、RM、DIS、CRIM、TAX、NOX、PTRATIO、NOX 和 AGE)。

接下来,让我们看看对于我们的随机森林模型来说重要的特性的等级是否有任何变化。

def feat_importance(m,df_raw_train_keep):
    importance = m.feature_importances_
    importance =
pd.DataFrame(importance,index=df_train.columns,columns=["Importance"])
    return importance.sort_values(by=['Importance'],ascending=False)importance

去除冗余特征后的分级特征重要性系数

移除冗余特征后的分级特征重要性条形图

我们观察到,在先前移除冗余特征之后,最重要的特征仍然是 LSTAT 和 RM。我们想探究逐一删除剩余的每个功能会如何影响我们的总体得分。

请注意,删除 RM、LSTAT、DIS 和 CRIM 会导致更差的验证 RMSE,而删除 AGE 和 PTRATIO 会给我们一个稍好的分数。因此,在运行最终模型之前,我们将进一步从数据集中删除 AGEPTRATIO

4.3 去除独立要素间的多重共线性

在 2.3(i)中,有一些相互关联的特征。为了提高模型的性能,我们最好是移除特征之间的多重共线性

为了了解这些特征是如何相互关联的,我们可以绘制一个树状图。

#Dendogram plotfrom scipy.cluster import hierarchy as hc
corr = np.round(scipy.stats.spearmanr(df_raw_train_keep).correlation,4)
corr_condensed = hc.distance.squareform(1-corr)
z = hc.linkage(corr_condensed,method='average')
fig = plt.figure(figsize=(16,10))
dendogram = hc.dendrogram(z,labels=df_raw_train_keep.columns,orientation='left',leaf_font_size=16)
plt.show()

重要特征之间的树状图

从树状图中,在排名方面我们可以看到,没有一个特征是衡量同样的东西。排名最接近的是 NOX 和 CRIM。

如果在排名方面存在非常接近的特征,下一步将是移除这些特征,一次移除一个,看看我们的模型是否可以进一步简化,而不影响我们的验证 RMSE 分数。然而在这种情况下,我们不需要。

步骤 5:超参数调整

我们已经到了最后一步(万岁!)才能建立最终的随机森林模型。

图片来自 tech-quantum.com

超参数调整是一个迭代过程 s,由此我们选择超参数的最佳配置,这为我们提供了最佳模型性能输出。对于随机森林模型,我们将重点调整 3 个超参数:

(1) n_estimators :在我们的随机森林中创建和推广的树的数量。很可能,我们创建的树越多越好,因为这将使我们能够对更多的数据集进行采样,并帮助我们更好地进行归纳。然而,会有这样一种情况,即以计算能力为代价,增加树的数量只会对我们的验证 RMSE 产生非常小的改变。

(2) min_samples_leaf :表示叶子节点中的样本数。每当我们将 min_sample_leaf 加倍时,我们就从树中删除了一层,并将叶节点的数量减半。因此,增加 min_samples_leaf 的结果是,我们的每个叶节点内将有多个样本,因此当我们计算该叶节点的平均值时,它将更加稳定,尽管我们将获得稍小的深度和较少的节点数。因此,尽管每棵树的预测性和相关性都不会降低,但我们的模型应该能够更好地概括并防止过度拟合。

(3) max_features :表示每次分割要考虑多少个特征。

为了优化和搜索最佳超参数,我们将使用随机网格搜索方法

n_estimators = [int(x) for x in np.arange(start = 10, stop = 2000, step = 10)]
max_features = [0.5,'auto', 'sqrt','log2']
min_samples_leaf = [1, 2, 4]
bootstrap = [True, False]
random_grid = {'n_estimators': n_estimators,
               'max_features': max_features,
               'min_samples_leaf': min_samples_leaf,
               'bootstrap': bootstrap}# First create the base model to tune
m = RandomForestRegressor()
# Fit the random search model
m_random = RandomizedSearchCV(estimator = m, param_distributions = random_grid, n_iter = 100, cv = 3, verbose=2, random_state=42, n_jobs = -1)
m_random.fit(X_train, y_train)
m_random.best_params_

从我们的随机网格搜索中,我们发现我们的随机森林模型的最佳超参数是上面那些。

第六步:最终模型

最后一步——构建我们的最终模型。为此,我们将放弃前面讨论过的年龄和比率特性。

图片来自 gurutzeunzalu.blogspot.com

我们已经获得了 2.847 的验证 RMSE 分数,这比我们原来的基础模型验证 RMSE 分数 3.021** 要好!**

另外,****最终验证 R 分0.87 ,这比基础款验证 R 分0.85 要好。R 分数告诉我们我们的模型能够在多大程度上解释数据集中的变化。得分为 0.87 表明我们的模型可以解释数据集中 87%的变化。

因此,我们看到简单的最终模型即使具有较少的输入特性也表现得更好!

额外的一步:部分独立

虽然我们已经创建了一个更好的模型,让我们后退一步,进一步探索我们的结果。

之前,我们观察到房价上涨中值(MDEV)和房间数量(RM) 之间存在线性关系。****

让我们试着做一个 ggplot。

from pdpbox import pdp
from plotnine import *
ggplot(df_raw_train, aes('RM', 'MEDV'))+stat_smooth(se=True, method='loess')

ggplot

基于上面的 gg 图,我们观察到 RM 和 MEDV 之间的关系是而不是我们所期望的。例如,人们通常会认为房价会随着房间数量的增加而上涨。然而,我们看到 4 房和 5 房之间的价格下降,同样 8 房和 9 房之间的价格下降。

这里的问题是我们正在查看单变量关系并且在单变量图中丢失的特征之间有许多相互作用。例如,为什么 5 间房的价格比 4 间房的价格低,而 6 间房的价格和 4 间房的价格差不多?

因此,要找到 RM 和 MEDV 之间的真实关系,我们需要做一个部分独立图(即假设所有其他特征相同,房子的价格如何随房间数量而变化)来查看真实关系。

def plot_pdp(feat,clusters=None,feat_name=None):
    feat_name = feat_name or feat
    p = pdp.pdp_isolate(m,X_train,feat)
    return pdp.pdp_plot(p,feat_name,plot_lines=True,cluster=clusters is not None,n_cluster_centers = clusters)
plot_pdp('RM')

PDP 图

从上面的部分依赖图(PDP)中注意到,在去除所有其他外部因素后,我们观察到 RM 和 MEDV 之间的关系几乎是一条直线(即大致线性),这正是我们所预期的。黄线代表所有交易的平均 MEDV。

现在我们来探讨 LSTAT 和 RM 是如何影响房价中位数的。

feats = ['LSTAT','RM']
p = pdp.pdp_interact(m,X_train,feats)
pdp.pdp_interact_plot(p,feats)

因此,查看 PDP 图,我们可以有把握地得出结论:房间数量(RM)线性影响中值房价(MEDV)。人口的状况反过来影响着 MEDV。

最后的想法和下一步

我们建立了一个随机森林模型,其验证 RMSE 分数为 3.021** 和验证 R 分数为 0.87 。**

我们还从我们的随机森林模型中确定了影响关键特征。波士顿的中值房价(MEDV)** 是 (1) LSAT :低人口状况的百分比 (2) RM :每所住宅的平均房间数 (3) NOX :氮氧化物浓度 (4) CRIM :城镇人均犯罪率。**

我们建造的最终模型远非完美。例如,观察我们最终模型中的培训 R 分数0.87验证 R 分数高出0.98。这表明最终模型能够解释训练数据中 98%的变化,而仅解释验证数据中 87%的变化(即最终模型仍然过度拟合训练数据,并且没有将** 以及推广到验证数据)。**

解决过度拟合的一个简单方法是尝试增加数据集的大小来训练我们的模型。目前,我们的数据集中只有 406 个条目,根本不够用

祝贺并感谢你坚持到最后。我真诚地希望你学到了新的东西!快乐学习!😬

用 R 预测房价

原文:https://towardsdatascience.com/predicting-housing-prices-with-r-c9ec0821328d?source=collection_archive---------17-----------------------

实践教程

使用 ARIMA 模型和 Case-Shiller 指数以及一些创造性的 R 程序,我们可以预测下一年的全国房价。这怎么可能呢?!让我们来了解一下!

照片由亚历克斯·瓦西Unsplash 上拍摄

目标

  1. 预测下一年美国房价
  2. 获得使用真实经济数据的经验
  3. 将数据可视化
  4. 理解数据的基本假设
  5. 了解使用 ARIMA 方法的预测建模

介绍

这个项目是为两种人设计的——对代码感兴趣的人和对房地产市场感兴趣的人。虽然这些概念将通过技术定义和代码示例来介绍,但要了解房价、预测模型或经济数据的周期性本质,并不需要理解代码。

对于那些只是阅读的人来说,尽量不要被代码所困扰。沿途寻找图像和情节,因为我会尽可能简单地用简单的英语解释正在发生的事情以及为什么这对我们很重要。

对于那些跟随代码的人来说,我假设您可以设法设置一个 R 环境。我的示例将使用 RStudio 在 Mac 上的 R Markdown 文件中本地运行,但任何其他本地或基于云的方法也应该工作得很好。

你可以从我的 GitHub 这里获得所有文件。

让我们投入进去吧!

获取数据

获取数据最简单的方法是从我的 GitHub 这里下载文件,或者去 FRED(美联储经济数据)为自己下载 S & P/Case-Shiller 20 个城市房价销售对计数(SPCS20RPSNSA) 数据[1]。如果你是从 FRED 那里下载的,就把它作为一个 CSV 文件来使用。

出于各种原因,我们在这个项目中使用了 20 个城市的变量,但主要是因为它没有经过季节性调整,并能很好地反映房地产市场每月的变化。

数据的原始来源来自标准普尔基于一个指数,该指数最初由耶鲁大学教授、2013 年诺贝尔经济学奖得主罗伯特·希勒[2][3]和卡尔·凯斯(Karl Case)共同开发,后者获得了哈佛大学经济学博士学位,并在韦尔斯利大学任教数十年[4]。看看最后参考文献中的链接,了解更多关于席勒博士和凯斯博士的信息。

代码

加载库

第一项任务是加载一些我们需要完成项目的库。为此,我们所需要的就是预测序列潮汐库。单击上一句中的名称可获得每个文档的链接!

代码如下:

# If these libraries are not installed on your machine, you can use the install.packages("name_of_package") command and library(name_of_package) to do the same thing as the require() function I am using below. I just like require because it is a single line of code :)# Import Libraries
require(forecast)
require(tseries)
require(tidyverse)

导入数据

接下来,我们需要导入数据。我使用的是直接从 FRED [1]下载的 CSV(逗号分隔值)文件。您还可以通过不同的方式阅读 Excel 格式,或者通过获得加分并从 FRED API 中提取来使用 Excel 格式。对于这个,它只有几千字节,所以本地 CSV 就可以了。确保数据与您的 R 或 R Markdown 文件在同一个目录下,以便使用 my code,或者如果数据在不同的位置,则从其确切的文件路径导入数据

MAC 用户注意:不要打开带数字的 CSV 文件。如果你这么做,r 将很难解码数据。下载的时候忍住双击的冲动。如果您这样做,您将需要删除该文件并下载一份新的副本,而不要在 Numbers 中打开它。

代码如下:

# Import Data
CaseShiller <- read.csv("SPCS20RPSNSA.csv")# Check data import
head(CaseShiller)

以下是输出结果:

凯斯席勒索引的前 6 行。数据由标准普尔和圣路易斯美联储银行提供(美联储经济数据)。参考文献中的引文[1]。

将数据转换为时序对象

为了做 ARIMA 模型(我们马上就要到了!),我们需要用 ts() 函数将原始数据转换成时间序列对象。通过一点数据争论,我们可以使列名更好一些,简化数据结构,并使我们的日期更容易配合。做这件事的方法不止一种,但这是我知道的最简单的方法。

代码如下:

# Change name of data column to Units
names(CaseShiller)[2] <- "Units"# Creates a Units Object as intermediate to transform into time series
CSUnits <- CaseShiller$Units# Creates Time Series Object that starts in January 2000 with a monthly frequency
tCaseShiller <- ts(CSUnits, start = c(2000, 1), frequency = 12)# Check Data Transformation
tCaseShiller

以下是输出结果:

为 Case-Shiller 索引创建的时序对象的表。数据由标准普尔和圣路易斯美联储银行提供(美联储经济数据)。参考文献中的引文[1]。

那么,为什么我们需要将数据转换成时间序列对象呢?这不是和我们开始的时候一样的数据吗?

嗯,是和不是。当创建 ARIMA(自回归综合移动平均),只有一个变量被使用[5]。ARIMA 模型使用真实值,然后将数据滞后一段时间以创建残差,残差是衡量现实和预期之间差异的值[5]。当处理这样的数据时,创建一个时间序列对象是让单变量数据与 R [5]合作的最佳方式。

ARIMA 模型是复杂的统计工作。他们有 pdq 值与之相关联[5]。通常会写成这样:ARIMA(p,d,q) [5]。

p 值处理模型的自回归部分,通常处理模型的线性部分如何与前面的点结合的顺序[5]。

d 值处理模型中出现差异的次数,这有助于使数据随着时间的推移更加稳定,不同的值以不同的方式影响输出[5]。

q 值处理模型的移动平均部分,通常处理误差如何以线性方式与模型交互[5]。

为 ARIMA 模型确定正确的 pdq 值是一门艺术和科学,我们需要检查一些自相关数并做一些实验,但我们在这里学习并将使用自动选择功能,如下一段代码所示[5]。

要记住的最后一个想法是,ARIMA 模型不喜欢方差很大的数据,所以需要做一些工作,这通常涉及到对数变换[5]。我们以后再担心那个,所以你会明白我的意思的。

ARIMA 模型创建

现在是有趣的部分!我们可以使用 R 中的 auto.arima() 函数来替我们完成这项艰巨的工作。

代码如下:

# Automatically create ARIMA model
fit <- auto.arima(tCaseShiller)
fit

以下是输出结果:

R 中 auto.arima()函数对时间序列 Case-Shiller 数据的结果

根据我的理解,当自动函数给出两组 pdq 值时,这意味着它们给出了相同的结果,这种情况确实会不时发生,取决于数据如何通过建模过程计算出来[5]。

我们可以再花一个小时来详细说明这里的每一点统计数据,但故事的重点是我们希望我们的模型少出错。为此,我们将重点关注 AIC(赤池的信息标准)值,并使其尽可能小。

模型精度

通过测量模型准确性,我们可以得到各种统计方法来衡量模型错误程度。

代码如下:

# Check Accuracy
accuracy(fit)

以下是输出结果:

时间序列 Case-Shiller 数据的第一个 auto.arima 拟合精度

如果你擅长统计学,你会认识这些术语。就我们的目的而言,大数值是不好的,小数值是好的。我们稍后将回到这些值。如果你不知道这些是什么意思,试着在谷歌上搜索“统计在这里插入缩写”来获得更完整的定义。

制作并绘制我们的第一个预测

通过创造性地使用 plot()forecast() 函数,我们可以用预测值绘制原始数据,预测值周围有 80%和 95%的误差阴影。我选择预测 12 个周期,因为我们有月度数据,我们可以真正看到该模型在一年的时间内是否有意义。

代码如下:

# Create a Simple Plot with a forecast for the next year
plot(forecast(fit, 12), xlab = "Date", ylab = "Units", main = "ARIMA Forecast for Case-Shiller Index")

以下是输出结果:

基于凯斯席勒指数 ARIMA 模型的历史值和预测值图。数据由标准普尔和圣路易斯美联储银行提供(美联储经济数据)。参考文献中的引文[1]。

如果您想查看带有置信区间的预测值表,请使用以下代码:

# Get table of forecasted values. Check back next year to see whether this was close!
pred_values <- forecast(fit, 12)
pred_values

这是表格的前 10 行:

凯斯席勒指数 R 中 ARIMA 模型的预测值和置信带数。

很神奇,对吧?!蓝线是下一年的预测值。较暗的阴影区域是 80%置信区间,较亮的阴影区域是 95%置信区间。

看起来很棒,但是这是什么话?如果我们打算用它来计算如何投资,我们真正能看到的是它上下波动,我们不知道价格会比往年更高、更低还是完全一样。这是一个好的开始。我们继续吧。

检查我们的假设

我们有一个模型,但我们如何知道我们甚至可以开始信任它?首先,我们需要检查数据是否正常(或者至少足够正常!)分布式[5]。其次,我们需要看看我们是否有任何有意义的自相关[5]。

为此,我们将使用 Q-Q 图来观察常态。简而言之,如果我们几乎所有的点都在这条线上或相对接近这条线,我们就有正常的数据[5]。对于 ARIMA 模型和一般的数据科学来说,正常的数据意味着我们的生活要容易得多。

对于自相关,我们将使用 Box-Ljung 检验。自相关对我们的目的是不利的。这意味着我们的数据本质上是一个逻辑同义反复,下一条数据有它的价值,因为前一条数据说那是它应该被估价的[5]。自相关有点像从 1 到 10 的整数序列,表示 2 跟随 1,3 跟随 2,4 跟随 3,等等。因为这就是模式。A 是 A,因为 A 是 A,我们不想用它来预测未来。这里没有帮助。

让我们来看看一个简单的方法来验证我们的假设是有根据的。

代码如下:

# Check assumptions of normality & Autocorrelation
qqnorm(fit$residuals)
qqline(fit$residuals)
Box.test(fit$residuals, type = "Ljung-Box")# Has high p-value, so autocorrelations not significantly different than 0
# There are a few possible outliers, but most of the data is pretty normally distributed

以下是输出结果:

我们第一个 ARIMA 模型的 Q-Q 图

我们的第一个 ARIMA 模型的 Box-Ljung 测试输出

这里的生活真好!我们的数据在 Q-Q 图上看起来很好,所以我们得出结论这是正常的[5]。对于 Box-Ljung 检验,我们有一个大的 p 值,表明我们的自相关与 0 没有显著差异[5]。如果这里的 p 值为 0.05 或更小,我们将至少 95%确定我们的数据不同于 0,这意味着自相关可能存在[5]。谢天谢地,这里一切正常!

时间序列数据的对数变换

目测数据,看起来我们的数据是季节性的。我们需要做一个季节分解来证实这是真的。然而,强烈建议使用对数转换数据[5]。所以让我们开始吧!

代码如下:

# Transform time series to log scale
ltCaseShiller <- log(tCaseShiller)# check it worked
head(ltCaseShiller)

以下是输出结果:

对数变换我们的时间序列数据的对数的 ARIMA 模型

季节性分解

做一个季节性分解可以去除每年的变化,从而发现数据是真的季节性的还是看起来像是季节性的[5]。我们可以看到去除所有噪声后的数据的季节变化和总体趋势[5]。让我们看看那个。

代码如下:

# Create new fit on log scale series for seasonal decomposition
fit2 <- stl(ltCaseShiller, s.window = "period")# Plot Seasonal Decomposition
plot(fit2, main = "Seasonal Decomposition of log(Case-Shiller Units)")

以下是输出结果:

凯斯席勒指数的季节性分解。数据由标准普尔和圣路易斯美联储银行提供(美联储经济数据)。参考文献中的引文[1]。

我们可以清楚地看到,这些数据始终具有很强的季节性,并且具有长期的涨跌趋势。

按年份的季节性绘图

让我们更仔细地看看这个问题,并在我们的数据集中绘制每年的指数。作为 tidyverse 的一部分,ggplot2 库可以通过使用 ggseasonplot() 函数来帮助使用。

代码如下:

# Create a Season Plot
ggseasonplot(tCaseShiller, year.labels = TRUE, col = rainbow(20))

以下是输出结果:

凯斯席勒指数的季节曲线图。数据由标准普尔和圣路易斯美联储银行提供(美联储经济数据)。参考文献中的引文[1]。

我们可以很清楚地看到,记录在案的每一年都遵循同样的模式。冬天价格低,夏天价格高。听起来差不多。

循环返回以比较模型

还记得我说过 ARIMA 模型喜欢波动性较小的数据吗?让我们看看当我们使用我们的日志转换数据时会发生什么。我们已经讨论了这些步骤,所以让我们用新数据快速地重复一遍这个过程,以比较结果。

创建新的 ARIMA 模式

自动创建我们的新 ARIMA 模型的代码与之前完全相同,除了我们将数据对象的名称改为 log 转换的名称。

代码如下:

# Automatically create ARIMA model
fit3 <- auto.arima(ltCaseShiller)
fit3

以下是输出结果:

使用对数转换数据的新 ARIMA 值

那么这里有什么不同呢?嗯,这次我们有不同的 pdq 值,以及非常不同的 AIC 值。未经对数变换的原始数据的 AIC 约为 4500。现在我们在-966。正负并不重要,所以我们唯一关心的是得到绝对值最小的 AIC 值[5]。这意味着我们基于对数转换数据的模型更适合[5]。

再次检查准确性

让我们再来看看准确度分数。原始精度在顶部,新精度在底部。请记住,较低的数字意味着模型错误较少。你注意到了什么?

代码如下:

# Check Accuracy
fitAccuracy <- data.frame(accuracy(fit))
fitAccuracy2 <- data.frame(accuracy(fit3))fitAccuracyFinal <- rbind(fitAccuracy, fitAccuracy2)
fitAccuracyFinal

以下是输出结果:

两种 ARIMA 模型的误差度量精度表

我注意到,当使用对数转换数据时,几乎每个误差的统计测量都至少比原始数据小一个数量级。这是一个好迹象!

绘制测井转换数据

就像之前一样,让我们看看一个基本的情节来形象化的预测。当然,y 轴是以对数为单位的,但是你也会有同样的想法。

代码如下:

# Create a Simple Plot with a logged forecast for the next year
plot(forecast(fit3, 12), xlab = "Date", ylab = "Units", main = "ARIMA Forecast for Case-Shiller Index")

以下是输出结果:

基于凯斯席勒指数 ARIMA 模型的历史和对数转换预测值图。数据由标准普尔和圣路易斯美联储银行提供(美联储经济数据)。参考文献中的引文[1]。

需要明确的是,这个模型中仍然存在大量的不确定性,但这里的要点是,它给了我们一组不同的值,可能更接近真实的中心趋势。

最终预测结果

为了轻松获得最终表格,我们可以将预测放入数据框中,使用 exp() 函数,通过将输出缩放回对数转换数据的正常值,然后将预测数字合并到带有适当标签的数据框中,从而消除对数值。

代码如下:

# Get table of forecasted values. Check back next year to see whether this was close!
# Original Data
pred_values <- data.frame(forecast(fit, 12))# Log transformed data
pred_values2 <- data.frame(forecast(fit3, 12))
pred_values2[,1:5] <- exp(pred_values2[,1:5])# Merge forecast predictions!
mergedDF <- data.frame(Date = rownames(pred_values), Original_Data_Forecast = pred_values$Point.Forecast, Log_Transformed_Data_Forecast = pred_values2$Point.Forecast, Difference = round(pred_values$Point.Forecast - pred_values2$Point.Forecast, 2))
mergedDF

以下是输出结果:

原始数据和对数转换数据预测的最终结果

对于最终的解释,模型通常是接近的。在接下来的几个月里,他们的预测更加接近 4-10 个月的时间范围。这是有道理的,因为不确定性源于多种原因。

结论

希望这篇文章有趣,有娱乐性,有教育意义。我认为使用真实数据用代码探索想法是学习和变得更好的好方法。这个项目和代码源自我的正规教育背景,是经济理念和编程的良好结合。我认为它也很好地强调了经济的某些部分既可以是周期性的,也可以是稳定的。

如果您有任何改进建议或未来要探索的主题,请联系我们。

参考

[1] S&P 道琼斯指数有限责任公司,S&P/凯斯席勒 20 个城市房价销售对计数[SPCS20RPSNSA],从圣路易斯美联储银行的弗雷德检索;https://fred.stlouisfed.org/series/SPCS20RPSNSA, 2020 年 10 月 15 日。

[2] R .席勒,在线数据罗伯特·席勒 (2018),【http://www.econ.yale.edu/~shiller/data.htm】T2

[3]罗伯特·J·希勒——传记。NobelPrize.org。诺贝尔媒体 AB 2020。周四。2020 年 10 月 15 日。https://www . nobel prize . org/prices/economic-sciences/2013/shiller/biographical/

[4]p·鲍尔、卡尔·凯斯|美国经济学家 (2020)、https://www.britannica.com/biography/Karl-Case

[5] R. Kabacoff, R 在行动(第二版。) (2015),纽约州谢尔特岛:曼宁出版公司

基于支持向量机的人力资源流失预测

原文:https://towardsdatascience.com/predicting-hr-attrition-using-support-vector-machines-d8b4e82d5351?source=collection_archive---------38-----------------------

学习按照最佳实践训练 SVM 模型

凯文·Ku 在 Unsplash 上的照片

继我之前的帖子之后,我将介绍我们如何在真实世界数据集上使用 python 和 Scikit-Learn 来应用支持向量机。这些数据取自最近由 IIT、古瓦哈蒂在 Kaggle 上举办的 InClass hackathon,作为他们夏季分析 2020 顶点项目的一部分,你可以从这里下载。

在这篇文章中,你会看到训练和调音 SVM 并让他们为你的问题陈述工作是多么容易。用这个我在黑客马拉松中排名第 29 位(前 4%),只做了很少的预处理和特征工程。

在我们继续之前,您必须对 SVM 的工作方式有一个直观的了解。我建议你仔细阅读我之前的文章,深入了解这个算法。

[## 解码支持向量机

直观理解支持向量机的工作原理

towardsdatascience.com](/decoding-support-vector-machines-5b81d2f7b76f)

现在假设你理解支持向量机背后的理论…

来源: imgflip

问题陈述

随着新冠肺炎不断释放它的浩劫,世界继续被推入大经济衰退的危机,越来越多的公司开始削减他们表现不佳的员工。公司解雇成百上千的员工是当今典型的头条新闻。裁员或降薪是一个艰难的决定。这一点需要非常小心,因为对表现不佳的员工的识别不准确可能会破坏员工的职业生涯和公司在市场上的声誉。

目的:根据给定的员工历史数据,预测员工流失情况。

导入所有必需的包

**import** **pandas** **as** **pd**
**import** **numpy** **as** **np**
**import** **matplotlib.pyplot** **as** **plt**
**from** **sklearn.model_selection** **import** StratifiedKFold
**from** **sklearn.compose** importmake_column_transformer
**from** **sklearn.ensemble** **import** RandomForestClassifier
**from** **sklearn.model_selection** **import** GridSearchCV,RandomizedSearchCV
**from** **sklearn.svm** **import**  SVC
**from** **sklearn.decomposition** **import** PCA
**from** **xgboost** **import** XGBClassifier
**from** **sklearn.model_selection** **import** cross_val_score
**from** **sklearn.preprocessing** **import** StandardScaler,RobustScaler
**from** **sklearn.preprocessing** **import** OneHotEncoder,LabelEncoder
**from** **sklearn.pipeline** **import** make_pipeline
pd.set_option('display.max_columns', 500)
pd.set_option('display.max_rows', 1000)

加载数据集

为了保存原始的培训数据,我制作了一份副本。

training = pd.read_csv('train.csv')
train_data = training.copy()
test_data = pd.read_csv('test.csv')

基础 EDA

train_data.info()

图 1

我们有 1628 个观察值和 29 个特征,其中 22 个是整数,7 个是对象。一些整数数据类型特征也可能是分类的。我们必须预测自然减员,它可以是 0 或 1(如果员工离开公司,则为 1)。

train_data.head()

图 2

让我们打印出一些变量的统计数据

图 3

这里要注意的奇怪的事情是行为的标准差为 0,均值=min=max = 1。这意味着对于所有的观察,该列的值都是 1,所以我们将删除它。我们还将删除 Id ,因为它对所有员工都有唯一的值。

train_id = train_data.Id
train_data = train_data.drop(['Behaviour','Id'],axis = 1)

test_id = test_data.Id
test_data = test_data.drop(['Behaviour','Id'],axis = 1)

进一步研究后,我发现特性 Pperformance rating只有两个值,3 或 4,所以我将它们分别映射到 0 和 1。

train_data['PerformanceRating'] = train_data['PerformanceRating'].apply(**lambda** x: 0 **if** x == 3 **else** 1)
test_data['PerformanceRating'] = test_data['PerformanceRating'].apply(**lambda** x: 0 **if** x == 3 **else** 1)

让我们检查我们的目标变量消耗的分布。

train_data[‘Attrition’].value_counts().plot(kind = ‘bar’)

图 4

我们的分布大致平衡。

检查重复项

print('Number of duplicates: ',train_data.duplicated().sum())

train_data[train_data.duplicated()]['Attrition'].value_counts().plot(kind = 'bar')

图 5

好了,数据有 628 个副本,所有副本都对应于损耗 1。这意味着数据被过采样以保持平衡。我们现在将删除重复的内容,并再次检查分布情况。

train_unq = train_data.drop_duplicates()
print('New train set: ',train_unq.shape)
X = train_unq.drop('Attrition',axis = 1)
y = train_unq['Attrition']
y.value_counts().plot(kind = 'bar')
plt.show()

图 6

现在我们的训练数据有 1000 个数据点,而目标变量是不平衡的。有许多方法可以处理不平衡的数据集,如使用 SMOTE 进行上采样或下采样。

我们还可以使用交叉验证策略,例如分层 k 折叠,它可以保持目标变量(此处为损耗)在折叠中的分布相似。使用分层抽样而不是随机抽样来分割训练和验证数据。这里的 stratas 是我们的目标变量的两个值。如果你不明白这意味着什么,那么不要担心,只要记住这是一个有效的方法来处理不平衡的数据集,而我们训练我们的模型。你可以在 scikit-learn 交叉验证用户指南中了解更多信息点击

预处理、培训和验证

我们现在将遵循以下步骤:

  • 降低性能等级(在探索中,我发现 85%的值属于一个类,这可能会导致过度拟合)
  • 一个热编码所有的“对象”数据类型特征
  • 对所有整数数据类型要素使用标准缩放。
  • 使用预处理的数据,并使用分层 K-Fold 对其进行分割。
  • 用 3 个候选模型进行拟合和验证:随机森林、XGBoost 和支持向量分类器

这是很多步骤。scikit-learn 允许我们使用管道列变压器用几行简单的代码完成所有这些工作。

所以,首先,我们为预处理做一个管道

categorical = [f **for** f **in** training.columns **if** training[f].dtype == object]
numeric = [f **for** f **in** X.columns **if** f **not** **in** categorical+['Id',','Behaviour','PerformanceRating']]

pre_pipe = make_column_transformer((OneHotEncoder(),categorical),(StandardScaler(),numeric))

变量分类存储对象数据类型特征的所有列名,而数字存储所有整数数据类型列。

现在,我们为模型定义管道,并打印出不同模型的交叉验证分数。使用 cross_val_score,我们可以将“skf”传递给“cv”参数,它将负责为我们进行拆分迭代和计算分数。由于数据不平衡,我使用“roc_auc”作为评分标准。为了更好地理解 cross_val_score 的参数,请查看其文档

# random forest pipeline
pipe_rf = make_pipeline(pre_pipe,RandomForestClassifier())
#xgboost pipeline
pipe_xgb = make_pipeline(pre_pipe,XGBClassifier()) 
# SVM pipeline
pipe_svc = make_pipeline(pre_pipe,SVC(probability=**True**))print(‘RF:‘,np.mean(cross_val_score(X=X,y=y,cv=skf,estimator=pipe_rf,scoring=’roc_auc’))) print(‘XGB:‘,np.mean(cross_val_score(X=X,y=y,cv=skf,estimator=pipe_xgb,scoring=’roc_auc’))) print(‘SVC:’,np.mean(cross_val_score(X=X,y=y,cv=skf,estimator=pipe_svc,scoring=’roc_auc’)))

图 7

显然,支持向量分类器比基于树的模型表现更好。移除更多功能和调整后,随机森林和 XGBoost 的性能可能会更好,但在本文中,我们将使用 SVM。

在一次热编码后,我们在数据集中总共有 46 个特征,随着维度的增加,有更多的机会过度拟合,也可能有不相关的特征。所以我决定用主成分分析来降低维数。

所以,首先我拿了 46 个组件,并在我们的管道中加入了 PCA。我已经看到了累积的解释差异。

n = 46
pipe_svc = make_pipeline(pre_pipe,PCA(n_components=n),SVC(probability=**True**,C = 1,kernel='rbf'))

plt.figure(figsize=(10,8))
pipe_svc.fit(X,y)
plt.plot(range(1,n+1),pipe_svc.named_steps['pca'].explained_variance_ratio_.cumsum())
plt.xticks(range(1,n+1,2))
plt.title('Explained Variance')

图 8

我们可以看到大约 34 个成分解释了 100%的方差。所以我们用了 34 个组件来适应我们的模型。

n = 34
pre_pipe = make_column_transformer((OneHotEncoder(),categorical),(StandardScaler(),numeric),remainder = 'passthrough')
pipe_svc = make_pipeline(pre_pipe,PCA(n_components=n),SVC(probability=True,C = 1,kernel='rbf'))
print('SVC: ',np.mean(cross_val_score(X=X,y=y,cv=skf,estimator=pipe_svc,scoring='roc_auc')))

我们的分数降低了 0.01,但我们已经大大降低了维度,现在这个模型在看不见的数据上表现更好的机会更大了。

超参数调谐

为了从模型中挤出所有的性能,现在是时候调整我们的 SVM 模型了。我们将为此使用 GridSearchCV,如果你不熟悉它,请看一下文档

我们可以调整的参数有:

  • c:这是正则化参数
  • 核:线性、多项式或 RBF(高斯)
  • Gamma:相当于高斯核中的方差项
  • 类别权重:平衡目标变量中类别的权重(权重与类别频率成反比)

还有更多参数,但这些是影响性能的重要参数,在进一步讨论之前,请查看 scikit-learn 文档

对于管道,调整也是一个非常简单的过程,我们只需定义参数网格,然后将整个管道传递到网格搜索中。我没有在这里调优内核。因为“rbf”是最常用的内核,并且适用于大多数任务,所以我只使用它来节省一些计算时间。您也可以继续尝试调优内核。

param_grid = {

    'svc__C':[0.001,0.01,0.1,1,10,100,1000],
    'svc__gamma': ['auto','scale'],
    'svc__class_weight': ['balanced',**None**]
}

grid_search = GridSearchCV(pipe_svc,param_grid=param_grid,cv = skf, verbose=2, n_jobs = -1,scoring='roc_auc')
grid_search.fit(X,y)
print('Best score ',grid_search.best_score_)
print('Best parameters ',grid_search.best_params_)
best_svc = grid_search.best_estimator_

图 9

您可能已经注意到,我在参数网格中的所有参数前面添加了“svc__ ”,这样做只是为了指定我们在网格搜索中调整管道的哪个步骤,因为我们不只是将一个估计器传递给 GridSearchCV,而是传递给整个管道。我相信可能有更好的方法来做到这一点,如果你知道更好的技术,请在评论中告诉我。

我们可以尝试进一步调整我们的模型,通过调整 C 的范围和固定其他超参数的值来找到最佳的 C,就像这样

pipe_svc = make_pipeline(pre_pipe,PCA(n_components=n),SVC(probability=**True**,C = 1,kernel='rbf',class_weight=**None**,gamma='auto'))
param_grid={
    'svc__C':[0.01,0.03,0.05,0.07,0.1,0.3,0.5,0.7,1]  
}
grid_search = GridSearchCV(pipe_svc,param_grid=param_grid,cv = skf, verbose=2, n_jobs = -1,scoring = 'roc_auc')
grid_search.fit(X,y)
print('Best score ',grid_search.best_score_)
print('Best parameters ',grid_search.best_params_)
best_svc = grid_search.best_estimator_

图 10

最终的平均验证分数现在是 0.8319。是时候向 Kaggle 提交了。

best_svc.predict_proba(test_data)[:,1]
submission = pd.DataFrame(prediction,columns=['Attrition'])submission['Id'] = test['Id']
submission = submission[['Id','Attrition']]
submission.to_csv('submissionfile_SVC.csv',index = None)

瞧啊。

图 11

正如你所看到的,我的排名下降了 4 位。发生这种情况是因为我的模型过度适应训练数据,我可能不应该太疯狂地调整“C”。更好的特征选择也可能有助于提高分数。你怎么想呢?请随意查看我的 Kaggle 笔记本并执行代码。

如果你坚持到最后,谢谢你。我希望你觉得这篇文章有用,并从中学习到新的东西。请在评论中提供宝贵的反馈,我很想知道你对提高性能的想法。

使用监督机器学习预测 IMDb 电影评级

原文:https://towardsdatascience.com/predicting-imdb-movie-ratings-using-supervised-machine-learning-f3b126ab2ddb?source=collection_archive---------13-----------------------

照片由佩克斯的达莉亚·谢夫索娃拍摄

我叫 Joe Cowell,我最近参加了 Metis 数据科学训练营。为期 12 周的沉浸式项目将把我从“数据新手”变成一名成熟的数据科学家。我的意思是,这个帖子的标题包括“有监督的机器学习”,而我只参加了这个项目三周,所以看起来 Metis 正在履行他们的承诺。无论如何,我会试着为感兴趣的人写一篇关于我是谁的帖子,但现在,让我们看看我是如何使用监督机器学习来预测 IMDb 电影评级的。

背景:

在我的音乐生涯中,问题总是“这首歌有多好?”也从来没有“这首歌会赚多少钱?”也许这就是为什么我们是典型的饥饿艺术家…不管怎样,我把这个概念应用到电影中。这个想法是,电影行业的艺术家可以利用这个模型来预测观众对电影的接受程度,因此,专注于 IMDb 评级作为目标,而不是 Metacritic 的评级系统或烂番茄的 Tomatometer。

总体而言,该项目探索了数据科学家所需的几项关键技能:

  • 网络抓取(请求、HTML、美汤)
  • EDA(熊猫,numpy)
  • 线性回归(scikit-learn)
  • 数据可视化(seaborn,matplotlib)

第一步:数据采集&清洗🔍

简单地说,IMDb 有一个 API 可以下载大量数据,但是这个项目的主要需求是通过 web 抓取获得数据;因此,我继续使用请求和漂亮的汤从 IMDb 获得信息。Requests 是获取网页并将其转换为 python 中的对象所需的模块。Beautiful Soup 采用了该对象,即网页背后的 HTML 信息,并使搜索和访问 HTML 文本中的特定信息变得容易。你真的需要这两者来完全完成网页抓取的过程。

在 IMDb 的页面上,我使用了高级搜索功能来搜索 2000 年到 2020 年间的书籍。结果跨越了数千页,每一页都有 100 部电影的标题和链接。经过进一步检查,我注意到该 URL 包含短语:' start=1 '。将起始数字增加 100 将会翻页。通过一个助手函数,我使用请求和漂亮的 Soup 来获取每个页面的链接,并返回这些链接的列表。

为了利用电影超链接列表,我创建了另一个函数来从每个页面提取尽可能多的数据。该函数接收一个链接并返回一个包含以下信息的字典:标题、IMDb 评分、IMDb 评分者的数量、美国电影协会评分、类型、导演、作者、前三名明星、发行的初始国家、发行的原始语言、发行日期、预算、美国首映周末、美国总票房、全球累计总票房、制作公司和运行时间。

作为 EDA 的一部分,必须清理一些数据。这包括将字符串中的任何数值转换成整数。运行时间必须转换成分钟,所有的货币值都需要去掉逗号和美元符号,发布日期必须转换成日期时间。此外,包含列表的类别需要从字符串转换成实际的 python 列表(流派、导演、明星、制作公司)。检索函数完成了大部分清理工作,但是在将数据放入数据帧之后,还需要做一些其他的清理工作。

一个数据帧中有 2000 多部电影,我需要做更多的处理来获得一个用于建模的功能性数据帧。这意味着放弃没有预算信息的电影,预算低于 1000 美元的电影,以及评分低于 1500 美元的电影。关于最后一个要求,评级者数量少的电影被证明报告了更极端的电影评级(电影倾向于完美的 10 或一个大鹅蛋)。总而言之,我最终得到了一个包含 1100 多部电影的数据框架。现在是时候开始建模了。

在进入下一部分之前,我想提一下 Pairplots。Pairplots 是一个很好的可视化工具,用于探索数据中的关系,并告知 MVP 从哪里开始。看起来信息量很大,但是当您以第一列或最后一列为目标来格式化数据帧时,解释所有这些信息会容易得多。对于此配对图,第一列中的图显示了自变量和目标之间的关系。虽然我没有使用大部分数值数据,但很明显存在线性和指数关系,这可以很容易地告知从哪里开始建模。

sns.pairplot(movies_df_drop, height=1.2, aspect=1.25)

(图片由作者提供)

第二步:模型和特征📈

值得注意的是,这个项目的另一个要求是使用线性回归,所以我试验的模型是线性回归和岭回归。有了这么多可用的特性,而且这是我第一次使用 python 进行回归,我花了一些时间来整理每个特性。

首先,我决定走一条简单的路线,以运行时间为唯一特征,以 IMDb 评级为目标,进行简单的线性回归。这导致 R 值为 0.2687。老实说,我对任何大于零的数字都相当兴奋,所以我已经准备好钻研其余的数据了。

对于美国电影协会评分和流派,我创建了虚拟变量添加到数据框架中,得到的 R 为 0.3997。至于导演、编剧、明星和制作公司,我在每个类别中创建了一个最常出现的玩家列表,并为顶级竞争者创建了虚拟变量。如果一个导演只在我的数据中出现过一次,那么这个导演的权重(或系数)将是该特定电影评级的直接结果,因此让玩家拥有多行数据将为模型提供更多信息,以创建更好的知情系数。

为了更有创意,我选择了发布日期,制作了一个“发布月”专题。同样,我采用了上映日期,并创建了另一个功能来确定电影上映以来的年份。这可能不是最相关的特性,但是我很高兴能够试验日期时间信息。

将特征加载到模型中后,得到的 R 值为 0.4751,这看起来很有希望,但下一步是通过交叉验证对模型进行严格测试。

第三步:测试和培训/结果🎥

虽然线性回归完成了工作,但我知道我想比较模型的系数,使用岭回归是一种迫使自己缩放输入并尝试不同方法来创建模型的好方法。

对于这一部分,我建议查看一下项目库,以了解训练和测试模型背后的过程,但是我将直接跳到最终的模型和结果。

(图片由作者提供)

最终模型的 R 为 0.432,平均绝对误差为 0.64。这是一个相当低的 R,但是这篇文章描述了为什么预测人类行为的 R 低于 0.5 是可以预期的。此外,预测评级与实际评级左侧的图表为模型提供了更多的信心,因为两者之间存在某种线性关系。此外,残差最高的电影要么收视率低,要么是像猫、五十度灰、表情电影这样的电影。这些特定的电影背后有很好的统计数据,但公众并没有很好地接受它们,这是一个很难纳入这个模型的指标。

(图片由作者提供)

查看与每个特征相关的系数也很重要。如左图所示,运行时间、发行后的年数和预算都是模型中的重要角色,一些类型和作者也在上面。这就是岭回归的美妙之处:能够使用系数来确定特定特征的权重。

最终,我有了一个预测 IMDb 评级的模型,其 R 为 0.432,明显优于仅用平均值进行预测,MSE 为 0.64,这意味着预测可能在两个方向上都有 0.64 个点的误差。

总结:📘

这不仅是我第一次在网上搜集数据,也是我第一次创建模型,更不用说线性回归模型了。总的来说,我对这种模式相当自豪。此外,单独遍历数据科学工作流的体验非常有益;我:

  • 通过在网上搜集信息,我创建了自己的数据集
  • 浏览数据集并清理掉所有不相关的内容
  • 开发了一个 MVP,在任何给定的时刻都有一个工作模型
  • 迭代地改进模型,以获得具有每个特性的更好的产品
  • 可视化我的模型的有效性以及对电影评级的贡献

在训练营的三周内,我就熟悉了网页抓取、EDA、线性回归建模和数据可视化。再一次,对于我的过程的更多代码的解释,检查我的 GitHub 库,如果你有任何问题或意见,请随时联系我。

我真的很期待在 Metis 学习更多的技术和技能,所以如果你对我的数据科学之旅感兴趣,请回来查看更新。

随意伸手:
LinkedIn|Twitter

用图卷积神经网络预测首次公开发行股票

原文:https://towardsdatascience.com/predicting-initial-public-offerings-using-graph-convolutional-neural-networks-42df5ce16006?source=collection_archive---------48-----------------------

从数据库到预测

大约一年前,我了解了图形数据库的概念,以及它们与表格、关系数据库相比,如何不同地表示数据。我很感兴趣的是,有一种存储和查找数据关系的方法,我发现这种方法比在表格数据上计算连接更直观。如果两条数据是相关的,在图形数据库中,您只需在它们之间创建一条边。由于数据在图中,您可以在数据库上执行所有标准的图算法,例如广度和深度优先搜索、最短路径算法和相似性算法。所有这些算法都处理不同数据点之间的边缘(关系)。事实证明,有机器学习算法也可以处理数据之间的关系。本文将详细介绍建立和运行您自己的图形机器学习管道的步骤——从数据库到预测。

照片由里克在 Unsplash 上敲击

首先,我们将使用来自 Crunchbase 的示例数据集建立一个 TigerGraph 云实例。该数据包含大约 200,000 家处于不同融资阶段的公司,并包含诸如它们是否实现了首次公开募股(IPO)、公司的主要投资者、创始人及其总部所在地等信息。然后,我们将使用 Jupyter 笔记本中的 pyTigerGraph 和 Giraffle 连接到数据库。最后,我们将建立一个图形卷积神经网络(GCN)来预测我们数据集中的某个公司是否会 IPO。要了解代码,请点击这里的库。

设置 TigerGraph 云

我不打算深入介绍如何设置 TigerGraph 云实例,因为这篇文章很好地指导了您配置实例的步骤。在步骤 1 中,只需选择“企业知识图(Crunchbase)”初学者工具包。一旦你启动并运行了你的初学者工具包,我们将不得不通过 Gradle 获得一个 SSL 证书来访问服务器。在您的项目目录中,在您的终端中键入以下内容:

openssl s_client -connect <YOUR_HOSTNAME_HERE>.i.tgcloud.io:14240 < /dev/null 2> /dev/null | \
openssl x509 -text > cert.txt

我们还需要创建另外两个文件。首先,让我们在基础项目目录中创建一个grad le-local . properties文件。这应包括:

gsqlHost=YOUR_HOSTNAME_HERE.i.tgcloud.iogsqlUserName=tigergraphgsqlPassword=YOUR_PASSWORD_HEREgsqlAdminUserName=tigergraphgsqlAdminPassword=YOUR_PASSWORD_HEREgsqlCaCert=./cert.txt

另一个应该放在 py_scripts/目录中,命名为 cfg.py 。这应包括:

secret = "YOUR_SECRET_HERE"token = “”password = “YOUR_PASSWORD_HERE”

秘钥可以在 Graph Studio 的管理页面下获得。

安装查询和提取数据

我们将使用两种不同的工具与 TigerGraph 云实例进行交互:Giraffle 和 pyTigerGraph。Giraffle 将允许我们安装需要在数据库上运行的查询,而 pyTigerGraph 将为我们提供一个接口,将这些查询的结果拉入 Python。

长颈鹿

Giraffle 是 Gradle 的一个插件,一个构建系统。这允许您轻松地将代码打包以部署在各种不同的平台上,并使用版本控制软件(如 Git)来跟踪您为数据库编写的查询。更多信息,请查看其项目页面这里

这些疑问

我们通过几个终端命令将查询安装在 Jupyter 笔记本的前几个单元格中。每个查询的功能概述如下:

  • companyLinks 在 TigerGraph 中计算公司之间的关系,并将其返回到一个 JSON 有效负载中,我们可以用 Python 解析该负载。这过度简化了这里的图表。该查询返回有共同点的公司对。这损害了准确性,因为一些常见的元素(创始人、投资者等。)可能比位置或行业更重要。创建具有多种类型顶点的 GCN 是可能的,(称为关系图卷积笔记本),但它更复杂。开始的一个好方法是简化图表,直到你只有相同类型事物之间的关系。
  • getAllCompanies 顾名思义,它返回数据集中所有公司的列表。我们需要它的原因将在下一节中变得明显。
  • getAllIpo 获取数据集中所有已经上市的公司。这在下一节很有用,也可以用来检查我们预测的准确性。

pyTigerGraph

为了从我们安装的查询中获得结果,我们将使用 pyTigerGraph。要了解更多信息,请点击这里查看我的 GitHub 上的包。

欠采样数据

好了,现在我们已经安装了所有的查询,并将数据放入笔记本,请注意一些事情。首先,与公司总数(约 200,000 家)相比,IPO 公司的数量微不足道(约 1,200 家)。这意味着数据集非常不平衡,这将导致 GCN 预测每家公司不会 IPO(这样它的准确率将达到 99.4%)。另一件需要考虑的事情是,大多数计算机没有足够的内存来运行全图上的 GCN。便利的是,不平衡的数据意味着我们应该对未上市公司进行欠采样,以便得到一个更加平衡的数据集。这就产生了一个大约有 2000 个顶点的图,平均分布在已经上市和没有上市的公司之间。然而,这种方法有一个缺点。由于这些公司是从非 ipod 和 ipod 名单中随机抽样的,我们不能保证每个公司之间有很多边缘,这对我们的准确性有很大影响。

图形卷积神经网络

使用图卷积神经网络进行分类(来源:https://docs.dgl.ai/en/latest/tutorials/basics/1_first.html

图形卷积神经网络(GCN)是一种半监督分类算法,它处理图形中的连接以及每个顶点的特征。这个概念类似于传统的基于图像的卷积神经网络,但 GCN 不是查看相邻的像素,而是查看通过边连接的顶点。顶点特征可以是任何向量,比如顶点的各种属性的 doc2vec 表示,或者仅仅是一个一键编码的向量,这就是我在这里选择做的。然后我们标记两个不同的顶点,一个已知有 IPOed,另一个没有。

我们的神经网络架构非常简单。它由两层组成,输入维数等于特征向量中的条目数(它也恰好是图中的顶点数,因为我们对它们进行了一次性编码)。然后,我们将输入通过一个有 32 个神经元的层,然后通过 2 个神经元输出。我们使用 Adam 作为训练过程的优化器。然后我们开始训练循环。不幸的是,由于我们之前对图表的采样不足,GCN 在图表中并不总是有足够的边来准确可靠地做出预测。我通常得到大约 60%的准确率,但由于公司的随机抽样,它确实变化很大。

结论

GCN 并不是一个预测一家公司是否 IPO 的好方法,因为内存限制和对图表的欠采样。其他图形机器学习方法,如 node2vec 可能会更好。另一种可能提高精确度的方法是使用关系图卷积神经网络(R-GCN ),它可以处理具有多种不同类型顶点的图。

信用

Parker Erickson 写的文章和笔记本,他是明尼苏达大学攻读计算机科学学士学位的学生。他的兴趣包括图形数据库、机器学习、旅行、演奏萨克斯管和观看明尼苏达双城棒球赛。随意伸手!在以下地址找到他:

GCN 资源:

笔记本改编自:https://docs.dgl.ai/en/latest/tutorials/basics/1_first.html

使用 Python +大数据预测住院患者的住院时间

原文:https://towardsdatascience.com/predicting-inpatient-length-of-stay-at-hospitals-using-python-big-data-304e79d8c008?source=collection_archive---------18-----------------------

医疗保健中的机器学习

从原始数据集检索到机器学习建模的端到端项目

来自纽约邮报文章的纽约医院病人的照片(图片来自 Shutterstock)

背景:

病人住院时间是医院管理效率的一个关键指标。医院资源有限,需要有效利用床位和临床医生的时间。随着最近新冠肺炎疫情的出现,这一概念得到了体现。现在,我们比以往任何时候都更能看到,将住院时间限制在不必要的时间内,并了解特定住院患者可能需要住院多长时间,符合患者、医院和公共卫生的最佳利益。

因此,只有在患者一进入医院并被诊断出就可以获得信息的情况下,预测患者将停留多长时间的能力可以对医院及其效率产生许多积极的影响。可以预测患者住院时间的模型可以让医院更好地分析对住院时间影响最大的因素。这种分析可以为缩短住院时间铺平道路,从而降低感染风险和药物副作用,提高治疗质量,并通过更有效的床位管理增加医院利润。此外,预测患者的住院时间也极大地有利于患者和患者家属,因为他们可以知道他们在入院时预计会住院多长时间。该项目的目标是创建一个模型,用于预测患者入院后的住院时间,此处详细介绍了完成此任务的步骤。

在整个分析中使用的全部代码可以在这里找到。

数据集介绍:

为了进行这一分析,我使用了公开的“2015 年纽约医院住院病人出院”数据集,该数据集可在纽约州政府健康数据网站上找到。该数据集包含 230 多万行患者数据,包括患者人口统计、诊断、治疗、服务、成本和收费等信息。根据 HIPAA 法规,患者数据已被取消身份。为了分析这种规模的数据集,我利用了 Python 接口中的各种大数据分析工具,如 Spark、AWS clusters、SQL 查询优化和降维技术。然而,本文中显示的大部分代码使用了 Pandas 和 scikit learn。让我们先来看看数据集中的所有要素和相关数据类型。

接下来,让我们看看我们的数字特征是如何相互关联的。我们可以通过使用关联热图来实现这一点。

从我们数据的关联图中可以看出,有几个特征相互之间有很强的相关性,也许更重要的是,与住院时间有很强的相关性。尽管查看我们所有的列(如许可证号)的相关性矩阵没有意义,但我们可以从中看出,APR 疾病严重程度代码与住院时间、总费用和总成本有很强的正相关性。CCS 诊断代码似乎也与住院时间略有正相关。我们可以在数据集中看到特征之间的其他正相关,例如 CCS 诊断代码和 APR DRG 代码。除了让我们知道数据中是否存在多重共线性之外,该图还让我们了解了哪些功能对于预测住院时间可能特别重要。

探索性数据分析与可视化:

接下来,让我们探索并可视化数据中的潜在关系。在下面的分析中,住院时间作为我创建的图的 y 轴上的主要变量,因为它是这个项目的预测变量。首先,住院时间的单变量分布是可视化的。

正如我们所看到的,停留时间值的范围从 1 天到 120 天以上(120 天已经被合计为包括所有停留 120 天或更长时间的时间)。此外,分布非常不均匀,数据中大多数患者的住院时间在 1 到 5 天之间。这是需要记住的数据的一个重要方面。我们暂时先把它放在这里,以后再来看。接下来,我们来看看不同年龄组的住院时间分布是如何变化的。

住院时间长短会随着患者年龄的变化而变化吗?

由于存在许多异常值,y 轴被限制在 0 到 30 之间。

从该图中,随着年龄组的增加,平均住院时间分布变长的趋势显而易见。

哪些诊断的平均住院时间最长?

平均而言,被诊断患有分娩并发症的患者平均住院时间最长,其次是患有呼吸系统疾病的患者。让我们来看看一些我们可能不认为会有太大影响的特性是如何随着停留时间的变化而变化的。

停留时间长短会因种族而异吗?

我们可以看到,正如人们可能会怀疑的那样,病人的种族不会导致住院时间分布的很大差异。然而,有趣的是,黑人/非洲裔美国人与分布第二大的群体(白人)在住院时间值上的差距最大,相差约 2 天。

住院时间长短如何因患者付费类型而异?

从该图中可以明显看出,不同的医疗保险支付方式往往具有不同的住院时间分布。具体来说,我们可以看到,例如,医疗保险患者往往平均住院时间最长。然而,健康保险计划与其他因素密切相关,如收入和年龄。因此,这可能是因为医疗保险患者往往有更长的住院时间,因为他们也在一个较大的年龄段。让我们更深入地探讨这个想法:

以医疗保险为主要支付方式的患者年龄分布如何?

这一想法得到了上述图表的支持,并让我们了解了不同变量是如何相互作用来影响停留时间的。

让我们继续讨论数据集中存在的一些最重要的特征:疾病的严重程度和入院病人的类型。

住院时间长短因病情严重程度而异?

我们可以看到 APR 疾病严重程度特征中的大量差异,这表明它很可能是包含在机器学习(ML)模型中的一个重要特征。

住院时间长短如何因入院类型而异?

每种疾病严重程度类型的诊断描述有何不同?

在这里,我对数据集的诊断描述列执行文本解析分析,然后创建 wordclouds 来可视化这些结果。使用根据疾病严重程度分类的每个患者的诊断描述创建了词云。

使用了 NLTK tokenizer 包,随后移除了停用词(a、and、the 等。)来自 wordcloud 创建之前的描述。

从该分析中,我们可以看到每种疾病严重程度类型的诊断描述中的一些相似之处,但也有一些巨大差异。

网页抓取附加功能

在上面关于健康保险项目的简短讨论中,我也提到了患者收入可能会起到一定作用,并且最终可能与住院时间长短相关。这种情况的一个例子是,对于一些低收入病人来说,医院提供的生活条件比他们在医院外的情况要好。因此,这些患者被激励尽一切努力延长他们的住院时间。不幸的是,我们的数据集不包括任何关于患者收入的信息。但是,它包括患者的 3 位数邮政编码。当我们准备开始这个项目的建模部分时,重要的是要考虑这样一个事实,即对于大多数 ML 模型来说,zipcode 并不是一个好的特性。虽然它的信息是用数字编码的,但它不是一个数字特征,因为它的数字在数学上没有任何意义。反过来,这使得邮政编码很难理解,也很难通过 ML 模型创建预测模式。因此,在我的分析中,下一步将是用患者收入的粗略衡量标准来取代这种原始的 3 位数邮政编码数据,这将证明是一个更有用的功能。

为了做到这一点,我通过邮政编码从这个网站收集了平均收入数据,包含了 2006-2010 年的数据。下面是数据集中每个 3 位数邮政编码的中值收入图,是通过内部连接(通过 python 中的 SQL)将网络抓取的数据连接到我们的数据框架上实现的。

y 轴上的收入以美元为单位。请注意,邮政编码 999 是那些不在本州的患者的聚合邮政编码(详见博客开头的完整编码链接)。

我们可以使用这个新的收入特征来可视化其他特征如何随着新构造的特征而变化。

我们现在准备开始准备这个分析的建模部分。

建模准备:

为了开始这一部分,我首先将删除所有对预测建模没有用的列。这包括邮政编码、诊断描述、操作证书编号等。,此外还有患者入院时不会出现的特征,如总费用和总收费,从而防止数据泄露

接下来,我对包含字符串的所有分类列执行特征编码。使用具有相应数字代码的类别,如 APR 疾病严重程度代码与 APR 疾病严重程度描述,而不是它们的字符串对应物,以防止类别二进制化的需要,从而防止维度的潜在大幅增加。

此外,我将对特性的特定子集使用字符串索引。对于年龄组和 APR 死亡风险,由于这些特征中的类别存在固有的顺序性,所以进行了串索引。例如,“0 至 17 岁”年龄组比“70 岁或以上”年龄组更小。因此,用 1 对最小的年龄组“0 到 17”进行编码,用越来越大的整数对较大的年龄组进行编码是有意义的。类似地,APR 死亡风险的“轻微”类别为 1,而“极端”为 4。对这类特定要素进行字符串索引非常有益,因为它可以防止增加数据集的维度,并允许模型了解要素类别中存在的普通性。手动完成此操作的代码如下所示。但是,对不具有固有顺序性的要素(如“医疗服务区”)使用字符串索引时,一定要小心。因此,执行剩余分类特征的一键编码。

mort_string_index = {'Minor': 1, 'Moderate': 2, 'Major': 3, 'Extreme': 4}
age_string_index = {'0 to 17': 1, '18 to 29': 2, '30 to 49': 3, '50 to 69': 4, '70 or Older': 5}df['Age Group'] = df['Age Group'].apply(lambda x: age_string_index[x])
df['APR Risk of Mortality'] = df['APR Risk of Mortality'].apply(lambda x: mort_string_index[x])

现在,让我们来看看我们的预测功能,住院时间。停留时间的范围从 1 到 120,并且只接受整数值。我决定将预测停留时间视为一个多类分类问题(而不是回归)。与我使用的回归相比,多类分类产生了一个很大的优势:手动定义类仓来手动控制预测特异性的能力。我们可以将这些值分组到对预测更有意义的箱中,而不是将停留时间视为 120 个不同的类别,而不会显著降低预测的特异性。在探索了这些条柱的多种选择后,其中包括权衡模型的有用性(如果条柱太大,预测将不再有用)和模型准确性,我最终确定了以下条柱格式:

1–5 天、6–10 天、11–20 天、21–30 天、31–50 天和 50–120 天以上

从这个图像来看,一个巨大的阶级不平衡是显而易见的。在回顾在本分析开始时绘制的原始住院时间数据的单变量分布时,同样的趋势是明显的。数据中的这种不平衡必须小心处理,因为它会导致误导性的准确性分数。类别不平衡会导致模型过度预测最常出现的类别,因为简单地预测大多数数据实例的类别,而不考虑它们的特征,将会导致最高的整体准确度分数。因此,旨在优化准确度分数的模型可能落入这个陷阱。例如,即使该模型总是预测住院患者的住院时间为 1 至 5 天(在该数据集中最常见的住院时间),它也会达到约 1.6e6/2.3e6 = 69%的准确度。与模型的基线精度(如果随机猜测,模型将达到的精度)相比,它是 1/6 或大约 17%,乍一看,这是明显更好的模型性能。

处理阶层失衡

对最频繁出现的类进行欠采样和对过度预测的类进行惩罚是处理类不平衡的两种最常见的方法,这两种方法都在该数据集上进行了探索。最终,我发现分配惩罚是最有效的方法,它比欠采样方法具有更高的模型精度,同时还能像欠采样一样防止与类别不平衡相关的风险。为了将这些惩罚分配给类,我使用了 scikit learn 的 ML 函数中的“类权重”参数,并将该参数设置为“平衡”。这有效地给每个类分配了一个与它出现的频率成反比的权重。

ML 造型

主成分分析:

在训练任何模型之前,我在使用 StandardScaler()函数标准化训练和测试数据集之后对数据执行 PCA。主成分分析是一种强大的工具,它允许人们降低数据集的维数,这对大型数据集非常有益,例如我们在这里处理的数据集。此外,它还消除了数据中的任何多重共线性。尽管 PCA 不适合用于混合了数字和分类特征的数据集(已经进行了一键编码/字符串索引),但使用 PCA 并不会对性能造成显著影响(更多信息请参见此处关于何时使用 PCA 与 MFA)。在应用 PCA 之前,务必对数据进行归一化处理,因为 PCA 会将原始数据投影到通过计算要素内点之间的相对距离来最大化方差的方向上。因此,当特征在不同的尺度上时,可以抛弃 PCA。

import numpy as np
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScalerx_train = StandardScaler().fit_transform(X_train)
x_test = StandardScaler().fit_transform(X_test)
pca1 = PCA()
pca1.fit(x_train)
explained_variance_ratio = pca1.explained_variance_ratio_
pc_vs_variance = np.cumsum(pca1.explained_variance_ratio_)

下面,我绘制了相对于使用的 PCA 成分数量的%解释方差。从这个图中,我们可以决定在剩下的分析中使用多少个成分,以便在数据中保留一定百分比的解释方差。这里,我选择保留 29 个组件,因为这是解释数据中 95%的方差所需的最少组件数。

逻辑回归:

接下来,让我们训练一个一对多逻辑回归分类器。逻辑回归分类器是分类问题的强模型。让我们在将 PCA 应用于标准化数据后训练一个模型,如下所示。

pca = PCA(n_components=29) #29 components, as found above
x_train = pca.fit_transform(x_train)
x_test = pca.transform(x_test)from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
import numpy as nplog_reg = LogisticRegression(multi_class='ovr').fit(x_train, y_train)
y_train_pred = log_reg.predict(x_train)
y_pred = log_reg.predict(x_test)test_acc = accuracy_score(y_test, y_pred)
train_acc = accuracy_score(y_train, y_train_pred)print('Test accuracy:', test_acc)
print('Train accuracy:', train_acc)

列车精度:0.7315117403879348
测试精度:0.20000001

鉴于该数据集的基线准确性和性质,我们得到了非常好的结果。然而,这个模型是在没有平衡任何类别权重的情况下对数据进行训练的。在进行预测后创建混淆矩阵是一个很好的做法,这样可以更仔细地检查模型性能,因为仅准确性分数就可能会产生误导。

标签是根据每个箱子中较长的停留时间值创建的。例如,标签 5 对应于 bin (0,5),或者停留时间范围从 1 天到 5 天。

混淆矩阵展示了忽视数据集中的类别不平衡的危险。虽然我们获得了非常高的准确度分数,但是该模型明显过度预测了预测标签 5,因为它是具有最高频率的标签。另一方面,该模型从不预测标签 30 和 50。这两种趋势在热图中第一列的较暗颜色中都很明显,与 30 和 50 列中的最亮颜色形成对比(也用 0 表示)。现在,让我们看看我们是否能处理这个问题。

平衡类权重参数的 Logistic 回归:

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
import numpy as nplog_reg = LogisticRegression(class_weight='balanced', multi_class='ovr').fit(x_train, y_train)
y_train_pred = log_reg.predict(x_train)
y_pred = log_reg.predict(x_test)test_acc = accuracy_score(y_test, y_pred)
train_acc = accuracy_score(y_train, y_train_pred)print('Test accuracy:', test_acc)
print('Train accuracy:', train_acc)

训练精度:0.5892498813701775
测试精度:0.200000001

正如我们所看到的,定义类权重参数对我们的模型的性能有巨大的改善,防止分类器简单地过度预测最高频率的类。尽管整体准确性下降,但在未来的“真实世界”测试中,我们的模型现在将是任何给定实例的更好的预测器。此外,由热点图对角线上的深色表示,即使模型预测了错误的标签,它通常也会向右或向左偏离一个标签。

让我们打印出更多的分类指标,以便更好地了解我们的模型的表现:

from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))

让我们使用 f1 分数将逻辑回归分类器与我们将创建的其他模型进行比较。F1-score 是对模型准确性的度量,它是通过取精度和召回率的调和平均值来计算的,从而将精度和召回率组合成一个度量。如果您不熟悉精确度和召回率的概念,请参考本文了解更多信息。本质上,f1-score 提供了一种定量的方法来评估过度预测某些类别标签的趋势以及模型区分类别的能力。

决策树:

对于我们的下一个模型,让我们尝试在我们的数据上训练一个决策树分类器。决策树往往在多类分类问题中表现得非常好,并且直观易懂。然而,在我们创建模型之前,让我们首先优化决策树分类器的超参数。为此,我们可以在字典定义的超参数值组合范围内运行随机搜索。通过这种搜索,我们可以返回找到的最佳值。这种超参数搜索通过 scikit RandomizedSearchCV 函数实现。这里,我选择优化 max_depth 和 max_leaf_nodes 参数,因为它们是防止过度拟合的关键参数,这是决策树特别容易出现的一个属性。利用三重交叉验证。

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import RandomizedSearchCVdtree = DecisionTreeClassifier(class_weight='balanced')
search_vals = dict(max_depth=[35,50,75,100], max_leaf_nodes=[800,1000,1500,2000])
dtree_search = RandomizedSearchCV(dtree, search_vals, cv=3)
search = dtree_search.fit(X_train,y_train)
search.best_params_

输出:{ '最大深度':50,'最大叶节点':1000}

我还绘制了一条验证曲线,同时利用三重交叉验证,以可视化超参数优化和模型复杂性对模型准确性的影响。max_depth 参数的验证曲线如下所示。

随着 max_depth 参数变得不太严格(允许更深的树),验证曲线突出了决策树过度拟合的趋势。然而,有趣的是注意到,尽管在训练和验证精度之间有很大的差距,但是验证精度在这个最大深度范围之间并没有下降。

使用上面找到的超参数,让我们训练一个决策树分类器,并使用它来创建预测。下面是我用来训练模型的代码。让我们像以前一样将“class_weight”参数设置为“balanced”。注意,我在原始训练数据上训练模型,而不是 PCA 缩放+变换的数据,因为决策树是尺度不变的。因此,它们不需要对训练数据进行缩放。此外,当决策树在 PCA 变换的数据上训练时,实现了较低的准确性。

from sklearn.tree import DecisionTreeClassifier
dtree=DecisionTreeClassifier(max_depth= 50, max_leaf_nodes=1000, class_weight='balanced')
dtree.fit(X_train,y_train)from sklearn import metrics
train_predictions = dtree.predict(X_train)
test_predictions = dtree.predict(X_test)print("Train Accuracy:",metrics.accuracy_score(y_train, train_predictions))
print("Test Accuracy:",metrics.accuracy_score(y_test, test_predictions))

训练精度:0.6170775710955541
测试精度:0.200000001

最终,我们可以看到决策树分类器的准确性有所提高!每个类别标签的 F1 分数也有所增加,表明模型性能有所提高。让我们看看我们是否可以用决策树集成做得更好,或者被称为随机森林模型。

随机森林:

我们可以改进决策树分类器,将树打包成一个集合,并在所有构建的树之间利用多数投票的能力。这被称为随机森林模型。下面是这个模型的代码和模型性能。请注意,模型参数是通过反复试验(同时观察 f1 和准确度分数)选择的,因为网格搜索/随机搜索在计算上非常昂贵。然而,使用所述技术可以进一步优化参数。

from sklearn.ensemble import RandomForestClassifierrf = RandomForestClassifier(n_estimators=150, max_depth=15, class_weight='balanced')
rf.fit(X_train,y_train)train_predictions = rf.predict(X_train)
test_predictions = rf.predict(X_test)print("Train Accuracy:",metrics.accuracy_score(y_train, train_predictions))
print("Test Accuracy:",metrics.accuracy_score(y_test, test_predictions))

训练精度:0.6729519125323106
测试精度:0.100000001

我们提高了决策树的准确性,以及每个职业的 f1 分数。接下来,让我们利用 scikit 中的一个函数在随机森林模型中生成一个特性重要性图。这里,特征重要性是通过计算得到的,即节点杂质的减少量,该减少量是通过到达树中该节点的概率来加权的。

从该图中,我们可以看到 APR DRG 代码(根据入院原因、疾病严重程度和死亡风险对患者进行分类的分类系统)和 APR 疾病严重程度代码是预测患者住院时间的两个最重要的特征。有趣的是,与其他支付类型组相比,医疗保险支付类型组在预测住院时间方面具有相对较高的重要性。病人的平均收入也起了重要作用。

提升决策树:

最后,让我们看看另一种类型的集成方法:boosting 可以实现什么样的性能。使用 scikit learn 中的 AdaBoostClassifier,我们可以创建一个增强的决策树分类器。该模型通过创建 n 个短的决策树树桩来工作,其中每个连续的树桩都旨在改善前一个树桩的分类错误。这些树的多数投票然后被组合以产生最终的预测。用于实现这一点的代码如下所示,其中使用与随机森林模型等效的方法优化了超参数。

from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_scoredtree = DecisionTreeClassifier(random_state = 1, class_weight = "balanced", max_depth = 15)
boost = AdaBoostClassifier(dtree, n_estimators=75, random_state=0)
boost.fit(X_train, y_train)train_predictions = boost.predict(X_train)
test_predictions = boost.predict(X_test)print("Train Accuracy:", accuracy_score(y_train, train_predictions))
print("Test Accuracy:", accuracy_score(y_test, test_predictions))

训练精度:0.9397049441494455
测试精度:0.20000001

在这里,我们可以看到增强决策树实现了最高的模型准确性,击败了逻辑回归分类器和随机森林集成。然而,少数民族班级(不经常出现)的大多数 f1 分数略低。因此,根据患者不同,假阳性或假阴性的严重程度的变化可以保证在使用随机森林模型或增强决策树分类器作为最佳模型之间进行切换。

星火团环境:

由于此数据的规模,一些建模方面(如超参数优化)需要很长时间来运行。因此,我想加入一个关于 Apache Spark 好处的注释。如果我们通过并行化许多计算密集型任务来利用 Apache Spark 和 AWS 集群,我们可以实现显著的代码加速。查看我在这篇博客文章开头链接的完整代码,了解可以用来完成这一任务的脚本。该代码包括如何在 Python 环境中设置 Spark,将 AWS 集群连接到笔记本,从 S3 桶中检索数据集,以及创建模型。我发现在这个项目中使用 Spark 的一个缺点是 Spark ML 模型函数中缺少类权重参数。在完整的代码中,我还展示了手动分配类权重的方法。这段代码改编自一篇博客文章,点击这里可以看到。

结论

最终,通过这篇博文中强调的步骤,我能够使用从患者进入医院并被诊断出的那一刻起就有的数据来预测患者的住院时间,准确率约为 70%。这种模式能够极大地改善医院管理和患者福祉。未来的方向可能是开发第二个模型,允许进行一系列模型预测,最终预测给定患者在住院期间的治疗费用。这可以通过首先通过模型预测住院时间来实现,例如这里创建的模型。接下来,可以创建第二个模型来根据住院时间预测“总成本”。

在将此处创建的模型投入使用之前,还需要考虑重要的伦理因素,因为患者收入和种族等特征被用来预测住院时间。关于这个话题的更多内容可以在这里阅读

外卖:

  • 多类分类设置中分类与回归的优势
  • 字符串索引与一次性编码分类变量的重要性
  • 处理阶层失衡的重要性
  • class_weights 参数的有效性,它消除了对最高频率类进行欠采样的需要(欠采样的缺点是减少了可用于训练的训练数据量)
  • 获取原始数据集并使用它来收集见解和生成预测所需的一般步骤
  • APR DRG 代码和 APR 疾病严重程度代码是预测患者住院时间的两个最重要的特征。此外,与其他支付类型组相比,医疗保险支付类型组在预测住院时间方面具有相对较高的重要性。平均收入对住院时间也有显著影响。

参考文献:

[1].Baek,h .,Cho,m .,Kim,s .,Hwang,h .,Song,m .,和 Yoo,S. (2018 年)。使用电子健康记录分析住院时间长度:一种统计和数据挖掘方法。 PloS one13 (4),e0195901。https://doi.org/10.1371/journal.pone.0195901

[2].sci kit-学习。(未注明)。从 https://scikit-learn.org/stable/取回

本文中的工作扩展了我的最终项目,并利用了我在宾夕法尼亚大学的 CIS 545:大数据分析中学到的概念

IPL 比赛的预测分析

原文:https://towardsdatascience.com/predicting-ipl-match-winner-fc9e89f583ce?source=collection_archive---------6-----------------------

使用 SVM 二元分类器的预测

Alessandro Bogliari 在 Unsplash 上的照片

自 2008 年 IPL 诞生以来,它吸引了全球各地的观众。高度的不确定性和最后时刻的紧张刺激了球迷观看比赛。在很短的时间内,IPL 已经成为收入最高的板球联赛。长期以来,数据分析一直是体育娱乐的一部分。在一场板球比赛中,我们可能会看到根据当前比赛情况显示球队获胜概率的比分线。我的朋友,这是在行动中的 D ata A 分析!

想起什么了吗?我们可以把它看作是数据分析的人类版本!来源

作为一个板球迷,可视化的板球统计数据是迷人的。当我在 Kaggle 上浏览 Medium 和 kernels(比如说代码剧本)的博客时,我被所做的分析迷住了。因此,我决定通过构建一个分类器来预测获胜的团队,从而获得第一次实践经验。

在机器学习中,问题主要分为两类:回归问题和分类问题。回归问题处理具有连续值作为输出的问题,而在分类问题中,输出是分类值。由于赢家预测的输出是一个分类值,我们试图解决的问题是一个分类问题。

那么从哪里开始,做什么呢?

  1. 了解数据集。
  2. 清理数据。
  3. 分析要成为特征的候选列。
  4. 按照模型/算法的要求处理特征。
  5. 根据训练数据训练模型/算法。
  6. 在测试数据上测试模型/算法。
  7. 调整模型/算法以获得更高的准确性。

我们开始吧!

英国广播公司的

为了顺利学习,我建议浏览一下我用过的 Python 库,比如 PandasNumpyScikit-learn

步骤 1 —了解数据集!

在处理数据的同时, Kaggle:你的数据科学之家是 to-go 平台。我使用了 https://www.kaggle.com/nowke9/ipldata 的数据集。该数据集有 2 个文件:matches.csv,包含 2008 年至 2019 年的每场比赛的详细信息 deliveries.csv,包含每场比赛的逐球详细信息。

第 2 步—将数据放入操场并进行清理!

我用的是。read_csv() 读取 csv 文件。中的路径。read_csv() 函数可以是相对的,也可以是绝对的。在这里,我使用谷歌合作实验室作为我的游乐场,因此文件存储在那里。

没有什么是完美的。生活很乱。关系很复杂。结果不确定。人是不理智的。—休·麦凯

正如 Hugh Mackay 在上面的引用中正确指出的“没有什么是完美的”,在这种情况下,它与我们的数据有关。我们拥有的数据在几列中包含空值。

column null_values
city      7 
winner    4 
player_of_match 4 
umpire1   2 
umpire2   2 
umpire3  637 
dtype: int64

有几种方法可以处理空值,其中,我将对列城市使用插补。插补是一种统计上填补缺失值的方法。更多参考,你可能会发现https://www.kaggle.com/alexisbcook/missing-values很有帮助。由于在列 winner 中填充值是不合理的,我们可以删除这些记录。

的组合。选择()。如果城市中的值为空,则 where()* from numpy 根据地点列替换城市列中的值。*

步骤 3 —进一步预处理数据

在摆弄数据时,我发现了一个有趣的冗余。队伍上升浦那超级巨星队伍 _1队伍 _2胜利者投掷 _ 胜利者中被复制。

用一个值替换这些值显然是下一步要做的事情。Python 库使得数据操作变得容易执行。Pandas 允许我们将数据加载到数据帧中,并轻松有效地对其进行操作。

!!数据现在是干净的。我们终于可以开始分析特性(列)了。

第 4 步—特征工程

注:考虑的栏目有: team_1 team_2 toss_winner toss_decision venue city and winner。

为了使这些列能够帮助模型进行预测,这些值应该对计算机有一定的意义。由于他们(仍然)没有能力理解文本并从中得出结论,我们需要将字符串编码为数字分类值。虽然我们可以选择手动完成这个过程,但是 Scikit-learn 库为我们提供了一个使用label encoder的选项。

在我们开始构建模型之前,必须承认一个重要的观察结果。像 toss_winnertoss_decisionwinner 这样的栏目对我们来说可能有意义,但是机器呢?

他刚刚过了什么日子?照片由:Guylaine BrunetFlickr上的

我来详细说明一下。 toss_winnerwinner 中的值包含团队名称,但这些变量与 team_1team_2 有什么关系呢?他们之间唯一的共同点是他们会分享相同的价值,但这不足以成为逻辑。另外, toss_decision 可能是球棒或者场地,但是他们指的是哪支球队呢?为了解决这个问题,我们将为列 winnertoss_winnertoss_decision 添加新列 team1_winteam1_toss_winteam1_bat ,以便它们反映与列 team_1 的关系。

如果 team1 赢了,则列 team1_win 中的值将为 1,否则为 0,对于列 team1_toss_decision 来说,如果 team1 赢了,则该值将为 1,并且如果 team1 首先击球,则最后 team1_bat 将为 1。

步骤 5 —特征选择

我们基于我们所拥有的领域知识手动选择了一些特性。但是我们没有统计数据证明所选择的特征对我们的数据集是重要的。 Scikit-learn 提供了一个名为feature _ selection的优秀模块,它为我们提供了几种进行特征选择的方法。首先,我们将检查这些列中是否有任何一列表示与其他列相同的值。为此,我们需要创建一个相关矩阵来找出列之间的关系。如果列之间相关性的绝对值足够高,我们可以说它们表示相似的值。

我们数据的相关矩阵看起来像这样:

在这里,我们看到 team1_bat 表示与 team1_toss_win 相同的信息。很奇怪,对吧?这就是数据集是如何建立的,如果第一队赢了掷硬币,那么他们将一直击球,如果第二队赢了掷硬币,那么他们将一直投球。所以我们从我们的特性列表中删除了列 team1_bat

步骤 6 —构建、训练和测试模型

对于一个分类问题,多种算法可以根据我们拥有的数据和使用的模式训练分类器,预测某些输入条件的结果。我们将尝试决策树分类器随机森林分类器逻辑回归SVM ,并选择最适合我们数据分布的算法。

一旦我们构建了模型,我们需要使用从未向模型公开的值来验证该模型。因此,我们使用train _ test _ split(Scikit-learn 提供的一个类)将我们的数据分成两部分,每部分 80–20。该模型针对 80%的数据进行训练,并针对另外 20%的数据进行验证。

我们现在可以训练各种模型并比较性能。

这导致了:

从结果可以明显看出,对于该数据分布,【SVM】给出了比其他算法更高的准确率 66.23%

尽管精确度不够高,没有用,但它给出了一个关于设计机器学习问题的解决方案时所使用的策略和方法的基本概念。

下一步是什么?

影响比赛结果的还有很多其他因素,比如天气,球员的状态主场优势等等,这里不包括。尝试添加这些功能,并尝试使用它。通过使用作为 train_test_split 替代方案的 K 倍交叉验证的概念,可以对代码进行进一步修改。在 K-Fold 的链接中查看一篇令人惊叹的文章。

最后!

既然你已经做到了,我们在预测 IPL 团队获胜的概率方面做了很好的工作,通过将其转换为二进制分类问题,并在学习 Python 库的同时使用 Python 库。如果您有任何问题、建议或反馈,请随时通过[电子邮件](mailto: gpithadia@gmail.com)或 LinkedIn 联系我。你可以在我的 GitHub 上找到这段代码,非常欢迎你来贡献。

预测快乐!

感谢 德鲁米尔·帕特尔赛义德·祖拜尔萨希尔·桑加尼 ,以及 亚什·沙阿 的帮助!**

使用分类模型预测 Kickstarter 活动的成功

原文:https://towardsdatascience.com/predicting-kickstarter-campaign-success-with-classification-models-91b07c63e6ec?source=collection_archive---------36-----------------------

旨在帮助活动家提高他们成功发起运动的机会!

Unsplash 上的byrk拍摄的照片

Kickstarter 是一个神奇的平台,帮助企业家发起运动,并“帮助将创意项目带入生活”。虽然任何人都可以在这个网站上传播他们的创意,但不是每个人都能在竞选截止日期前获得足够的承诺。我的项目旨在帮助活动家缩小关注标准,以发起一场成功的运动。

方法学

1。数据来源

从网站 Web Robots 获取 Kickstarter 数据集,该网站抓取所有 Kickstarter 项目并收集 CSV 和 JSON 格式的数据。

2。数据清理

在进一步研究数据之前,对我的特征和虚拟类别变量进行预处理。

项目类别:该功能是一个字典,包含有关活动类别的各种信息。我从这个变量中提取了类别名称、类别位置和类别父 ID 信息,做了三个新变量。

类别名称:从项目类别变量中提取这些信息后,我将它转换成一个哑变量。

状态:最初有 5 种不同的活动状态,包括暂停、取消、成功、失败和活动,为了简化预测,我将分组减少为成功/失败。

3。特征选择&工程

通过计算每个变量的信息值(IV)并仅保留值大于 0.1 的变量来执行特征选择。有关信息价值计算的更多信息,请访问本网站

我的功能 IV 表的快照

至于特性工程,我采用了时间戳特性,如创建时间、启动时间、状态更改时间和截止时间,计算它们的差异,得到每个阶段的持续时间。

不同时间戳特性的特性工程快照

4。建模

我选择逻辑回归作为我的基线模型,并将数据分成 20%测试、20%验证和 60%训练样本。在将不同的训练、验证和测试样本拟合到我的基线模型中之后,我得到了下表中的结果:

逻辑回归模型的结果

训练精度和测试精度非常相似,因此没有过度拟合的迹象。然而,测试召回率高于测试精确度,因此我在其他模型上的精确度得分还有一定的提升空间。

我们还可以查看混淆矩阵,以获得关于模型在哪里出错的更多信息。

逻辑回归模型的混淆矩阵

该模型做出的假阳性预测比假阴性预测更多,这意味着对实际上不成功的成功活动的预测比实际上成功的成功活动的预测更多。为了降低我的假阳性预测率,我运行了其他模型来寻求改进。

我首先将我的数据分成 20%的测试和 80%的交叉验证,并将样本拟合到 KNN、随机森林和 AdaBoost 等模型中。在 RandomizedSearchCV 的帮助下,我能够微调每个模型中的参数,并确保我从它们中获得最佳性能。下面是我得到的每个型号的结果表:

KNN、随机森林和 AdaBoost 的结果表

虽然随机森林给了我们三个模型中最高的 F-1 分数,但我认为 AdaBoost 是我最好的模型,因为它给了我们最高的精度分数。我把精确的表现放在回忆的表现之上,因为我不想预测不成功的活动会成功。AdaBoost 给我们的精确分数是 0.72,这意味着在 10 次活动中,我的模型正确预测了 7 次活动成功。

结果

为了更好地理解上面的模型是如何工作的,让我们来看看我的特性是如何执行的。下图显示了功能的重要性:

特征重要性图

我们可以看到,目标和时间相关特征是预测活动成功的最重要特征。这一发现是有意义的,因为你的竞选活动的成功取决于认捐的数额是否符合你的目标,以及你是否在竞选活动的最后期限内得到认捐的数额。

我们还可以查看下图,了解这些功能以何种方式影响营销活动的结果。

特征值与模型输出图

SHAP 值表示特征对模型输出变化的责任。SHAP 值越高,特征对模型的积极影响越大。如果我们只看图表的右半部分,即模型受到积极影响的那一半,我们可以看到哪些特征值有助于发起成功的营销活动。

以“准备持续时间”特性为例,其特性值在图表的整个右半部分都很低(蓝色)。这意味着较短的准备时间有更好的机会发起一场成功的运动。以“目标”特征为例,其特征值在图表的整个右半部分也很低(蓝色)。这意味着一个小目标有更好的机会发起一场成功的运动。至于其他与项目类别相关的特性,不同的类别会对模型产生不同的影响。

图表中的见解与我们的直觉相关,因为如果你的准备时间很短,你更有可能在项目截止日期内完成活动。同样,如果你有一个较小的目标,你就有更大的机会达到符合目标的认捐额。

我还用 Flask 和 Javascript 构建了一个 web 应用程序来演示我的模型性能。该应用程序允许用户输入前 4 个重要特性的值,并检索活动成功的预测。

Web 应用程序演示

结论

根据我的结果部分,我建议活动家:

  • 设定一个适合项目范围的小目标
  • 保持活动持续时间短
  • 仔细考虑类别

为了增加他们成功发起运动的机会!

对于未来的步骤,我想做一个多类分类,考虑到不同的活动状态,而不是成功/失败。此外,我还想收集更长时间内的数据。根据我的直觉,有一些功能会影响模型的性能,但是,对当前模型没有太大影响。也许一旦我延长了数据收集的时间,这些特性就会显示出它们的影响。

如需更多信息,请随时联系我!你也可以在 Github 上查看这个项目的源代码和文档。

预测 Airbnb 房源的市场排名

原文:https://towardsdatascience.com/predicting-market-rank-for-airbnb-listings-59009a886d6?source=collection_archive---------39-----------------------

使用机器学习模型量化房地产竞争力

图片来源:Airbnb

动机

有几个原因使得 Airbnb 数据更具挑战性,也更有价值:

  • 与定义目标和指标的 Kaggle 不同,开放式问题定义是一项关键的数据科学技能-如何确定有价值的业务目标并围绕它创建分析框架和建模解决方案?
  • 包括结构化数据、文本和图像在内的丰富信息需要评估和叙述——如何处理数据过多,同时又遗漏了某些数据?
  • 来自 insideairbnb.com 等来源的定期数据更新,提供关键反馈并实现迭代优化
  • 在数据的背后,是有待解释和发掘的地方、人和他们的多元文化。增强 Airbnb 体验可以为人类带来丰富,并使其成为数据科学家的一个有意义和迷人的目标

为什么预测市场排名而不是价格?

在设计机器学习模型之前,首先要问的问题是,我们的目标是什么?目标还应考虑数据的可用性和质量。许多已发表的工作集中在价格预测上。然而,价格可能在不同日期之间大幅波动,这限制了模型的实用性。相反,我会把重点放在一家上市公司相对于其市场竞争对手的排名上。这是一个重要的设计考虑因素,因为相对排名得分捕捉了列表的相对吸引力,并使模型更通用,以适应更多的数据并用于更多的应用。

在这里,我们将市场排名定义为一个列表在特定城市或社区的相对竞争力得分。这个预测模型怎么用?想象一下,如果你是一个主持人,你不仅可以看到你目前的排名与竞争对手相比如何,你还可以评估改变功能(降低价格,增加设施……)以提高你的排名的效果。对于 Airbnb 来说,预测房源受欢迎程度的能力可以为潜在的客人提供有效的推荐(“以下是好莱坞为你推荐的日期和价格范围的前 10 个房源”),或者为主人提供优化推荐(“如果你将清洁费降低 20 美元,你的排名将从前 25%提高到前 10%)。最终,目标是增加销售额和提高客户满意度。

模型设计和培养目标

上市做得越好,它的市场排名就应该越高。我们如何定义和获取监督培训的“市场排名”信息?我们正在寻找能告诉我们一个列表有多受欢迎的数据。虽然我们没有实际的预订信息,但我们有每月更新的可用性和审查数据。让我们来看看这两个关键指标的优缺点:

可用性——可用性本身可能会产生误导,因为列表可能因为被预订或主机退出市场而不可用。通过观察从时间 A 到时间 B 的可用性变化,并查看主机上次更新日历的时间,我们可以更智能地解释变化并导出大多数列表的预订活动

评论——目标观察窗口中评论数量的增加很好地代表了列表的表现。仍然有一个陷阱,那些最小日期越长的列表评论越少(相对于预订的天数)

如图所示,预订率和点评增长率可通过以下方式估算:

  • 对于目标时间范围,查看主机何时更新日历以及可用性如何随时间变化,计算预订率
  • 对于相同的目标时间范围,查看添加了多少评论,并计算评论率

预订率和评论率相辅相成,为单个房源提供市场排名指标。它们被缩放和标准化以用作回归模型的训练目标。为了进一步多样化,我基于列表特征的子集训练了预订率模型和评论率模型,同时防止数据泄露。所得到的预订率得分和评论率得分然后被合计为一个组合得分,该组合得分然后被用来以百分位数的形式生成市场排名,量化列表在任何城市、区域或邻近地区的相对实力。

开发基线模型

对于原型,我使用了洛杉矶 airbnb 房源的数据,2019 年 3 月 6 日为时间 A,2019 年 12 月 5 日为时间 B,2019 年 12 月 5 日+ 30 日为目标预订时间窗口。为了简单起见,我使用 XGBoost 进行最少量的数据处理和调优。

下图显示了审核率模型的样本验证曲线,其 R2 分数约为 0.6。这将作为一个基线,通过添加功能、数据、调整等,有可能进行改进

下图显示了预订率模型的学习曲线示例。随着数据量的增加,训练和验证之间的差距(表示方差)显示出缩小的趋势。正如所料,从误差水平来看,偏差明显存在,可以通过特性和算法来改善。

下图显示了两个回归模型的 SHAP 汇总图。这些特征按照它们对模型结果的影响从上到下排列。对于每个特征,其影响通过其在水平轴上的范围来可视化。红色表示较高的特征值,蓝色表示较低的特征值。向右扩展量化了积极影响(特征值越高,预订和评论率越高,因此列表越热门)。向左延伸量化了负面影响。一些快速观察:

  • 不出所料,更高的价格、更少的点评、更长的最低住宿时间会对预订率产生负面影响
  • 客人最喜欢整个家/公寓
  • 咖啡机、自助入住等简单功能有助于提升房源
  • 这两种型号的功能影响不同,因此它们是互补的

SHAP(SHapley Additive exPlanations)是一种新兴的算法不可知的可解释 AI (XAI)方法,它利用博弈论来衡量特征对预测的影响。详细的 SHAP 分析超出了这里的范围。

图解市场排名

在这里,我们使用洛杉矶地区保留的列表测试集来评估模型。在结合预订模型和评论模型的得分后,我们以百分位数的形式获得一个城市范围的排名得分(“market_rank_city”)。例如,就其市场竞争力而言,列表 ID 8570847 位于顶部 98.6%,而列表 ID 14014479 位于底部 6.9%。

按照标准 url 格式【https://www.airbnb.com/rooms/查看实际列表,看看分数是否有意义。

市场排名也可以计算出一个明确的目标群体,导致更多的应用。例如,我们可以对某个价格范围内某个特定区域的列表进行排名。我们可以应用任何特征值作为过滤器来比较子集中列表的竞争力。

下面是计算好莱坞附近价格为 150 美元到 250 美元的列表的百分位数排名(“market_rank_neighborhood”)的示例。

从上面的列表中,我们来看看最上面的列表,这是一个新的带完整厨房的 2 卧室公寓,售价 174 美元/晚:【https://www.airbnb.com/rooms/32792761】T4

下面是一个 13 平方英尺的房间,配有一张双人床,价格为 199 美元/晚:https://www.airbnb.com/rooms/28012404

对新上市公司的业绩进行建模

请注意,我们包括历史信息,如评论和预订活动的增长率,以预测未来的结果。这不是数据泄露的一种形式。相反,它真实地反映了潜在客户对房源的评价。因此,model 对新上市的产品更加中立,因为它缺少许多特性的信息。这也是现实的真实反映。

为了更准确地区分新上市公司的质量,需要开发侧重于便利设施、照片、文本和位置等特征的模型。想想 KNN 建立在随时间恒定的特征子集上。

下一步是什么

我分享了一个利用真实世界数据的数据科学项目的旅程,从一个有意义的目标开始,通过研究可用数据和试验模型组合,到有希望的结果。开发的基线模型仅仅触及了可能的表面。由于 airbnb 数据的巨大数量和动态性质,进一步的改进可能来自更多的数据清理、功能工程和算法调整。添加图像和文本信息也有助于深度学习的激动人心的探索。

更多 Airbnb 功能分析及可解释 AI (XAI)的图解使用请参考:https://medium . com/@ Wang . Sean . x/boosting-machine-learning-models-with-explable-AI-xai-601683119 c84

回归预测国际足联足球运动员的市场价值

原文:https://towardsdatascience.com/predicting-market-value-of-fifa-soccer-players-with-regression-5d79aed207d9?source=collection_archive---------18-----------------------

线性、套索、岭、弹性网和多项式回归的案例研究。

福赞·萨里Unsplash 上拍摄的照片

自 Metis 数据科学训练营开始以来,三周已经过去了,这段旅程可谓紧张而激动人心。在这篇文章中,我详细介绍了我利用过去两周仔细学习的关于 web 抓取和回归的技能和知识构建的项目。在浏览了各种网站后,我最终选定了一个有趣的话题——国际足联足球运动员的市场价值预测!

一个足球运动员的市场价值是多少?

当我们谈论一名足球运动员的市场价值时,我们指的是他的足球俱乐部可以出售或将其合同转让给另一家俱乐部的估计金额。足球俱乐部可以支付天文数字来获得顶级球员。正如我们将在后面看到的,足球运动员的市场价值遵循指数趋势,这表明一小部分运动员具有很高的价值。因此,预测市场价值的能力可能会给一些富有的足球俱乐部带来商业优势。

推动市场价值的最重要因素是什么?经过研究,我列出了以下因素:

  • 足球技能:因为没有一个足球运动员是 100%全能的,所以足球技能分为防守、射门和守门几个领域。在这些领域中的任何一个领域拥有高评级都可以提升你的市场价值。
  • 场上位置:平均来说,前锋比中场更被看重,其次是后卫。
  • 年龄:或者青春的系数。自然,年轻球员将拥有更高的市场价值,因为他们有更大的增长潜力和更长的服务期限。
  • 媒体覆盖率:或媒体系数。一般来说,拥有受欢迎的球员,他们会产生更大的媒体影响,可以为俱乐部带来更多的收入。

尽管如此,由于这些因素的一些数据很难获得,我将尝试创建一个可行的回归模型,仅基于足球技能和年龄来预测市场价值。下面我详细介绍这个项目的过程和结果。

美汤刮网

I web 用经典的 Python 模块美汤刮出了 FIFA 指数网站。我总共收集了 19,401 名球员的数据,包括他们的身高、体重、年龄、偏好的脚和技能评分。每个技能等级都被细分到不同的领域,这些领域的得分从 0 到 100。因此,技能等级是通过取其领域的平均值来进行网络搜集的。足球运动员及其各自领域的技能评级如下:

  • 球技 : 控球,运球
  • 传球 : 传中,短传,长传
  • 防守 : 盯人,滑铲,立铲
  • 心理 : 攻击性、反应、攻击位置、拦截、视野、沉着
  • 体能 : 加速度、耐力、力量、平衡、冲刺速度、敏捷性、跳跃
  • 射门 : 头球、射门力度、射门、远射、弧线球、任意球准确性、点球、凌空抽射
  • 守门员 : 定位、假摔、处理、踢球、反应

以下是我用来收集所有数据的脚本:

在做了一些轻微的处理和剔除一些没有市场价值数据的球员后,这里是数据框架的总结:

探索性数据分析

绘制特征和目标(市场价值)的热图揭示了一些有趣的趋势:身高、体重、年龄、偏好的脚和守门员似乎与目标变量无关:

作者图片

因此,问题是我们应该删除这些功能吗?我们已经从领域知识中了解到,年龄是市场价值的一个重要预测指标。守门员技术怎么样?请注意,守门与其他技能指标呈负相关。这并不奇怪,因为守门员大多是专业的,很少上场比赛。然而,如配对图所示,其中一些守门员的价值很高:

作者图片

因此,删除守门员特征可能会导致对守门员市场价值的预测下降,也使模型不稳定。配对图还显示了市场价值的指数分布,揭示了赢家通吃的情况。

特征选择和工程

因此,我们继续对市场价值取对数,试图使数据线性化。此外,身高、体重和偏好的脚的特征被删除。如使用 Statsmodels 软件包绘制的 OLS 回归总结所示,该模型得到了显著改进:

作者图片

更不用说调整后的 R 值从 0.32 提高到 0.67,对数似然性也增加了,表明拟合优度更好。此外,残差遵循更加正态的分布,偏斜度几乎降至 0,峰度几乎降至 3,满足正态假设。此外,与目标变量的相关性在所有特性中得到了极大的提高。

我们可以从 OLS 总结中观察到的其他见解是年龄和流逝特征的负系数。虽然我们已经知道年龄与市场价值呈负相关,但及格的负系数还是令人吃惊。这意味着,如果一个球员提高了他的传球技术,平均来说,他的市场价值会随之下降!一个可能的解释是,市场会奖励更有统治力的球员,而更擅长传球的球员可能在其他领域更弱。

型号选择

现在,为了拟合数据,我们希望比较的回归模型是简单线性回归、套索回归、岭回归、弹性网回归和多项式回归。请注意,LASSO、Ridge 和 Elastic Net 只是线性回归的正则化版本,它将额外的正则化项添加到我们希望最小化的成本函数中。这些正则化项中的每一项都包含超参数α,其值在模型选择期间选择。在继续之前,我们将整个数据框架随机分为 80%的训练集和 20%的测试集,其中我们保留测试集用于最终的模型评估。对于模型选择,我们进一步随机将训练集分成 5 个部分进行交叉验证。

作者图片

通过对 5 重 CV 中的验证集取平均分数(平均绝对误差),为套索、脊和弹性网选择最佳阿尔法。多项式回归也选择最佳次数。因此,最佳 Alphas 和度数为:

  • 套索回归:大约。0
  • 岭回归:0.93
  • 弹性净回归:大约。0
  • 多项式回归:4 次

因为套索和弹性网的 Alpha 值可以忽略不计,所以它们可以近似为线性回归模型。比较其余模型的性能,显然多项式回归(4 次)胜出:

模型评估

是时候在测试集上给我们的多项式回归模型打分了!在对日志市场价值的测试集进行评分时,结果仍然非常具有可比性,r 为 0.930,平均绝对误差为 0.279,尽管峰度约为 1。

作者图片

Q-Q 图也是非常线性的,代表了对数据的良好模型拟合。然而,在我们对结果感到高兴之前,我们应该记住,我们已经在前面对目标变量取了对数。当我们“取消记录”预测的目标变量,并与测试集中的原始市场价值进行比较时,会发生什么?

作者图片

在不取对数的情况下,对市场价值的测试集进行评分,我们得到 r 为 0.836,€平均绝对误差为 668,684,峰度为 234!结果是令人惊讶的,但是我应该强调,这是我们用回归和我们选择的有限特性可能实现的最佳模型。

下面是比较市场价值和预测市场价值的测试集的最终数据框架的快照。虽然预测通常遵循实际市场价值的趋势,但我们能够观察到一些异常值。此外,该模型似乎也有利于捍卫者,如将维吉尔·范·迪克和吉奥吉奥·基耶利尼排在前 5 行所证明的。一个更准确的模型会更有利于罢工者。

结论和未来工作

尽管如此,考虑到我使用的有限特性,最终模型的结果还是相当不错的。今后,如果有其他数据来源,应考虑球员在场上的位置和媒体系数等重要特征。

话虽如此,我期待在未来几周从 Metis 数据科学训练营学习更多的机器学习技术!谁知道呢?随着更多的机器学习工具,如神经网络,我们可能会重新访问该项目,并设计一个更好的模型。

这里是到我的 GitHub 的链接,它包含了这个项目的所有代码和演示幻灯片。

你觉得我的模型怎么样?通过我的 LinkedIn联系我或者在下面评论来讨论!

附:感谢阅读我关于 回归 的作品。如果你也有兴趣了解 分类 ,那就来看看我的下一个项目:

[## 用分类预测航空旅客的满意度

案例研究与 KNN,逻辑回归,高斯 NB,决策树和随机森林。

towardsdatascience.com](/predicting-satisfaction-of-airline-passengers-with-classification-76f1516e1d16)

支持我! —如果你没有订阅 Medium,并且喜欢我的内容,请考虑通过我的推荐链接加入 Medium 来支持我。

[## 加入我的介绍链接媒体-谭师鹏阿尔文

阅读谭·师鹏·阿尔文(以及媒体上成千上万其他作家)的每一个故事。您的会员费直接…

tanpengshi.medium.com](https://tanpengshi.medium.com/membership)

使用 Python 预测缺失值

原文:https://towardsdatascience.com/predicting-missing-values-with-python-41e581511117?source=collection_archive---------14-----------------------

建立数据插补模型

来源

对于数据科学家来说,处理缺失数据是数据清理和模型开发过程的重要部分。通常,真实数据包含多个稀疏字段或充满错误值的字段。在本帖中,我们将讨论如何构建模型来估算数据中缺失或错误的值。

我们开始吧!

出于我们的目的,我们将使用葡萄酒数据集,这个数据集可以在这里找到。

首先,让我们将数据读入熊猫数据框:

import pandas as pd
df = pd.read_csv("winemag-data-130k-v2.csv")

接下来,让我们打印前五行数据:

print(df.head())

让我们从这些数据中随机抽取 500 条记录。这将有助于加速模型训练和测试,尽管读者可以很容易地修改它:

import pandas as pd
df = pd.read_csv("winemag-data-130k-v2.csv").sample(n=500, random_state = 42)

现在,让我们打印与我们的数据相对应的信息,这将使我们了解哪些列有缺失值:

print(df.info())

有几列的非空值少于 500 个,这相当于缺少值。首先,让我们考虑建立一个模型,使用“点”估算缺失的“价格”值。首先,让我们打印“价格”和“积分”之间的相关性:

print("Correlation: ", df['points'].corr(df['price']))

我们看到有一个微弱的正相关。让我们建立一个线性回归模型,用“点”来预测“价格”。首先,让我们从“scikit-learn”导入“LinearRegresssion”模块:

from sklearn.linear_model import LinearRegression

现在,让我们将我们的数据分开用于训练和测试。我们希望能够预测缺失的值,但是我们应该使用基本事实“价格”值来验证我们的预测。让我们通过只选择正价格值来过滤掉缺少的值:

import numpy as np 
df_filter = df[df['price'] > 0].copy()

让我们也初始化我们将用来存储我们的预测和实际值的列表:

y_pred = []
y_true = []

我们将使用 K 折交叉验证来验证我们的模型。让我们从“scikit-learn”导入“KFolds”模块。我们将使用 10 个折叠来验证我们的模型:

from sklearn.model_selection import KFold
kf = KFold(n_splits=10, random_state = 42)
for train_index, test_index in kf.split(df_filter):
    df_test = df_filter.iloc[test_index]
    df_train = df_filter.iloc[train_index]

我们现在可以定义我们的输入和输出:

for train_index, test_index in kf.split(df_filter):
    ...
    X_train = np.array(df_train['points']).reshape(-1, 1)     
    y_train = np.array(df_train['price']).reshape(-1, 1)
    X_test = np.array(df_test['points']).reshape(-1, 1)  
    y_test = np.array(df_test['price']).reshape(-1, 1)

并符合我们的线性回归模型:

for train_index, test_index in kf.split(df_filter):
    ...
    model = LinearRegression()
    model.fit(X_train, y_train)

现在让我们生成并存储我们的预测:

for train_index, test_index in kf.split(df_filter):
    ...
    y_pred.append(model.predict(X_test)[0])
    y_true.append(y_test[0])

现在让我们来评估我们模型的性能。让我们使用均方误差来评估我们模型的性能:

print("Mean Square Error: ", mean_squared_error(y_true, y_pred))

我们看到表演不是太好。我们可以通过对平均价格加上一个标准差的价格进行训练来改善这一点:

df_filter = df[df['price'] <= df['price'].mean() + df['price'].std() ].copy()
...
print("Mean Square Error: ", mean_squared_error(y_true, y_pred))

虽然这显著提高了性能,但代价是无法准确估算高价葡萄酒的价值。我们可以不使用单一特征的回归模型来预测价格,而是使用基于树的模型,如随机森林,它可以处理分类和数字变量。让我们建立一个随机森林回归模型,使用“国家”、“省份”、“品种”、“酒厂”和“点数”来预测葡萄酒的“价格”。首先,让我们将分类变量转换成可由随机森林模型处理的分类代码:

df['country_cat'] = df['country'].astype('category')
df['country_cat'] = df['country_cat'].cat.codesdf['province_cat'] = df['province'].astype('category')
df['province_cat'] = df['province_cat'].cat.codesdf['winery_cat'] = df['winery'].astype('category')
df['winery_cat'] = df['winery_cat'].cat.codesdf['variety_cat'] = df['variety'].astype('category')
df['variety_cat'] = df['variety_cat'].cat.codes

让我们将随机样本量增加到 5000:

df = pd.read_csv("winemag-data-130k-v2.csv").sample(n=5000, random_state = 42)

接下来,让我们从 scikit-learn 导入随机森林回归器模块。让我们还定义我们将用来训练我们的模型的特征列表:

from sklearn.ensemble import RandomForestRegressor
features = ['points', 'country_cat', 'province_cat', 'winery_cat', 'variety_cat']

让我们使用具有 1000 个估计器和最大深度 1000 的随机森林来训练我们的模型。然后,让我们生成预测并将它们追加到一个新列表中:

for train_index, test_index in kf.split(df_filter):
    df_test = df_filter.iloc[test_index]
    df_train = df_filter.iloc[train_index]

    X_train = np.array(df_train[features])
    y_train = np.array(df_train['price'])
    X_test = np.array(df_test[features])
    y_test = np.array(df_test['price'])
    model = RandomForestRegressor(n_estimators = 1000, max_depth = 1000, random_state = 42)
    model.fit(X_train, y_train) y_pred_rf.append(model.predict(X_test)[0])
    y_true_rf.append(y_test[0])

最后,让我们评估随机森林和线性回归模型的均方误差:

print("Mean Square Error (Linear Regression): ", mean_squared_error(y_true, y_pred))
print("Mean Square Error (Random Forest): ", mean_squared_error(y_pred_rf, y_true_rf))

我们看到随机森林模型具有优越的性能。现在,让我们使用我们的模型预测缺失的价格值,并显示预测示例:

df_missing = df[df['price'].isnull()].copy()X_test_lr = np.array(df_missing['points']).reshape(-1, 1)
X_test_rf = np.array(df_missing[features])X_train_lr = np.array(df_filter['points']).reshape(-1, 1)    
y_train_lr = np.array(df_filter['price']).reshape(-1, 1)X_train_rf = np.array(df_filter[features])
y_train_rf = np.array(df_filter['price'])model_lr = LinearRegression()
model_lr.fit(X_train_lr, y_train_lr)
print("Linear regression predictions: ", model_lr.predict(X_test_lr)[0][0])model_rf = RandomForestRegressor(n_estimators = 1000, max_depth = 1000, random_state = 42)
model_rf.fit(X_train_rf, y_train_rf)
print("Random forests regression predictions: ", model_rf.predict(X_test_rf)[0])

我就讲到这里,但我鼓励您尝试特性选择和超参数调整,看看是否可以提高性能。此外,我鼓励您扩展此数据估算模型,以估算分类字段中的缺失值,如“区域 _1”和“指定”。在这里,您可以构建一个基于树的分类模型,该模型根据分类和数字特征进行训练,以预测所列类别的缺失值。

结论

总之,在这篇文章中,我们讨论了如何建立机器学习模型,我们可以用它来估算数据中的缺失值。首先,我们建立了一个线性回归模型,对评论的葡萄酒进行“点数”训练,以预测葡萄酒的价格。然后,我们建立了一个随机森林模型,根据“点数”和其他分类变量来预测葡萄酒价格。我们看到随机森林模型明显优于基于线性回归的数据插补模型。我希望你觉得这篇文章有用/有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!

用 GPflow 预测分子性质

原文:https://towardsdatascience.com/predicting-molecular-properties-with-gpflow-bd25bf4c08eb?source=collection_archive---------63-----------------------

拉斐尔·比斯卡尔迪在 Unsplash 上的照片

gp flow 中分子的高斯过程回归

瑞安-里斯·格里菲斯 — 5 分钟阅读

这篇文章演示了如何通过创建自定义的 Tanimoto 内核来操作 Morgan 指纹,使用 GPflow 库训练高斯过程(GP)来预测分子属性。请访问我的 GitHub repo 获取 Jupyter 笔记本!

瓦伦汀·b·克雷默在 Unsplash 上的照片

来自深度学习大师的教训

罗摩罗摩克里希南 — 11 分钟阅读

Yoshua Bengio 是深度学习的传奇人物,与 Geoff Hinton 和 Yann LeCun 一起获得了 2018 年的图灵奖。
在这篇简短的帖子中,我想为你强调一下 Yoshua 和他的合作者从 381 个参赛团队中赢得机器学习比赛的一些聪明的事情。也许这些想法会对你自己的工作有用。

布鲁克·卡格尔在 Unsplash 上拍摄的照片

10 标志着一家初创公司拥有令人敬畏的工作文化

凯特·玛丽·刘易斯 — 15 分钟阅读

数据科学家需求量很大。因此,在寻找工作的公司时,你可以有点挑剔。即使你正在寻找你的第一份数据科学工作,我也要提醒你不要盲目接受你收到的第一份工作。做好功课,确保这家公司非常适合你是非常重要的。

我们的每日精选将于周一回归!如果你想在周五收到我们的 每周文摘 ,很简单!跟随 我们的刊物 然后进入你的设置,打开“接收信件”您可以在此 了解更多关于如何充分利用数据科学 的信息。

在前期制作阶段预测电影的盈利能力和风险

原文:https://towardsdatascience.com/predicting-movie-profitability-and-risk-at-the-pre-production-phase-2288505b4aec?source=collection_archive---------16-----------------------

使用机器学习预测的可变性作为风险的代理,可以帮助电影公司的高管和制片人决定是否批准一个电影项目

凯尔·史密斯Unsplash 上拍摄

好莱坞是一个年收入 100 亿美元的产业,电影从热门到票房炸弹。预测一部电影的票房会有多好是很难的,因为成功有太多的因素。编剧威廉姆·高德曼(布奇卡西迪和圣丹斯小子所有总统的男人公主新娘)对这个行业有一句名言,“没人知道任何事情。”

罗伯特·尼克森在 Unsplash 上拍摄的照片

人们已经花了很多精力来理解和预测电影的成功(例如,参见亚瑟·德·万尼的 好莱坞经济学 和卡格尔最近的票房预测挑战),目前的尝试正在使用越来越复杂的技术。我在这里的目标不是改进当前的预测算法,而是描述我设计的一个名为 ReelRisk 的模型,该模型使用随机重采样来生成一系列预测,然后可以用作风险评估工具,以尽早决定是否资助一部电影。2019 年,仅网飞就发布了 371 部新电视剧和电影。随着新内容的不断涌现,拥有像 ReelRisk 这样的工具可以帮助制作人选择何时前进或何时放弃。

电影数据和票房数字

为了建立我的预测算法,我从几个网上来源收集了电影数据。我从互联网电影数据库(IMDb)获得了大部分数据,该数据库提供了一组免费下载的文件。然而,IMDb 档案并不包含电影预算和票房收入的估计数据。为此,我从一个名为的行业网站上搜集了一些数据。为了简单起见,我将电影的范围限制在 1960 年后上映的非成丨人丨电丨影,并且只考虑美国票房收入(“国内总收入”)。

接下来,我花了相当多的时间清理数据;由于我有两个数据来源,它们之间的信息并不总是一致的。我必须根据电影名称将我的电影数据与适当的预算和票房数字相匹配。许多不匹配的标题案例可以通过删除或替换字符的算法来解决。即使在那时,一些手工清洗也是必要的(例如,最初的 1977 年星球大战电影在数字中被简单地列为星球大战,而在 IMDb 它被列为星球大战:第四集——新的希望)。

一旦两个数据集被清理和合并,我就剩下大约 4300 部电影要处理了。我拿出其中的 20%作为测试集,剩下的用于训练和验证。

特征选择和工程

我的模型的大部分输入要么是来自数据源,要么经过了最少的处理。这些是:

  • 标题(以字符为单位的长度,用作数字特征)
  • 预算(使用消费者价格指数转换为 2019 年美元)
  • 运行时间(分钟)
  • 发布日期(月份和年份被视为独立的特征)
  • 流派(23 个类别,每部电影可以有多个类别)
  • 演员(排名前四的演员的名字)
  • 导演
  • 美国电影协会分级(例如,PG-13)
  • 续作或特许经营的一部分(是/否)

我还花了大量时间来构建我自己的有用特性,以包含在我的模型中。我想到了三个:演员 starpower导演 starpower流派独特性。人们有理由认为,电影演员和导演的相对知名度将有助于电影的成功。如果一部电影以一种新颖的方式结合了几种类型(例如,黑色电影+科幻+惊悚),这也可能会激起电影观众的兴趣。下图解释了演员 starpower 的计算。

演员 starpower 的计算。对于每部电影,演员明星效应是排名前四的演员的个人明星效应的总和。根据 IMDb 的说法,每个演员的明星效应是 IMDb 用户对该演员前四部“知名”电影的平均评分之和。

导演星光值的计算类似于单个演员的星光值。

流派独特性是衡量一部电影的流派类别组合相对于我的数据集中所有电影的独特程度。

这里的“log”用于创建一个更正态分布的数量,同时确保更多独特的类型具有更大的正值。

最后,我有 38 个特征,其中大部分是分类的和一次性编码的。选择和设计特征的过程既费力又重要,因为任何模型的成功都在很大程度上取决于输入数据的数量和质量(回想一下:“垃圾进,垃圾出!”).

构建预测电影盈利能力的模型

在这里,我将盈利能力作为衡量一部电影成功的标准,并将盈利能力定义为投资回报率(ROI)。投资回报率就是电影票房收入占预算的比例(即投资回报率=利润/预算)。由于投资回报率的极端值在电影中相当常见(包括巨大的成功和重大的失败),而且范围很大,所以我打算预测的目标变量是 log(投资回报率+ 1)。

我使用 XGBoost 作为我的回归模型,因为我发现当使用均方根误差(RMSE)作为品质度量时,它稍微优于随机森林回归。我使用了 5 重交叉验证来调优 XGBoost 模型的几个超参数,包括树的数量、每棵树的最大深度和学习速率。下面是单个 XGBoost 模型对 80%的数据进行训练并对未知的 20%进行测试的结果。

保留测试集的预测 ROI 与真实 ROI 的散点图。实线表示用于比较的 y=x 线。该模型表现相当好,但有很多分散,特别是在分布的极端。

散点图证明了预测电影的成功确实很难!从单个模型输出的 ROI 的单个预测是不太可信的。但是,使用训练数据的随机子样本创建 ROI 预测的分布可以给出预测的可变性,作为投资电影所涉及的风险的代理(这本质上也是刀切和引导重采样背后的想法)。给定我的完整训练集 N 个样本,我生成了 500 个子样本,每个子样本的大小为 N /2,每个子样本都是从完整的 N 集中随机抽取的。值 500 和 N /2 在某种程度上是任意的,但是选择它们是为了获得 ROI 值的平滑分布,并且平衡对预测中足够可变性的期望与为每个模型保持足够大的训练集的需要。我在这 500 个随机子样本上训练了 500 个模型,并建立了 ROI 值的分布,从中我可以提取汇总统计数据,如中值和 95%的置信区间。我的建模过程的示意图如下所示。

概述 ReelRisk 背后的建模流程的图表。

ReelRisk:电影制作的风险评估工具

下面是我开发的 web 应用程序 ReelRisk 的输入页面截图,该应用程序帮助电影公司高管和制片人评估资助拟议电影项目所涉及的风险。

ReelRisk 的输入页面。用户可以输入关于提议的电影项目的信息,并接收关于项目风险的报告。

在这里,用户可以输入关于提议的电影的信息(估计的预算和运行时间,他们想要签约的潜在演员,等等。)甚至设定自己的风险承受能力。例如,该页面预先填充了 1990 年成功的电影《虎胆龙威 2》的信息。单击绿色按钮后,用户将被重定向到结果页面,该页面给出了模型的建议操作过程以及一些分析:

《虎胆龙威 2》的 ReelRisk 结果。鉴于用户设定的风险承受能力,我们建议投资这部电影,因为 95%的投资回报率预测都在 24% — 158%之间(平均投资回报率为 82%)!

结果中显示的蓝色直方图是来自我的预训练 XGBoost 模型的 500 个 ROI 预测的分布。绿色阴影区域表示正利润(ROI > 0%),而灰色区域表示亏损。几乎所有对《虎胆龙威 2》的投资回报预测都在“利润”范围内,所以建议是这个项目是“可靠的”,你应该投资这部电影!风险容忍度设置允许用户选择 ROI 预测的百分比可以落在“损失”范围内,同时仍然将电影评估为“可靠”投资。不被视为“可靠”投资的电影被标记为“高风险”,下面显示了每种投资的示例分布以供比较:

比较一个“可靠”的项目(虎胆龙威 2,一个重大的成功)和一个“危险”的项目(但丁的巅峰,一个失败)。前者的大部分预测位于盈利区域,而后者的大部分预测位于亏损区域。

我想指出,我预测投资回报率和投资回报率不确定性的技术是为了补充而不是取代创造性的决策过程。该方法也可以应用于其他领域的风险管理。

警告和改进

电影制作是一项庞大而复杂的合作事业,因此有些特征很难量化。对我的模型的一个改进是加入捕捉电影情节的特征,例如,使用自然语言处理(NLP)来提取主题或情感,并将它们编码为数字向量。

我设计的 starpower 功能是对演员或导演受欢迎程度的粗略估计;一个更严格的算法将通过只允许在给定电影 i 之前上映的电影被包括在电影 i 的计算中来确保没有数据泄露。票房收入可能也是比 IMDb 用户平均评分更具体的成功衡量标准。一个更复杂但更有见地的算法是对演员/导演的网络分析,利用他们以前合作的成功来计算他们的联系强度(如 Lash &赵在本文中所做的)。即便如此,也没有演员“受欢迎程度”的硬性衡量标准,也没有电影“成功”的绝对知识——这也是造成这一点如此困难的部分原因!如今其他令人困惑的变量是通过点播流媒体平台发行的电影(如何衡量它们的盈利能力?)以及营销的效果,尤其是通过社交媒体进行的电影推广(如何量化病毒式视频或模因的效果?)。

另一个潜在的改进将是从许多不同的算法(即,从 XGBoost、随机森林、神经网络等的预测的某种加权平均)创建集合模型。).这可以更准确地描述预测的可变性。

我在担任 洞察数据科学研究员 期间,建立了reel risk*作为一个为期 4 周的项目。Insight 计划让拥有各种定量领域博士学位的人做好准备,帮助他们在行业中从事数据科学工作。*

预测电影的美国电影协会评分

原文:https://towardsdatascience.com/predicting-mpaa-ratings-for-movies-47fb85970bd4?source=collection_archive---------46-----------------------

利用 KNN 预测年龄分级使用 IMDb 评论和票房收入

除了回归,分类是监督机器学习中最常见的任务之一。分类是将事物分类的任务。例如,将图像分为狗和猫的图像,标记 x 射线是否有骨折,以及更具争议的是,某人是否会偿还贷款。

按照这个教程,你可以用这个 Colab 笔记本:
https://Colab . research . Google . com/drive/1 xzibt _ y 4 be 22k 7 D1 btfakd 6-ax 8d dbxb?usp =分享

请观看这段 4 分钟的视频:

在大多数情况下,分类是通过在数据点之间绘制决策边界来完成的。例如,在这个图中,我们可以画一个这样的决策边界来分隔 x 和 Os。如果一个点在这条线上,我们把它归类为 X,如果它在这条线以下,我们把它归类为 o。

让我们看一个可以使用分类解决的实际问题。我们可以仅仅通过查看关于电影的两个变量来将电影划分为美国电影协会评级(即 G、PG、PG13 或 R)吗?这两个变量是:电影在 iMDB 上的观众评级和电影在全球的票房收入。换句话说,这些变量对美国电影协会评级有任何预测价值吗?

让我们在这里画出 48 电影的数据。票房收入将在 X 轴上,而 iMDB 评级将在 Y 轴上。我们将美国电影协会分级编码为从 1 到 3 的数字,1 表示 PG,3 表示 R。为了更好地显示该数据集,我们将 PG 电影着色为绿色,PG 13 电影着色为橙色,R 电影着色为红色。正如我们所看到的,使用简单的决策界限将电影分为美国电影协会等级几乎是不可能的。

输入 K-最近邻。k-最近邻或简称 KNN 是一种分类和回归方法,它基于一个简单的前提,即彼此接近的数据点往往具有相似的值或结果。例如,如果你的邻居都有车,那么你可能会认为你也有车。

从数学上来说,为了预测特定点的结果,KNN 挑选 K 个最接近该点的数据点,并对它们的结果进行平均。

例如,让我们回到我们的电影数据集,选择一部我们想要预测其美国电影协会评分的电影。《重磅炸弹》是 2019 年的一部电视剧,讲述了福克斯新闻频道的三名女性着手揭露该网络首席执行官的性骚扰行为。当然,了解这一背景提供了关于电影分级的有价值的信息,但是假设我们只有这两条关于电影的信息。

在我们做出任何预测之前,让我们后退一步,看看我们的坐标轴。因为 KNN 依赖于点与点之间的欧几里得距离,这个过程的一个重要步骤是确保我们的轴被适当地缩放。我们希望垂直距离和水平距离一样重要。在我们的电影示例中,我们放大了 IMDB,缩小了票房收入,这样两个轴的范围都是大约 50 个点。每次使用 KNN 时,缩放坐标轴是非常重要的。

data["IMDB2"] = data["IMDB"]*10data["Box Office2"]=data["Box Office"]/(0.8*10**7)X =  data[["IMDB2","Box Office2"]].valuesy = np.expand_dims(data["MPAA"].values,1)train_split = 40knn = KNeighborsClassifier(5, weights='distance')knn.fit(X[:train_split],y[:train_split])

正如我们在 X 轴上看到的,它在 iMDB 上获得了 6.8 的收视率,在 Y 轴上我们看到它的票房收入接近 600 亿美元。KNN 将寻找 K 个最近的邻居,在我们的例子中我们选择 K 为 5,但这可以根据需要调高或调低。最接近的 5 部电影是 R 级的《长镜头》和《午夜梦回》,PG13 级的《朱迪》和《哈里特》,G 级的《邻居的美好一天》。然后,KNN 将对这 5 个美国电影协会评分进行加权平均,在图表中,距离“重磅炸弹”较近的电影比距离较远的电影权重更大。瞧啊。我们预测“Bombshell”的评级为 r。这不仅准确,而且我们的模型还在几乎 88%的时间内正确预测了测试集中所有电影的美国电影协会评级!

movie = 'Bombshell'dist,neighbors = knn.kneighbors(data[data['Title']==movie][["IMDB2","Box Office2"]])prediction = knn.predict( data[data['Title']==movie][["IMDB2","Box Office2"]])[0]

这就对了。KNN 是另一个简单的机器学习模型,在复杂的问题上效果惊人。在评论中让我们知道你打算把这个算法应用到什么样的问题上!

快乐学习!

在新冠肺炎疫苗研究中使用 GNNs 和 RNNs 预测 mRNA 降解

原文:https://towardsdatascience.com/predicting-mrna-degradation-using-gnns-and-rnns-in-the-search-for-a-covid-19-vaccine-b3070d20b2e5?source=collection_archive---------28-----------------------

关于 Kaggle OpenVaccine 竞赛第四名解决方案的报道

当前的新冠肺炎疫情需要一种有效的疫苗来赢得与这种病毒的斗争。斯坦福大学的研究人员正在研究 mRNA 疫苗,因为这可能很快提供一种候选解决方案。这些类型的疫苗面临的一个挑战是它们的稳定性:除非保存在强烈的冷藏条件下,否则它们往往会自发降解。为了找到稳定的 mRNA 序列,来自斯坦福大学的人们在 OpenVaccine:新冠肺炎 mRNA 疫苗降解预测比赛中联系了 Kaggle 社区。比赛于 9 月 11 日开始,仅持续了 26 天,由于时间紧迫,这对 Kaggle 来说是不寻常的短。前三名竞争者有 25,000 美元的奖金。Bram SteenwinckelMichele Tinti我和能够达到第四的位置,在金钱上差了一英寸!希望我们能在新冠肺炎疫苗的研究中尽绵薄之力,我们发布了这篇讨论我们解决方案的博文。

我们的团队“来自鞋店&染坊&石店”获得了第四名!我们的团队名由我们的姓组成,这些姓是从我们的母语(荷兰语和意大利语)翻译成英语的。此图为 Kaggle 排行榜截图。

问题陈述

该竞赛的目标是预测提供的 RNA 序列中每种碱基(A、C、G 或 U)在某些情况下的反应性和降解,例如在高温或高 pH 下有或没有镁的情况下温育。总之,我们必须预测序列中每种碱基的三个连续值(即回归)(即序列对序列)。

训练集由 2400 个长度为 107 的序列组成,公共测试集包含 629 个长度为 107 的序列,私有测试集由 3005 个长度为 130 的序列组成。因此,私人测试数据中的序列长度存在差异。因此,模型对序列长度具有内在的不变性是非常重要的。此外,序列仅被部分评分。对于训练和公共测试集,只有 107 个碱基中的前 68 个被评分,而对于私有测试集,130 个碱基中的前 91 个被评分。下面提供了一个训练序列的目标的例子:

一个训练序列的目标值的时间序列。图片作者。

我们也可以在 RNA 序列图上直接显示这些目标值,就像在下面的例子中对反应性所做的那样:

RNA 序列可能的折叠之一。节点颜色描述了反应性值(红色=高,蓝色=低)。请注意,107–68 节点没有着色,因为没有为序列的尾部指定目标。图片作者。

高级解决方案概述

通过查看目标,可以清楚地看到,某个值与其在时间序列中的相邻值相关联。递归神经网络非常适合这种情况,因为它们的内置内存会考虑附近的预测值。我们学习序列中每个碱基的表示,并通过 2 个(双向)RNN 层。通过使用节点本身的信息和关系或边信息来学习每个节点的表示。从引言中可以看出,RNA 序列可以用图表来表示,并且序列中某些碱基之间的关系是存在的。我们使用图层来聚集这种关系信息。我们的最终解决方案由 4 个不同的模型组成,其中我们改变了 RNN 层(LSTM+LSTM,LSTM+GRU,GRU+LSTM 和 GRU+GRU)。这个高层次的概述忽略了一些细节。一个重要的细节是,我们预先训练网络,直到 RNN 层作为自动编码器。这使得我们也可以在未标记的测试数据上进行训练。

我们解决方案的高级概述。图片作者。

阿尼生成额外信息

ARNIE 是一个软件包,包含 6 个不同的库,可用于为每个序列生成额外的信息:

对于提供的 RNA 序列,ARNIE 能够计算碱基配对概率(BPP)矩阵。基于该 BPP,可以预测潜在的结构,并且从这些结构中,可以推断序列中每个碱基的环类型。

我们在 ARNIE 中使用不同的库来生成额外的信息。这通常需要一点 bash 魔法来安装所有的东西。我们提供了一个笔记本来演示如何生成这些信息。我们对所有 6 个文库进行了实验,但只发现 CONTRAfold 是最有用的,其次是 RNAsoft、RNAstructure 和 Vienna。

节点特征

从我们的高级概述中,我们可以看到我们的网络需要两种类型的输入:节点信息和边缘信息。节点信息是一个NxLxV矩阵,其中N是 RNA 序列的数量,L是序列的长度,V是每个节点的特征数量。我们总共使用V=25功能:

  • 一次热编码底座(‘A’、‘G’、‘C’或‘U’)(4 个特征)
  • 单热编码循环类型(提供:' S ':成对茎,' M ':多循环,' I ':内部循环,' B ':凸出,' H ':发夹循环,' E ':悬空端或' X ':外部循环)(7 个特征)
  • 一次热编码位置特征(索引% 3) (3 个特征)
  • ****确定性:预测(). (3 个特征)的包的分数(3 个不同的包:Vienna、CONTRAfold 和 RNAstructure)。
  • ****CapR 循环类型概率(6 个特征)
  • BPP 零和数(2 个特征)

边缘特征

NxLxLxE矩阵中捕获边缘信息,其中N是 RNA 序列的数量,L是序列的长度,E是边缘特征的数量。总的来说,每条边都有E=5个特征:

  • 3 个不同的bpp:提供的,用 RNAsoft (ARNIE)生成的,用 contrafold (ARNIE)生成的
  • 结构(())中是否有指示的碱基配对****
  • 碱基之间的距离(曼哈顿),通过序列长度标准化

模型

我们的作品改编自 mrmakr 的《T7》。一定要给那个笔记本一个向上的投票!我们确实对原始笔记本做了一些修改:

  • 修正了网络分类部分的损失函数。
  • 改变了自动编码器的损失函数,它是为二进制表示而定制的(它是二进制交叉熵的变体)。我们简单地使用重建损失/MAE (|y — y_hat|)。
  • 在编码器后增加了两个 RNN 层。正如比赛期间所展示的那样(由 @tuckerarrants 和其他人),混合 GRU+GRU、LSTM+GRU、GRU+LSTM 和 LSTM+LSTM 的模式会产生轻微的推动作用。我们为这 4 个组合中的每一个生成了 10 倍 CV 的模型(总共 40 个模型),并以统一的权重混合这些模型。
  • 调整了一些超参数。AE 的时代,分类部分,GCN 层中的单元数,…
  • 添加补充数据,来自 @its7171 制作的笔记本
  • 对所有样本进行训练,但是基于它们的信噪比使用不同的样本权重。为此再次向 @its7171 喊出!仅对 SN_filter=1 的数据执行评估。因为我们预计私人银行也会这么做。)

不起作用的事情

我们尝试了很多不奏效的方法:

  • 我们得到了所有 RNA 的 3D 折叠,并计算了 RNA 碱基之间的 3D(欧几里德)距离。我们还尝试使用角度信息(装箱,然后分类编码):这提高了我们简单的 LSTM 架构,但恶化了 AE+LSTM 的性能。这些功能肯定有一些潜力,但它们需要一些更彻底的实验。允许这种实验的数据集可以在找到。
  • 许多提供一些 RNA 特征的软件包信息不多。其中一些包括 RNAup,Shaker,MXFold,…
  • 本文中讨论的所有光谱表示法。
  • 更丰富的图形表示(例如,包括氨基酸信息)
  • 熵特征
  • 原子信息

总结词

我真的很喜欢这场比赛。我特别喜欢它只持续了相当短的一段时间。在整个比赛过程中,这是一场公共排行榜上不分上下的比赛。压力很大,但是很有趣!这种“闪电战”比赛或许可以被卡格尔认为是一种独立的形式?

虽然我们刚刚错过了奖金(1 个位置),但我们仍然为我们的结果感到非常自豪!有了这个结果,我的两个队友:布拉姆米歇尔也成为了 Kaggle 比赛高手。因此,向他们表示热烈祝贺!

我们在 KaggleGithub 上都提供了我们解决方案的代码。

像往常一样,如果有任何不清楚的地方或者需要更多的解释:不要犹豫,留下你的评论或者联系我!

请关注这篇文章,因为它可能会在不久的将来收到一些更新!

下次比赛再见!吉勒、布拉姆和米歇尔

第 2/3 部分——预测我的半程马拉松完成时间,误差小于 45 秒。

原文:https://towardsdatascience.com/predicting-my-half-marathon-finish-time-with-less-than-45-seconds-error-part-two-9cf6bb930e79?source=collection_archive---------38-----------------------

跑步的机器学习。特征工程和傲慢分析。

照片由mārtiņš·泽姆利克斯Unsplash 上拍摄

这是结束时间预测系列的第 2 部分:

在这篇文章中,我们将深入研究速度分析,看看我们是否能进一步了解跑步者。

让我们从停止的地方开始:

配速变化——完成时间与年龄

为每位跑步者单独计算的五个不同检查点的跑步配速标准偏差。越暗意味着速度越不均衡。每个跑步者一圈。

因为这个标准差是为每个跑步者单独计算的,所以它给出了你相对于自己的配速变化的合理值。很明显,保持匀速是有利的。

那个绿色十字架?这就是我,虽然我可以变得更年轻,但通过在图表上进一步向右移动,肯定还有改进的空间。当你能在数据中找到自己,并学习如何改进时,做这样的分析特别有趣。

让我们进一步看看跑步者如何改变他们的速度,以及男性、女性和不同年龄组之间是否存在差异:

按性别划分的平均配速概况

每次分段的配速曲线,计算为每次分段的配速与跑步者全程配速之间的百分比差异。女性的步伐比男性稍微平稳一些。

先前关于马拉松配速性别差异的研究显示,男性比女性更高估自己。然而,上图中显示的结果并不像 J.Hubble 和 J.Zhao 提出的那样显著。这与对卢布尔雅那马拉松和半程马拉松完成时间的研究相一致——半程马拉松的性别差异不如普通马拉松显著。

狂妄分析

高估是什么意思?

今天的研究表明,将高估定义为整个比赛中的配速损失是正确的吗?很可能,但我会建议另一个度量标准,它可能会提供一些更深入的见解,并且更适用于我们的机器学习模型: hubris

让我们将自大定义为跑步者相对于初始配速(前 5 公里)的配速损失。

按性别分列的相对于开始配速的配速差异百分比

某一段的配速与第一段配速之间的百分比差异。例如,在 10-15 公里之间,男性和女性的平均配速比前 5 公里慢了 8%。

事实上,在比赛的后半段,男性似乎比女性更容易疲劳,但女性在 5-10 公里和 10-15 公里之间的配速比开始时下降更多。哪个性别最狂妄?

如果我们看一下个人的差异,很明显,女性在比赛的早期阶段最傲慢。然而,如果我们从整体上考虑这个情节,它可能暗示:

  • 男子更努力地保持他们的起跑速度,但在比赛的后期速度会大大降低。
  • 女性在意识到自己开得太快后,会比男性慢下来更多——从而导致更稳定的步伐。

让我们看看年龄组是否显示出同样的效果:

相对于起始配速的百分比配速差

百分比差异(如上计算,但按年龄组计算)。年轻和年老的跑步者最狂妄自大。

这里也可以看到类似的效果,但只是在比赛的最后一公里。

因为我们无法观察到在比赛前半段和后半段对不同年龄组的男女运动员产生的相同影响,所以速度调整的影响似乎是性别特异性的。

请记住,这些是独立的性别和年龄组的平均值,虽然男性通常比女性更高估自己,但对于特定的性别和年龄组组合来说并不一定如此。

作为一个简化的衡量自大的单一指标,我们计算了相对于前 5 公里,在 5 公里和 20 公里之间的平均配速损失。

与初始配速相比,5-20 公里的平均配速损失

5-20 公里的平均狂妄自大。很明显,对于这个种族来说,在比较年龄和性别群体时,年龄更为重要。性别之间的差异几乎不明显。

我们为什么要这么做?

我们试图理解指标之间相互作用的内容、原因和方式。这有助于我们创建数据的数学概念,以更好地预测特定跑步者的终点时间。

傲慢与完成时间

狂妄与采样点的完成时间(30 000)。图例显示与完成时间的相关性。

在现实世界中,我们不知道跑步者的速度,直到他/她通过一个检查站。假设一名跑步者的步速在 10 到 15 公里之间,相当于第一段路程的步速(5 公里)。虽然我们不知道该运动员在剩余比赛中的表现,但统计数据告诉我们,平均而言,该运动员将比其他运动员有更好的完成时间。

具有更深层含义的功能

根据他们的年龄和起跑组的平均完成时间来估计跑步者的完成时间是相对直接的。这样做的问题是,你要预测所有年龄相同的跑步者,并在相同的结束时间开始跑步。因此,这是而不是我们要做的。

相反,我们将创建一个专注于个人跑步者的机器学习模型。这种模式的特征可以概念化为两组:一般 & 特定特征。

一个一般特征例如是跑步者的性别、年龄、起跑组别或第一棒的速度。对我来说,这些价值是:

  • 性别:
  • 年龄: 28
  • 开始组: 5
  • 配速(5 公里): 4 分 40 秒

一个特定的特征例如是一个跑步者在 10 公里后的狂妄自大,相对于其他跑步者的狂妄自大。特定功能的强大之处在于,我们可以将它们折叠成任何桶型——我们可以根据年龄组或开始组,或者两者都有。作为一个例子,让我们看看我相对于我的年龄组开始组性别,以及开始组和年龄组的组合的狂妄程度:

作者的一些狂妄自大相关的功能示例。

Oskar 与四个不同示例时段的百分比绝对差异。奥斯卡比其他和他相似的跑步者更少傲慢。这使得奥斯卡的完成时间比同类跑步者的平均时间更短。耶!

在第 1 部分中,我们主要看了一般特性,而这一部分应该让您对具体特性有所了解。特定的功能用比以前更多的信息丰富了我们的数据。机器学习算法可以在训练期间利用这些额外的数据来建立更准确的模型。

这些功能是干什么用的?

想象一下,我们在多维空间中有几个点,其中除了一个维度之外的每个维度都代表一个特征。最后一个维度代表我们的目标预测—完成时间。每个点都对应于其在空间中的坐标,因此一个点是其所有可能特征的值的表示。这是我们的训练数据。我们可以根据这些点拟合一个模型(可以是一个多维函数),并使用得到的模型对我们知道其特征值的新的、未知的数据进行预测。

这在三维以上是很难考虑的,所以这里有一个二维的例子——使用开始组作为我们的特征,完成时间作为我们的目标值:

简单示例模型—开始组

针对目标变量完成时间,用单个特征 拟合简单模型(二阶多项式)

这种模式不会做得很好。为了获得更好的预测,它需要更好的算法来拟合这些点,更多的例子来学习,或者额外的特征。改变我们使用的函数不会有很大帮助,因为每个起始组的方差都很高。我们可以做的是增加更多的功能——维度——并使用类似的算法(但在更高维度)。

幸运的是,我们现在碰巧有大量的特征,我们的一般和我们的特定特征,我们可以将它们放入多维空间并拟合一个模型。

当您考虑到您需要在真实的生活场景中执行预测时,一个有趣的挑战就显现出来了:在跑步者开始跑步之前,我们不能使用特定的功能。因此,赛前预测只能基于一般特征。当跑步者在比赛中前进时,可以使用特定的特征,这将极大地改进完成时间的预测。

接下来是第 3 部分,包括模型训练、性能分析和一些示例预测。该模型设法在比赛开始前 30 秒内预测我的完成时间(仅一般特征),并随着比赛的进行而变得更好(当它可以包括具体特征时)。

继续阅读:

预测 NBA 胜率

原文:https://towardsdatascience.com/predicting-nba-win-percentage-84148ae8d3e6?source=collection_archive---------27-----------------------

我如何建立一个多元回归模型,在给定当前每场比赛统计数据的情况下,预测一支球队的最终胜率

克里斯蒂安·门多萨在 Unsplash 上拍摄的照片

作为一个篮球迷和体育迷,我想在我的数据科学训练营期间,我会选择处理大量的体育数据,因为每项运动都涉及大量的统计数据——我是对的。在了解了回归之后,我立刻感觉到使用体育数据对我的项目来说是完美的。由于我的合作伙伴拉斐尔也是一名 NBA 球迷,我们决定走这条分析路线,建立一个多元回归模型。我们的目标是能够根据球队每场比赛的平均数据来预测球队最终的常规赛胜率。

我们是这样做的:

数据

由于统计学在当今体育中的重要性,我们能够在 stats.nba.com 找到 NBA 官方统计数据。使用 Selenium 我们从 1996 年到 2019 年的每个赛季为每个球队搜集了每场比赛的统计数据。在一些数据清理之后,我们创建了下面的数据框架:

创建的数据帧片段(未显示所有列和行)

最终,由于它们分布的形状或它们的 OLS p 值(我将在下面进一步解释),我们结束了使用 NumPy 对一些变量运行对数(log)变换。所有的变量,包括那些经过对数变换的变量,都被归一化,这样,考虑到统计数据之间的差异,它们都在相同的范围内。

总而言之:

1996-2019 年 NBA 基本统计数据

特点:胜率(Win_Percent)、得分(PTS)、投篮命中率(FGM)、投篮命中率(FGA)、投篮命中率(FG_Percent)、三分球命中率(Three_PM)、三分球命中率(Three_PA)、三分球命中率(Three_P_Percent)、罚球命中率(FTM)、罚球命中率(FTA)、进攻篮板(OREB)、防守篮板(DREB)、篮板总数(REB)、助攻(AST)、失误(TOV)、抢断(STL)、盖帽(BLK)

我们最终没有使用这些特征:胜(W)、负(L)、分(MIN)、个人犯规(PFD)和+/–*(加号 _ 减号)

探索性数据分析

1。我们抓取的所有特征的关联热图:

2。带有变量分布形状直方图的散点图—正态分布与非正态分布(图表的一小部分):

正如我们从上图中看到的,一些特征具有偏斜分布。这可能是因为篮球领域最近的趋势,即自 2014 年以来三分球的大幅增加,因此对数转换可能是必要的。

使用普通最小二乘(OLS)表创建模型

1.首先,在进行任何转换之前,对所有变量创建一个 OLS 回归表

2.随后创建了一个 OLS 表,其中每个变量都经过了日志转换

3.最后,制作了一个 OLS 表,仅对数转换那些在对数转换时具有较低 p 值的变量

参见下面的上述步骤:

4.初始细化:

  • 移除了具有高 p 值的变量
  • R = 0.844
  • 检查变量之间的(其中 方差膨胀因子 大于 5)

5.第二次提炼:

  • 从每个多共线性对中移除一个变量,并再次运行 OLS
  • R = 0.558
  • p 值都远低于α = 0.05
  • 变量之间似乎不再存在多重共线性
  • p(f-统计量)= 6.88 e-⁰⁷;我们可以得出结论这个模型比仅拦截模型更适合

评估优化模型

  1. 用 Q-Q 图检查正态分布:
  • 数据点应该在对角线上

2。检查了 同方差 与误差项的散点图:

  • 数据点应该是随机的/没有模式

测试模型

在对模型执行 Scikit-Learn 的 训练-测试分割 之后,我们确定不需要 正则化 ,因为非正则化线性回归很好——训练模型的误差和测试模型的误差之间的差异非常小。

最终模型

R = 0.558

均方误差 (MSE) = 0.0108

WIN % = 0.5000–0.0330 ln(PTS)+0.0587(FTM)+0.0186 ln(OREB)+0.0543 ln(DREB)+0.0376 ln(AST)-0.0480(TOV)+0.0408(STL)+0.0186 ln(BLK)-0.0639 ln(BLKA)-0.0107(PF)

从上面的最终模型中,我们可以看到哪些篮球统计数据在最终决定一个球队将赢得多少场比赛中起着潜在的重要作用。毫无疑问,最终模型中没有包括的类别仍然非常重要。此外,当你认为你希望它们是正的时候,方程中的一些变量却是负的,这看起来很奇怪。这些情况可能会受到积极变量的影响。

虽然我们可能无法了解 NBA 篮球目前在世界各地发生的事件,但我希望这能为你提供一点你非常想念的运动。如果你认为自己是一个赌徒,也许现在就试一试,看看我们的模型在常规赛结束时有多准确。

如果你有兴趣看我项目的完整代码,可以在我的 GitHub 上查看一下!

使用时间序列分析(ARIMA 模型)预测 Covid19 死亡人数

原文:https://towardsdatascience.com/predicting-number-of-covid19-deaths-using-time-series-analysis-arima-model-4ad92c48b3ae?source=collection_archive---------8-----------------------

执行摘要:

2020 年 3 月 11 日,世界卫生组织(世卫组织)宣布新型冠状病毒(Covid19)爆发为全球疫情。本文对预测美国从 8 月 1 日—8 月 21 日和 8 月 1 日—11 月 1 日开始的死亡人数的时间序列分析进行了建模和研究。用于预测的时间序列模型称为自回归综合移动平均(ARIMA)模型。

本文分为以下几个部分:

  1. 为什么&什么是时间序列分析
  2. 当我们不能使用时间序列分析时
  3. 时间序列分析的组成部分
  4. 时间序列分析演示
  5. 结论

[## 冠状病毒(新冠肺炎)死亡-统计和研究

关于已确认的死亡数字,有三点需要记住:这三点对所有目前可用的数据都是真实的…

ourworldindata.org](https://ourworldindata.org/covid-deaths)

这些数据来自于数据中的我们的世界,包括进行时间序列分析的必要信息。与回答我们的研究问题相关的变量是日期(2019/12/31–2020–08/01)、总死亡人数、新死亡人数和地点(美国)。数据已经过清理和调整,以满足使用 ARIMA 进行预测的所有必要假设。

未来 21 天和 90 天的新增死亡人数预测分别达到 18,589 人(总死亡人数 171,903 人)和 82,653 人(总死亡人数 235,967 人)。与 CNN 的预测相比,我们的预测结果非常接近。美国有线电视新闻网(CNN 月 2 日预测,8 月 2 日至 8 月 21 日期间,美国可能有约 1.9 万人死亡。除了这一预测,他们还在 7 月 31 日的节目“CNN 冠状病毒市政厅”中预测了 11 月份的死亡总人数。美国有线电视新闻网预测,到 11 月,Covid19 将导致 231,000 人死亡。与 CNN 的预测相比,我们的 ARIMA 模型的结果非常接近。

结果:

作者图片

1.为什么&什么是时间序列分析:

时间序列分析(TSA)是一种统计技术,由按时间顺序排列的数据点组成。x 轴由等间距的时间点组成,y 轴包含根据之前的观察值从我们的模型中预测的结果值。这种技术适用于研究问题,如预测未来销售。时间序列分析之所以存在,是由于我们模型中的结果变量只依赖于一个解释变量: 时间

假设你经营一家鞋店,并且有数据告诉你在过去的几年里你卖出了多少双鞋。给定可用的数据,如果您想预测您的商店未来将销售多少鞋子,时间序列分析将是适用的。在这种情况下,结果变量是售出的鞋子数量,唯一的解释变量是时间。

其他预测算法,如线性回归或逻辑回归,使用一个或多个解释变量。此外,当比较线性回归、逻辑回归和时间序列技术 ARIMA 时,在假设方面存在差异。

线性回归中,必须满足以下假设:

  • 观察的独立性。
  • 误差的同方差性(等方差)。
  • 线性关系。
  • 误差呈正态分布。

逻辑回归中,必须满足以下假设:

  • 因变量必须为二进制。
  • 观察的独立性。
  • 连续变量 logit 中的线性。
  • 缺乏有影响力的离群值
  • 多重共线性缺失

时间序列分析 ARIMA 中,必须满足以下假设:

  • 数据必须是静态的。
  • 数据应该是单变量的。如上所述,美国运输安全管理局 ARIMA 只对单一变量起作用。
  • 数据应该是时间序列数据格式。

2.什么时候可以不用时间序列分析:

有时候时间序列分析并不是回答一个研究问题的最佳统计技术。有 3 点使这种技术不适合。

a.当数据点总是不变时。

作者图片

x 轴上等距分布的点代表唯一的变量时间,y 值代表结果变量。在一段时间内有恒定的数据点确实使得这种统计技术没有真正的用处。再次考虑鞋店的例子。如果我们在所有月份中销售相同数量的鞋,那么进行时间序列分析来预测未来的销售是没有意义的,因为预测的结果总是相同的。

b.当数据点代表一个已知函数时。

作者图片

在上图中,我们看到了 sin(x)函数。如果我们给这个函数加上一个值,就可以很容易地计算出预测的结果。没有必要使用时间序列分析技术,因为我们只需将预测值代入 sin(x)函数就可以计算出预测值。这适用于所有其他函数,如 cos(x)等。因此,如果我们的数据点图看起来像一个函数,那么时间序列分析就不适用。

c.当我们的数据不稳定时。

如上所述,时间序列分析(ARIMA)的一个假设是数据必须是平稳的。为了获得稳定的数据,必须满足以下条件:

  • 平均值必须是随时间变化的常数。
  • 方差必须在不同的时间间隔内与平均值相等。换句话说,这些点的距离应该与平均值相同。
  • 协方差也必须相等。

作者图片

上图显示了 1 月至 8 月 1 日因 Covid19 导致的死亡人数。红线显示平均值,正如我们在上面看到的,平均值在不断增加。首先,我们可以看到平均值不是恒定的,因此数据违反了在整个时间内平均值恒定的假设。其次,我们也看到方差不相等。正如我们在上面看到的,点和中线之间的距离变化很大。考虑一下 4 月中旬和 5 月的点数峰值。我们可以清楚地看到,从数据点到平均值的距离并不相同。因此,数据不仅违反了等均值假设,也违反了等方差假设。

3.时间序列分析的组成部分:

说到时间序列分析,我们需要理解三个组成部分。

a.一般趋势

作者图片

b.季节性

在进行时间序列分析时,季节性起着很大的作用。季节性的一个例子是当你看到我们的数据点出现峰值时。假设你有一整年的航空旅客的数据。该图的数据点显示,由于圣诞节假期,12 月份的峰值较大。另一方面,我们可能会在 2020 年 3 月和 4 月看到大幅下降,Covid19 刚刚开始传播。这将导致航空旅客数量的大幅下降。

c.不规则波动

这个部分被称为时间序列分析的随机部分。不规则波动是不受控制的情况,其中 y 值会发生变化。在航空旅客的例子中,由于天气条件(如暴风雨)导致的航班取消会导致航空旅客数量的减少。由于风暴导致的航班取消就是 y 值受到影响的不可控情况的一个例子。这并不一定意味着明年同一时间会有一场风暴。这就是随机效应产生的原因。

4.时间序列分析演示

研究问题:8 月 1 日—8 月 21 日和 8 月 1 日—11 月 1 日,美国将有多少人因 Covid19 死亡。我们准备用时间序列分析来回答这个问题。特别是,我们将使用 ARIMA 模型。时间序列分析是回答这个问题的完美的统计技术,因为我们要预测有多少人会不幸地死于 Covid19 这种疾病。

数据来源:数据中的我们的世界

数据由 34,033 行和 34 列组成。下面是数据中的变量列表。

作者图片

收集方法:观察值

数据定义:为了解决研究问题,我们必须清理数据并提取相关变量,以帮助我们进行时间序列分析。我们创建了一个数据框,由日期(2019/12/31–2020–08/01)、总死亡人数、新死亡人数和地点(美国)组成。

【日期】 变量:表示我们将用于分析的日期。幸运的是,日期列的类已经是 date。如果日期列不是日期,我们就必须将该类转换为日期。

【total _ deaths】变量:代表美国 Covid19 死亡总人数。这个变量的类是数字的。

【new _ deaths】变量:代表美国每天 Covid19 死亡人数。这个变量的类是数字的。

【位置】 变量:代表国家的名称。这个变量的类别是因子。

数据岗数据清理汇总:

Index
Min. :2019-12-31 
1st Qu.:2020-02-22 
Median :2020-04-16 
Mean :2020-04-16 
3rd Qu.:2020-06-08 
Max. :2020-08-01

dat_demoMin. : 0.0 
1st Qu.: 0.0 
Median : 500.0 
Mean : 713.1 
3rd Qu.:1167.0 
Max. :4928.0

在查看我们的数据汇总时,可以看到我们的时间序列指数从 2019/12/08 开始,到 2020/08/01 结束。此外,我们可以看到,美国每天的平均死亡人数为 713 人。4 月 16 日死亡人数最多时达到 4928 人。

时间序列分析:

在对我们的数据进行时间序列分析时,我们首先使用 zoo 库创建了日期序列,这是一个众所周知的 R 包,涉及到这种特殊的统计技术。之后,我们检查我们的数据是否不违反任何时间序列分析的假设。我们必须确保数据是稳定的。换句话说,它需要在不同的时间间隔内具有相等的均值、方差和协方差。

作者图片

如上所述,上图显示我们没有稳定的数据。红线,也就是平均线,正在增加。方差也不是常数,因为数据点和中线之间的距离在 x 轴上是变化的。因此,我们必须将数据转换为静态数据。

根据数据的不同,有不同的技术使数据稳定。对数等数据转换有助于稳定时间序列分析的方差。另一方面,差分可以帮助稳定平均值。每个数据集都有自己的需求,在我们的数据上,我们只是使用差异。差分是指计算连续观测值之间的差异。一旦我们对我们的数据应用了差分,我们的数据的图形就变成了下面这样:

作者图片

发生了数据转换,我们可以在这里看到平均值是如何保持不变的。为了检查我们的数据现在是否是稳定的,我们进行了扩展的 Dickey-Fuller 测试,它告诉我们我们的数据是否是稳定的。

h0:零假设是有单位根。

H_A:另一个假设是时间序列是平稳的。

我们测试的 p 值在 0.05 的显著性水平上是 0.01。因此,我们拒绝了零假设。换句话说,我们的数据现在是静态的,我们可以继续进行分析。

下一步是进行建模。选择 ARIMA 模型进行时间序列分析。这种特定的模型根据其以前的值进行预测,它有 3 个参数。进行预测所需的参数是 p、d 和 q。在我们开始讨论如何选择正确的参数数字之前,我们首先需要了解参数的含义。

“p”:代表自动回归。自动回归指的是用过去的值来预测未来的值。“d”:代表整合。集成会考虑将用于时间序列的差异量。“q”:代表移动平均线。移动平均线是你计算不同区间的平均值。

我们选择 p、d 和 q 值的方式取决于 ACF 和 PACF 函数,它们分别代表自协方差或自相关函数和偏自相关函数。

当我们的数据不稳定时查看 ACF 图,我们得到以下结果:

作者图片

这里我们看到我们的值都超过了蓝线。目标是将值放在蓝线之下,并且它们也应该反转。现在,当我们查看稳态数据的 ACF 和 PACF 时,我们得到以下结果。

作者图片

作者图片

在 ACF 和 PCF 图中,我们现在可以看到大多数线没有超过蓝线,也有反转线。使用 acf 图时可以选择 q 值,p 值可以从 pacf 图中找到。在这两种情况下,我们都选择第一条反向线之前的数字。根据数据,您可以使用该规则并查看模型的拟合程度,也可以使用 auto.arima 函数,该函数根据 AIC 或 BIC 返回最佳模型。我们小组决定继续使用 auto.arima 函数,它返回给我们以下模型。

作者图片

auto.arima 函数选择 p=3,d=0,q=2。当应用这个模型预测未来 21 天和 90 天的死亡人数时,结果与 CNN 所做的预测非常接近。如执行摘要中所述,我们的模型预测接下来的 21 天和 90 天分别有 18,589 人(总死亡人数为 171,903 人)和 82,653 人(总死亡人数为 235,967 人)死亡。美国有线电视新闻网(CNN 月 2 日预测,在未来两周内,美国约有 19,000 人可能死亡,到 11 月份,将有 231,000 名美国人死于 Covid19。在下面的表格中,我们可以看到预测和结果的图表。请注意,图中的紫色线代表预测值。

预测图 2020/08/01–2020/08/21:

作者图片

投影图 2020/08/01–2020/10/31:

作者图片

作者图片

这个项目背后的动机是想看看我们的模型与 CNN 的模型相比会如何。下面我们看到了 CNN 发布的公告。

7 月 31 日环球市政厅秀的电视截图

作者图片

作者图片

5.结论:

基于我们的 ARIMA 模型和我们的预测,当与 CNN 的预测进行比较时,我们可以看到稍微不同但足够接近的结果。21 天预测的差异可以由 CNN 四舍五入他们的数字来解释,因为这是一个新闻标题,使读者更容易阅读。只差 19000–18589 = 411 人,非常接近。当谈到未来 90 天的预测时,我们可以看到更大的差异 235,967- 231,000 = 4,967。4967 的差额,是合理的。归根结底,没有完美的模式。正如英国著名统计学家乔治·博克斯曾经说过的那样,

“所有的模型都是错的,但有些是有用的。”

这些模型很有用,学习时间序列分析是一次很棒的经历。我确信还有更多关于这种统计技术的知识需要学习,以便更深入地了解我们如何改进我们的模型,但是没有完美的模型。看到由于疫情在不久的将来将要失去的生命数量的结果是非常令人难过的。

[## 纳维德·马辛奇作品集

我是 Navid Mashinchi,是加利福尼亚州萨克拉门托的一名数据科学家。我一直在分析领域工作…

www.navidma.com](https://www.navidma.com/)

编者按: 走向数据科学 是一份以数据科学和机器学习研究为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里

预测诗歌运动

原文:https://towardsdatascience.com/predicting-poetic-movements-51006847cc6f?source=collection_archive---------67-----------------------

对诗歌进行分析和分类,为基于内容的推荐做准备

图片由阿比伊斯上的 Unsplash

在书面媒体中,诗歌通常被认为是神秘的、轻浮的或过于小众的。因此,诗歌(甚至是知名诗人的作品)经常被大型出版商和文学网站所忽视。(诗歌的反资本主义性质在这里可能也起了作用)。GoodReads、Amazon 或 Bookish 等网站提供整本书(公平地说,包括诗集)的评级和推荐服务,但据我所知,没有任何网站或服务在个人层面上推荐诗歌。

考虑到这一点,我想知道诗歌推荐是如何工作的。一个人经常会找到一两种他们喜欢的体裁,然后搜索出来,但是诗歌中肯定有超越体裁的元素。如果有,机器学习似乎是找到它们的完美工具。在这篇文章中,我将探索诗歌的一些特征,使其成为一种独特的写作风格,并调查我将称为“运动”的四种总括体裁之间的差异。建立模型后,我可以创建一个推荐系统,它基于一个单词、多个单词或另一首诗来推荐诗歌。

数据

历史可以追溯到 1912 年,诗歌基金会是世界上最大的诗歌供应商之一,也是诗人和读者的重要资源。我从他们的网站上搜集了 4307 首诗,每首都标有流派。总共有 13 个流派,我把它们分成四个乐章:

  • 1900 年前(维多利亚和浪漫)
  • 现代(独立类别)
  • 大都会(纽约学派【第一代和第二代】,忏悔派,垮掉派,哈莱姆文艺复兴,黑人艺术运动)
  • 先锋派(意象派,布拉克山,语言诗派,客观主义者)

通过使用四个大致平衡的类别而不是最初的十三个,我能够更容易地分析和分类每一类诗歌。现代诗歌(包括流派和运动)约占数据的 29%。先锋派是诗歌数量最少的运动,约占数据的 22%。

关于刮削过程的说明

搜集过程面临着两种形式的诗歌的挑战:HTML 文本和 T2 扫描图片。我能够使用 BeautifulSoup 轻松捕捉基于文本的诗歌,但不得不依靠 PyTesseract 从扫描图像中获取诗歌。虽然我确信大部分都被适当地删除了,但毫无疑问,还是有一些诗歌被删节了,包含错别字,或者有多余的行,这仅仅是图像到文本库不准确的结果。尽管如此,在拥有更多数据的名义下,使用扫描图像诗是必要的。

概述

在一个漫长的抓取(再抓取)过程之后,我通过删除部分标题(罗马数字和类似第 1 部分、第 2 部分等内容)来清理数据。),空行,任何多余的行都包含诗人的名字和发表年份。这让我能够更准确地设计几个特征,包括诗中的行数、每行的平均字数、每个单词的平均音节数和词汇丰富度。我也研究了诗歌的极性和主观性。

在特征工程之后,我研究了这些新特征旁边的数据,并处理了文本以调查最常用的词。我创造了各种各样的形象来支持我的发现。最后,我运行了几个预测模型,以进一步了解我在数据探索过程中所看到的情况。

特征工程和 EDA

我对诗歌文本中可以设计的一系列特征感到非常兴奋,其中大多数在分析和分类中都非常有用。诗歌是一种独特的写作媒介,其结构和形式是诗歌风格(有时甚至是意义)的组成部分。

正如我将要展示的,先锋派诗歌,通常被视为一种更具实验性的风格和对过去的一种卑鄙的拒绝,几乎总是与 1900 年以前的诗歌处于光谱的另一端,这从文学批评的角度来看并不奇怪。简而言之,我在这个项目中量化的形式和结构元素为成熟的文学理论和分析提供了统计确认。

行数

这是衡量一首诗长度的标准,而不是字数。这就是为什么我之前描述的数据清理是如此重要,在删除任何不属于实际诗歌本身的行。

我惊讶地发现,所有运动的中值都相当相似,只有现代诗歌例外,它的中值最小。

(图片作者)

尽管有这些相似之处,1900 年以前的诗歌平均来说确实要长得多。平均长度是 55 行,而第二高的大都会只有 38 行。上图中上四分位数的分布进一步描绘了一首长诗中并不陌生的乐章。下方的 1900 年前的胡须也显示出这些诗歌往往至少有几行长(最少是 4 行),而其他运动对一行诗没有问题。

现代诗歌往往是最短的,平均值最低(33 行),中位数比第二低的少 4 行。先锋诗歌和都市诗歌在统计上是相似的,先锋诗歌和现代诗歌也是如此。

平均行长度(每行字数)

另一个对一首诗如何出现在页面上以及如何阅读有很大影响的关键指标是每行的平均字数。一首平均每行两个词的诗,看起来和感觉上会和一首平均每行八个词的十四行诗非常不同。

一个重要的发现是散文诗的出现如何扭曲了我的数据。散文诗是一种看起来更像小说的诗歌,使用段落或大段文字,而不是人们通常与诗歌联系在一起的分行符。所以上一节讨论的一些单行诗可能只是一段散文诗。

这些类型的诗歌在 20 世纪变得更加流行,在我的数据中没有出现在 1900 年以前的类别中。因此,1900 年以前的诗歌中平均线长的最大值是 23,而其他三个乐章的线长都在几百以上,甚至远远超过一千。

虽然这明显扭曲了先锋派、都市派和现代派诗歌的平均值,但它们的中值却讲述了一个不同的故事。

(图片作者)

到目前为止,前卫倾向于每行最少的单词,中位数约为 5.1 个单词,相比之下,第二低的大都市,约为 6.6 个单词。前卫派恰好同时拥有最高的平均水平,每行 9.3 个单词,这表明散文诗在运动中很流行。

1900 年以前的诗歌往往具有最长的线条,中值为 7.0 个词,也往往最有规律,值的范围最小。这是有意义的,因为它坚持已建立的结构,如十四行诗和村庄。还值得注意的是,1900 年以前的诗歌平均值最小(7.2,其次是 8.3),这也很可能是因为没有散文诗的例子。

极性

1900 年以前的诗歌是绝对正面的,中值为 0.90!在下面的方框图中,注意红线相对于其他运动的位置。其他三种运动彼此都很相似,它们的极性之间没有统计上的显著差异。

(图片作者)

诗歌很少是中性的,倾向于正面;如下图所示,每个乐章中至少有 61%的诗歌有正极性得分。71%的 1900 年前的诗歌有正极性得分。

先锋诗歌包含了几乎不到 5%的最中性的诗歌,但这仍然是一个相对较小的份额。

(图片作者)

结尾押韵

我能够使用艾利森·帕里什的发音包来确定一首诗包含多少个结尾韵脚。当一行末尾的单词与另一行末尾的另一个单词押韵时,就出现了尾韵。我将这个数字除以总行数,得到一个比率,这个比率成为我的分类模型最重要的特征之一。(注:我只数了独特的押韵。)

不出所料,1900 年以前的诗歌和其他运动之间有很大的区别。

(图片作者)

先锋诗歌倾向于不用尾韵,在都市诗歌中相对不多见。结尾押韵在现代诗歌中并不少见,但在 1900 年以前的诗歌中却很常见(而且似乎是必须的!),如下图。

(图片作者)

只有 8%的先锋诗歌的尾韵比超过 0.25,相比之下,1900 年以前的诗歌有 85%的尾韵比超过 0.25。

语言的复杂性(每个单词的音节数)

再次使用发音包,我计算了每首诗中每个单词的平均音节数。我用这个来衡量一首诗中所用语言的复杂程度;音节多的单词往往比只有一个音节的单词更复杂。

我原以为 1900 年以前的诗歌,用的是华丽的维多利亚时代的英语,每个单词的平均音节数要高得多。相反,它的用词最简单(音节最少),而 Metropolitan 的中值最高,勉强超过了 Avant-Garde。

(图片作者)

值得注意的是,到目前为止,前卫的音域最大,如上图所示。这表明了使用简单和复杂语言的各种诗歌运动。

词汇丰富度

语言复杂性的另一个衡量标准是词汇丰富度,它是通过将一首诗的词汇量(独特单词的数量)除以文本中的总单词数来计算的。一首重复的诗价值很低,而一首价值很高的诗(几乎或完全是独一无二的词)会被描述为“词汇丰富”。每个单词只出现一次的诗歌得分为 1.0。

1900 年以前的诗歌似乎是最重复的运动,而先锋诗歌是词汇最丰富的。在下面的图表中,前卫是唯一一个胡须值达到 1.0 的运动,它的所有四分位数都远远高于其他运动。

(图片作者)

重要的是要结合这些观察来认识到,1900 年以前是罗嗦的重复,而前卫往往是简洁和充满独特的语言。

文本处理

我处理了这些诗,以便更好地了解每个乐章中最常用的词。为了处理文本,我:

  • 把诗歌变成小写
  • 将缩写转换为词根
  • 删除标点符号
  • 词条化
  • 删除了停用词

我的停止词包括:

  • NLTK 停止字
  • 那些停用词的旧英语对等词(即 thydoesere 等)。)
  • 诗人的名字(因为一些可能已经在抓取过程中通过了),减去任何也可能被用作单词的名字
  • HTML 标签可能已经通过了刮擦过程(这是我最初刮擦时的一个问题,但我相信在清理过程中已得到纠正;不过,安全总比后悔好)
  • 在第一轮 EDA 中发现的有价值问题的单词(如可能)

在语料库中有 119,285 个独特的单词,总共有 1,165,726 个单词。经过处理后,这减少到 36,443 个唯一单词和 585,256 个总单词。

25 个最常用的单词是(同样,在处理和词条化之后):

(作者图片)

还有一大堆视觉 ( (

我觉得有趣的是来了才勉强挤掉坐上头把交椅。同样,这是在词汇化之后,所以这是 come,comes,coming,come 等的组合。这也许同时指向一个行动的号召(一个招手,一个“过来!”),一个被动的观察(“他来自一个遥远的城市……”,出自黛安·迪·普里马的一个恋爱中的练习),以及性动词,后者无疑在 19 世纪后的运动中更为常见。

通过移动来分解词频,可以更清晰地描绘出语言使用中的一些差异:

(图片作者 ) |(点击放大)

都市、现代和先锋派诗歌往往更注重视觉和时间,先锋派也包括一些更具体的自然词汇,如。同样值得注意的是, love 仅仅是先锋派的第八大流行术语,然而它却位列其他运动的前三名。

1900 年以前的诗歌更倾向于概念性和空灵性,像灵魂上帝这样的词是这个运动前 25 名所独有的。我还对相对缺乏自然术语感到惊讶(除了),考虑到这一运动包括以赞美自然而闻名的浪漫主义流派。

黑色对于大都会的名单来说是独一无二的,这大概可以用哈莱姆文艺复兴和黑人艺术运动流派来解释,也可以用垮掉派和纽约派诗人以城市为基础的更黑暗、更坚韧的美学来解释。

最后,值得注意的是这些图表的规模,它们反映了 1900 年前诗歌的冗长和重复以及先锋诗歌中相反的品质。在我的分析中,大都市诗歌和现代诗歌通常处于中间位置。

建模

我使用 TF-IDF 矢量器运行了朴素贝叶斯、KNN、决策树、随机森林和 SVM 模型。然而,我的最终实现是一个使用 Doc2Vec 文档向量的 SVM 模型,它为我提供了一个不错的 F1 分数,也是迄今为止最合适的。虽然为了简洁起见,我没有在我的最终 Jupyter 笔记本中使用它们,但我也运行了 XGBoost 和 LSTM 模型,它们显示了一些前景,但还没有达到我最终模型的水平。

数字数据的重要性

当同时使用单词(或文档)向量和我的工程特征时,我的所有模型都表现得更好。一般来说,当包含这些功能时,模型会有大约 10%的提升。

我在 TF-IDF 向量和我的工程特征上使用了伯努利朴素贝叶斯的基线模型取得了 42.7%的 F1 分数。这比仅仅预测占数据 29%的主导阶层要好得多。尽管如此,正如你在下面的困惑矩阵中所看到的,它确实高估了占主导地位的现代阶级,尽管并没有太多的不平衡。

我在 K-最近邻方面取得了一些成功,这表明数据中存在一定数量的聚类,以及随机森林。然而,后者是极其过分的。

同样,overfit 是我最好的模型,一个 SVM,有 TF-IDF 向量和数值数据。考虑到 SVM 在文本分类和数据方面的普遍成功,这相对来说并不令人惊讶,因为这些数据的特征多于数据点。这取得了最好的 F1 成绩,但在看不见的数据上不能很好地推广。

基线——SVM(TF-IDF)——SVM(doc 2 vec)混淆矩阵| ( 图片由作者提供)

将我的数字特征与 Doc2Vec 嵌入相结合,被证明是对看不见的数据进行最佳概括的模型,而不会对 F1 分数造成太大影响。

除了基线,我的模型在挑选 1900 年前的诗歌方面一直表现得更好,在那场运动和其他三场运动之间没有太多混淆。事实证明,前卫、都市和现代更难区分,通常会相互混淆。最终的模型似乎表明现代是最接近 1900 年以前的运动,15%的现代诗被错误地归类为 1900 年以前的诗。先锋派和大都市派看起来非常相似,这从诗歌的角度来看是有道理的。

对我的大多数模型来说,运行时间不是问题,这部分是因为数据集相对较小。我的 Doc2Vec 模型几乎可以即时运行,只有 100 个维度和 7 个工程特性。

最终模型

我使用所有的数据训练了一个最终模型,F1 分数增加到了 66.8%。1900 年以前确实是最容易识别的,其他三个运动彼此相当相似,现代是最难正确识别的(F1 得分为 60%)。

(图片作者)

在对整个数据集进行训练后,每个单独动作的 F1 得分都有所增加。现代的增幅最大,从 46%升至 60%。在对整个数据集进行训练后,Avant-Garde 的准确率有了惊人的大幅度提高,准确率从 51%提高到 65%。作为最小的阶层(大约 22%)可能解释这一点;更多的数据几乎总是一件好事。它的 F1 得分从 53%跃升至 62%。

顶级功能

除了我的基线和 TF-IDF SVM 模型之外,我的许多(如果不是全部)工程特性都在十大最重要特性之列。

在我的最终模型中,我的七个特性中有五个位于前十名:

(图片作者)

结尾押韵占总行数的比例遥遥领先,其次是每行平均字数、总行数和词汇丰富度。每个单词的平均音节数是另一个进入前十的工程特征。极性和情绪得分是唯一两个对模型不太重要的指标。

通过使用文档向量而不是 TF-IDF 向量,我最终失去了一些可解释性,因为上图中的其他特性只是 100 个神秘维度中的 5 个。尽管如此,通过使用一组总共 107 个而不是 43,053 个特征,我产生了一个更简单的模型,具有相似的功效和更好的概括能力。

这将帮助我更容易产生一个推荐系统!

推荐系统

本周晚些时候,请收听我如何构建 PO-REC 的分解,这是一种算法,可以基于一个词、任意格式的多个词以及我的数据集中的另一首诗来推荐诗歌。

结论

形式和结构的力量!基于一首诗的形式和结构的数字数据被证明是一首诗的运动的一贯有效的预测。

1900 年以前的诗歌倾向于冗长、积极、充满韵律,并使用简单、重复的语言。

先锋派诗歌往往短小精悍,词不达意,使用复杂的词汇丰富的语言。

都市诗和现代诗介于两者之间。都市诗歌与先锋派诗歌最为相似,而现代诗歌与所有流派都有相似之处,是唯一一种与 1900 年以前的诗歌有些相似的其他流派。

沉浸在完整预测模型的荣耀中|(图片由维基共享资源提供)

未来的考虑

在未来,设计更多的功能会很有趣,比如其他类型的押韵(使用内部押韵或倾斜押韵),动词时态(一首诗主要使用现在时还是过去时),以及空白的使用(即一首诗是否总是从行的左边开始)。主题建模也可能产生一些有趣的结果。

此外,我计划尝试使用实际的流派(共有 13 种)来建立这一点,而不是这里讨论的四种伞状运动。这将带来一些显著的挑战,尤其是巨大的阶层失衡。现代诗歌,这是它自己的流派运动,占所有诗歌的四分之一以上。虽然这肯定会导致更不准确的模型,但它也将揭示诗歌运动中的错综复杂。

项目回购

你可以在 GitHub 上查看我的项目回购:
https://github.com/p-szymo/poetry_genre_classifier

词云—整体| ( 图片作者)

预测警察电话需求的乐趣(和先知)

原文:https://towardsdatascience.com/predicting-police-call-demand-for-fun-and-prophet-2e278828a1a1?source=collection_archive---------57-----------------------

用 LAPD 呼叫数据进行快速和肮脏的预测

在这个容易获取数据科学的时代,预测警务需求有多难?我一直在探索时间序列回归技术,虽然在更高级的方面,它们可能会变得非常复杂,但你也可以使用开源工具来快速创建运营洞察,就像这里,我使用公开可用的 LAPD 呼叫数据来预测需求。

虽然一些时间序列技术需要相当多的额外技术知识——我花了比任何正常人都多的时间来试图理解 ARIMA 模型是如何工作的——但我们很幸运,因为脸书已经开源了他们的预测模型 Prophet,,而且非常容易使用。在 R 和 Python(我在这里使用的)中,这个库很容易安装,并且遵循您可能熟悉的技术。最基本的,你所做的就是给它一系列的时间点和你试图预测的值,它会考虑每天,每周和每年的季节性,并产生一些令人惊讶的准确预测。

感谢警方数据倡议,我得以获得 LAPD 从 2015 年到 2019 年底的详细通话数据。数据大部分都是干净的,所以聚合数据非常简单— 代码可以在 Github 上找到。

在可能的情况下,确保您的数据有一个可靠的频率(例如每天、每周、每小时等)——一些时间序列模型将与丢失的数据作斗争,尽管 Prophet 在我的测试中没有问题。在我的数据集中,我每小时观察 43825 次,总计刚刚超过 600 万次调用。

然后,我使用脸书预言家快速入门文档来引导我将我们的数据拟合到模型中,并进行一些初步预测。

一旦你将你的模型与你现有的数据相匹配,Prophet 就可以根据你的需要对未来进行预测。出于我的目的,我已经要求 Prophet 绘制 2020 年以后的预测需求数据-显然它无法解释 COVID,但请注意算法的置信度是在最初几个月(基于历史趋势数据)以及这如何随着时间的推移而偏离。

每小时通话需求(历史和预测)

这可能看起来很混乱,但请记住,这是预测小时需求,而不是每日需求,这允许更细粒度的预测,但确实增加了相当多的噪声。

每日通话量(历史和预测)

Prophet 的模型结合了各种较小的季节性趋势(每周、每天和每年),也让您可以单独观察这些趋势,尽管这些趋势不会让任何有经验的警察感到震惊,但它们有助于进行有力的观察——需求在一周和一年中的波动非常惊人。它还清晰地展现了自 2010 年以来需求的持续增长。

季节性趋势细分,每小时通话需求

在试图做出任何预测之前,这确实提出了一些严重的实际问题——2019 年发生了什么,基本上使的需求翻了一番?我最初假设我已经导入了两次年度文件,但它看起来确实像是“真正的”增长,尽管它可能是由计算机系统、分类规则或类似规则的变化所驱动的。这就是让操作专家与您的研究人员合作的重要性!

然而,关键问题是,我们的模型在预测实际需求方面表现如何?有益的是,Prophet 包括交叉验证功能:它会自动将你的数据分成块,为每个块创建一个模型,并根据它知道的数据测试它创建的模型的准确性,以检查准确性。

性能指标,每小时需求模型

这里,Prophet 创建了 5 个不同的交叉验证集,您可以看到中值绝对百分比误差(MDAPE)徘徊在 15%左右。我不是专业统计学家,但这听起来并不坏,尤其是当你考虑到 2019 年的巨大意外跳跃时。即使在更远的未来,均方根误差(RMSE)仍然保持在 50-70 左右。

值得指出的是,这是你能得到的最直接的预言家或时间序列预测应用——我真的把算法扔给了我的数据,没有试图提高拟合度或解释我的数据的特定特征。Prophet 包含了考虑异常值、假日和更多因素的功能,如果您正在考虑部署这样一个工具,进行更多的探索和调整是绝对必要的。也就是说,在几个小时内,我们已经创建了一个模型,用于预测每小时的警察需求,如果我们给它提供更多的数据,这只会有所改善——这是对隔离的一个不错的使用!

那么,对于试图预测犯罪需求的警察部门来说,有什么教训呢?

  • 你不需要一个昂贵的数据科学家来使用复杂的工具来预测你的需求(尽管你可能应该有一个)。虽然拥有博士学位的人可能会比普通分析师做得更好,但让任何人用你的数据做实验本身就有价值。也就是说,数据科学家将帮助调整模型,提高其性能,并阐明其内部工作原理。
  • 你确实需要一个可以部署这些技术的数据环境——这在 Excel 中是行不通的。我在这里使用 Python,尽管 R 或等效语言也一样好。同样,这并不意味着您需要花费大量资金购买尖端的云解决方案,而是要认识到将所有数据锁在一个完全安全的生态系统中是有成本的。
  • 你的数据越容易获取,就有越多的人可以利用它,向你展示“可能性的艺术”。并非所有的分析都需要来自内部:我已经在几个小时内将这种技术应用于 LAPD 数据。在警方重新布线事件中,我看到人们在几天内对血液飞溅运行机器学习技术,并制作真正的、专注于操作的工具。数据安全是不容商量的,但是每多一层不透明都是有代价的。

我期待着在几个月后重温这些预测,并将它们与“真实”数据进行比较,尽管我不认为任何数量的机器学习可以解释 COVID。

所有分析的代码和数据都在我的 GitHub 上可用。这次分析的数据是由警方数据倡议收集的,非常有帮助,如果你喜欢这类事情,你应该考虑加入警方重组 数据社区

利用客户评论预测产品质量

原文:https://towardsdatascience.com/predicting-product-quality-using-customer-reviews-ac1a215226d1?source=collection_archive---------31-----------------------

深入探究误导性客户评级以及贝叶斯思维如何欺骗我们的信念。

在竞争激烈的市场中,一家公司的成功建立在满足品味高雅、有鉴赏力的消费者群的严格标准之上。特别是,客户产品评论都很重要。但是我们应该如何根据顾客的评论来判断一个产品的质量呢?

Stux 在 Pixabay 上的图片

在本文中,我们构建统计模型,使用客户评论中观察到的评分来比较两个虚拟产品(Lotus World 和 Toysmith)。特别是,我们正在查看产品被评为给定等级(1 到 5 星)的次数。

使用贝叶斯概念分析客户评级,如最大似然、最大后验、后验均值估计、后验预测估计和可信区间。

Lotus World vs Toysmith 的两个竞争产品的客户评论(图片由 Amazon.com 的制作,出于本文目的,这些评论并不反映真实的评级,作者的观点是真实的)

如果你需要复习概率和分布,下面这篇文章可能是合适的。

[## 理解概率。终于!

数据科学家概率概念实用指南

towardsdatascience.com](/understanding-probability-finally-576d54dccdb5)

最大似然模型

我们感兴趣的是估计 θi 顾客用 i 颗星评价的概率。由于每个新评级都有一个介于 1 和 5 之间的值,因此它遵循分类分布 Cat ( θ )。

对于给定的产品,我们得到一个评级向量 R =[ r 1, r 2, r 3, r 4, r 5】。每个评分 r _ ii 星评论的总数。每个 i 星的评审都是以概率 θi 进行的。我们看到每个评论 r 都独立于其他评论,并由分类分布建模:

N 独立评论中观察到出现向量 R 的可能性由多项式分布给出,该分布由 θ 参数化:

对数似然将由下式给出:

现在我们可以计算两种产品的 θ最大似然估计量(MLE) 。我们需要找到使可能性最大化的θ**L。我们需要对关于 θ 的似然函数进行微分。但是,我们不能就这么一意孤行,去做。我们必须考虑约束,我们必须使用拉格朗日乘数。

假设所有的导数都为 0,我们得到最自然的估计:

因此,最大似然估计值如下所示:

基于这两种型号的 θ 最大似然估计,你有信心决定一种产品是否优于另一种吗?这并不简单。但是,我们可以通过计算最大似然(ML)阿凯克信息准则(AIC) 来回答这个问题。首选模型是具有最小 AIC 值和最大 ML 的模型,如下所示。

莲花世界的产品似乎优于 Toysmith。我们对此有多不确定?

贝叶斯模型

最大似然法找出参数值 θ ,使其最大化模型描述的审查过程产生实际观察到的数据的可能性。

先验信念

正如我们在下面的前一篇文章中解释的,MLE 的一个缺点是不可能包含我们对正在估计的参数的先验信念。

[## 贝叶斯噩梦。解决了!

通过 Python PyMC3 中的示例和代码对贝叶斯数据分析进行了温和的介绍。

towardsdatascience.com](/bayesian-nightmare-how-to-start-loving-bayes-1622741fa960)

假设我们被告知,市场上客户的意见非常两极分化。

大多数评论将是 5 星或 1 星,很少处于中间水平。一个关于 θ狄利克雷先验将极大地抓住这个事实。狄利克雷分布是在一个概率单形上采样,这个概率单形是一串相加等于 1 的数。

Dirichlet 对多个互斥选择的概率进行建模,由 α 参数化,α被称为集中参数,代表每个选择的权重。

如果我们想要产生一致的公平评论,那么 α →∞就可以了。对于具有α1 的对称狄利克雷分布,我们将平均产生一个公正的评价。如果目标是产生有偏见的评论,具有 1 星和 5 星的较高概率,我们会想要一个不对称的狄利克雷分布,具有更高的值为 α 1 和α5。下面我们建议一个不对称阿尔法的例子。

后验分布

贝叶斯方法可以被视为最大似然估计的扩展。当我们有数据、先验和生成模型时,我们可以应用贝叶斯定理根据数据计算模型参数的后验概率分布,如下所示。

最大后验概率(MAP)

通常汇总后验分布以发现一些集中趋势。最大后验概率(MAP) 或后验模式是具有最高后验概率的点,由下式给出:

下面我们实现这个公式来计算 Lotus World 对 Toysmith 的地图。这给了我们一个更现实的未来评级概率的概念。例如,在考虑不对称评论的先验信念后,客户给 Lotus World 提供 5 星评级的可能性相当于 65%。MLE 模型为这种可能性提供了一个更乐观的值(67%)。通过包含领域专家的先验信念,贝叶斯方法只允许更接近业务现实的估计。

如果我们将 α 设为 1,那么我们获得了 θi 的最大似然估计。

后验均值估计(PME)

后验均值估计或期望值是后验分布的均值或众数。对于我们的问题,它由下面的公式给出。

PyMC3 下的贝叶斯推理

到目前为止,我们已经手动分析计算了后验分布。尽管这种方法在概念上很简单,但是对于大型数据集来说,这种方法可能会非常慢,而且伸缩性也很差。

还有更快的方法,主要是所谓的马尔可夫链蒙特卡罗 ( MCMC )算法家族。下面,我们使用 Python 库 PyMC3 实现 MCMC 来寻找模型参数的后验分布。这允许我们从每种产品的后验预测中抽取 1000 个评级向量样本,并总结 theta 的后验预测估计值

虽然后验均值估计和最大后验估计非常相似,但两者都与最大似然估计有很大不同。

可信区间

可信区间告诉我们在特定概率下未观察到的参数值的可能范围。这不要与置信区间相混淆,置信区间不能捕捉我们当前参数值位置的不确定性。

下面我们使用后验分布(从中抽取样本)来计算每种产品的 θ 的 95%可信区间。

对于 Toysmith,上述后验均值估计的可信区间平均更窄。我们可能倾向于增加对 Toysmith 产品的评价的信任度。

你会选择 θ 的哪个点估计(MAP、MLE、后验平均 PME 或后验预测估计)来对这两个产品进行排序?

平均评级不考虑之前的信念,例如偏向 1 星和 5 星的倾斜评级。正如我们上面所展示的,当包含先验知识时,客户给出具体评论的可能性更可信。

在我们的例子中,我们将选择后验均值估计(PME)。MLE 和 MAP 是相似的,因为它们计算的是单一的估计值,而不是完整的分布。MLE 是映射的特例,其中先验是一致的!PME 或后验预测估计是从后验预测分布得出的,后验预测分布是可能参数的分布。因此,PME 将提供更可信的预测,随着数据量的增加,预测将变得更加准确。

结论

我们已经应用贝叶斯方法来检测基于客户评级的两个产品的感知质量。提供 Python 代码用于实际演示。

在我下面的下一篇文章中,你可以自由地学习更多关于贝叶斯方法的知识。

[## 贝叶斯逻辑回归简介

使用 Python 和 PyJAGS 进行贝叶斯分类方法的实践演示。

towardsdatascience.com](/introduction-to-bayesian-logistic-regression-7e39a0bae691)

我进一步推荐以下资源:

感谢阅读。注意安全!

预测实际 GDP 增长

原文:https://towardsdatascience.com/predicting-real-gdp-growth-85f34fdca97a?source=collection_archive---------20-----------------------

经济领先指标能在多大程度上预测实际 GDP 增长的方向?

如果你关注财经新闻,你可能会听到“消费者情绪”或“ISM 新订单”这样的词汇。这些是经济学家用来衡量经济未来走向的数据点或经济指标。但是他们对经济增长的预测有多准确呢?为了找到答案,我用 Python 开发了一个预测模型,来看看这些经济指标的预测能力。

米歇尔·汉德森在 Unsplash 上的照片

行话的澄清

商业周期

在我们进入模型之前,让我们首先对商业周期建立一个牢固的理解。周期的四个阶段是高峰期、收缩期、低谷期和扩张期。高峰和低谷是周期的转折点。在收缩期间,经济活动或 GDP 下降,这可能导致衰退或萧条。在扩张期间,经济活动正在加速。峰值是指经济过热,通胀高企,GDP 增速放缓。

资料来源:CFA 学院计划课程一级第二卷:经济学,2019

国内生产总值

美国的 GDP 或国内生产总值是在一定时间范围内在美国生产的最终商品和服务的价值。它是消费者支出、国内投资、政府支出以及进出口差额的总和。

GDP = C + I+G+(X-M)

前导指数

经济学家和金融分析师使用领先指标来帮助理解经济的未来状态。它有助于确定我们在商业周期曲线上的位置。以下是我在模型中使用的领先指标:

  • 平均每周首次申请失业保险:衡量首次裁员和重新招聘的好指标
  • 制造业平均工作时间(季度百分比变化):企业更有可能在裁员前削减加班时间,在返聘前增加加班时间;因此,在商业周期转变之前,这个指标首先移动
  • ISM 制造商的新订单:不包括飞机在内的非国防资本货物:月度新订单提供了工业部门活动的第一个信号,也是商业预期的良好代表
  • 私人住房单元建筑许可证:预示新的建筑活动
  • 标准普尔 500 指数:提供经济商业周期运动的早期迹象
  • 10 年期国债收益率和联邦基金利率之间的息差:息差越宽,预示着经济上行,息差越窄,预示着经济下行
  • 平均消费者预期/信心:如果消费者有信心,支出就会增加。消费占美国经济的 66%

数据

所有数据点都是从圣路易斯弗雷德网站检索的季度总量。这些数据是从 1947 年到 2020 年 Q1 的 293 项记录。

特征工程

新变量创建:

  1. 季度:创建起始日期
  2. 标准普尔 500 百分比:用标准普尔 500 的百分比变化替换实际值,因为随着时间的推移,标准普尔 500 值会增加

目标

目标变量是年化实际 GDP 增长率。我用季度实际 GDP 的变化计算了这个变量,如下:([Q2/Q1 * 4 ]-1)。使用实际国内生产总值是因为它根据通货膨胀进行了调整。

处理空值

很少有变量有空值,因为我找不到可以追溯到 1947 年的数据,而我找到了 GDP 数据。为了填补缺失的数据,我使用了 k-最近邻算法。

from sklearn.impute import KNNImputer
imputer = KNNImputer(n_neighbors=2)
df_filled = imputer.fit_transform(df2)
dataframe=pd.DataFrame(df_filled, columns = cols)

模型

我决定使用弹性网络回归模型,因为它在处理高度相关的独立变量方面做得更好。我把数据分成 30/70(测试/训练)。然后,我使用 ElasticNetCV 找到了模型的最佳 alpha,这是一个交叉验证类。

#Separate Features and target
X_Target = dataframe3[‘GDP_Change’] # the 
feature_df= dataframe3.loc[:, dataframe3.columns != ‘GDP_Change’]
#Split the data
X_train, X_test, y_train, y_test = train_test_split(feature_df, X_Target, test_size=0.3, random_state=0)alphas = [0.0001, 0.001, 0.01, 0.1, 0.3, 0.5, 0.7, 1]elastic_cv=ElasticNetCV(alphas=alphas, cv=5)
model = elastic_cv.fit(X_train, y_train)ypred = model.predict(X_test)
score = model.score(X_test, y_test)
mse = mean_squared_error(y_test, ypred)
print("R2:{0:.4f}, MSE:{1:.4f}, RMSE:{2:.4f}"
      .format(score, mse, np.sqrt(mse)))

输出:

R2:0.4323, MSE:0.0008, RMSE:0.0275

然后,我将模型的预测值与实际值可视化

x_ax = range(len(X_test))
plt.scatter(x_ax, y_test, s=5, color=”blue”, label=”original”)
plt.plot(x_ax, ypred, lw=0.8, color=”red”, label=”predicted”)
plt.legend()
plt.show()

均方误差非常低,但是均方根误差较大,因为它惩罚了较大的误差。这些大的误差可能是由于不可预见的事件导致的市场波动。0.4323 的 R 平方揭示先行指标只能解释 GDP 增长中 43%的差异。因此,仅使用领先指标不足以预测 GDP 增长。为了更好地了解经济的发展方向,我们需要关注更多的指标,比如同步指标。

向模型中添加重合指标

同步指标衡量当前的经济状况。因此,通过了解我们在商业周期中的位置,我们可以预测我们将走向何方。

我添加了以下指标:

  • 月失业率的变化(季度平均值)
  • 不包括食品和能源的个人消费支出(环比价格指数),与一年前相比的价格变化
  • 房屋月供应量:待售房屋与已售房屋的比率
  • 抵押贷款还本付息额占个人可支配收入的百分比,价格与一年前相比有所变化

新的弹性网回归模型误差略低,R 平方增加。这个模型解释了 GDP 增长中约 65%的可变性。同时使用同步指标和领先指标可以更好地描绘出我们前进的方向。

R2:0.6477, MSE:0.0006, RMSE:0.0235

特征的预测能力

该模型强有力的预测指标是 ISM 新订单、消费者信心和失业率变化。

ISM 新订单指数与 GDP 增长密切相关,相关系数为 0 . 60。因此,随着新的制造业订单增加,它有助于 GDP 增长。第二个强有力的预测因素是消费者信心(0.34)。GDP 计算的很大一部分是支出。随着消费者对经济状况更有信心,他们可能会增加支出,从而提高 GDP。失业率的变化和 GDP 的增长也有很强的负相关(-0.65)。

从上面的相关矩阵中,您可以看到独立变量也是相关的(这就是我使用弹性网回归模型的原因)。例如,消费者信心和每周失业申请人数之间有很强的负相关性,这是有道理的,因为如果一个人没有工作来支付账单,消费者对经济的信心就会下降。

下图说明了前两个预测指标(ISM 新订单和消费者情绪)之间的趋势。例如,2008 年第四季度,由于新订单和消费者信心下降,经济收缩了约 8%。2020 年第一季度,我们又经历了一次经济收缩(-4.8%)。在此期间,由于对冠状病毒的担忧日益加剧,新订单指数和消费者信心指数均下降了约 10%。

预测 2020 年 Q2 国内生产总值增长

使用 4 月份的最新数据预测 2020 年第二季度的 GDP 增长,我的模型预测将大幅下降 24.2%。起初,这令人瞠目结舌。所以我将我的结果与其他领先组织的预测进行了比较。

美国国会预算办公室(CBO)估计,下一季度 GDP 将下降 12%,年化降幅为 40%。

亚特兰大联邦储备银行估计 GDP 将大幅下降 40%。蓝筹股的普遍预测从-6%到 40%不等。

世界大型企业联合会预测美国经济下个季度将收缩 45%。据世界上最大的投资公司之一太平洋投资管理公司(PIMCO)称,30%⁴.的国内生产总值将会收缩我对经济收缩 24%的惊人预测,实际上与许多其他人的预测是一致的。

连续两次 GDP 负增长就是衰退。不管实际的 GDP 增长数字如何,人们普遍认为,2020 年第二季度 GDP 将大幅下降。这表明我们将陷入衰退,因为 2020 年第一季度也将收缩。

[1]:菲尔·斯韦尔。(2020 年 4 月 24 日)。CBO 目前对产出的预测。https://www.cbo.gov/publication/56335T2

[2]:亚特兰大美联储银行。 GDPNowwww.frbatlanta.org

[3]:会议板。美国经济的经济预测https://www . conference-board . org/publications/Economic-Forecast-US

[4]:凯特·杜吉德(2020 年 4 月 8 日)。太平洋投资管理公司称,美国第二季度 GDP 将收缩 30%,2020 年将收缩 5%。https://www . Reuters . com/article/us-USA-GDP-pimco/us-GDP-will-contract-30-in-second-quarter-5-in-2020-pimco-iduskcn 21 q2vl

使用机器学习预测 Reddit Flairs 并使用 Heroku 部署模型—第 1 部分

原文:https://towardsdatascience.com/predicting-reddit-flairs-using-machine-learning-and-deploying-the-model-on-heroku-part-1-574b69098d9a?source=collection_archive---------39-----------------------

Kon Karampelas 在 Unsplash 上拍摄的照片

Reddit 天赋预测系列

问题定义和数据收集

如果你被困在付费墙后面,点击这里获取我的朋友链接并查看这篇文章。

Reddit 是一个非常受欢迎的社交媒体网站,大约有 3.3 亿活跃用户,它产生了大量的用户生成内容,像我这样的数据科学家喜欢挖掘和分析这些内容。我最近完成了一个使用 Reddit 数据的项目,我打算谈谈我的经历以及我解决问题的过程。这将帮助任何正在寻找一个端到端机器学习项目的人。我将向您介绍收集数据、分析数据、构建模型、部署模型并最终使用 Heroku 将其上传到服务器的过程。到本系列结束时,您将已经使用了许多 Python 模块、API 和方法,这将使您在自己的机器学习之旅中更加自信。

我已经把这个项目分成了几个部分,希望我能够用 3-4 个部分来介绍它。欢迎来到本系列的第 1 部分,我将向您介绍这个问题的背景,并执行这项任务的数据收集方面。

背景

在着手解决实际问题之前,这项任务需要一些领域知识。对于那些从来没有去过 reddit 网站的人,我强烈建议你去看看,因为它真的会帮助你分析你将要收集的数据。在这项任务之前,我从未使用过 reddit,在我理解为什么某些东西对我的模型不起作用之前,我花了一些时间来适应这个网站。

reddit 和 subreddit 到底是什么?

我经常发现自己试图回答这个问题,因此让我尽可能简单地为你解答。本质上,它是一个论坛的集合,人们可以在这里分享新闻和内容,或者对其他人的帖子发表评论。 [Reddit](https://www.digitaltrends.com /social-media/what-is-reddit/) 被分成超过 100 万个被称为“子 Reddit”的社区,每个社区涵盖不同的主题。subreddit 的名称以/r/开头,这是 reddit 使用的 URL 的一部分。比如 /r/nba 是人们谈论国家篮球协会的子编辑,而 /r/boardgames 是人们讨论桌游的子编辑。

出于我们分析的目的,我们将使用' India '子编辑,因为我来自印度,这个帖子上有很多内容。你可以自由选择你喜欢的线。

Reddit Flairs

reddit 上的另一个功能是 flair ,我们将在接下来的分析和预测中使用它。flair 是一个“标签”,可以添加到 reddit 网站的子 reddit 中的帖子中。它们帮助用户了解文章所属的类别,并帮助读者根据他们的偏好过滤特定类型的文章。

使用 PRAW 收集 Reddit 数据

所以,让我们言归正传。任何机器学习任务都需要你给它输入数据。我们将通过编写一个脚本来从印度收集数据。这些数据将在问题的未来部分用于构建分类器。为此,我们将使用一个名为 PRAW 的专用库,它是 Reddit API 的 Python 包装器,使您能够从子编辑中抓取数据。

安装 PRAW

我们可以在终端中使用 pip 或 conda 安装 PRAW:

pip install praw 
or 
conda install praw
or
pip3 install praw

一旦安装了库,您就可以通过

import pandas as pd # data manipulation 
import praw # python reddit API wrapper

然而,在我们开始使用 praw 收集数据之前,我们必须对自己进行身份验证。为此,我们需要创建一个 Reddit 实例,并输入client_idclient_secretuser_agent作为参数。

创建 Reddit 实例

认证部分已经从这篇文章中引用,我想给作者吉尔伯特·坦纳满分,因为这是我从那里学到这项技术的原始文章。

为了获得认证信息,我们需要通过导航到该页面并点击创建应用创建另一个应用来创建 reddit 应用。

图 1: Reddit 应用程序[1]

这将打开一个表单,您需要在其中填写名称、描述和重定向 uri。对于重定向 uri,你应该选择http://localhost:8080,正如优秀的 PRAW 文档中所描述的。

图 2:创建新的 Reddit 应用程序[1]

按下创建应用程序后,会出现一个新的应用程序。在这里,您可以找到创建praw.Reddit 实例所需的认证信息。

图 3:认证信息[1]

一旦获得了这些信息,就可以将它添加到上面的代码段中,并创建一个praw.Reddit的实例。Reddit 类提供了对 Reddit API 的方便访问。该类的实例是通过 PRAW 与 Reddit 的 API 交互的门户。你可以在这里阅读更多关于这个类及其方法的内容。

获取子编辑数据

使用上面的实例,我们可以从我们想要的子编辑区(即印度)获得前 1000 个帖子或 1000 个热门帖子或最新帖子。

收集热门帖子并展示它们

结果将如下所示:

Will donate thrice the number of upvotes (amount in Rs.) i get for this thread in next 24 hours
Indian reply to NYtimes cartoon on Paris climate accord by Satish Acharya.
The essence of the Indian soap opera, distilled into one GIF.
This looks legit..
German exchange Student at IIT Madras is being sent back home by the Indian immigration department because he joined the protest.
Tragedy of India
Today's The Hindu
Irrfan Khan dies at 54
If you are not moved by this picture, I wish I had your heart. [NP]
.... 

以类似的方式,我们可以使用下面的代码获得“最热”或“最新”的帖子。

hot_posts = reddit.subreddit(‘India’).hot(limit=num_of_posts)new_posts = reddit.subreddit(‘India’).new(limit=num_of_posts)

物体hot_poststop_postsnew_posts属于ListingGenerator类,更多可以在这里读到。现在让我们将数据以结构化格式存储在一个pandas.DataFrame和一个.csv文件中,以便进一步分析。

首先,我们需要为每个线程创建一个从 reddit 网站提取的特性列表。详细名单可以在这里找到。每个特性都是Submission类的一个属性。我已经描述了我收集的一些,但是你可以自由增减你的列表。

这些是我们将从数据集中提取的数据列。

被擦除数据的功能描述

提取数据并转换为数据帧

下面是我们的数据框架:

包含抓取数据的数据帧

下一步是修复我们的created_on字段,因为它目前用 UNIX 时间表示。

将 UNIX 时间转换为人类可读的日期时间

输出:

虽然从数据搜集的角度来看这个结果是可以接受的,但是从 ML 的角度来看,它有一些问题。在分组和 value_counts 等基本数据分析之后,人们会发现这些数据非常不平衡,并且偏向某些类。此外,我们还可以通过收集评论数据来收集更多信息。有时仅仅是标题和正文可能还不够,添加评论可以增加很多关于文章及其所属风格的有价值的信息。那么,让我们来看看一种即兴的数据收集方法。

数据收集:即兴

我要做的第一件事是创建更少数量的分类目标,这样就不会有信息溢出,也不用花费几个小时来收集信息。这意味着我将有更多的数据为每个天赋,因此,我可以建立更强大的模型,并提高准确性。

posts[‘Flair’].value_counts().sort_values(ascending=False)

我按降序排列了这些文件,并挑选了最受欢迎的文件,以避免数据失真。我将收集热门帖子及其评论,以及一些与分析和模型相关的其他信息。

相关标志

值得注意的是,这些标记在我写这篇文章时是相关的,在你进行分析时可能会改变,所以相应地创建这个列表。我保留了或多或少相同的功能,增加了一个评论字段。

收集数据的第二种方法

在上面的代码段中,replace_more()方法有助于处理[MoreComments](https://praw.readthedocs.io/en/latest/tutorials/comments.html)对象,如果不检查的话会导致错误。该方法替换或删除了MoreComments。您可以设置limit=None获取所有评论,而设置limit=0删除所有评论。由于时间限制,我选择了limit=0.。最后,从 ML 的角度来看,还有一个非常重要的步骤。在这种方法中,数据被聚类成相似的 flair 类型,因为我们将它们一个接一个地追加到一个列表中。很有可能在分割训练和测试数据之后,在训练或测试数据中甚至没有一个特定天赋的例子。这可能会导致明显的性能问题。让我们通过对随机排列的数据进行采样来解决这个问题。通过设置frac=1,我们得到全部数据。

# Data Shuffling
data = posts.sample(frac=1).reset_index(drop=True)
data.head()

最终数据帧

最后,将数据帧保存为. csv 格式,以便进一步分析。

# Save Data in a CSV file
data.to_csv('data.csv')

这让我结束了本教程。这里有一个链接到我原来的笔记本。在下一部分,我将分析这些数据并建立模型。我还将创建 NLP 管道,以加快数据分析。在 第二部分 中继续阅读该项目。你可以在这里找到本系列的所有文章。

参考

  1. https://towards data science . com/scraping-Reddit-data-1c 0af 3040768
  2. https://praw . readthedocs . io/en/latest/code _ overview/praw _ models . html
  3. https://www.digitaltrends.com/web/what-is-reddit/】

使用机器学习预测 Reddit Flairs 并使用 Heroku 部署模型—第 2 部分

原文:https://towardsdatascience.com/predicting-reddit-flairs-using-machine-learning-and-deploying-the-model-using-heroku-part-2-d681e397f258?source=collection_archive---------59-----------------------

图片由皮克斯拜的 Gerd Altmann 提供

Reddit 天赋预测系列

文本分析和模型构建

本文音频

如果你被困在付费墙后面,点击这里获取我的朋友链接并查看这篇文章。

欢迎来到本系列的第 2 部分,在这里我将继续解决 Reddit Flair 检测问题。在第 1 部分中,我讨论了问题的背景和数据收集方法。强烈建议您在开始之前阅读第 1 部分,因为我已经分享了数据收集过程背后的见解和推理。我还描述了我在项目和模型构建中使用的各种指标。如果您还没有完成第 1 部分,但想继续第 2 部分,您必须从这里获取 data.csv 文件。一旦你获得了数据,我们就开始吧。

介绍

在课程的这一部分,我将致力于数据分析、文本分析和文本分类。虽然本教程是针对我从事的项目的,但是这些技术可以应用于任何文本分类问题。值得注意的是,这是一个多类文本分类问题,有一些专门针对这类问题的警告。大多数在线教程都是关于二进制文本分类的,比如垃圾邮件过滤器。然而,您将主要处理现实世界中的多类问题。因此,本教程应该是一个很好的起点。

问题回顾

正如我已经讨论过的,这是一个有监督的多类文本分类问题。我们已经收集了特征和标签,我们的目标是建立一个模型,它可以根据我们收集的帖子的特征来预测帖子的风格。我们开始吧

重要的图书馆

这些是我们将在此过程中使用的库。

任务所需的库

如果您的系统中没有安装它们,您可以下载这个文件,并在您的终端中运行以下命令。

pip install -r requirements.txt

注意:-这将在您的工作目录中安装所有的软件包。如果您想在虚拟环境中安装这些,请参考此链接

探索性数据分析

首先将数据从 csv 文件读入数据帧。

# Reading Data 
data = pd.read_csv('data.csv')

如果您已经从 GitHub 链接获得了数据,那么下一步对您来说很重要。其他人可以跳过这个。在这里可以找到的解释。

# Data Shuffling
data.drop(['Unnamed: 0'], inplace=True, axis=1)
data[:] = data.sample(frac=1).values
data.head()

先看数据

由于这是一个文本分类问题,我们将只对机器学习模型使用包含文本的特征。它们是标题、正文、评论和 URL(可选)。让我们看看列的数据类型和缺少的值。

# Display data types and null values
data.info()

data.info()之后的输出

Body列中有许多空值,在Comments部分中有一些缺失值。我们不能估算它们,因为它们包含用户生成的内容。然而,每个条目都有一个TitleFlair,所以我们不必删除任何一行,我们可以使用它们进行分析。在Flair.的数据集中有许多要预测的类

print(len(data[‘Flair’].unique()))
data[‘Flair’].unique()**OUTPUT:**11
['Sports' 'Politics' '[R]eddiquette' 'Business/Finance' 'Food' 'AMA'
 'AskIndia' 'Photography' 'Non-Political' 'Science/Technology'
 'Policy/Economy']

因此,有 11 个独特的类。对于我们收到的每一个新帖子,我们都需要将其归入这 11 个类别中的一个。我已经提到了我们将用于分析的重要特性。让我们减小数据帧的大小,只保留相关的特征。

# List of relevant features
features = [‘Flair’, ‘URL’, ‘Title’, ‘Comments’, ‘Body’]
data = data[features]
data.head()

过滤数据

现在我们有了更多的相关数据,我们需要创建几个字典供将来使用[1]。第一步是为每个天赋生成一个唯一的 ID。然后,我们将根据它们创建字典。这些字典将让我们引用我们为它们生成的独特 id,反之亦然。

每种天赋类型的唯一 id

词典的输出

我们创建了两本词典:-

  1. category_labels:该字典将 flairs 作为关键字,将 ID 作为值分配给它们,这些值将在预测后用作分配标签的方式。
  2. category_reverse:这是前一个字典的反例,使用 id 作为键,flairs 作为值。

下一步是创建一个由TitleBodyComments组合而成的组合特征。我现在不使用 URL,让你来分析它。有很多有创意的方法可以做到这一点,你可以在下面的评论中提到它们。我将创建一个新的功能Combine,它将纳入上述功能。

创建新功能Combine

添加组合特征后的数据帧

文字清理

这是文本分类项目最重要的方面之一,因为并非所有的单词都同样重要,一些单词如是如此常见,以至于它们会出现在所有 flair 类别的数据中,并混淆分类器。强烈建议删除它们。在情感分析项目中,我们可能会保留标点符号,因为感叹号的数量可能会完全改变那里的含义。然而,我觉得没有必要把它们留在这里,因此,我将在下一步中删除它们。我刚才提到的常用词在 nltk 库中都有,所以你不必自己列一个清单。

# Collect all the english stopwords and display them
STOPWORDS = nltk.corpus.stopwords.words(‘english’)
print(STOPWORDS)

英语中的 nltk 停用词列表

让我们定义一个清洗函数。我们将通过这个函数来清理我们的特征。

函数来清理我们的数据

清洁后的组合功能

文本表示

分类器和学习算法不能直接处理原始形式的文本文档,因为它们中的大多数期望具有固定大小的数字特征向量,而不是具有可变长度的原始文本文档。因此,在预处理步骤中,文本被转换成更易于管理的表示[1]。矢量化是一种将单词转换成长串数字的方法,这些数字可能具有某种复杂的结构,只有使用某种机器学习或数据挖掘算法的计算机才能理解。[2]

对于文章的这一部分,我要感谢苏珊李。她在她的文章中介绍的最相关单字和双字测试是一种非常有见地的技术,它让我们找到在特定类型的天赋中出现最多的单词,并让我们深入了解模型的预测方法。如果一个特殊的天赋有很多不相关的词,那么我们可能会考虑添加更多的数据或删除一些数据。

现在,对于我们数据集中出现的每个术语,我们将计算一个称为术语频率的度量,逆文档频率,缩写为 tf-idf。我们将使用sklearn.feature_extraction.text.TfidfVectorizer 来计算每个消费者投诉叙述的tf-idf向量:

  • sublinear_df设置为True以使用对数形式的频率。
  • min_df是一个单词必须存在的最小文档数。
  • norm被设置为l2,以确保我们所有的特征向量具有 1 的欧几里德范数。
  • ngram_range被设置为(1, 2),表示我们既要考虑单元组,也要考虑二元组。
  • stop_words设置为"english"删除所有常用代词("a""the"、...)以减少噪声特征的数量。[1]

组合数据的 tfidf 矢量化

**Output** (1650, 3299)

现在,1650 个消费者投诉叙述中的每一个都由 3299 个特征表示,代表不同单字和双字的 tf-idf 得分。

我们可以使用sklearn.feature_selection.chi2找到与每个产品最相关的术语:

打印每种天赋最相关的单字和双字列表

您会发现下面的输出对于每种天赋都非常直观。

Flair 'AMA':
Most correlated unigrams:
	. hi
	. anything
	. ask
	. questions
	. ama
Most correlated bigrams:
	. ask us
	. us anything
	. hi reddit
	. answer questions
	. ask anything

Flair 'AskIndia':
Most correlated unigrams:
	. advice
	. dad
	. situation
	. afraid
	. family
Most correlated bigrams:
	. ive seen
	. want know
	. feel like
	. work home
	. dont want

Flair 'Business/Finance':
Most correlated unigrams:
	. firms
	. emi
	. hdfc
	. mukesh
	. bank
Most correlated bigrams:
	. credit card
	. mukesh ambani
	. share market
	. reliance jio
	. yes bank

Flair 'Food':
Most correlated unigrams:
	. restaurant
	. chutney
	. recipe
	. chicken
	. food
Most correlated bigrams:
	. im trying
	. every day
	. couldnt find
	. dont eat
	. indian food

Flair 'Non-Political':
Most correlated unigrams:
	. rural
	. dads
	. found
	. bored
	. comics
Most correlated bigrams:
	. im gonna
	. palghar lynching
	. amazon prime
	. india live
	. amid lockdown

Flair 'Photography':
Most correlated unigrams:
	. mm
	. beach
	. nikon
	. shot
	. oc
Most correlated bigrams:
	. stay home
	. equipment nikon
	. one plus
	. da mm
	. nikon da

Flair 'Policy/Economy':
Most correlated unigrams:
	. gdp
	. govt
	. investments
	. nirmala
	. economy
Most correlated bigrams:
	. health workers
	. https internetfreedomin
	. petrol diesel
	. indian economy
	. raghuram rajan

Flair 'Politics':
Most correlated unigrams:
	. sonia
	. removed
	. modi
	. arnab
	. muslims
Most correlated bigrams:
	. home minister
	. arnab goswami
	. pm modi
	. rahul gandhi
	. john oliver

Flair 'Science/Technology':
Most correlated unigrams:
	. vpn
	. iit
	. develop
	. zoom
	. users
Most correlated bigrams:
	. anyone else
	. covid virus
	. home affairs
	. ministry home
	. cow urine

Flair 'Sports':
Most correlated unigrams:
	. ipl
	. football
	. sports
	. cricket
	. cup
Most correlated bigrams:
	. india pakistan
	. know people
	. one time
	. times india
	. world cup

Flair '[R]eddiquette':
Most correlated unigrams:
	. boop
	. askaway
	. beep
	. creator
	. bot
Most correlated bigrams:
	. bot problem
	. bot bot
	. askaway creator
	. beep boop
	. discussion thread

你会发现,对于大多数 flairs 来说,最相关的单词是很有解释力的。

对输入要素和标注建模

我们的下一个任务是以分类器可以理解的方式对输入数据进行建模。我们需要将输入转换成与数字标签相关的数字向量。获得文本的向量表示后,我们可以训练监督分类器来预测用户提交的每个 Reddit 帖子的“风格”。让我们从按数据划分成训练集和测试集开始。我没有先对数据进行矢量化是有原因的,因为如果你这样做,那么你的矢量化工具会将整个数据视为样本,并基于此进行拟合。这意味着您的.fit().fit_transform()将使用整个数据进行拟合。当我们稍后拆分数据时,测试数据将基于组合的训练和测试数据进行拆分。然而,这种模式将被部署,我们没有同样的奢侈品与看不见的数据,因此,我们不能转换它的基础上综合数据。这可能会降低测试的准确性,但在我看来,从长远来看,这是一个更好的模型,因为它消除了偏见。

向量化和转换数据

在所有上述数据转换之后,现在我们已经有了所有的特征和标签,是时候训练我们的分类器了。对于这个问题,我们可以使用许多不同的分类器。我将使用四种不同类型的模型,由于本文的长度,我将只讨论可能作为良好比较的基线结果。我将会写一篇关于 Google 当前模型的 BERT 和超参数调整的文章。我将使用的模型是:-

这些分类器各有优缺点。由你来决定哪一个最适合你的需要。我将向您介绍实现和流水线化它们的过程。以下是训练数据的方法。

# Create an instance 
model = MultinomialNB()# Fit to training data
model.fit(X_train_tfidf, y_train)# Predictions on X_test_tfidf
# Obtain X_test_tfidf in the manner described above
model.predict(X_test_tfidf) 

这是很基本的,对吧?如果你曾经训练过一个简单的分类器,你一定已经这样做过很多次了。那我们学点新东西吧。

管道铺设

机器学习(ML)模型中有许多活动的部分,它们必须连接在一起,ML 模型才能成功地执行并产生结果。流水线的每一级都被馈送从其前一级处理的数据;也就是说,处理单元的输出作为输入提供给下一个步骤。在软件工程中,人们建立管道来开发从源代码到部署的软件。类似地,在 ML 中,创建管道以允许数据从其原始格式流向一些有用的信息。数据在管道中流动,就像水在管道中流动一样。掌握管道概念是创建无错误 ML 模型的一种强有力的方法,而管道是 AutoML 系统的一个至关重要的元素。它提供了一种构造多 ML 并行流水线系统的机制,以便比较几种 ML 方法的结果。[3]这是我们的管道的样子。

我们的管道流程图(用 SmartDraw 制作)

让我们从多项式朴素贝叶斯分类器开始。

nb_fit = Pipeline([(‘vect’, CountVectorizer()),
                   (‘tfidf’, TfidfTransformer()),
                   (‘clf’, MultinomialNB())])

类似地,我们可以为每个分类器创建函数,以实现更简化的方法。

制作我们的预测函数

进行预测和评估结果

使上面创建的功能模块化你的代码,使你的任务更容易。现在你可以方便地进行预测和评估结果。

print(“Evaluate Naive Bayes Classifier”)
nb_classifier(X_train, X_test, y_train, y_test)print(“Evaluate Random Forest Classifier”)
random_forest(X_train, X_test, y_train, y_test)print(“Evaluate Logistic Regression Model”)
log_reg(X_train, X_test, y_train, y_test)print(“Evaluate SVC Model”)
svc(X_train, X_test, y_train, y_test)

以下命令打印结果。根据您所使用的数据和您所做的预处理,结果可能会有所不同。这些是基线结果,后来使用超参数调整进行了临时调整。然而,这篇文章足够长,所以我将在另一篇文章中介绍它。

Evaluate Naive Bayes Classifier
Model Accuracy: 0.53951612903225806
Evaluate Random Forest Classifier
Model Accuracy: 0.6074193548387097
Evaluate Logistic Regression Model
Model Accuracy: 0.6645161290322581
Evaluate SVC Model
Model Accuracy: 0.5248387096774194

我们可以看到,逻辑回归模型似乎是最好的。然而,在超参数调优之后,这种情况会很快改变,所以我现在把这个问题留给你。现在性能低的原因有很多,包括数据质量,它们可以在下面的评论中进行很好的讨论。在下一部分中,我将为部署对这个模型进行序列化。我们还将与 Flask 合作部署我们的机器学习模型。该网络应用程序将以这样一种方式工作,用户将发布一个链接,我们将得到预测的类回来。要学习如何创建网络应用,请继续阅读第三部分。你可以在这里找到这个系列的所有文章

参考

  1. https://towards data science . com/multi-class-text-classification-with-scikit-learn-12 f1 e 60 E0 a9 f
  2. https://towards data science . com/effectively-pre-processing-the-text-data-part-1-text-cleaning-9 ecae 119 cb3e
  3. https://dzone . com/articles/how-to-build-a-simple-machine-learning-pipeline
  4. https://towards data science . com/text-mining-for-dummies-text-class ification-with-python-98e 47 C3 a9 deb

使用机器学习预测 Reddit Flairs 并使用 Heroku 部署模型—第 3 部分

原文:https://towardsdatascience.com/predicting-reddit-flairs-using-machine-learning-and-deploying-the-model-using-heroku-part-3-c3cd19374596?source=collection_archive---------61-----------------------

SpaceX 在 Unsplash 上拍摄的

REDDIT 天赋预测系列

创建 web 应用程序并部署机器学习模型

如果你被困在付费墙后面,点击这里获取我的朋友链接并查看这篇文章。

欢迎来到本系列的第 3 部分,我将继续解决 Reddit Flair 检测问题。在第 1 部分中,我讨论了问题的背景和数据收集方法,在第 2 部分中,我建立了一个机器学习模型来预测相应的 Fla。强烈建议您在开始这一篇之前通读这两篇文章,因为我已经分享了数据收集和模型构建过程背后的见解和推理。如果你已经完成了第一部分和第二部分,是时候恭喜你自己了,我真的为你完成了两个非常乏味的任务感到骄傲。你已经收集、整理、分析和模拟了大量数据,并且还建立了一个 ML 模型。大多数 ML 从业者通常在这里停下来,但是这是我们在第 3 部分中继续学习的地方。

在这一部分中,我们将继续使用我们在上一篇文章中构建的模型,并使用该模型根据 Reddit 帖子在 India subreddit 中的 URL 对任何新条目进行预测。

概述

到目前为止,我们已经使用 PRAW 图书馆收集了来自 India Subreddit 的数据。在执行文本分析后,我们尝试了 4 种机器学习模型,并根据性能选择了其中一种。我还在一个管道中转换了模型和数据预处理,以提高执行效率。我将使用逻辑回归,因为它是一个简单的模型,易于部署。这也不会在 Heroku 内部引发任何问题。你可以为此选择你自己的模型。这就是我们如何制作管道和训练模型。

model = Pipeline([(‘vect’, CountVectorizer()),
                   (‘tfidf’, TfidfTransformer()),
                   (‘model’, LogisticRegression()),
         ])# Fit Model to the Data
model.fit(X_train, y_train)

部署

部署过程有几个步骤:-

  • 保存模型
  • 创建 web 应用程序界面
  • 创建烧瓶应用程序
  • 把所有的都集中在一起

保存模型

一旦您将您的模型保存为变量model中的管道,并使其适合训练数据,现在是时候将它保存到一个文件中,以便我们稍后可以加载它以部署到我们的 web 应用程序中。我们使用一种叫做序列化的技术来保存我们的模型。简而言之,序列化是一种在磁盘上编写 python 对象的方法,该对象可以传输到任何地方,稍后可以由 python 脚本反序列化(读取)回来。有两种方法可以实现这一点[1]。

  1. 利用 腌制

图片由来自 Pixabay照片合成

当然,图片是一个笑话,但泡菜图书馆其实真的很受欢迎,超级有用。(有趣的事实:泡菜只是蘸了醋的黄瓜)。总之,Pickle 是 Python 中序列化对象的标准方式。您可以使用 pickle 操作来序列化您的机器学习算法,并将序列化格式保存到文件中。稍后,您可以加载此文件来反序列化您的模型,并使用它来进行新的预测。

使用 pickle 库保存模型

2。使用Joblib(推荐用于较大型号)

Joblib 是 SciPy 生态系统的一部分,它提供了管道化 Python 作业的工具。因此,这就是我在这个项目中使用的。它提供了实用程序来有效地保存和加载利用 NumPy 数据结构的 Python 对象

这对于保存大量参数或者有时甚至存储整个数据集的机器学习算法是有用的。对于深度学习模型,我们通常会切换到. h5 文件。

使用 joblib 库保存模型

创建 flask 应用程序及其接口。

这一步对机器学习从业者来说有些新,这就是为什么我会给出我对大多数步骤的见解。我也会尽量不要用信息轰炸你。这里的可以参考整个代码。为此,我们将使用 flask。

注意:- 这是一条非常重要的注意事项,请务必注意!很多人更喜欢下一步用 python 创建一个虚拟环境。这是因为它有助于通过为不同的项目创建独立的 python 虚拟环境来保持不同项目所需的依赖关系。这是大多数 Python 开发人员使用的最重要的工具之一。然而,对于本教程,我不是创建一个虚拟环境。如果你想创建一个虚拟环境,你可以在这里找到教程。如果您继续进行虚拟环境,那么您将需要的依赖项列表可以在这里找到。确保下载文件并在虚拟环境中运行命令。

pip install -r requirements.txtor pip3 install -r requirements.txt

这个文件对于虚拟 env 和非虚拟 env 用户都是必需的,但是,那些不使用虚拟环境的用户可能已经满足了大部分要求。

为什么是烧瓶?【2】

  • 好用。
  • 内置的开发服务器和调试器。
  • 集成单元测试支持。
  • RESTful 请求调度。
  • 大量记录。

我们开始吧!您可以在这里访问存储库

前端

让我们从使用 HTML 为用户输入帖子的 URL 的前端开始。我将保持这个相当简单和实用,因为这不是一个前端开发课程。这个页面看起来非常简单。为此你需要三个文件,我已经把它们放在模板库下面了

  1. base.html: 基础文件
  2. index.html: 接受输入的启动页面
  3. show.html: 显示结果的页面

我已经使用 Django 模板扩展前端。如果你不知道那是什么,那么你不必担心。这是一个简单的概念,通过类可以更好地理解。我已经定义了一个基础文件,它在索引和显示文件中被扩展,这样我就不必一次又一次地编写引导程序和头文件代码。基本文件从存储在名为 Flask_Bootstrap 的 Python 库中的引导基本文件中获取内容。你可以在这里阅读更多关于扩展的内容

从引导基本文件继承的基本文件

默认起始页的索引文件

这是输出的样子。我说过,这只是为了我们的效用。你可以自由添加你自己的 CSS。事实上,我对来自任何想为这个页面贡献和添加样式的人的拉请求持开放态度。

索引页

show.html 网页将按以下方式设计。当我显示弹出的结果时,我会在最后显示输出。你可以把这三个都放在模板文件夹中,而任何图像和样式都放在静态文件夹中(这是惯例)。

接收数据并显示结果的 API

下一步是创建一个 API 来接收 URL,然后在预测之后显示结果。所有这些都要通过 GUI 来完成。基本概念是,我们需要创建一个执行以下步骤的接口:-

  1. 使用表单将 URL 作为索引页面的输入
  2. 从 Reddit 网站上抓取数据
  3. 取消模型的序列化
  4. 使用反序列化的模型对数据进行预测
  5. 显示输出

现在,在一个文件中完成所有这些是可能的,但是,我认为如果有两个不同的文件,这只会使过程更加直观和灵活。当您必须通过单个文件处理多个 POST 请求时,这也很有帮助。我将创建两个文件— **app.py**文件,在这里我将通过来自index.html文件的 POST 请求从表单中获取数据,在**inference.py** 文件中我将反序列化模型并获取预测。我将把预测的类返回到app.py文件,并通过show.html文件显示结果。有道理,对吧?

获取数据并发送输出的 app.py 文件

做出预测的推论

您可以看到 app.py 文件导入了推理模块并调用了方法get_flair(text=url).。我已经将推理文件中的模型反序列化,并将其作为参数与 URL 一起发送给了方法。其他一切都发生在推理文件中。您可能已经注意到,这些是我们在第 1 部分和第 2 部分中遵循的步骤。我们下载并清理数据,然后将其发送到我们的模型,该模型对数据进行矢量化和转换。然后,该模型进行预测并返回预测的类,该类存储在第 6 行的show.html 文件选取的result变量中。

让我们来看看这个应用程序的运行情况。这是到我测试过的帖子的链接。

上传链接。

输出

如果这种风格不像这个那样来自印度 Subreddit,那么我们就用这个。

不正确的子编辑

结论

本文展示了一种部署机器学习模型的非常简单的方法。你可以利用在本博客中获得的知识制作一些很酷的模型,并投入生产。到目前为止,这是一个漫长的旅程,我们已经做了很多事情,如废弃数据、建立模型并最终部署它们。一定很忙。所以,接下来的部分不再有机器学习了。在第 4 部分中,我将讨论如何使用 Heroku 使您的应用程序上线,Heroku 是一个平台即服务(PaaS ),它使开发人员能够完全在云中构建、运行和操作应用程序。您将能够像我在这里 所做的那样 部署您的应用程序。

继续第 4 部分!本系列的最后一部分。

参考

  1. https://machine learning mastery . com/save-load-machine-learning-models-python-sci kit-learn/
  2. https://towards data science . com/how-to-easy-deploy-machine-learning-models-using-flask-b 95 af 8 Fe 34d 4

使用机器学习预测 Reddit Flairs 并使用 Heroku 部署模型—第 4 部分

原文:https://towardsdatascience.com/predicting-reddit-flairs-using-machine-learning-and-deploying-the-model-using-heroku-part-4-7d5cb923d3d3?source=collection_archive---------86-----------------------

SpaceX 在 Unsplash 上拍摄的

Reddit 天赋预测系列

在 Heroku 上部署应用程序

如果你被困在付费墙后面,点击这里获取我的朋友链接并查看这篇文章。

我真的为你骄傲!你已经完成了前面所有的部分,它们真的很重。恭喜你走到这一步。您已经收集了自己的数据,对其建模,对其进行预测,并且您还使用 web 应用程序在部分 1 23 中部署了模型。经过这么多努力,我认为你的模型值得让全世界看到。Heroku 会帮你的。

背景

Heroku 是一个平台即服务(PaaS ),支持开发者完全在云中构建、运行和操作应用。你可以很容易地从一个想法到获得应用程序自己的 URL,而不用担心基础设施的细节。基本上,你可以毫不费力地获得一个应用网站。让我们开始吧。

部署

这是一个循序渐进的教程,我会带你走过这一切。从设置帐户到部署应用程序。所以,跟着走。

1.设立一个账户

第一步是建立一个 Heroku 帐号,这样你就可以访问他们的基础设施和 GUI。在线使用 Heroku 客户端也是部署应用程序的一种简单和交互式的方式,但我们是程序员,所以我们将使用终端,因为它更灵活,老实说,更酷!

您可以通过此链接设置您的帐户。填写完所有个人信息后,将您的主要开发语言设置为 Python。不要担心,这不是本质上的限制,你以后也可以用其他语言和框架部署应用程序。一旦您填写了这些详细信息,您将收到一封电子邮件来设置您的密码。

Heroku 注册页面

2.下载 Heroku 命令行界面(CLI)

Heroku 命令行界面(CLI)使得直接从终端创建和管理 Heroku 应用程序变得简单。这是使用 Heroku 的重要部分。

注意:Heroku CLI 需要 Git ,流行的版本控制系统。所以,如果你没有安装 git,先做那个。我在我的 Linux 终端上使用了 Heroku。如果你使用的是 MacOS,那么命令几乎是相似的。对于 Windows,您必须下载并安装将与您的 PowerShell 无缝集成的应用程序。同样,它将与您的 Linux 或 Mac shells 集成。确保您的 PowerShell 以管理员权限运行。

一旦外壳被打开,我们需要鉴定 Heroku。

$ heroku login

这会将您重定向到一个新的浏览器窗口,您可以在其中登录并添加您的详细信息(如果需要)。

登录窗口

3.创建并初始化 git 存储库

这是一项非常关键的任务,因为 Heroku CLI 从 GitHub 或本地 git 存储库中获取变更。如果您已经创建了一个初始化的 git 存储库,那么您可以跳过这一部分,直接从

步骤 1:进入项目目录。我的目录名为 reddit-flair-predictor,保存在我的 Dekstop 上。

$ cd Desktop\reddit-flair-predictor

步骤 2: 在 GitHub 上创建一个新的存储库。为了避免错误,不要用自述文件、许可证或gitignore文件初始化新的存储库。您可以在您的项目被推送到 GitHub 后添加这些文件。

步骤 3:将本地目录初始化为 Git 存储库。

$ git init

步骤 4:将文件添加到新的本地存储库中,并第一次提交到存储库中。

$ git add . 
$ git commit -m "My First Commit"

步骤 5:在 GitHub 存储库的快速设置页面顶部,点击复制远程存储库 URL。一旦复制完毕,添加远程存储库的URL,您的本地存储库将被推送至该存储库。

复制存储库 URL

$ git remote add origin *remote repository URL*# Verify the new remote URL 
$ git remote -v

步骤 6:将更改推送到 GitHub

$ git push origin master

4.创建和设置虚拟环境[可选]

在第 3 部分中,我已经讨论了使用虚拟环境的一些优点和缺点,现在我就不再赘述了。你可以在这里阅读虚拟环境设置。如果您决定使用虚拟环境,那么建议您也安装这个文件,它包含项目的依赖列表。

5.安装依赖项

这个项目需要的一个新库是 Gunicorn 。它是一个 Python Web 服务器网关接口 HTTP 服务器,广泛兼容各种 Web 框架,实现简单,占用服务器资源少,速度相当快。

$ pip install gunicorn

下一步是创建一个 Procfile 。Heroku 应用程序包括一个 Procfile ,它指定了应用程序在启动时执行的命令。请注意,Procfile 始终是一个简单的文本文件,名为Procfile ,没有文件扩展名。比如Procfile.txt不是有效。Procfile 包含以下代码行。

web: gunicorn app:app — log-file=-

6.创建 Heroku 应用程序

第一步是设置您的构建包。Buildpacks 负责将部署的代码转换成 slug,然后可以在 dyno 上执行。构建包由一组脚本组成,根据编程语言的不同,脚本将检索依赖项、输出生成的资产或编译的代码,等等。

$ heroku buildpacks:set heroku/python 

这有可能导致错误。在这种情况下,您可以在应用程序创建期间设置 buildpack。

一旦构建包设置好了,我们就可以用应用名reddit-flair-app.来创建我们的应用了,这个名字有可能不可用,所以你必须调整它,无论你喜欢什么。

$ heroku create reddit-flair-app

如果以前不工作,您也可以在创建应用程序的过程中设置构建包。

$ heroku create reddit-flair-app --buildpack heroku/python

一旦创建命令运行,您将能够看到 2 个 URL。第一个 URL 显示应用程序可用的链接,而第二个 URL 是远程 git 存储库 URL;默认情况下,heroku create命令会自动添加一个名为“heroku”的 git 遥控器,指向这个 URL。这是一个 git 端点,我们也可以在这里推送我们的代码。

**https://****reddit-flair-app****.herokuapp.com/** | 
**https://git.heroku.com/****reddit-flair-app****.git**

当你点击链接时,你会看到这个窗口。这意味着应用程序已成功创建,占位符应用程序正在显示。

应用程序创建成功

我们需要将我们的代码从本地 git 存储库推到 heroku 存储库,以显示 web 应用程序。要确认您正在推送正确的 repo,请运行以下命令。

$ git remote -v 

如果它显示以下内容,则意味着您的遥控器设置正确,这意味着代码将被推送到 heroku repo。

heroku  https://git.heroku.com/reddit-flair-app.git (fetch)
heroku  https://git.heroku.com/reddit-flair-app.git (push)

如果没有显示,您可以使用此命令更换遥控器。

$ heroku git:remote -a reddit-flair-app

最后,将代码推送到 Heroku 存储库,让它在线显示,并等待一段时间。

$ git push heroku master 

最后一步是给你的应用分配一个 dyno 。Dynos 是为任何 Heroku 应用程序提供动力的构建模块,用外行人的话来说就是充当应用程序的服务器。

$ heroku ps:scale web=1

您可以单击您的 URL,也可以从 CLI 打开您的应用程序。

$ heroku open

由于免费的 dynos 是有限的,你也可以关闭你的应用程序。

$ heroku ps:scale web=0

这就把我带到了本系列教程的结尾。如果你坚持到最后真的很棒,如果这是一次很好的学习经历,因为这对我来说肯定是一次很好的经历。

参考

  1. https://help . github . com/en/github/importing-your-projects-to-github/add-an-existing-a-project-to-github-using-the-command-line
posted @ 2024-10-14 11:53  绝不原创的飞龙  阅读(195)  评论(0)    收藏  举报