一条鱼 2018-05-25
机器学习可以用来预测未来。您可以提供一个包含一组训练实例的模型,将该模型拟合到该数据集上,然后将该模型应用于新实例以进行预测。预测建模对创业公司非常有用,因为您可以根据预期的用户行为制定适应的产品。例如,如果观众持续观看流媒体服务上的同一个广播公司,则应用程序可以在应用程序启动时加载该频道。预测模型也可以用来构建数据产品,比如可以向观众推荐新广播公司的推荐系统。
这篇文章简要介绍了机器学习的预测建模。我将讨论不同类型的预测问题,并介绍一些常用的方法,介绍使用开放工具和脚本语言构建模型的方法,并提供聚类应用示例。本文的目标不是提供对特定方法的深入理解,而是展示如何使用各种工具快速对不同类型的模型进行原型设计。
机器学习模型通常分为两类:监督学习和无监督学习。对于受监督的问题,用于拟合模型的数据具有指定的标签或目标变量。例如,如果目标是确定手机游戏中的哪些用户有可能成为购买者,那么我们可以使用过去用户的交易数据作为标签,其中1代表付费用户,0代表免费用户。该标签被用作监督算法的输入,以在将模型拟合到训练数据集时提供反馈。分类和回归算法是两类监督学习。在分类任务中,目标是预测结果的可能性,例如移动游戏用户是否会进行购买。对于回归,目标是预测一个连续变量,
对于无监督问题,不提供明确的标签来训练模型。最常见的无监督学习方法是聚类,它通过在数据集中形成不同实例的组来推断标签。群集对于回答细分问题很有用,比如产品应该支持哪些不同的用户原型。
还有两种其他类型的机器学习模型,我不会在这里讨论:半监督学习和强化学习。半监督学习是一个过程,可以将目标标签识别为培训过程的一部分,并且通常通过深度学习中的自编码器实施。强化学习是根据奖励政策进行更新的模型,其中模型采取的行动提供积极和消极的反馈信号并用于更新模型。
对于初创公司而言,您很可能会开始使用分类和回归模型,这些模型通常被称为经典或浅机器学习问题。有各种不同的方法可以使用。一些常见的分类方法是逻辑回归,朴素贝叶斯,决策树和集合方法,如随机森林和XGBoost。常见的回归方法包括许多与分类相同的方法,但使用线性回归来代替逻辑回归。当十年前我在读研究生时,支持矢量机器很受欢迎,但现在XGBoost似乎是浅层学习问题之王。
了解不同算法的实现方式非常重要,因为如果要将预测模型作为产品的一部分提供,它需要具有可靠性和可扩展性。一般来说,在运送产品时,热衷模式比懒惰模式更受欢迎。热切模型是生成规则集作为训练过程一部分的方法,例如线性回归模型中的系数,而惰性模型在运行时生成规则集。例如,最近邻居(k-NN)模型是一种懒惰的方法。惰性方法通常用于构建在线学习系统,其中模型在部署时经常使用新数据进行更新,但可能存在可扩展性问题。
如何评估预测模型的性能取决于正在执行的问题的类型。例如,平均绝对误差(MAE),均方根误差(RMSE)和相关系数等指标可用于评估回归模型,而曲线下的ROC区域(AUC),精确度,召回率和提升量都很有用用于分类问题。
本节介绍可用于构建分类模型的几种不同方法。我们将使用与EDA上的过去文章相同的数据集,但不是预测Natality数据集中的出生体重,我们将尝试预测哪些怀孕会导致双胞胎而不是单身。
首先,我们需要在本地提取一个数据集,以便将其用作不同工具的输入。下面的R代码显示了如何抽样10万次怀孕并将数据帧保存为CSV。这个查询类似于过去发布的查询,但是我在where子句中包含了额外的约束,以避免提取缺少(NA)值的记录。
library(bigrquery)
project <- "your_project_id"
options(stringsAsFactors = FALSE)
sql <- "SELECT year, mother_age, father_age, gestation_weeks
,case when ever_born > 0 then ever_born else 0 end as ever_born
,case when mother_married then 1 else 0 end as mother_married
,weight_pounds
,case when plurality = 2 then 1 else 0 end as label
FROM `bigquery-public-data.samples.natality`
where plurality in (1, 2) and gestation_weeks between 1 and 90
and weight_pounds between 1 and 20
order by rand()
LIMIT 100000"
df <- query_exec(sql, project = project, use_legacy_sql = FALSE)
write.csv(df, "natality.csv", row.names = FALSE)
这个数据集的一个挑战是,在这个数据集合中有更多的负面例子,而不是正面的例子。在抽样数据中,只有2.4%的孕妇有“1”的标签,这意味着双胞胎。这意味着我们需要使用其他指标来衡量不同方法的性能。对于像这样的大的类不平衡问题,准确性并不是一个好的度量标准,因为预测每个记录的0的标签结果的准确性为97.6%。相反,我们将使用AUC曲线度量来评估不同的模型,因为它对于处理不平衡类的问题很有用。
评估不同模型时的另一个考虑是使用不同的培训、测试和holdout数据集。将holdout数据集保留到模型训练过程的结束,并且只使用一次进行评估。培训和测试数据集可以在构建和优化模型时经常使用。方法如10倍交叉验证对建立模型性能的稳健估计是有用的。这通常是我在构建模型时所采用的方法,但是为了简便起见,在下面的所有例子中都没有涉及到。
我喜欢用于探索性分析和评估不同建模算法的工具之一是Weka,它使用Java实现,并提供用于探索不同模型的GUI。现在有点过时了,但我仍然发现它对于快速挖掘数据集并确定是否有大量可用于预测结果的信号非常有用。
上面的图表显示了数据集中不同特征的可视化。红色数据点代表正面例子(双胞胎),蓝色数据点代表负面例子(单例)。对于具有强信号的特征,通常可以绘制一条垂直线,将大部分红色和蓝色数据点分开。这个数据集不是这种情况,我们需要结合不同的功能来构建一个好的分类器。
我使用Weka探索以下算法,并在使用10倍交叉验证时计算AUC指标:
Logistic: 0.892
Naive Bayes: 0.893
LogitBoost: 0.908
我研究的算法中性能最好的算法是LogitBoost。该算法具有许多超参数,例如迭代次数,可以进行调整以进一步提高模型的性能。Weka中可能有其他算法在这个数据集上工作得更好,但是我们最初的探索导致了很有前途的结果。
上图显示了逻辑回归模型的ROC曲线的可视化。Weka还可以探索逻辑回归模型中不同特征的重要性。您可以直接检查模型的系数。例如,weight_pounds具有0.93的最高系数值。也可以使用InfoGain属性排序器确定哪些要素对于此分类任务最重要。Weka发现weight_pounds(0.0415)是最具影响力的特征,其次是gestation_weeks(0.0243)。
Weka通常不是产品化模型的最佳选择,但它确实为探索各种不同的算法提供了有用的工具。
我在启动体验中使用的另一个工具是BigML。该工具与Weka类似,因为它提供了一个GUI(基于Web),用于探索不同类型的模型,而不需要任何编码。该工具的选项比Weka少,但具有更新的模型,如DeepNets。
上图显示了BigML提供的一个重要功能工具。这些工具对于了解哪些功能可用于预测结果很有用。我用BigML探索了两种不同的模型,得出以下AUC指标:
Logistic: 0.890
DeepNet: 0.902
我没有使用10倍交叉验证,而是使用单个80/20的数据分割来评估不同的模型。BigML中模型的性能与Weka类似,但与LogitBoost的性能不太匹配。
除了绘制ROC曲线(如上所示)之外,BigML还可以绘制其他有用的可视化对象,例如升降图。BigML还提供了有用的分类度量标准,如精度,召回率和F1分数。
我们可以实现我们已经在R中使用glm库进行评估的逻辑回归模型。通过将二项系列指定为输入,可以将广义线性模型函数应用于逻辑回归。加载CSV并训练逻辑回归模型的R代码如下所示。
df <- read.csv("Natality.csv")
fit <- glm(label ~ .,family=binomial(),data=df)
fit
library(Deducer)
rocplot(fit)
拟合模型后,拟合声明输出模型的系数。为了评估模型的性能,我使用了包含rocplot函数的Deducer库。对于这种基本的模型拟合方法,我没有执行任何交叉验证。训练数据集的结果是AUC为0.890。
为了在R中拟合逻辑回归模型时使用正则化,我们可以使用glmnet库,它提供了lasso和ridge回归。下面的代码中显示了一个使用此包来评估特性重要性的示例:
library(glmnet)
x <- sparse.model.matrix(label ~ ., data = df)
y <- as.factor(df$label)
fit = glmnet(x, y, family = "binomial")
plot(fit, xvar = "dev", label = TRUE)
默认情况下,“最小二乘”模型用于拟合训练数据。下面的图表显示了模型的系数如何随着附加因素被用作模型的输入而变化。最初,只有weight_pounds功能被用作输入。一旦这个词开始受到惩罚,在-0.6的值附近,模型会考虑附加特征。
cvfit = cv.glmnet(x, y, family = "binomial", type.measure = "auc")
cat(paste("ROC:", max(cvfit$cvlo)))
plot(cvfit)
glmnet软件包提供了一个内置的交叉验证功能,可用于针对不同的指标(如AUC)进行优化。上面的R代码显示了如何使用此功能训练逻辑回归模型,并将结果绘制在下图所示的图中。正则化逻辑回归模型的AUC指标为0.893。
本节中我想讨论的另一个工具是scikit-learn,因为它提供了一种探索不同类型模型准确性的标准方法。到目前为止,我一直专注于R模型拟合和EDA,但通过scikit-learn提供的Python工具非常有用。
# load the data set
import pandas as pd
df = pd.read_csv('./Natality.csv')
# build a random forest classifier
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier()
x = df.drop('label', axis=1)
y = df['label']
rf.fit(x, y)
# evaluate the results
from sklearn.metrics import roc_curve, auc
false_positive_rate, true_positive_rate, _ = roc_curve(y, rf.predict(x))
roc_auc = auc(false_positive_rate, true_positive_rate)
# plot the curve
import matplotlib.pyplot as plt
plt.plot(false_positive_rate, true_positive_rate,
'b', label='AUC = %0.2f'% roc_auc)
plt.legend(loc='lower right')
plt.show()
上面的Python代码展示了如何使用熊猫读取数据框,使用sklearn来拟合随机森林模型,评估模型的性能并绘制结果,如下图所示。对于这个模型,我在评估模型时没有应用任何交叉验证。使用scikit-learn的好处之一是适合度和评分函数在不同的算法中是一致的,这使得探索不同的选项变得微不足道。
对初创公司有用的分析类型之一是了解是否存在不同的细分市场或用户群。这类工作的一般方法是首先识别数据中的群集,为这些群集分配标签,然后根据标记的群集将标签分配给新记录。本节介绍如何使用2016年美联储消费者财务调查数据(https://www.federalreserve.gov/econres/scfindex.htm)执行此类流程,
调查数据集提供了美国数千户家庭的资产明细。这次clustering exercise 的目标是确定是否有不同类型的富裕家庭,净值为100万美元+美元。Jupyter笔记本提供了加载数据和执行分析的完整代码。
对于每个被调查的家庭,我们都有许多专栏,详细说明如何为家庭分配资产,包括住宅和商业房地产,商业股权,退休和其他许多资产。我们想要做的第一件事就是确定哪些资产对群集用户有强烈的信号。我们可以使用PCA和一个因子图来实现这个目标:
# filter on affluent households, and print the total number
affluent <- households[households$netWorth >= 1000000 ]
cat(paste("Affluent Households: ", floor(sum(affluent$weight))))
# plot a Factor Map of assets
fviz_pca_var(PCA(affluent, graph = FALSE), col.var="contrib",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"), repel = TRUE)+
labs(title ="Affluent Households - Assets Factor Map")
下面显示的结果显示,富裕家庭中存在几个不同的资产组。最重要的因素是商业资产。其他一些因素包括投资资产(股票,债券)和房地产资产/退休基金。
要使用多少个clusters ?
我们现在已经显示出有迹象表明存在不同类型的百万富翁,并且资产根据净值部分而不同。为了理解资产配置如何根据净值区间而不同,我们可以使用聚类分析。我们首先在富裕的调查对象中确定clusters ,然后将这些标签应用于调查对象的总体人群。
k <- 7
res.hc <- eclust(households[sample(nrow(households), 1000) ],
"hclust", k = k, graph = FALSE)
fviz_dend(res.hc, rect = TRUE, show_labels = FALSE)
为了确定要使用多少个clusters,我使用上面的代码片段创建了cluster 树状图。结果如下图所示。我还改变了聚类数量k,直到我们拥有数量最多的明显可识别的聚类。
cluster 描述
现在我们已经确定了要使用多少个clusters,检查clusters并根据功能集分配定性标签很有用。下面的代码片段展示了如何计算7个不同cluster的平均特征值。
groups <- clarax$clustering
results <- as.data.frame(t(aggregate(affluent,list(groups),mean)))
results[2:18]
该代码块的结果如下所示。基于这些结果,我们提出了以下群体描述:
V1:股票/债券 - 资产的31%,其次是家庭和共同基金
V2:多元化 - 53%的房产,10%的家庭和9%的其他房地产
V3:住宅不动产 - 资产的48%
V4:共同基金 - 资产的50%
V5:退休 - 资产的48%
V6:商业资产 - 85%的资产
V7:商业地产 - 59%的资产
除群V7仅包含3%的人口外,大多数群体的规模相对均匀。第二小群代表12%的人口,而最大的群代表20%。您可以使用表(组)来显示未加权的群集群体大小
按净值
区分的群体人口本分析的最后一步是将不同的群体分配应用于总体人口,并按净值部分对人群进行分组。由于我们仅对富裕家庭进行了群体训练,因此我们需要使用分类算法来标记人口中的非富裕家庭。下面的代码片段使用knn来完成这个任务。剩余的代码块计算每个净值区段被分类为每个群体的家庭数量。
# assign all of the households to a cluster
groups <- knn(train = affluent, test = households,
cl = clarax$clustering, k = k, prob = T, use.all = T)
# figure out how many households are in each cluster
clusters <- data.frame(
c1 = ifelse(groups == 1, weights, 0),
...
c7 = ifelse(groups == 7, weights, 0)
)
# assign each household to a net worth cluster
nw <- floor(2*log10(nwHouseholds))/2
results <- as.data.frame(t(aggregate(clusters,list(nw),sum)))
# compute the number of households that belong to each segment
results$V1 <- results$V1/sum(ifelse(nw == 4, weights, 0))
...
results$V11 <- results$V11/sum(ifelse(nw == 9, weights, 0))
# plot the results
plot <- plot_ly(results, x = ~10^Group.1, y = ~100*c1, type = 'scatter', mode = 'lines', name = "Stocks") %>%
add_trace(y = ~100*c2, name = "Diversified") %>%
...
add_trace(y = ~100*c7, name = "Commercial R.E.") %>%
layout(yaxis = list(title = '% of Households', ticksuffix = "%"),
xaxis = list(title = "Net Worth ($)", type = "log"),
title = "Cluster Populations by Net Worth")
这个过程的结果如下图所示。该图显示了一些显而易见的和一些新颖的结果:房屋所有权和退休基金占非富裕家庭的大部分资产,相对均匀的大约200万美元的组合(不包括商业房地产和商业股权)和商业股权支配着超富裕家庭的净资产,其次是其他投资资产。
对于这个聚类示例,我探索了调查数据并确定了七种不同类型的富裕家庭。然后,我使用这些群集为其余家庭分配标签。在启动时可以使用类似的方法将分割标签分配给用户群。
预测建模是机器学习的一个应用,可以使用各种可用于开始的工具。在构建预测模型时首先要考虑的事情之一是确定您尝试预测的结果,并建立您将用来衡量成功的指标。